Whamcloud - gitweb
8471c6d6180b6794301b8766e09e8ddb82a035ff
[fs/lustre-release.git] / lustre / utils / lfs_project.c
1 /*
2  * GPL HEADER START
3  *
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
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.
9  *
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).
15  *
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
19  *
20  * GPL HEADER END
21  */
22 /*
23  * Copyright (c) 2017, DataDirect Networks Storage.
24  * Copyright (c) 2017, Intel Corporation.
25  */
26 /*
27  * This file is part of Lustre, http://www.lustre.org/
28  *
29  * lustre/utils/lfs_project.c
30  *
31  * Author: Wang Shilong <wshilong@ddn.com>
32  * Author: Fan Yong <fan.yong@intel.com>
33  */
34 #include <errno.h>
35 #include <getopt.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <strings.h>
39 #include <unistd.h>
40 #include <fcntl.h>
41 #include <dirent.h>
42 #include <stddef.h>
43 #include <libintl.h>
44 #include <sys/stat.h>
45 #include <sys/types.h>
46 #include <string.h>
47 #include <libcfs/util/list.h>
48 #include <libcfs/util/ioctl.h>
49 #include <sys/ioctl.h>
50
51 #include "lfs_project.h"
52 #include <lustre/lustreapi.h>
53
54 const char      *progname;
55
56 struct lfs_project_item {
57         struct list_head lpi_list;
58         char *lpi_pathname;
59 };
60
61 static int
62 lfs_project_item_alloc(struct list_head *head, const char *pathname)
63 {
64         struct lfs_project_item *lpi;
65
66         lpi = malloc(sizeof(struct lfs_project_item));
67         if (lpi == NULL) {
68                 fprintf(stderr,
69                         "%s: cannot allocate project item for '%s': %s\n",
70                         progname, pathname, strerror(ENOMEM));
71                 return -ENOMEM;
72         }
73
74         lpi->lpi_pathname = strdup(pathname);
75         if (!lpi->lpi_pathname) {
76                 free(lpi);
77                 return -ENOMEM;
78         } else
79                 list_add_tail(&lpi->lpi_list, head);
80
81         return 0;
82 }
83
84 static const char *mode_to_type(mode_t mode)
85 {
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";
94         }
95
96         return "unknown";
97 }
98
99 static int project_get_xattr(const char *pathname, struct fsxattr *fsx,
100                              struct stat *st)
101 {
102         int ret, fd;
103
104         ret = lstat(pathname, st);
105         if (ret) {
106                 fprintf(stderr, "%s: failed to stat '%s': %s\n",
107                         progname, pathname, strerror(errno));
108                 return -errno;
109         }
110
111         /* currently, only file and dir supported */
112         if (!S_ISREG(st->st_mode) && !S_ISDIR(st->st_mode)) {
113                 errno = ENOTSUP;
114                 fprintf(stderr, "%s: unable to get xattr for %s '%s': %s\n",
115                                 progname, mode_to_type(st->st_mode), pathname,
116                                 strerror(errno));
117                 return -errno;
118         }
119
120         fd = open(pathname, O_RDONLY | O_NOCTTY | O_NDELAY);
121         if (fd < 0) {
122                 fprintf(stderr, "%s: failed to open '%s': %s\n",
123                         progname, pathname, strerror(errno));
124                 return -errno;
125         }
126
127         ret = ioctl(fd, FS_IOC_FSGETXATTR, fsx);
128         if (ret) {
129                 fprintf(stderr, "%s: failed to get xattr for '%s': %s\n",
130                         progname, pathname, strerror(errno));
131                 close(fd);
132                 return -errno;
133         }
134         return fd;
135 }
136
137 static int
138 project_check_one(const char *pathname, struct project_handle_control *phc)
139 {
140         struct fsxattr fsx;
141         int ret;
142         struct stat st;
143
144         ret = project_get_xattr(pathname, &fsx, &st);
145         if (ret < 0)
146                 return ret;
147
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;
152         }
153
154         if (!(fsx.fsx_xflags & FS_XFLAG_PROJINHERIT) &&
155             S_ISDIR(st.st_mode)) {
156                 if (!phc->newline) {
157                         printf("%s%c", pathname, '\0');
158                         goto out;
159                 }
160                  printf("%s - project inheritance flag is not set\n",
161                         pathname);
162         }
163
164         if (fsx.fsx_projid != phc->projid) {
165                 if (!phc->newline) {
166                         printf("%s%c", pathname, '\0');
167                         goto out;
168                 }
169                 printf("%s - project identifier is not set (inode=%u, tree=%u)\n",
170                        pathname, fsx.fsx_projid, phc->projid);
171         }
172 out:
173         close(ret);
174         return 0;
175 }
176
177 static int
178 project_list_one(const char *pathname, struct project_handle_control *phc)
179 {
180         struct fsxattr fsx;
181         struct stat st;
182         int ret;
183
184         ret = project_get_xattr(pathname, &fsx, &st);
185         if (ret < 0)
186                 return ret;
187
188         printf("%5u %c %s\n", fsx.fsx_projid,
189                (fsx.fsx_xflags & FS_XFLAG_PROJINHERIT) ?
190                 'P' : '-', pathname);
191
192         close(ret);
193         return 0;
194 }
195
196 static int
197 project_set_one(const char *pathname, struct project_handle_control *phc)
198 {
199         struct fsxattr fsx;
200         struct stat st;
201         int fd, ret = 0;
202
203         fd = project_get_xattr(pathname, &fsx, &st);
204         if (fd < 0)
205                 return fd;
206
207         if ((!phc->set_projid || fsx.fsx_projid == phc->projid) &&
208             (!phc->set_inherit || (fsx.fsx_xflags & FS_XFLAG_PROJINHERIT)))
209                 goto out;
210
211         if (phc->set_inherit)
212                 fsx.fsx_xflags |= FS_XFLAG_PROJINHERIT;
213         if (phc->set_projid)
214                 fsx.fsx_projid = phc->projid;
215
216         ret = ioctl(fd, FS_IOC_FSSETXATTR, &fsx);
217         if (ret)
218                 fprintf(stderr, "%s: failed to set xattr for '%s': %s\n",
219                         progname, pathname, strerror(errno));
220 out:
221         close(fd);
222         return ret;
223 }
224
225 static int
226 project_clear_one(const char *pathname, struct project_handle_control *phc)
227 {
228         struct fsxattr fsx;
229         struct stat st;
230         int ret = 0, fd;
231
232         fd = project_get_xattr(pathname, &fsx, &st);
233         if (fd < 0)
234                 return fd;
235
236         if ((!(fsx.fsx_xflags & FS_XFLAG_PROJINHERIT)) &&
237              (fsx.fsx_projid == 0 || phc->keep_projid))
238                 goto out;
239
240         fsx.fsx_xflags &= ~FS_XFLAG_PROJINHERIT;
241         if (!phc->keep_projid)
242                 fsx.fsx_projid = 0;
243
244         ret = ioctl(fd, FS_IOC_FSSETXATTR, &fsx);
245         if (ret)
246                 fprintf(stderr, "%s: failed to set xattr for '%s': %s\n",
247                         progname, pathname, strerror(errno));
248 out:
249         close(fd);
250         return ret;
251 }
252
253 static int
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 *))
258 {
259         char fullname[PATH_MAX];
260         struct dirent *ent;
261         DIR *dir;
262         int ret = 0;
263         int rc;
264
265         dir = opendir(pathname);
266         if (dir == NULL) {
267                 ret = -errno;
268                 fprintf(stderr, "%s: failed to opendir '%s': %s\n",
269                         progname, pathname, strerror(-ret));
270                 return ret;
271         }
272
273         while ((ent = readdir(dir)) != NULL) {
274                 /* skip "." and ".." */
275                 if (strcmp(ent->d_name, ".") == 0 ||
276                     strcmp(ent->d_name, "..") == 0)
277                         continue;
278
279                 if (strlen(ent->d_name) + strlen(pathname) + 1 >=
280                     sizeof(fullname)) {
281                         ret = -ENAMETOOLONG;
282                         errno = ENAMETOOLONG;
283                         fprintf(stderr, "%s: ignored too long path: %s/%s\n",
284                                         progname, pathname, ent->d_name);
285                         continue;
286                 }
287                 snprintf(fullname, PATH_MAX, "%s/%s", pathname,
288                          ent->d_name);
289
290                 rc = func(fullname, phc);
291                 if (rc && !ret)
292                         ret = rc;
293                 if (phc->recursive && ent->d_type == DT_DIR) {
294                         rc = lfs_project_item_alloc(head, fullname);
295                         if (rc && !ret)
296                                 ret = rc;
297                 }
298         }
299
300         closedir(dir);
301         return ret;
302 }
303
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 *))
308 {
309         struct lfs_project_item *lpi;
310         struct list_head head;
311         struct stat st;
312         int ret = 0;
313         int rc = 0;
314
315         ret = stat(pathname, &st);
316         if (ret) {
317                 fprintf(stderr, "%s: failed to stat '%s': %s\n",
318                         progname, pathname, strerror(errno));
319                 return ret;
320         }
321
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);
326
327         /* dironly first, recursive will be ignored */
328         if (!S_ISDIR(st.st_mode) || phc->dironly || ret)
329                 return ret;
330
331         INIT_LIST_HEAD(&head);
332         ret = lfs_project_item_alloc(&head, pathname);
333         if (ret)
334                 return ret;
335
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,
340                                              phc, func);
341                 if (!ret && rc)
342                         ret = rc;
343                 free(lpi->lpi_pathname);
344                 free(lpi);
345         }
346
347         return ret;
348 }
349
350
351 int lfs_project_check(const char *pathname,
352                       struct project_handle_control *phc)
353 {
354         return lfs_project_iterate(pathname, phc, project_check_one);
355 }
356
357 int lfs_project_clear(const char *pathname,
358                       struct project_handle_control *phc)
359 {
360         return lfs_project_iterate(pathname, phc, project_clear_one);
361 }
362
363 int lfs_project_set(const char *pathname,
364                     struct project_handle_control *phc)
365 {
366         return lfs_project_iterate(pathname, phc, project_set_one);
367 }
368
369 int lfs_project_list(const char *pathname,
370                      struct project_handle_control *phc)
371 {
372         return lfs_project_iterate(pathname, phc, project_list_one);
373 }