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>
56 struct lfs_project_item {
57 struct list_head lpi_list;
62 lfs_project_item_alloc(struct list_head *head, const char *pathname)
64 struct lfs_project_item *lpi;
66 lpi = malloc(sizeof(struct lfs_project_item));
69 "%s: cannot allocate project item for '%s': %s\n",
70 progname, pathname, strerror(ENOMEM));
74 lpi->lpi_pathname = strdup(pathname);
75 if (!lpi->lpi_pathname) {
79 list_add_tail(&lpi->lpi_list, head);
84 static const char *mode_to_type(mode_t mode)
86 switch (mode & S_IFMT) {
87 case S_IFDIR: return "dir";
88 case S_IFREG: return "regular";
89 case S_IFLNK: return "symlink";
90 case S_IFCHR: return "char device";
91 case S_IFBLK: return "block device";
92 case S_IFIFO: return "fifo";
93 case S_IFSOCK: return "sock";
99 static int project_get_xattr(const char *pathname, struct fsxattr *fsx,
104 ret = lstat(pathname, st);
106 fprintf(stderr, "%s: failed to stat '%s': %s\n",
107 progname, pathname, strerror(errno));
111 /* currently, only file and dir supported */
112 if (!S_ISREG(st->st_mode) && !S_ISDIR(st->st_mode)) {
114 fprintf(stderr, "%s: unable to get xattr for %s '%s': %s\n",
115 progname, mode_to_type(st->st_mode), pathname,
120 fd = open(pathname, O_RDONLY | O_NOCTTY | O_NDELAY);
122 fprintf(stderr, "%s: failed to open '%s': %s\n",
123 progname, pathname, strerror(errno));
127 ret = ioctl(fd, FS_IOC_FSGETXATTR, fsx);
129 fprintf(stderr, "%s: failed to get xattr for '%s': %s\n",
130 progname, pathname, strerror(errno));
138 project_check_one(const char *pathname, struct project_handle_control *phc)
144 ret = project_get_xattr(pathname, &fsx, &st);
148 /* use top directory's project ID if not specified */
149 if (!phc->assign_projid) {
150 phc->assign_projid = true;
151 phc->projid = fsx.fsx_projid;
154 if (!(fsx.fsx_xflags & FS_XFLAG_PROJINHERIT) &&
155 S_ISDIR(st.st_mode)) {
157 printf("%s%c", pathname, '\0');
160 printf("%s - project inheritance flag is not set\n",
164 if (fsx.fsx_projid != phc->projid) {
166 printf("%s%c", pathname, '\0');
169 printf("%s - project identifier is not set (inode=%u, tree=%u)\n",
170 pathname, fsx.fsx_projid, phc->projid);
178 project_list_one(const char *pathname, struct project_handle_control *phc)
184 ret = project_get_xattr(pathname, &fsx, &st);
188 printf("%5u %c %s\n", fsx.fsx_projid,
189 (fsx.fsx_xflags & FS_XFLAG_PROJINHERIT) ?
190 'P' : '-', pathname);
197 project_set_one(const char *pathname, struct project_handle_control *phc)
203 fd = project_get_xattr(pathname, &fsx, &st);
207 if ((!phc->set_projid || fsx.fsx_projid == phc->projid) &&
208 (!phc->set_inherit || (fsx.fsx_xflags & FS_XFLAG_PROJINHERIT)))
211 if (phc->set_inherit)
212 fsx.fsx_xflags |= FS_XFLAG_PROJINHERIT;
214 fsx.fsx_projid = phc->projid;
216 ret = ioctl(fd, FS_IOC_FSSETXATTR, &fsx);
218 fprintf(stderr, "%s: failed to set xattr for '%s': %s\n",
219 progname, pathname, strerror(errno));
226 project_clear_one(const char *pathname, struct project_handle_control *phc)
232 fd = project_get_xattr(pathname, &fsx, &st);
236 if ((!(fsx.fsx_xflags & FS_XFLAG_PROJINHERIT)) &&
237 (fsx.fsx_projid == 0 || phc->keep_projid))
240 fsx.fsx_xflags &= ~FS_XFLAG_PROJINHERIT;
241 if (!phc->keep_projid)
244 ret = ioctl(fd, FS_IOC_FSSETXATTR, &fsx);
246 fprintf(stderr, "%s: failed to set xattr for '%s': %s\n",
247 progname, pathname, strerror(errno));
254 lfs_project_handle_dir(struct list_head *head, const char *pathname,
255 struct project_handle_control *phc,
256 int (*func)(const char *,
257 struct project_handle_control *))
259 char fullname[PATH_MAX];
265 dir = opendir(pathname);
268 fprintf(stderr, "%s: failed to opendir '%s': %s\n",
269 progname, pathname, strerror(-ret));
273 while ((ent = readdir(dir)) != NULL) {
274 /* skip "." and ".." */
275 if (strcmp(ent->d_name, ".") == 0 ||
276 strcmp(ent->d_name, "..") == 0)
279 if (strlen(ent->d_name) + strlen(pathname) + 1 >=
282 errno = ENAMETOOLONG;
283 fprintf(stderr, "%s: ignored too long path: %s/%s\n",
284 progname, pathname, ent->d_name);
287 snprintf(fullname, PATH_MAX, "%s/%s", pathname,
290 rc = func(fullname, phc);
293 if (phc->recursive && ent->d_type == DT_DIR) {
294 rc = lfs_project_item_alloc(head, fullname);
304 static int lfs_project_iterate(const char *pathname,
305 struct project_handle_control *phc,
306 int (*func)(const char *,
307 struct project_handle_control *))
309 struct lfs_project_item *lpi;
310 struct list_head head;
315 ret = stat(pathname, &st);
317 fprintf(stderr, "%s: failed to stat '%s': %s\n",
318 progname, pathname, strerror(errno));
322 /* list opeation will skip top directory in default */
323 if (!S_ISDIR(st.st_mode) || phc->dironly ||
324 project_list_one != func)
325 ret = func(pathname, phc);
327 /* dironly first, recursive will be ignored */
328 if (!S_ISDIR(st.st_mode) || phc->dironly || ret)
331 INIT_LIST_HEAD(&head);
332 ret = lfs_project_item_alloc(&head, pathname);
336 while (!list_empty(&head)) {
337 lpi = list_entry(head.next, struct lfs_project_item, lpi_list);
338 list_del(&lpi->lpi_list);
339 rc = lfs_project_handle_dir(&head, lpi->lpi_pathname,
343 free(lpi->lpi_pathname);
351 int lfs_project_check(const char *pathname,
352 struct project_handle_control *phc)
354 return lfs_project_iterate(pathname, phc, project_check_one);
357 int lfs_project_clear(const char *pathname,
358 struct project_handle_control *phc)
360 return lfs_project_iterate(pathname, phc, project_clear_one);
363 int lfs_project_set(const char *pathname,
364 struct project_handle_control *phc)
366 return lfs_project_iterate(pathname, phc, project_set_one);
369 int lfs_project_list(const char *pathname,
370 struct project_handle_control *phc)
372 return lfs_project_iterate(pathname, phc, project_list_one);