4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 only,
8 * as published by the Free Software Foundation.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License version 2 for more details (a copy is included
14 * in the LICENSE file that accompanied this code).
16 * You should have received a copy of the GNU General Public License
17 * version 2 along with this program; If not, see
18 * http://www.gnu.org/licenses/gpl-2.0.html
23 * Copyright (c) 2017, DataDirect Networks Storage.
24 * Copyright (c) 2017, Intel Corporation.
27 * This file is part of Lustre, http://www.lustre.org/
29 * lustre/utils/lfs_project.c
31 * Author: Wang Shilong <wshilong@ddn.com>
32 * Author: Fan Yong <fan.yong@intel.com>
45 #include <sys/types.h>
47 #include <libcfs/util/list.h>
48 #include <libcfs/util/ioctl.h>
49 #include <sys/ioctl.h>
51 #include "lfs_project.h"
52 #include <lustre/lustreapi.h>
54 struct lfs_project_item {
55 struct list_head lpi_list;
56 char lpi_pathname[PATH_MAX];
60 lfs_project_item_alloc(struct list_head *head, const char *pathname)
62 struct lfs_project_item *lpi;
64 lpi = malloc(sizeof(struct lfs_project_item));
67 "%s: cannot allocate project item for '%s': %s\n",
68 progname, pathname, strerror(ENOMEM));
72 strncpy(lpi->lpi_pathname, pathname, sizeof(lpi->lpi_pathname));
73 list_add_tail(&lpi->lpi_list, head);
78 static int project_get_xattr(const char *pathname, struct fsxattr *fsx)
82 fd = open(pathname, O_RDONLY | O_NOCTTY);
84 fprintf(stderr, "%s: failed to open '%s': %s\n",
85 progname, pathname, strerror(errno));
89 ret = ioctl(fd, LL_IOC_FSGETXATTR, fsx);
91 fprintf(stderr, "%s: failed to get xattr for '%s': %s\n",
92 progname, pathname, strerror(errno));
99 project_check_one(const char *pathname, struct project_handle_control *phc)
105 ret = stat(pathname, &st);
107 fprintf(stderr, "%s: failed to stat '%s': %s\n",
108 progname, pathname, strerror(errno));
112 ret = project_get_xattr(pathname, &fsx);
116 /* use top directory's project ID if not specified */
117 if (!phc->assign_projid) {
118 phc->assign_projid = true;
119 phc->projid = fsx.fsx_projid;
122 if (!(fsx.fsx_xflags & LL_PROJINHERIT_FL)) {
124 printf("%s%c", pathname, '\0');
127 printf("%s - project inheritance flag is not set\n",
131 if (fsx.fsx_projid != phc->projid) {
133 printf("%s%c", pathname, '\0');
136 printf("%s - project identifier is not set (inode=%u, tree=%u)\n",
137 pathname, fsx.fsx_projid, phc->projid);
145 project_list_one(const char *pathname, struct project_handle_control *phc)
150 ret = project_get_xattr(pathname, &fsx);
154 printf("%5u %c %s\n", fsx.fsx_projid,
155 (fsx.fsx_xflags & LL_PROJINHERIT_FL) ?
156 'P' : '-', pathname);
163 project_set_one(const char *pathname, struct project_handle_control *phc)
168 fd = project_get_xattr(pathname, &fsx);
172 if ((!phc->set_projid || fsx.fsx_projid == phc->projid) &&
173 (!phc->set_inherit || (fsx.fsx_xflags & LL_PROJINHERIT_FL)))
176 if (phc->set_inherit)
177 fsx.fsx_xflags |= LL_PROJINHERIT_FL;
179 fsx.fsx_projid = phc->projid;
181 ret = ioctl(fd, LL_IOC_FSSETXATTR, &fsx);
183 fprintf(stderr, "%s: failed to set xattr for '%s': %s\n",
184 progname, pathname, strerror(errno));
191 project_clear_one(const char *pathname, struct project_handle_control *phc)
196 fd = project_get_xattr(pathname, &fsx);
200 if ((!(fsx.fsx_xflags & LL_PROJINHERIT_FL)) &&
201 (fsx.fsx_projid == 0 || phc->keep_projid))
204 fsx.fsx_xflags &= ~LL_PROJINHERIT_FL;
205 if (!phc->keep_projid)
208 ret = ioctl(fd, LL_IOC_FSSETXATTR, &fsx);
210 fprintf(stderr, "%s: failed to set xattr for '%s': %s\n",
211 progname, pathname, strerror(errno));
218 lfs_project_handle_dir(struct list_head *head, const char *pathname,
219 struct project_handle_control *phc,
220 int (*func)(const char *,
221 struct project_handle_control *))
223 char fullname[PATH_MAX];
228 dir = opendir(pathname);
231 fprintf(stderr, "%s: failed to opendir '%s': %s\n",
232 progname, pathname, strerror(-ret));
236 while (ret == 0 && (ent = readdir(dir)) != NULL) {
237 /* skip "." and ".." */
238 if (strcmp(ent->d_name, ".") == 0 ||
239 strcmp(ent->d_name, "..") == 0)
242 if (strlen(ent->d_name) + strlen(pathname) >=
243 sizeof(fullname) + 1) {
245 errno = ENAMETOOLONG;
248 snprintf(fullname, PATH_MAX, "%s/%s", pathname,
251 ret = func(fullname, phc);
252 if (phc->recursive && ret == 0 && ent->d_type == DT_DIR)
253 ret = lfs_project_item_alloc(head, fullname);
257 fprintf(stderr, "%s: failed to handle dir '%s': %s\n",
258 progname, pathname, strerror(errno));
264 static int lfs_project_iterate(const char *pathname,
265 struct project_handle_control *phc,
266 int (*func)(const char *,
267 struct project_handle_control *))
269 struct lfs_project_item *lpi;
270 struct list_head head;
275 ret = stat(pathname, &st);
277 fprintf(stderr, "%s: failed to stat '%s': %s\n",
278 progname, pathname, strerror(errno));
282 /* list opeation will skip top directory in default */
283 if (!S_ISDIR(st.st_mode) || phc->dironly ||
284 project_list_one != func)
285 ret = func(pathname, phc);
287 /* dironly first, recursive will be ignored */
288 if (!S_ISDIR(st.st_mode) || phc->dironly || ret)
291 INIT_LIST_HEAD(&head);
292 ret = lfs_project_item_alloc(&head, pathname);
296 while (!list_empty(&head)) {
297 lpi = list_entry(head.next, struct lfs_project_item, lpi_list);
298 list_del(&lpi->lpi_list);
300 ret = lfs_project_handle_dir(&head, lpi->lpi_pathname,
302 /* only ignore ENOENT error if this is
303 * not top directory. */
304 if (ret == -ENOENT && !top_dir)
315 inline int lfs_project_check(const char *pathname,
316 struct project_handle_control *phc)
318 return lfs_project_iterate(pathname, phc, project_check_one);
321 inline int lfs_project_clear(const char *pathname,
322 struct project_handle_control *phc)
324 return lfs_project_iterate(pathname, phc, project_clear_one);
327 inline int lfs_project_set(const char *pathname,
328 struct project_handle_control *phc)
330 return lfs_project_iterate(pathname, phc, project_set_one);
333 inline int lfs_project_list(const char *pathname,
334 struct project_handle_control *phc)
336 return lfs_project_iterate(pathname, phc, project_list_one);