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>
52 #include "lfs_project.h"
53 #include <lustre/lustreapi.h>
57 struct lfs_project_item {
58 struct list_head lpi_list;
63 lfs_project_item_alloc(struct list_head *head, const char *pathname)
65 struct lfs_project_item *lpi;
67 lpi = malloc(sizeof(struct lfs_project_item));
70 "%s: cannot allocate project item for '%s': %s\n",
71 progname, pathname, strerror(ENOMEM));
75 lpi->lpi_pathname = strdup(pathname);
76 if (!lpi->lpi_pathname) {
80 list_add_tail(&lpi->lpi_list, head);
85 static int project_get_fsxattr(const char *pathname, struct fsxattr *fsx,
86 struct stat *st, char *ret_bname)
89 char dname_path[PATH_MAX + 1] = { 0 };
90 char bname_path[PATH_MAX + 1] = { 0 };
92 struct lu_project lu_project = { 0 };
94 ret = lstat(pathname, st);
96 fprintf(stderr, "%s: failed to stat '%s': %s\n",
97 progname, pathname, strerror(errno));
102 /* currently, only file and dir supported */
103 if (!S_ISREG(st->st_mode) && !S_ISDIR(st->st_mode))
106 fd = open(pathname, O_RDONLY | O_NOCTTY | O_NDELAY);
108 fprintf(stderr, "%s: failed to open '%s': %s\n",
109 progname, pathname, strerror(errno));
114 ret = ioctl(fd, FS_IOC_FSGETXATTR, fsx);
116 fprintf(stderr, "%s: failed to get xattr for '%s': %s\n",
117 progname, pathname, strerror(errno));
122 strncpy(dname_path, pathname, PATH_MAX);
123 strncpy(bname_path, pathname, PATH_MAX);
124 dname = dirname(dname_path);
125 bname = basename(bname_path);
126 fd = open(dname, O_RDONLY | O_NOCTTY | O_NDELAY);
131 lu_project.project_type = LU_PROJECT_GET;
133 strncpy(lu_project.project_name, bname, NAME_MAX);
135 strncpy(ret_bname, bname, NAME_MAX);
137 ret = ioctl(fd, LL_IOC_PROJECT, &lu_project);
139 fprintf(stderr, "%s: failed to get xattr for '%s': %s\n",
140 progname, pathname, strerror(errno));
143 fsx->fsx_xflags = lu_project.project_xflags;
144 fsx->fsx_projid = lu_project.project_id;
149 return ret ? ret : fd;
153 project_check_one(const char *pathname, struct project_handle_control *phc)
159 ret = project_get_fsxattr(pathname, &fsx, &st, NULL);
163 /* use top directory's project ID if not specified */
164 if (!phc->assign_projid) {
165 phc->assign_projid = true;
166 phc->projid = fsx.fsx_projid;
169 if (!(fsx.fsx_xflags & FS_XFLAG_PROJINHERIT) &&
170 S_ISDIR(st.st_mode)) {
172 printf("%s%c", pathname, '\0');
175 printf("%s - project inheritance flag is not set\n",
179 if (fsx.fsx_projid != phc->projid) {
181 printf("%s%c", pathname, '\0');
184 printf("%s - project identifier is not set (inode=%u, tree=%u)\n",
185 pathname, fsx.fsx_projid, phc->projid);
193 project_list_one(const char *pathname, struct project_handle_control *phc)
199 ret = project_get_fsxattr(pathname, &fsx, &st, NULL);
203 printf("%5u %c %s\n", fsx.fsx_projid,
204 (fsx.fsx_xflags & FS_XFLAG_PROJINHERIT) ?
205 'P' : '-', pathname);
212 project_set_one(const char *pathname, struct project_handle_control *phc)
217 char bname[NAME_MAX + 1] = { 0 };
218 struct lu_project lp = { 0 };
220 fd = project_get_fsxattr(pathname, &fsx, &st, bname);
224 if ((!phc->set_projid || fsx.fsx_projid == phc->projid) &&
225 (!phc->set_inherit || (fsx.fsx_xflags & FS_XFLAG_PROJINHERIT)))
228 if (phc->set_inherit)
229 fsx.fsx_xflags |= FS_XFLAG_PROJINHERIT;
231 fsx.fsx_projid = phc->projid;
233 if (S_ISREG(st.st_mode) || S_ISDIR(st.st_mode)) {
234 ret = ioctl(fd, FS_IOC_FSSETXATTR, &fsx);
236 lp.project_xflags = fsx.fsx_xflags;
237 lp.project_id = fsx.fsx_projid;
238 lp.project_type = LU_PROJECT_SET;
239 strncpy(lp.project_name, bname, NAME_MAX);
240 lp.project_name[NAME_MAX] = '\0';
241 ret = ioctl(fd, LL_IOC_PROJECT, &lp);
245 fprintf(stderr, "%s: failed to set xattr for '%s': %s\n",
246 progname, pathname, strerror(errno));
252 project_clear_one(const char *pathname, struct project_handle_control *phc)
257 char bname[NAME_MAX + 1] = { 0 };
258 struct lu_project lp = { 0 };
260 fd = project_get_fsxattr(pathname, &fsx, &st, bname);
264 if ((!(fsx.fsx_xflags & FS_XFLAG_PROJINHERIT)) &&
265 (fsx.fsx_projid == 0 || phc->keep_projid))
268 fsx.fsx_xflags &= ~FS_XFLAG_PROJINHERIT;
269 if (!phc->keep_projid)
272 if (S_ISREG(st.st_mode) || S_ISDIR(st.st_mode)) {
273 ret = ioctl(fd, FS_IOC_FSSETXATTR, &fsx);
275 lp.project_xflags = fsx.fsx_xflags;
276 lp.project_id = fsx.fsx_projid;
277 lp.project_type = LU_PROJECT_SET;
278 strncpy(lp.project_name, bname, NAME_MAX);
279 lp.project_name[NAME_MAX] = '\0';
280 ret = ioctl(fd, LL_IOC_PROJECT, &lp);
283 fprintf(stderr, "%s: failed to set xattr for '%s': %s\n",
284 progname, pathname, strerror(errno));
291 lfs_project_handle_dir(struct list_head *head, const char *pathname,
292 struct project_handle_control *phc,
293 int (*func)(const char *,
294 struct project_handle_control *))
296 char fullname[PATH_MAX];
302 dir = opendir(pathname);
305 fprintf(stderr, "%s: failed to opendir '%s': %s\n",
306 progname, pathname, strerror(-ret));
310 while ((ent = readdir(dir)) != NULL) {
311 /* skip "." and ".." */
312 if (strcmp(ent->d_name, ".") == 0 ||
313 strcmp(ent->d_name, "..") == 0)
316 if (strlen(ent->d_name) + strlen(pathname) + 1 >=
319 errno = ENAMETOOLONG;
320 fprintf(stderr, "%s: ignored too long path: %s/%s\n",
321 progname, pathname, ent->d_name);
324 snprintf(fullname, PATH_MAX, "%s/%s", pathname,
327 rc = func(fullname, phc);
330 if (phc->recursive && ent->d_type == DT_DIR) {
331 rc = lfs_project_item_alloc(head, fullname);
341 static int lfs_project_iterate(const char *pathname,
342 struct project_handle_control *phc,
343 int (*func)(const char *,
344 struct project_handle_control *))
346 struct lfs_project_item *lpi;
347 struct list_head head;
352 ret = stat(pathname, &st);
354 fprintf(stderr, "%s: failed to stat '%s': %s\n",
355 progname, pathname, strerror(errno));
359 /* list opeation will skip top directory in default */
360 if (!S_ISDIR(st.st_mode) || phc->dironly ||
361 project_list_one != func)
362 ret = func(pathname, phc);
364 /* dironly first, recursive will be ignored */
365 if (!S_ISDIR(st.st_mode) || phc->dironly || ret)
368 INIT_LIST_HEAD(&head);
369 ret = lfs_project_item_alloc(&head, pathname);
373 while (!list_empty(&head)) {
374 lpi = list_entry(head.next, struct lfs_project_item, lpi_list);
375 list_del(&lpi->lpi_list);
376 rc = lfs_project_handle_dir(&head, lpi->lpi_pathname,
380 free(lpi->lpi_pathname);
388 int lfs_project_check(const char *pathname,
389 struct project_handle_control *phc)
391 return lfs_project_iterate(pathname, phc, project_check_one);
394 int lfs_project_clear(const char *pathname,
395 struct project_handle_control *phc)
397 return lfs_project_iterate(pathname, phc, project_clear_one);
400 int lfs_project_set(const char *pathname,
401 struct project_handle_control *phc)
403 return lfs_project_iterate(pathname, phc, project_set_one);
406 int lfs_project_list(const char *pathname,
407 struct project_handle_control *phc)
409 return lfs_project_iterate(pathname, phc, project_list_one);