Whamcloud - gitweb
d8b150047f0f59a5711d4e5a1c226337dee982b3
[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 struct lfs_project_item {
55         struct list_head lpi_list;
56         char lpi_pathname[PATH_MAX];
57 };
58
59 static int
60 lfs_project_item_alloc(struct list_head *head, const char *pathname)
61 {
62         struct lfs_project_item *lpi;
63
64         lpi = malloc(sizeof(struct lfs_project_item));
65         if (lpi == NULL) {
66                 fprintf(stderr,
67                         "%s: cannot allocate project item for '%s': %s\n",
68                         progname, pathname, strerror(ENOMEM));
69                 return -ENOMEM;
70         }
71
72         strncpy(lpi->lpi_pathname, pathname, sizeof(lpi->lpi_pathname) - 1);
73         list_add_tail(&lpi->lpi_list, head);
74
75         return 0;
76 }
77
78 static const char *mode_to_type(mode_t mode)
79 {
80         switch (mode & S_IFMT) {
81         case S_IFDIR:   return "dir";
82         case S_IFREG:   return "regular";
83         case S_IFLNK:   return "symlink";
84         case S_IFCHR:   return "char device";
85         case S_IFBLK:   return "block device";
86         case S_IFIFO:   return "fifo";
87         case S_IFSOCK:  return "sock";
88         }
89
90         return "unknown";
91 }
92
93 static int project_get_xattr(const char *pathname, struct fsxattr *fsx,
94                              struct stat *st)
95 {
96         int ret, fd;
97
98         ret = lstat(pathname, st);
99         if (ret) {
100                 fprintf(stderr, "%s: failed to stat '%s': %s\n",
101                         progname, pathname, strerror(errno));
102                 return -errno;
103         }
104
105         /* currently, only file and dir supported */
106         if (!S_ISREG(st->st_mode) && !S_ISDIR(st->st_mode)) {
107                 errno = ENOTSUP;
108                 fprintf(stderr, "%s: unable to get xattr for %s '%s': %s\n",
109                                 progname, mode_to_type(st->st_mode), pathname,
110                                 strerror(errno));
111                 return -errno;
112         }
113
114         fd = open(pathname, O_RDONLY | O_NOCTTY | O_NDELAY);
115         if (fd < 0) {
116                 fprintf(stderr, "%s: failed to open '%s': %s\n",
117                         progname, pathname, strerror(errno));
118                 return -errno;
119         }
120
121         ret = ioctl(fd, FS_IOC_FSGETXATTR, fsx);
122         if (ret) {
123                 fprintf(stderr, "%s: failed to get xattr for '%s': %s\n",
124                         progname, pathname, strerror(errno));
125                 close(fd);
126                 return -errno;
127         }
128         return fd;
129 }
130
131 static int
132 project_check_one(const char *pathname, struct project_handle_control *phc)
133 {
134         struct fsxattr fsx;
135         int ret;
136         struct stat st;
137
138         ret = project_get_xattr(pathname, &fsx, &st);
139         if (ret < 0)
140                 return ret;
141
142         /* use top directory's project ID if not specified */
143         if (!phc->assign_projid) {
144                 phc->assign_projid = true;
145                 phc->projid = fsx.fsx_projid;
146         }
147
148         if (!(fsx.fsx_xflags & FS_XFLAG_PROJINHERIT) &&
149             S_ISDIR(st.st_mode)) {
150                 if (!phc->newline) {
151                         printf("%s%c", pathname, '\0');
152                         goto out;
153                 }
154                  printf("%s - project inheritance flag is not set\n",
155                         pathname);
156         }
157
158         if (fsx.fsx_projid != phc->projid) {
159                 if (!phc->newline) {
160                         printf("%s%c", pathname, '\0');
161                         goto out;
162                 }
163                 printf("%s - project identifier is not set (inode=%u, tree=%u)\n",
164                        pathname, fsx.fsx_projid, phc->projid);
165         }
166 out:
167         close(ret);
168         return 0;
169 }
170
171 static int
172 project_list_one(const char *pathname, struct project_handle_control *phc)
173 {
174         struct fsxattr fsx;
175         struct stat st;
176         int ret;
177
178         ret = project_get_xattr(pathname, &fsx, &st);
179         if (ret < 0)
180                 return ret;
181
182         printf("%5u %c %s\n", fsx.fsx_projid,
183                (fsx.fsx_xflags & FS_XFLAG_PROJINHERIT) ?
184                 'P' : '-', pathname);
185
186         close(ret);
187         return 0;
188 }
189
190 static int
191 project_set_one(const char *pathname, struct project_handle_control *phc)
192 {
193         struct fsxattr fsx;
194         struct stat st;
195         int fd, ret = 0;
196
197         fd = project_get_xattr(pathname, &fsx, &st);
198         if (fd < 0)
199                 return fd;
200
201         if ((!phc->set_projid || fsx.fsx_projid == phc->projid) &&
202             (!phc->set_inherit || (fsx.fsx_xflags & FS_XFLAG_PROJINHERIT)))
203                 goto out;
204
205         if (phc->set_inherit)
206                 fsx.fsx_xflags |= FS_XFLAG_PROJINHERIT;
207         if (phc->set_projid)
208                 fsx.fsx_projid = phc->projid;
209
210         ret = ioctl(fd, FS_IOC_FSSETXATTR, &fsx);
211         if (ret)
212                 fprintf(stderr, "%s: failed to set xattr for '%s': %s\n",
213                         progname, pathname, strerror(errno));
214 out:
215         close(fd);
216         return ret;
217 }
218
219 static int
220 project_clear_one(const char *pathname, struct project_handle_control *phc)
221 {
222         struct fsxattr fsx;
223         struct stat st;
224         int ret = 0, fd;
225
226         fd = project_get_xattr(pathname, &fsx, &st);
227         if (fd < 0)
228                 return fd;
229
230         if ((!(fsx.fsx_xflags & FS_XFLAG_PROJINHERIT)) &&
231              (fsx.fsx_projid == 0 || phc->keep_projid))
232                 goto out;
233
234         fsx.fsx_xflags &= ~FS_XFLAG_PROJINHERIT;
235         if (!phc->keep_projid)
236                 fsx.fsx_projid = 0;
237
238         ret = ioctl(fd, FS_IOC_FSSETXATTR, &fsx);
239         if (ret)
240                 fprintf(stderr, "%s: failed to set xattr for '%s': %s\n",
241                         progname, pathname, strerror(errno));
242 out:
243         close(fd);
244         return ret;
245 }
246
247 static int
248 lfs_project_handle_dir(struct list_head *head, const char *pathname,
249                        struct project_handle_control *phc,
250                        int (*func)(const char *,
251                                    struct project_handle_control *))
252 {
253         char fullname[PATH_MAX];
254         struct dirent *ent;
255         DIR *dir;
256         int ret = 0;
257         int rc;
258
259         dir = opendir(pathname);
260         if (dir == NULL) {
261                 ret = -errno;
262                 fprintf(stderr, "%s: failed to opendir '%s': %s\n",
263                         progname, pathname, strerror(-ret));
264                 return ret;
265         }
266
267         while ((ent = readdir(dir)) != NULL) {
268                 /* skip "." and ".." */
269                 if (strcmp(ent->d_name, ".") == 0 ||
270                     strcmp(ent->d_name, "..") == 0)
271                         continue;
272
273                 if (strlen(ent->d_name) + strlen(pathname) + 1 >=
274                     sizeof(fullname)) {
275                         ret = -ENAMETOOLONG;
276                         errno = ENAMETOOLONG;
277                         fprintf(stderr, "%s: ignored too long path: %s/%s\n",
278                                         progname, pathname, ent->d_name);
279                         continue;
280                 }
281                 snprintf(fullname, PATH_MAX, "%s/%s", pathname,
282                          ent->d_name);
283
284                 rc = func(fullname, phc);
285                 if (rc && !ret)
286                         ret = rc;
287                 if (phc->recursive && ent->d_type == DT_DIR) {
288                         rc = lfs_project_item_alloc(head, fullname);
289                         if (rc && !ret)
290                                 ret = rc;
291                 }
292         }
293
294         closedir(dir);
295         return ret;
296 }
297
298 static int lfs_project_iterate(const char *pathname,
299                                struct project_handle_control *phc,
300                                int (*func)(const char *,
301                                            struct project_handle_control *))
302 {
303         struct lfs_project_item *lpi;
304         struct list_head head;
305         struct stat st;
306         int ret = 0;
307         int rc = 0;
308
309         ret = stat(pathname, &st);
310         if (ret) {
311                 fprintf(stderr, "%s: failed to stat '%s': %s\n",
312                         progname, pathname, strerror(errno));
313                 return ret;
314         }
315
316         /* list opeation will skip top directory in default */
317         if (!S_ISDIR(st.st_mode) || phc->dironly ||
318             project_list_one != func)
319                 ret = func(pathname, phc);
320
321         /* dironly first, recursive will be ignored */
322         if (!S_ISDIR(st.st_mode) || phc->dironly || ret)
323                 return ret;
324
325         INIT_LIST_HEAD(&head);
326         ret = lfs_project_item_alloc(&head, pathname);
327         if (ret)
328                 return ret;
329
330         while (!list_empty(&head)) {
331                 lpi = list_entry(head.next, struct lfs_project_item, lpi_list);
332                 list_del(&lpi->lpi_list);
333                 rc = lfs_project_handle_dir(&head, lpi->lpi_pathname,
334                                              phc, func);
335                 if (!ret && rc)
336                         ret = rc;
337                 free(lpi);
338         }
339
340         return ret;
341 }
342
343
344 int lfs_project_check(const char *pathname,
345                       struct project_handle_control *phc)
346 {
347         return lfs_project_iterate(pathname, phc, project_check_one);
348 }
349
350 int lfs_project_clear(const char *pathname,
351                       struct project_handle_control *phc)
352 {
353         return lfs_project_iterate(pathname, phc, project_clear_one);
354 }
355
356 int lfs_project_set(const char *pathname,
357                     struct project_handle_control *phc)
358 {
359         return lfs_project_iterate(pathname, phc, project_set_one);
360 }
361
362 int lfs_project_list(const char *pathname,
363                      struct project_handle_control *phc)
364 {
365         return lfs_project_iterate(pathname, phc, project_list_one);
366 }