Whamcloud - gitweb
LU-17744 ldiskfs: mballoc stats fixes
[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 #include <libgen.h>
51
52 #include "lfs_project.h"
53 #include <lustre/lustreapi.h>
54
55 const char      *progname;
56
57 struct lfs_project_item {
58         struct list_head lpi_list;
59         char *lpi_pathname;
60 };
61
62 static int
63 lfs_project_item_alloc(struct list_head *head, const char *pathname)
64 {
65         struct lfs_project_item *lpi;
66
67         lpi = malloc(sizeof(struct lfs_project_item));
68         if (lpi == NULL) {
69                 fprintf(stderr,
70                         "%s: cannot allocate project item for '%s': %s\n",
71                         progname, pathname, strerror(ENOMEM));
72                 return -ENOMEM;
73         }
74
75         lpi->lpi_pathname = strdup(pathname);
76         if (!lpi->lpi_pathname) {
77                 free(lpi);
78                 return -ENOMEM;
79         } else
80                 list_add_tail(&lpi->lpi_list, head);
81
82         return 0;
83 }
84
85 static int project_get_fsxattr(const char *pathname, struct fsxattr *fsx,
86                              struct stat *st, char *ret_bname)
87 {
88         int ret = 0, fd = -1;
89         char dname_path[PATH_MAX + 1] = { 0 };
90         char bname_path[PATH_MAX + 1] = { 0 };
91         char *dname, *bname;
92         struct lu_project lu_project = { 0 };
93
94         ret = lstat(pathname, st);
95         if (ret) {
96                 fprintf(stderr, "%s: failed to stat '%s': %s\n",
97                         progname, pathname, strerror(errno));
98                 ret = -errno;
99                 goto out;
100         }
101
102         /* currently, only file and dir supported */
103         if (!S_ISREG(st->st_mode) && !S_ISDIR(st->st_mode))
104                 goto new_api;
105
106         fd = open(pathname, O_RDONLY | O_NOCTTY | O_NDELAY);
107         if (fd < 0) {
108                 fprintf(stderr, "%s: failed to open '%s': %s\n",
109                         progname, pathname, strerror(errno));
110                 ret = -errno;
111                 goto out;
112         }
113
114         ret = ioctl(fd, FS_IOC_FSGETXATTR, fsx);
115         if (ret) {
116                 fprintf(stderr, "%s: failed to get xattr for '%s': %s\n",
117                         progname, pathname, strerror(errno));
118                 ret = -errno;
119         }
120         goto out;
121 new_api:
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);
127         if (fd < 0) {
128                 ret = -errno;
129                 goto out;
130         }
131         lu_project.project_type = LU_PROJECT_GET;
132         if (bname) {
133                 strncpy(lu_project.project_name, bname, NAME_MAX);
134                 if (ret_bname)
135                         strncpy(ret_bname, bname, NAME_MAX);
136         }
137         ret = ioctl(fd, LL_IOC_PROJECT, &lu_project);
138         if (ret) {
139                 fprintf(stderr, "%s: failed to get xattr for '%s': %s\n",
140                         progname, pathname, strerror(errno));
141                 ret = -errno;
142         } else {
143                 fsx->fsx_xflags = lu_project.project_xflags;
144                 fsx->fsx_projid = lu_project.project_id;
145         }
146 out:
147         if (ret && fd >= 0)
148                 close(fd);
149         return ret ? ret : fd;
150 }
151
152 static int
153 project_check_one(const char *pathname, struct project_handle_control *phc)
154 {
155         struct fsxattr fsx;
156         int ret;
157         struct stat st;
158
159         ret = project_get_fsxattr(pathname, &fsx, &st, NULL);
160         if (ret < 0)
161                 return ret;
162
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;
167         }
168
169         if (!(fsx.fsx_xflags & FS_XFLAG_PROJINHERIT) &&
170             S_ISDIR(st.st_mode)) {
171                 if (!phc->newline) {
172                         printf("%s%c", pathname, '\0');
173                         goto out;
174                 }
175                  printf("%s - project inheritance flag is not set\n",
176                         pathname);
177         }
178
179         if (fsx.fsx_projid != phc->projid) {
180                 if (!phc->newline) {
181                         printf("%s%c", pathname, '\0');
182                         goto out;
183                 }
184                 printf("%s - project identifier is not set (inode=%u, tree=%u)\n",
185                        pathname, fsx.fsx_projid, phc->projid);
186         }
187 out:
188         close(ret);
189         return 0;
190 }
191
192 static int
193 project_list_one(const char *pathname, struct project_handle_control *phc)
194 {
195         struct fsxattr fsx;
196         struct stat st;
197         int ret;
198
199         ret = project_get_fsxattr(pathname, &fsx, &st, NULL);
200         if (ret < 0)
201                 return ret;
202
203         printf("%5u %c %s\n", fsx.fsx_projid,
204                (fsx.fsx_xflags & FS_XFLAG_PROJINHERIT) ?
205                 'P' : '-', pathname);
206
207         close(ret);
208         return 0;
209 }
210
211 static int
212 project_set_one(const char *pathname, struct project_handle_control *phc)
213 {
214         struct fsxattr fsx;
215         struct stat st;
216         int fd, ret = 0;
217         char bname[NAME_MAX + 1] = { 0 };
218         struct lu_project lp = { 0 };
219
220         fd = project_get_fsxattr(pathname, &fsx, &st, bname);
221         if (fd < 0)
222                 return fd;
223
224         if ((!phc->set_projid || fsx.fsx_projid == phc->projid) &&
225             (!phc->set_inherit || (fsx.fsx_xflags & FS_XFLAG_PROJINHERIT)))
226                 goto out;
227
228         if (phc->set_inherit)
229                 fsx.fsx_xflags |= FS_XFLAG_PROJINHERIT;
230         if (phc->set_projid)
231                 fsx.fsx_projid = phc->projid;
232
233         if (S_ISREG(st.st_mode) || S_ISDIR(st.st_mode)) {
234                 ret = ioctl(fd, FS_IOC_FSSETXATTR, &fsx);
235         } else {
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);
242         }
243 out:
244         if (ret)
245                 fprintf(stderr, "%s: failed to set xattr for '%s': %s\n",
246                         progname, pathname, strerror(errno));
247         close(fd);
248         return ret;
249 }
250
251 static int
252 project_clear_one(const char *pathname, struct project_handle_control *phc)
253 {
254         struct fsxattr fsx;
255         struct stat st;
256         int ret = 0, fd;
257         char bname[NAME_MAX + 1] = { 0 };
258         struct lu_project lp = { 0 };
259
260         fd = project_get_fsxattr(pathname, &fsx, &st, bname);
261         if (fd < 0)
262                 return fd;
263
264         if ((!(fsx.fsx_xflags & FS_XFLAG_PROJINHERIT)) &&
265              (fsx.fsx_projid == 0 || phc->keep_projid))
266                 goto out;
267
268         fsx.fsx_xflags &= ~FS_XFLAG_PROJINHERIT;
269         if (!phc->keep_projid)
270                 fsx.fsx_projid = 0;
271
272         if (S_ISREG(st.st_mode) || S_ISDIR(st.st_mode)) {
273                 ret = ioctl(fd, FS_IOC_FSSETXATTR, &fsx);
274         } else {
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);
281         }
282         if (ret)
283                 fprintf(stderr, "%s: failed to set xattr for '%s': %s\n",
284                         progname, pathname, strerror(errno));
285 out:
286         close(fd);
287         return ret;
288 }
289
290 static int
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 *))
295 {
296         char fullname[PATH_MAX];
297         size_t size = sizeof(fullname);
298         int namelen;
299         struct dirent *ent;
300         DIR *dir;
301         int ret = 0;
302         int rc;
303
304         dir = opendir(pathname);
305         if (dir == NULL) {
306                 ret = -errno;
307                 fprintf(stderr, "%s: failed to opendir '%s': %s\n",
308                         progname, pathname, strerror(-ret));
309                 return ret;
310         }
311
312         while ((ent = readdir(dir)) != NULL) {
313                 /* skip "." and ".." */
314                 if (strcmp(ent->d_name, ".") == 0 ||
315                     strcmp(ent->d_name, "..") == 0)
316                         continue;
317
318                 if (strlen(ent->d_name) + strlen(pathname) + 1 >=
319                     sizeof(fullname)) {
320                         ret = -ENAMETOOLONG;
321                         errno = ENAMETOOLONG;
322                         fprintf(stderr, "%s: ignored too long path: %s/%s\n",
323                                         progname, pathname, ent->d_name);
324                         continue;
325                 }
326                 namelen = snprintf(fullname, size, "%s/%s",
327                                    pathname, ent->d_name);
328                 if (namelen >= size)
329                         fullname[size - 1] = '\0';
330
331                 rc = func(fullname, phc);
332                 if (rc && !ret)
333                         ret = rc;
334                 if (phc->recursive && ent->d_type == DT_DIR) {
335                         rc = lfs_project_item_alloc(head, fullname);
336                         if (rc && !ret)
337                                 ret = rc;
338                 }
339         }
340
341         closedir(dir);
342         return ret;
343 }
344
345 static int lfs_project_iterate(const char *pathname,
346                                struct project_handle_control *phc,
347                                int (*func)(const char *,
348                                            struct project_handle_control *))
349 {
350         struct lfs_project_item *lpi;
351         struct list_head head;
352         struct stat st;
353         int ret = 0;
354         int rc = 0;
355
356         ret = stat(pathname, &st);
357         if (ret) {
358                 fprintf(stderr, "%s: failed to stat '%s': %s\n",
359                         progname, pathname, strerror(errno));
360                 return ret;
361         }
362
363         /* list opeation will skip top directory in default */
364         if (!S_ISDIR(st.st_mode) || phc->dironly ||
365             project_list_one != func)
366                 ret = func(pathname, phc);
367
368         /* dironly first, recursive will be ignored */
369         if (!S_ISDIR(st.st_mode) || phc->dironly || ret)
370                 return ret;
371
372         INIT_LIST_HEAD(&head);
373         ret = lfs_project_item_alloc(&head, pathname);
374         if (ret)
375                 return ret;
376
377         while (!list_empty(&head)) {
378                 lpi = list_first_entry(&head, struct lfs_project_item,
379                                        lpi_list);
380                 list_del(&lpi->lpi_list);
381                 rc = lfs_project_handle_dir(&head, lpi->lpi_pathname,
382                                              phc, func);
383                 if (!ret && rc)
384                         ret = rc;
385                 free(lpi->lpi_pathname);
386                 free(lpi);
387         }
388
389         return ret;
390 }
391
392
393 int lfs_project_check(const char *pathname,
394                       struct project_handle_control *phc)
395 {
396         return lfs_project_iterate(pathname, phc, project_check_one);
397 }
398
399 int lfs_project_clear(const char *pathname,
400                       struct project_handle_control *phc)
401 {
402         return lfs_project_iterate(pathname, phc, project_clear_one);
403 }
404
405 int lfs_project_set(const char *pathname,
406                     struct project_handle_control *phc)
407 {
408         return lfs_project_iterate(pathname, phc, project_set_one);
409 }
410
411 int lfs_project_list(const char *pathname,
412                      struct project_handle_control *phc)
413 {
414         return lfs_project_iterate(pathname, phc, project_list_one);
415 }