Whamcloud - gitweb
b=22107 a fix for the warning message in filter_destroy_internal
[fs/lustre-release.git] / lustre / utils / lfs.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  * GPL HEADER START
5  *
6  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License version 2 only,
10  * as published by the Free Software Foundation.
11  *
12  * This program is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * General Public License version 2 for more details (a copy is included
16  * in the LICENSE file that accompanied this code).
17  *
18  * You should have received a copy of the GNU General Public License
19  * version 2 along with this program; If not, see
20  * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
21  *
22  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
23  * CA 95054 USA or visit www.sun.com if you need additional information or
24  * have any questions.
25  *
26  * GPL HEADER END
27  */
28 /*
29  * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
30  * Use is subject to license terms.
31  */
32 /*
33  * This file is part of Lustre, http://www.lustre.org/
34  * Lustre is a trademark of Sun Microsystems, Inc.
35  *
36  * lustre/utils/lfs.c
37  *
38  * Author: Peter J. Braam <braam@clusterfs.com>
39  * Author: Phil Schwan <phil@clusterfs.com>
40  * Author: Robert Read <rread@clusterfs.com>
41  */
42
43 /* for O_DIRECTORY */
44 #ifndef _GNU_SOURCE
45 #define _GNU_SOURCE
46 #endif
47
48 #include <stdlib.h>
49 #include <stdio.h>
50 #include <getopt.h>
51 #include <string.h>
52 #include <mntent.h>
53 #include <errno.h>
54 #include <pwd.h>
55 #include <grp.h>
56 #include <sys/types.h>
57 #include <sys/stat.h>
58 #include <sys/param.h>
59 #include <fcntl.h>
60 #include <dirent.h>
61 #include <time.h>
62 #include <ctype.h>
63 #ifdef HAVE_SYS_QUOTA_H
64 #include <sys/quota.h>
65 #endif
66
67 #include <lnet/api-support.h>
68 #include <lnet/lnetctl.h>
69
70 #include <liblustre.h>
71 #include <lustre/lustre_idl.h>
72 #include <lustre/liblustreapi.h>
73 #include <lustre/lustre_user.h>
74 #include <lustre_quota.h>
75
76 #include "parser.h"
77 #include "obdctl.h"
78
79 unsigned int libcfs_subsystem_debug = 0;
80
81 /* all functions */
82 static int lfs_setstripe(int argc, char **argv);
83 static int lfs_find(int argc, char **argv);
84 static int lfs_getstripe(int argc, char **argv);
85 static int lfs_osts(int argc, char **argv);
86 static int lfs_df(int argc, char **argv);
87 static int lfs_check(int argc, char **argv);
88 static int lfs_catinfo(int argc, char **argv);
89 #ifdef HAVE_SYS_QUOTA_H
90 static int lfs_quotachown(int argc, char **argv);
91 static int lfs_quotacheck(int argc, char **argv);
92 static int lfs_quotaon(int argc, char **argv);
93 static int lfs_quotaoff(int argc, char **argv);
94 static int lfs_setquota(int argc, char **argv);
95 static int lfs_quota(int argc, char **argv);
96 static int lfs_quotainv(int argc, char **argv);
97 #endif
98 static int lfs_join(int argc, char **argv);
99 static int lfs_poollist(int argc, char **argv);
100 static int lfs_path2fid(int argc, char **argv);
101
102 /* all avaialable commands */
103 command_t cmdlist[] = {
104         {"setstripe", lfs_setstripe, 0,
105          "Create a new file with a specific striping pattern or\n"
106          "set the default striping pattern on an existing directory or\n"
107          "delete the default striping pattern from an existing directory\n"
108          "usage: setstripe [--size|-s stripe_size] [--count|-c stripe_count]\n"
109          "                 [--index|-i|--offset|-o start_ost_index]\n"
110          "                 [--pool|-p <pool>] <directory|filename>\n"
111          "       or \n"
112          "       setstripe -d <directory>   (to delete default striping)\n"
113          "\tstripe_size:  Number of bytes on each OST (0 filesystem default)\n"
114          "\t              Can be specified with k, m or g (in KB, MB and GB\n"
115          "\t              respectively)\n"
116          "\tstart_ost_index: OST index of first stripe (-1 default)\n"
117          "\tstripe_count: Number of OSTs to stripe over (0 default, -1 all)\n"
118          "\tpool:         Name of OST pool to use (default none)"},
119         {"getstripe", lfs_getstripe, 0,
120          "To list the striping info for a given file or files in a\n"
121          "directory or recursively for all files in a directory tree.\n"
122          "usage: getstripe [--obd|-O <uuid>] [--quiet | -q] [--verbose | -v]\n"
123          "                 [--count | -c ] [--index | -i | --offset | -o]\n"
124          "                 [--size | -s ] [--pool | -p ] [--directory | -d]\n"
125          "                 [--recursive | -r] <directory|filename> ..."},
126         {"pool_list", lfs_poollist, 0,
127          "List pools or pool OSTs\n"
128          "usage: pool_list <fsname>[.<pool>] | <pathname>\n"},
129         {"find", lfs_find, 0,
130          "To find files that match given parameters recursively in a directory tree.\n"
131          "usage: find <directory|filename> ...\n"
132          "     [[!] --atime|-A [+-]N] [[!] --mtime|-M [+-]N] [[!] --ctime|-C [+-]N]\n"
133          "     [--maxdepth|-D N] [[!] --name|-n <pattern>] [--print0|-P]\n"
134          "     [--print|-p] [[!] --obd|-O <uuid[s]>] [[!] --size|-s [+-]N[bkMGTP]]\n"
135          "     [[!] --type|-t <filetype>] [[!] --gid|-g|--group|-G <gid>|<gname>]\n"
136          "     [[!] --uid|-u|--user|-U <uid>|<uname>]\n"
137          "     [[!] --pool <pool>]\n"
138          "\t !: used before an option indicates 'NOT' the requested attribute\n"
139          "\t -: used before an value indicates 'AT MOST' the requested value\n"
140          "\t +: used before an option indicates 'AT LEAST' the requested value\n"},
141         {"check", lfs_check, 0,
142          "Display the status of MDS or OSTs (as specified in the command)\n"
143          "or all the servers (MDS and OSTs).\n"
144          "usage: check <osts|mds|servers>"},
145         {"catinfo", lfs_catinfo, 0,
146          "Show information of specified type logs.\n"
147          "usage: catinfo {keyword} [node name]\n"
148          "\tkeywords are one of followings: config, deletions.\n"
149          "\tnode name must be provided when use keyword config."},
150         {"join", lfs_join, 0,
151          "join two lustre files into one - join A, B, will be like cat B >> A & del B\n"
152          "usage: join <filename_A> <filename_B>\n"},
153         {"osts", lfs_osts, 0, "list OSTs connected to client "
154          "[for specified path only]\n" "usage: osts [path]"},
155         {"df", lfs_df, 0,
156          "report filesystem disk space usage or inodes usage"
157          "of each MDS and all OSDs or a batch belonging to a specific pool .\n"
158          "Usage: df [-i] [-h] [--pool|-p <fsname>[.<pool>] [path]"},
159 #ifdef HAVE_SYS_QUOTA_H
160         {"quotachown",lfs_quotachown, 0,
161          "Change files' owner or group on the specified filesystem.\n"
162          "usage: quotachown [-i] <filesystem>\n"
163          "\t-i: ignore error if file is not exist\n"},
164         {"quotacheck", lfs_quotacheck, 0,
165          "Scan the specified filesystem for disk usage, and create,\n"
166          "or update quota files.\n"
167          "usage: quotacheck [ -ug ] <filesystem>"},
168         {"quotaon", lfs_quotaon, 0, "Turn filesystem quotas on.\n"
169          "usage: quotaon [ -ugf ] <filesystem>"},
170         {"quotaoff", lfs_quotaoff, 0, "Turn filesystem quotas off.\n"
171          "usage: quotaoff [ -ug ] <filesystem>"},
172         {"setquota", lfs_setquota, 0, "Set filesystem quotas.\n"
173          "usage: setquota <-u|-g> <uname>|<uid>|<gname>|<gid>\n"
174          "                <block-softlimit> <block-hardlimit>\n"
175          "                <inode-softlimit> <inode-hardlimit>\n"
176          "                <filesystem>\n"
177          "       setquota <-u|--user|-g|--group> <uname>|<uid>|<gname>|<gid>\n"
178          "                [--block-softlimit <block-softlimit>]\n"
179          "                [--block-hardlimit <block-hardlimit>]\n"
180          "                [--inode-softlimit <inode-softlimit>]\n"
181          "                [--inode-hardlimit <inode-hardlimit>] <filesystem>\n"
182          "       setquota -t <-u|-g> <block-grace> <inode-grace> <filesystem>\n"
183          "       setquota -t <-u|--user|-g|--group>\n"
184          "                [--block-grace <block-grace>]\n"
185          "                [--inode-grace <inode-grace>] <filesystem>\n"
186          "       -b can be used instead of --block-softlimit/--block-grace\n"
187          "       -B can be used instead of --block-hardlimit\n"
188          "       -i can be used instead of --inode-softlimit/--inode-grace\n"
189          "       -I can be used instead of --inode-hardlimit"},
190         {"quota", lfs_quota, 0, "Display disk usage and limits.\n"
191          "usage: quota [<-u|-g> <uname>|<uid>|<gname>|<gid>]\n"
192          "             [-q] [-v] [-o <obd_uuid>] <filesystem>\n"
193          "       quota [-o <obd_uuid>] -t <-u|-g> <filesystem>"},
194         {"quotainv", lfs_quotainv, 0, "Invalidate quota data.\n"
195          "usage: quotainv [-u|-g] <filesystem>"},
196 #endif
197         {"path2fid", lfs_path2fid, 0, "Display the fid for a given path.\n"
198          "usage: path2fid <path>"},
199         {"help", Parser_help, 0, "help"},
200         {"exit", Parser_quit, 0, "quit"},
201         {"quit", Parser_quit, 0, "quit"},
202         { 0, 0, 0, NULL }
203 };
204
205 static int isnumber(const char *str)
206 {
207         const char *ptr;
208
209         if (str[0] != '-' && !isdigit(str[0]))
210                 return 0;
211
212         for (ptr = str + 1; *ptr != '\0'; ptr++) {
213                 if (!isdigit(*ptr))
214                         return 0;
215         }
216
217         return 1;
218 }
219
220 /* functions */
221 static int lfs_setstripe(int argc, char **argv)
222 {
223         char *fname;
224         int result;
225         unsigned long long st_size;
226         int  st_offset, st_count;
227         char *end;
228         int c;
229         int delete = 0;
230         char *stripe_size_arg = NULL;
231         char *stripe_off_arg = NULL;
232         char *stripe_count_arg = NULL;
233         char *pool_name_arg = NULL;
234         unsigned long long size_units;
235
236         struct option long_opts[] = {
237                 {"size",        required_argument, 0, 's'},
238                 {"count",       required_argument, 0, 'c'},
239                 {"index",       required_argument, 0, 'i'},
240                 {"offset",      required_argument, 0, 'o'},
241                 {"pool",        required_argument, 0, 'p'},
242                 {"delete",      no_argument,       0, 'd'},
243                 {0, 0, 0, 0}
244         };
245
246         st_size = 0;
247         st_offset = -1;
248         st_count = 0;
249
250 #if LUSTRE_VERSION < OBD_OCD_VERSION(2,1,0,0)
251         if (argc == 5 && argv[1][0] != '-' &&
252             isnumber(argv[2]) && isnumber(argv[3]) && isnumber(argv[4])) {
253                 fprintf(stderr, "warning: deprecated usage of setstripe "
254                         "positional parameters.  Use -c, -i, -s instead.\n");
255                 /* for compatibility with the existing positional parameter
256                  * usage */
257                 fname = argv[1];
258                 stripe_size_arg = argv[2];
259                 stripe_off_arg = argv[3];
260                 stripe_count_arg = argv[4];
261                 optind = 4;
262         } else
263 #else
264 #warning "remove obsolete positional parameter code"
265 #endif
266         {
267                 optind = 0;
268                 while ((c = getopt_long(argc, argv, "c:di:o:s:p:",
269                                         long_opts, NULL)) >= 0) {
270                         switch (c) {
271                         case 0:
272                                 /* Long options. */
273                                 break;
274                         case 'c':
275                                 stripe_count_arg = optarg;
276                                 break;
277                         case 'd':
278                                 /* delete the default striping pattern */
279                                 delete = 1;
280                                 break;
281                         case 'i':
282                         case 'o':
283                                 stripe_off_arg = optarg;
284                                 break;
285                         case 's':
286                                 stripe_size_arg = optarg;
287                                 break;
288                         case 'p':
289                                 pool_name_arg = optarg;
290                                 break;
291                         case '?':
292                                 return CMD_HELP;
293                         default:
294                                 fprintf(stderr, "error: %s: option '%s' "
295                                                 "unrecognized\n",
296                                                 argv[0], argv[optind - 1]);
297                                 return CMD_HELP;
298                         }
299                 }
300
301                 fname = argv[optind];
302
303                 if (delete &&
304                     (stripe_size_arg != NULL || stripe_off_arg != NULL ||
305                      stripe_count_arg != NULL || pool_name_arg != NULL)) {
306                         fprintf(stderr, "error: %s: cannot specify -d with "
307                                         "-s, -c -o or -p options\n",
308                                         argv[0]);
309                         return CMD_HELP;
310                 }
311         }
312
313         if (optind == argc) {
314                 fprintf(stderr, "error: %s: missing filename|dirname\n",
315                         argv[0]);
316                 return CMD_HELP;
317         }
318
319         /* get the stripe size */
320         if (stripe_size_arg != NULL) {
321                 result = parse_size(stripe_size_arg, &st_size, &size_units, 0);
322                 if (result) {
323                         fprintf(stderr, "error: %s: bad size '%s'\n",
324                                 argv[0], stripe_size_arg);
325                         return result;
326                 }
327         }
328         /* get the stripe offset */
329         if (stripe_off_arg != NULL) {
330                 st_offset = strtol(stripe_off_arg, &end, 0);
331                 if (*end != '\0') {
332                         fprintf(stderr, "error: %s: bad stripe offset '%s'\n",
333                                 argv[0], stripe_off_arg);
334                         return CMD_HELP;
335                 }
336         }
337         /* get the stripe count */
338         if (stripe_count_arg != NULL) {
339                 st_count = strtoul(stripe_count_arg, &end, 0);
340                 if (*end != '\0') {
341                         fprintf(stderr, "error: %s: bad stripe count '%s'\n",
342                                 argv[0], stripe_count_arg);
343                         return CMD_HELP;
344                 }
345         }
346
347         do {
348                 result = llapi_file_create_pool(fname, st_size, st_offset,
349                                                 st_count, 0, pool_name_arg);
350                 if (result) {
351                         fprintf(stderr,"error: %s: create stripe file '%s' "
352                                 "failed\n", argv[0], fname);
353                         break;
354                 }
355                 fname = argv[++optind];
356         } while (fname != NULL);
357
358         return result;
359 }
360
361 static int lfs_poollist(int argc, char **argv)
362 {
363         if (argc != 2)
364                 return CMD_HELP;
365
366         return llapi_poollist(argv[1]);
367 }
368
369 static int set_time(time_t *time, time_t *set, char *str)
370 {
371         time_t t;
372         int res = 0;
373
374         if (str[0] == '+')
375                 res = 1;
376         else if (str[0] == '-')
377                 res = -1;
378
379         if (res)
380                 str++;
381
382         t = strtol(str, NULL, 0);
383         if (*time < t * 24 * 60 * 60) {
384                 if (res)
385                         str--;
386                 fprintf(stderr, "Wrong time '%s' is specified.\n", str);
387                 return INT_MAX;
388         }
389
390         *set = *time - t * 24 * 60 * 60;
391         return res;
392 }
393
394 #define USER 0
395 #define GROUP 1
396
397 static int name2id(unsigned int *id, char *name, int type)
398 {
399         if (type == USER) {
400                 struct passwd *entry;
401
402                 if (!(entry = getpwnam(name))) {
403                         if (!errno)
404                                 errno = ENOENT;
405                         return -1;
406                 }
407
408                 *id = entry->pw_uid;
409         } else {
410                 struct group *entry;
411
412                 if (!(entry = getgrnam(name))) {
413                         if (!errno)
414                                 errno = ENOENT;
415                         return -1;
416                 }
417
418                 *id = entry->gr_gid;
419         }
420
421         return 0;
422 }
423
424 static int id2name(char **name, unsigned int id, int type)
425 {
426         if (type == USER) {
427                 struct passwd *entry;
428
429                 if (!(entry = getpwuid(id))) {
430                         if (!errno)
431                                 errno = ENOENT;
432                         return -1;
433                 }
434
435                 *name = entry->pw_name;
436         } else {
437                 struct group *entry;
438
439                 if (!(entry = getgrgid(id))) {
440                         if (!errno)
441                                 errno = ENOENT;
442                         return -1;
443                 }
444
445                 *name = entry->gr_name;
446         }
447
448         return 0;
449 }
450
451 #define FIND_POOL_OPT 3
452 static int lfs_find(int argc, char **argv)
453 {
454         int new_fashion = 1;
455         int c, ret;
456         time_t t;
457         struct find_param param = { .maxdepth = -1 };
458         struct option long_opts[] = {
459                 /* New find options. */
460                 {"atime",     required_argument, 0, 'A'},
461                 {"ctime",     required_argument, 0, 'C'},
462                 {"mtime",     required_argument, 0, 'M'},
463                 {"maxdepth",  required_argument, 0, 'D'},
464                 {"gid",       required_argument, 0, 'g'},
465                 {"group",     required_argument, 0, 'G'},
466                 {"uid",       required_argument, 0, 'u'},
467                 {"user",      required_argument, 0, 'U'},
468                 {"name",      required_argument, 0, 'n'},
469                 /* no short option for pool, p/P already used */
470                 {"pool",      required_argument, 0, FIND_POOL_OPT},
471                 /* --obd is considered as a new option. */
472                 {"obd",       required_argument, 0, 'O'},
473                 {"ost",       required_argument, 0, 'O'},
474                 {"print",     no_argument,       0, 'P'},
475                 {"print0",    no_argument,       0, 'p'},
476                 /* Old find options. */
477                 {"quiet",     no_argument,       0, 'q'},
478                 {"recursive", no_argument,       0, 'r'},
479                 {"size",      required_argument, 0, 's'},
480                 {"type",      required_argument, 0, 't'},
481                 {"verbose",   no_argument,       0, 'v'},
482                 {0, 0, 0, 0}
483         };
484         int pathstart = -1;
485         int pathend = -1;
486         int neg_opt = 0;
487         time_t *xtime;
488         int *xsign;
489         int isoption;
490         char *endptr;
491
492         time(&t);
493
494         optind = 0;
495         /* when getopt_long_only() hits '!' it returns 1 and puts "!" in optarg */
496         while ((c = getopt_long_only(argc, argv, "-A:C:D:g:G:M:n:PpO:qrs:t:u:U:v",
497                                      long_opts, NULL)) >= 0) {
498                 xtime = NULL;
499                 xsign = NULL;
500                 if (neg_opt)
501                         --neg_opt;
502                 /* '!' is part of option */
503                 /* when getopt_long_only() finds a string which is not
504                  * an option nor a known option argument it returns 1
505                  * in that case if we already have found pathstart and pathend
506                  * (i.e. we have the list of pathnames),
507                  * the only supported value is "!"
508                  */
509                 isoption = (c != 1) || (strcmp(optarg, "!") == 0);
510                 if (!isoption && pathend != -1) {
511                         fprintf(stderr, "err: %s: filename|dirname must either "
512                                         "precede options or follow options\n",
513                                         argv[0]);
514                         return CMD_HELP;
515                 }
516                 if (!isoption && pathstart == -1)
517                         pathstart = optind - 1;
518                 if (isoption && pathstart != -1 && pathend == -1) {
519                         pathend = optind - 2;
520                         if ((c == 1 && strcmp(optarg, "!") == 0) ||
521                             c == 'P' || c == 'p' || c == 'O' ||
522                             c == 'q' || c == 'r' || c == 'v')
523                                 pathend = optind - 1;
524                 }
525                 switch (c) {
526                 case 0:
527                         /* Long options. */
528                         break;
529                 case 1:
530                         /* unknown; opt is "!" or path component,
531                          * checking done above.
532                          */
533                         if (strcmp(optarg, "!") == 0)
534                                 neg_opt = 2;
535                         break;
536                 case 'A':
537                         xtime = &param.atime;
538                         xsign = &param.asign;
539                         param.exclude_atime = !!neg_opt;
540                 case 'C':
541                         if (c == 'C') {
542                                 xtime = &param.ctime;
543                                 xsign = &param.csign;
544                                 param.exclude_ctime = !!neg_opt;
545                         }
546                 case 'M':
547                         if (c == 'M') {
548                                 xtime = &param.mtime;
549                                 xsign = &param.msign;
550                                 param.exclude_mtime = !!neg_opt;
551                         }
552                         new_fashion = 1;
553                         ret = set_time(&t, xtime, optarg);
554                         if (ret == INT_MAX)
555                                 return -1;
556                         if (ret)
557                                 *xsign = ret;
558                         break;
559                 case 'D':
560                         new_fashion = 1;
561                         param.maxdepth = strtol(optarg, 0, 0);
562                         break;
563                 case 'g':
564                 case 'G':
565                         new_fashion = 1;
566                         ret = name2id(&param.gid, optarg, GROUP);
567                         if (ret) {
568                                 param.gid = strtoul(optarg, &endptr, 10);
569                                 if (*endptr != '\0') {
570                                         fprintf(stderr, "Group/GID: %s cannot "
571                                                 "be found.\n", optarg);
572                                         return -1;
573                                 }
574                         }
575                         param.exclude_gid = !!neg_opt;
576                         param.check_gid = 1;
577                         break;
578                 case 'u':
579                 case 'U':
580                         new_fashion = 1;
581                         ret = name2id(&param.uid, optarg, USER);
582                         if (ret) {
583                                 param.uid = strtoul(optarg, &endptr, 10);
584                                 if (*endptr != '\0') {
585                                         fprintf(stderr, "User/UID: %s cannot "
586                                                 "be found.\n", optarg);
587                                         return -1;
588                                 }
589                         }
590                         param.exclude_uid = !!neg_opt;
591                         param.check_uid = 1;
592                         break;
593                 case FIND_POOL_OPT:
594                         new_fashion = 1;
595                         if (strlen(optarg) > LOV_MAXPOOLNAME) {
596                                 fprintf(stderr,
597                                         "Pool name %s is too long"
598                                         " (max is %d)\n", optarg,
599                                         LOV_MAXPOOLNAME);
600                                 return -1;
601                         }
602                         /* we do check for empty pool because empty pool
603                          * is used to find V1 lov attributes */
604                         strncpy(param.poolname, optarg, LOV_MAXPOOLNAME);
605                         param.poolname[LOV_MAXPOOLNAME] = '\0';
606                         param.exclude_pool = !!neg_opt;
607                         param.check_pool = 1;
608                         break;
609                 case 'n':
610                         new_fashion = 1;
611                         param.pattern = (char *)optarg;
612                         param.exclude_pattern = !!neg_opt;
613                         break;
614                 case 'O': {
615                         char *buf, *token, *next, *p;
616                         int len;
617
618                         len = strlen((char *)optarg);
619                         buf = malloc(len+1);
620                         if (buf == NULL)
621                                 return -ENOMEM;
622                         strcpy(buf, (char *)optarg);
623
624                         param.exclude_obd = !!neg_opt;
625
626                         if (param.num_alloc_obds == 0) {
627                                 param.obduuid = malloc(FIND_MAX_OSTS *
628                                                        sizeof(struct obd_uuid));
629                                 if (param.obduuid == NULL)
630                                         return -ENOMEM;
631                                 param.num_alloc_obds = INIT_ALLOC_NUM_OSTS;
632                         }
633
634                         for (token = buf; token && *token; token = next) {
635                                 p = strchr(token, ',');
636                                 next = 0;
637                                 if (p) {
638                                         *p = 0;
639                                         next = p+1;
640                                 }
641                                 strcpy((char *)&param.obduuid[param.num_obds++].uuid,
642                                        token);
643                         }
644
645                         if (buf)
646                                 free(buf);
647                         break;
648                 }
649                 case 'p':
650                         new_fashion = 1;
651                         param.zeroend = 1;
652                         break;
653                 case 'P':
654                         break;
655                 case 'q':
656                         new_fashion = 0;
657                         param.quiet++;
658                         param.verbose = 0;
659                         break;
660                 case 'r':
661                         new_fashion = 0;
662                         param.recursive = 1;
663                         break;
664                 case 't':
665                         param.exclude_type = !!neg_opt;
666                         switch(optarg[0]) {
667                         case 'b': param.type = S_IFBLK; break;
668                         case 'c': param.type = S_IFCHR; break;
669                         case 'd': param.type = S_IFDIR; break;
670                         case 'f': param.type = S_IFREG; break;
671                         case 'l': param.type = S_IFLNK; break;
672                         case 'p': param.type = S_IFIFO; break;
673                         case 's': param.type = S_IFSOCK; break;
674 #ifdef S_IFDOOR /* Solaris only */
675                         case 'D': param.type = S_IFDOOR; break;
676 #endif
677                         default: fprintf(stderr, "error: %s: bad type '%s'\n",
678                                          argv[0], optarg);
679                                  return CMD_HELP;
680                         };
681                         break;
682                 case 's':
683                         if (optarg[0] == '+')
684                                 param.size_sign = -1;
685                         else if (optarg[0] == '-')
686                                 param.size_sign = +1;
687
688                         if (param.size_sign)
689                                 optarg++;
690                         ret = parse_size(optarg, &param.size,
691                                          &param.size_units, 0);
692                         if (ret) {
693                                 fprintf(stderr,"error: bad size '%s'\n",
694                                         optarg);
695                                 return ret;
696                         }
697                         param.exclude_size = !!neg_opt;
698                         param.size_check = 1;
699                         break;
700                 case 'v':
701                         new_fashion = 0;
702                         param.verbose++;
703                         param.quiet = 0;
704                         break;
705                 case '?':
706                         return CMD_HELP;
707                 default:
708                         fprintf(stderr, "error: %s: option '%s' unrecognized\n",
709                                 argv[0], argv[optind - 1]);
710                         return CMD_HELP;
711                 };
712         }
713
714         if (pathstart == -1) {
715                 fprintf(stderr, "error: %s: no filename|pathname\n",
716                         argv[0]);
717                 return CMD_HELP;
718         } else if (pathend == -1) {
719                 /* no options */
720                 pathend = argc;
721         }
722
723         if (new_fashion) {
724                 param.quiet = 1;
725         } else {
726                 static int deprecated_warning;
727                 if (!deprecated_warning) {
728                         fprintf(stderr, "lfs find: -q, -r, -v options "
729                                 "deprecated.  Use 'lfs getstripe' instead.\n");
730                         deprecated_warning = 1;
731                 }
732                 if (!param.recursive && param.maxdepth == -1)
733                         param.maxdepth = 1;
734         }
735
736         do {
737                 if (new_fashion)
738                         ret = llapi_find(argv[pathstart], &param);
739                 else
740                         ret = llapi_getstripe(argv[pathstart], &param);
741         } while (++pathstart < pathend && !ret);
742
743         if (ret)
744                 fprintf(stderr, "error: %s failed for %s.\n",
745                         argv[0], argv[optind - 1]);
746
747         if (param.obduuid && param.num_alloc_obds)
748                 free(param.obduuid);
749
750         return ret;
751 }
752
753 static int lfs_getstripe(int argc, char **argv)
754 {
755         struct option long_opts[] = {
756                 {"obd", 1, 0, 'O'},
757                 {"quiet", 0, 0, 'q'},
758                 {"recursive", 0, 0, 'r'},
759                 {"count", 0, 0, 'c'},
760                 {"size", 0, 0, 's'},
761                 {"index", 0, 0, 'i'},
762                 {"offset", 0, 0, 'o'},
763                 {"pool", 0, 0, 'p'},
764                 {"verbose", 0, 0, 'v'},
765                 {"directory", 0, 0, 'd'},
766                 {0, 0, 0, 0}
767         };
768         int c, rc;
769         struct find_param param = { 0 };
770
771         param.maxdepth = 1;
772         optind = 0;
773         while ((c = getopt_long(argc, argv, "cdhioO:pqrsv",
774                                 long_opts, NULL)) != -1) {
775                 switch (c) {
776                 case 'O':
777                         if (param.obduuid) {
778                                 fprintf(stderr,
779                                         "error: %s: only one obduuid allowed",
780                                         argv[0]);
781                                 return CMD_HELP;
782                         }
783                         param.obduuid = (struct obd_uuid *)optarg;
784                         break;
785                 case 'q':
786                         param.quiet++;
787                         break;
788                 case 'd':
789                         param.maxdepth = 0;
790                         break;
791                 case 'r':
792                         param.recursive = 1;
793                         break;
794                 case 'v':
795                         param.verbose = VERBOSE_ALL | VERBOSE_DETAIL;
796                         break;
797                 case 'c':
798                         if (!(param.verbose & VERBOSE_DETAIL)) {
799                                 param.verbose |= VERBOSE_COUNT;
800                                 param.maxdepth = 0;
801                         }
802                         break;
803                 case 's':
804                         if (!(param.verbose & VERBOSE_DETAIL)) {
805                                 param.verbose |= VERBOSE_SIZE;
806                                 param.maxdepth = 0;
807                         }
808                         break;
809                 case 'i':
810                 case 'o':
811                         if (!(param.verbose & VERBOSE_DETAIL)) {
812                                 param.verbose |= VERBOSE_OFFSET;
813                                 param.maxdepth = 0;
814                         }
815                         break;
816                 case 'p':
817                         param.verbose |= VERBOSE_POOL;
818                         break;
819                 case '?':
820                         return CMD_HELP;
821                 default:
822                         fprintf(stderr, "error: %s: option '%s' unrecognized\n",
823                                 argv[0], argv[optind - 1]);
824                         return CMD_HELP;
825                 }
826         }
827
828         if (optind >= argc)
829                 return CMD_HELP;
830
831         if (param.recursive)
832                 param.maxdepth = -1;
833
834         if (!param.verbose)
835                 param.verbose = VERBOSE_ALL;
836         if (param.quiet)
837                 param.verbose = VERBOSE_OBJID;
838
839         do {
840                 rc = llapi_getstripe(argv[optind], &param);
841         } while (++optind < argc && !rc);
842
843         if (rc)
844                 fprintf(stderr, "error: %s failed for %s.\n",
845                         argv[0], argv[optind - 1]);
846         return rc;
847 }
848
849 static int lfs_osts(int argc, char **argv)
850 {
851         char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
852         struct find_param param;
853         int index = 0, rc = 0;
854
855         if (argc > 2)
856                 return CMD_HELP;
857
858         if (argc == 2 && !realpath(argv[1], path)) {
859                 rc = -errno;
860                 fprintf(stderr, "error: invalid path '%s': %s\n",
861                         argv[1], strerror(-rc));
862                 return rc;
863         }
864
865         while (!llapi_search_mounts(path, index++, mntdir, NULL)) {
866                 /* Check if we have a mount point */
867                 if (mntdir[0] == '\0')
868                         continue;
869
870                 memset(&param, 0, sizeof(param));
871                 rc = llapi_ostlist(mntdir, &param);
872                 if (rc) {
873                         fprintf(stderr, "error: %s: failed on %s\n",
874                                 argv[0], mntdir);
875                 }
876                 if (path[0] != '\0')
877                         break;
878                 memset(mntdir, 0, PATH_MAX);
879         }
880
881         return rc;
882 }
883
884 static int lfs_path2fid(int argc, char **argv)
885 {
886         char *path;
887         lustre_fid fid;
888         int rc;
889
890         if (argc != 2)
891                 return CMD_HELP;
892
893         path = argv[1];
894         rc = llapi_path2fid(path, &fid);
895         if (rc) {
896                 fprintf(stderr, "can't get fid for %s: %s\n", path,
897                         strerror(errno = -rc));
898                 return rc;
899         }
900
901         printf(DFID"\n", PFID(&fid));
902
903         return 0;
904 }
905
906 #define COOK(value)                                                     \
907 ({                                                                      \
908         int radix = 0;                                                  \
909         while (value > 1024) {                                          \
910                 value /= 1024;                                          \
911                 radix++;                                                \
912         }                                                               \
913         radix;                                                          \
914 })
915 #define UUF     "%-20s"
916 #define CSF     "%11s"
917 #define CDF     "%11llu"
918 #define HDF     "%8.1f%c"
919 #define RSF     "%4s"
920 #define RDF     "%3d%%"
921
922 static int showdf(char *mntdir, struct obd_statfs *stat,
923                   char *uuid, int ishow, int cooked,
924                   char *type, int index, int rc)
925 {
926         long long avail, used, total;
927         double ratio = 0;
928         char *suffix = "KMGTPEZY";
929         /* Note if we have >2^64 bytes/fs these buffers will need to be grown */
930         char tbuf[20], ubuf[20], abuf[20], rbuf[20];
931
932         if (!uuid || !stat)
933                 return -EINVAL;
934
935         switch (rc) {
936         case 0:
937                 if (ishow) {
938                         avail = stat->os_ffree;
939                         used = stat->os_files - stat->os_ffree;
940                         total = stat->os_files;
941                 } else {
942                         int shift = cooked ? 0 : 10;
943
944                         avail = (stat->os_bavail * stat->os_bsize) >> shift;
945                         used  = ((stat->os_blocks - stat->os_bfree) *
946                                  stat->os_bsize) >> shift;
947                         total = (stat->os_blocks * stat->os_bsize) >> shift;
948                 }
949
950                 if (total > 0)
951                         ratio = (double)used / (double)total;
952
953                 if (cooked) {
954                         int i;
955                         double cook_val;
956
957                         cook_val = (double)total;
958                         i = COOK(cook_val);
959                         if (i > 0)
960                                 sprintf(tbuf, HDF, cook_val, suffix[i - 1]);
961                         else
962                                 sprintf(tbuf, CDF, total);
963
964                         cook_val = (double)used;
965                         i = COOK(cook_val);
966                         if (i > 0)
967                                 sprintf(ubuf, HDF, cook_val, suffix[i - 1]);
968                         else
969                                 sprintf(ubuf, CDF, used);
970
971                         cook_val = (double)avail;
972                         i = COOK(cook_val);
973                         if (i > 0)
974                                 sprintf(abuf, HDF, cook_val, suffix[i - 1]);
975                         else
976                                 sprintf(abuf, CDF, avail);
977                 } else {
978                         sprintf(tbuf, CDF, total);
979                         sprintf(ubuf, CDF, used);
980                         sprintf(abuf, CDF, avail);
981                 }
982
983                 sprintf(rbuf, RDF, (int)(ratio * 100));
984                 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s",
985                        uuid, tbuf, ubuf, abuf, rbuf, mntdir);
986                 if (type)
987                         printf("[%s:%d]\n", type, index);
988                 else
989                         printf("\n");
990
991                 break;
992         case -ENODATA:
993                 printf(UUF": inactive device\n", uuid);
994                 break;
995         default:
996                 printf(UUF": %s\n", uuid, strerror(-rc));
997                 break;
998         }
999
1000         return 0;
1001 }
1002
1003 struct ll_stat_type {
1004         int   st_op;
1005         char *st_name;
1006 };
1007
1008 static int mntdf(char *mntdir, char *fsname, char *pool, int ishow, int cooked)
1009 {
1010         struct obd_statfs stat_buf, sum = { .os_bsize = 1 };
1011         struct obd_uuid uuid_buf;
1012         char *poolname = NULL;
1013         struct ll_stat_type types[] = { { LL_STATFS_MDC, "MDT" },
1014                                         { LL_STATFS_LOV, "OST" },
1015                                         { 0, NULL } };
1016         struct ll_stat_type *tp;
1017         __u32 index;
1018         int rc;
1019
1020         if (pool) {
1021                 poolname = strchr(pool, '.');
1022                 if (poolname != NULL) {
1023                         if (strncmp(fsname, pool, strlen(fsname))) {
1024                                 fprintf(stderr, "filesystem name incorrect\n");
1025                                 return -ENODEV;
1026                         }
1027                         poolname++;
1028                 } else
1029                         poolname = pool;
1030         }
1031
1032         if (ishow)
1033                 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
1034                        "UUID", "Inodes", "IUsed", "IFree",
1035                        "IUse%", "Mounted on");
1036         else
1037                 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
1038                        "UUID", cooked ? "bytes" : "1K-blocks",
1039                        "Used", "Available", "Use%", "Mounted on");
1040
1041         for (tp = types; tp->st_name != NULL; tp++) {
1042                 for (index = 0; ; index++) {
1043                         memset(&stat_buf, 0, sizeof(struct obd_statfs));
1044                         memset(&uuid_buf, 0, sizeof(struct obd_uuid));
1045                         rc = llapi_obd_statfs(mntdir, tp->st_op, index,
1046                                               &stat_buf, &uuid_buf);
1047                         if (rc == -ENODEV)
1048                                 break;
1049
1050                         if (poolname && tp->st_op == LL_STATFS_LOV &&
1051                             llapi_search_ost(fsname, poolname,
1052                                              obd_uuid2str(&uuid_buf)) != 1)
1053                                 continue;
1054
1055                         /* the llapi_obd_statfs() call may have returned with
1056                          * an error, but if it filled in uuid_buf we will at
1057                          * lease use that to print out a message for that OBD.
1058                          * If we didn't even fill in uuid_buf something is
1059                          * definitely incorrect and no point in continuing. */
1060                         if (uuid_buf.uuid[0] != '\0') {
1061                                 showdf(mntdir,&stat_buf,obd_uuid2str(&uuid_buf),
1062                                        ishow, cooked, tp->st_name, index, rc);
1063                         } else {
1064                                 char tmp_uuid[12];
1065
1066                                 sprintf(tmp_uuid, "%s%04x", tp->st_name, index);
1067                                 showdf(mntdir, &stat_buf, tmp_uuid,
1068                                        ishow, cooked, tp->st_name, index, rc);
1069                         }
1070                         if (rc == 0) {
1071                                 if (tp->st_op == LL_STATFS_MDC) {
1072                                         sum.os_ffree += stat_buf.os_ffree;
1073                                         sum.os_files += stat_buf.os_files;
1074                                 } else /* if (tp->st_op == LL_STATFS_LOV) */ {
1075                                         sum.os_blocks += stat_buf.os_blocks *
1076                                                 stat_buf.os_bsize;
1077                                         sum.os_bfree  += stat_buf.os_bfree *
1078                                                 stat_buf.os_bsize;
1079                                         sum.os_bavail += stat_buf.os_bavail *
1080                                                 stat_buf.os_bsize;
1081                                 }
1082                         } else if (rc == -EINVAL || rc == -EFAULT) {
1083                                 break;
1084                         }
1085                 }
1086         }
1087
1088         printf("\n");
1089         showdf(mntdir, &sum, "filesystem summary:", ishow, cooked, NULL, 0,0);
1090         printf("\n");
1091         return 0;
1092 }
1093
1094 static int lfs_df(int argc, char **argv)
1095 {
1096         char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
1097         int ishow = 0, cooked = 0;
1098         int c, rc = 0, index = 0;
1099         char fsname[PATH_MAX] = "", *pool_name = NULL;
1100         struct option long_opts[] = {
1101                 {"pool", required_argument, 0, 'p'},
1102                 {0, 0, 0, 0}
1103         };
1104
1105         optind = 0;
1106         while ((c = getopt_long(argc, argv, "ihp:", long_opts, NULL)) != -1) {
1107                 switch (c) {
1108                 case 'i':
1109                         ishow = 1;
1110                         break;
1111                 case 'h':
1112                         cooked = 1;
1113                         break;
1114                 case 'p':
1115                         pool_name = optarg;
1116                         break;
1117                 default:
1118                         return CMD_HELP;
1119                 }
1120         }
1121
1122         if (optind < argc && !realpath(argv[optind], path)) {
1123                 rc = -errno;
1124                 fprintf(stderr, "error: invalid path '%s': %s\n",
1125                         argv[optind], strerror(-rc));
1126                 return rc;
1127         }
1128
1129         while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
1130                 /* Check if we have a mount point */
1131                 if (mntdir[0] == '\0')
1132                         continue;
1133
1134                 rc = mntdf(mntdir, fsname, pool_name, ishow, cooked);
1135                 if (rc || path[0] != '\0')
1136                         break;
1137                 fsname[0] = '\0'; /* avoid matching in next loop */
1138                 mntdir[0] = '\0'; /* avoid matching in next loop */
1139         }
1140
1141         return rc;
1142 }
1143
1144 static int lfs_check(int argc, char **argv)
1145 {
1146         int rc;
1147         int num_types = 1;
1148         char mntdir[PATH_MAX] = {'\0'};
1149         char *obd_types[2];
1150         char obd_type1[4];
1151         char obd_type2[4];
1152
1153         if (argc != 2)
1154                 return CMD_HELP;
1155
1156         obd_types[0] = obd_type1;
1157         obd_types[1] = obd_type2;
1158
1159         if (strcmp(argv[1], "osts") == 0) {
1160                 strcpy(obd_types[0], "osc");
1161         } else if (strcmp(argv[1], "mds") == 0) {
1162                 strcpy(obd_types[0], "mdc");
1163         } else if (strcmp(argv[1], "servers") == 0) {
1164                 num_types = 2;
1165                 strcpy(obd_types[0], "osc");
1166                 strcpy(obd_types[1], "mdc");
1167         } else {
1168                 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
1169                                 argv[0], argv[1]);
1170                         return CMD_HELP;
1171         }
1172
1173         rc = llapi_search_mounts(NULL, 0, mntdir, NULL);
1174         if (rc < 0 || mntdir[0] == '\0') {
1175                 fprintf(stderr, "No suitable Lustre mount found\n");
1176                 return rc;
1177         }
1178
1179         rc = llapi_target_iterate(num_types, obd_types,
1180                                   mntdir, llapi_ping_target);
1181
1182         if (rc)
1183                 fprintf(stderr, "error: %s: %s status failed\n",
1184                                 argv[0],argv[1]);
1185
1186         return rc;
1187
1188 }
1189
1190 static int lfs_catinfo(int argc, char **argv)
1191 {
1192         char mntdir[PATH_MAX] = {'\0'};
1193         int rc;
1194
1195         if (argc < 2 || (!strcmp(argv[1],"config") && argc < 3))
1196                 return CMD_HELP;
1197
1198         if (strcmp(argv[1], "config") && strcmp(argv[1], "deletions"))
1199                 return CMD_HELP;
1200
1201         rc = llapi_search_mounts(NULL, 0, mntdir, NULL);
1202         if (rc == 0 && mntdir[0] != '\0') {
1203                 if (argc == 3)
1204                         rc = llapi_catinfo(mntdir, argv[1], argv[2]);
1205                 else
1206                         rc = llapi_catinfo(mntdir, argv[1], NULL);
1207         } else {
1208                 fprintf(stderr, "no lustre_lite mounted.\n");
1209                 rc = -1;
1210         }
1211
1212         return rc;
1213 }
1214
1215 int lfs_join(int argc, char **argv)
1216 {
1217         char *name_head, *name_tail;
1218         int fd, rc;
1219         loff_t size;
1220
1221         if (argc != 3)
1222                 return CMD_HELP;
1223         name_head = argv[1];
1224         fd = open(name_head, O_WRONLY);
1225         if (fd < 0) {
1226                 fprintf(stderr, "Can not open name_head %s rc=%d\n",
1227                         name_head, fd);
1228                 return fd;
1229         }
1230         size = lseek(fd, 0, SEEK_END);
1231         if (size % JOIN_FILE_ALIGN) {
1232                 fprintf(stderr,"head file %s size %llu must be mutiple of %d\n",
1233                         name_head, (long long)size, JOIN_FILE_ALIGN);
1234                 rc = -EINVAL;
1235                 goto out;
1236         }
1237         name_tail = argv[2];
1238         rc = ioctl(fd, LL_IOC_JOIN, name_tail);
1239 out:
1240         close(fd);
1241         if (rc) {
1242                 fprintf(stderr, "Lustre joining files: %s, %s, failed\n",
1243                         argv[1], argv[2]);
1244         }
1245         return rc;
1246 }
1247
1248 #ifdef HAVE_SYS_QUOTA_H
1249 static int quota_is_2_0_server(const char *mnt)
1250 {
1251         __u64 flags;
1252         int rc;
1253
1254         rc = llapi_get_connect_flags(mnt, &flags);
1255         if (rc < 0)
1256                 return rc;
1257
1258         if (flags & OBD_CONNECT_FID)
1259                 return 1;
1260         else
1261                 return 0;
1262 }
1263
1264 static int lfs_quotachown(int argc, char **argv)
1265 {
1266
1267         int c,rc;
1268         int flag = 0;
1269
1270         optind = 0;
1271         while ((c = getopt(argc, argv, "i")) != -1) {
1272                 switch (c) {
1273                 case 'i':
1274                         flag++;
1275                         break;
1276                 default:
1277                         fprintf(stderr, "error: %s: option '-%c' "
1278                                         "unrecognized\n", argv[0], c);
1279                         return CMD_HELP;
1280                 }
1281         }
1282         if (optind == argc)
1283                 return CMD_HELP;
1284         rc = llapi_quotachown(argv[optind], flag);
1285         if(rc)
1286                 fprintf(stderr,"error: change file owner/group failed.\n");
1287         return rc;
1288 }
1289
1290 static int lfs_quotacheck(int argc, char **argv)
1291 {
1292         int c, check_type = 0;
1293         char *mnt;
1294         struct if_quotacheck qchk;
1295         struct if_quotactl qctl;
1296         char *obd_type = (char *)qchk.obd_type;
1297         int rc;
1298         int v2;
1299
1300         optind = 0;
1301         while ((c = getopt(argc, argv, "ug")) != -1) {
1302                 switch (c) {
1303                 case 'u':
1304                         check_type |= 0x01;
1305                         break;
1306                 case 'g':
1307                         check_type |= 0x02;
1308                         break;
1309                 default:
1310                         fprintf(stderr, "error: %s: option '-%c' "
1311                                         "unrecognized\n", argv[0], c);
1312                         return CMD_HELP;
1313                 }
1314         }
1315
1316         if (check_type)
1317                 check_type--;
1318         else    /* do quotacheck for both user & group quota by default */
1319                 check_type = 0x02;
1320
1321         if (argc == optind)
1322                 return CMD_HELP;
1323
1324         mnt = argv[optind];
1325         v2 = quota_is_2_0_server(mnt);
1326         if (v2 < 0)
1327                 return v2;
1328
1329         /* For b1_8 server */
1330         if (v2 == 0) {
1331                 memset(&qctl, 0, sizeof(qctl));
1332                 qctl.qc_cmd = LUSTRE_Q_QUOTAOFF;
1333                 qctl.qc_type = check_type;
1334                 qctl.qc_id = QFMT_LDISKFS; /* compatibility: 1.6.5 and earliers
1335                                             * take this parameter into account */
1336                 rc = llapi_quotactl(mnt, &qctl);
1337                 if (rc) {
1338                         fprintf(stderr, "quota off failed: %s\n", strerror(errno));
1339                         return rc;
1340                 }
1341         }
1342
1343         rc = llapi_quotacheck(mnt, check_type);
1344         if (rc) {
1345                 fprintf(stderr, "quotacheck failed: %s\n", strerror(errno));
1346                 return rc;
1347         }
1348
1349         memset(&qchk, 0, sizeof(qchk));
1350         rc = llapi_poll_quotacheck(mnt, &qchk);
1351         if (rc) {
1352                 if (*obd_type)
1353                         fprintf(stderr, "%s %s ", obd_type,
1354                                 obd_uuid2str(&qchk.obd_uuid));
1355                 fprintf(stderr, "quota check failed: %s\n", strerror(errno));
1356                 return rc;
1357         }
1358
1359         memset(&qctl, 0, sizeof(qctl));
1360         qctl.qc_cmd = LUSTRE_Q_QUOTAON;
1361         qctl.qc_type = check_type;
1362         if (v2 == 0)
1363                 qctl.qc_id = QFMT_LDISKFS; /* compatibility: 1.6.5 and earliers
1364                                             * take this parameter into account */
1365         rc = llapi_quotactl(mnt, &qctl);
1366         if (rc) {
1367                 if (v2 > 0 && errno == EALREADY) {
1368                         /* This is for 2.0 server. */
1369                         rc = 0;
1370                 } else {
1371                         if (*obd_type)
1372                                 fprintf(stderr, "%s %s ", (char *)qctl.obd_type,
1373                                         obd_uuid2str(&qctl.obd_uuid));
1374                         fprintf(stderr, "%s turn on quota failed: %s\n",
1375                                 argv[0], strerror(errno));
1376                 }
1377         }
1378
1379         return rc;
1380 }
1381
1382 static int lfs_quotaon(int argc, char **argv)
1383 {
1384         int c;
1385         char *mnt;
1386         struct if_quotactl qctl;
1387         char *obd_type = (char *)qctl.obd_type;
1388         int rc;
1389         int v2;
1390
1391         memset(&qctl, 0, sizeof(qctl));
1392         qctl.qc_cmd = LUSTRE_Q_QUOTAON;
1393
1394         optind = 0;
1395         while ((c = getopt(argc, argv, "ugf")) != -1) {
1396                 switch (c) {
1397                 case 'u':
1398                         qctl.qc_type |= 0x01;
1399                         break;
1400                 case 'g':
1401                         qctl.qc_type |= 0x02;
1402                         break;
1403                 case 'f':
1404                         qctl.qc_cmd = LUSTRE_Q_QUOTAOFF;
1405                         break;
1406                 default:
1407                         fprintf(stderr, "error: %s: option '-%c' "
1408                                         "unrecognized\n", argv[0], c);
1409                         return CMD_HELP;
1410                 }
1411         }
1412
1413         if (qctl.qc_type)
1414                 qctl.qc_type--;
1415         else /* by default, enable quota for both user & group */
1416                 qctl.qc_type = 0x02;
1417
1418         if (argc == optind)
1419                 return CMD_HELP;
1420
1421         mnt = argv[optind];
1422         v2 = quota_is_2_0_server(mnt);
1423         if (v2 < 0)
1424                 return v2;
1425
1426         if (v2 == 0)
1427                 qctl.qc_id = QFMT_LDISKFS; /* compatibility: 1.6.5 and earliers
1428                                             * take this parameter into account */
1429
1430         rc = llapi_quotactl(mnt, &qctl);
1431         if (rc) {
1432                 if (v2 > 0 && errno == EALREADY) {
1433                         /* This is for 2.0 server. */
1434                         rc = 0;
1435                 } else if (errno == ENOENT) {
1436                         fprintf(stderr, "error: cannot find quota database, "
1437                                         "make sure you have run quotacheck\n");
1438                 } else {
1439                         if (*obd_type)
1440                                 fprintf(stderr, "%s %s ", obd_type,
1441                                         obd_uuid2str(&qctl.obd_uuid));
1442                         fprintf(stderr, "%s failed: %s\n", argv[0],
1443                                 strerror(errno));
1444                 }
1445         }
1446
1447         return rc;
1448 }
1449
1450 static int lfs_quotaoff(int argc, char **argv)
1451 {
1452         int c;
1453         char *mnt;
1454         struct if_quotactl qctl;
1455         char *obd_type = (char *)qctl.obd_type;
1456         int rc;
1457         int v2;
1458
1459         memset(&qctl, 0, sizeof(qctl));
1460         qctl.qc_cmd = LUSTRE_Q_QUOTAOFF;
1461
1462         optind = 0;
1463         while ((c = getopt(argc, argv, "ug")) != -1) {
1464                 switch (c) {
1465                 case 'u':
1466                         qctl.qc_type |= 0x01;
1467                         break;
1468                 case 'g':
1469                         qctl.qc_type |= 0x02;
1470                         break;
1471                 default:
1472                         fprintf(stderr, "error: %s: option '-%c' "
1473                                         "unrecognized\n", argv[0], c);
1474                         return CMD_HELP;
1475                 }
1476         }
1477
1478         if (qctl.qc_type)
1479                 qctl.qc_type--;
1480         else /* by default, disable quota for both user & group */
1481                 qctl.qc_type = 0x02;
1482
1483         if (argc == optind)
1484                 return CMD_HELP;
1485
1486         mnt = argv[optind];
1487         v2 = quota_is_2_0_server(mnt);
1488         if (v2 < 0)
1489                 return v2;
1490
1491         rc = llapi_quotactl(mnt, &qctl);
1492         if (rc) {
1493                 if ((v2 > 0 && errno == EALREADY) ||
1494                     (v2 == 0 && errno == ESRCH)) {
1495                         rc = 0;
1496                 } else {
1497                         if (*obd_type)
1498                                 fprintf(stderr, "%s %s ", obd_type,
1499                                         obd_uuid2str(&qctl.obd_uuid));
1500                         fprintf(stderr, "quotaoff failed: %s\n",
1501                                 strerror(errno));
1502                 }
1503         }
1504
1505         return rc;
1506 }
1507
1508 static int lfs_quotainv(int argc, char **argv)
1509 {
1510         int c;
1511         char *mnt;
1512         struct if_quotactl qctl;
1513         int rc;
1514
1515         memset(&qctl, 0, sizeof(qctl));
1516         qctl.qc_cmd = LUSTRE_Q_INVALIDATE;
1517
1518         optind = 0;
1519         while ((c = getopt(argc, argv, "ugf")) != -1) {
1520                 switch (c) {
1521                 case 'u':
1522                         qctl.qc_type |= 0x01;
1523                         break;
1524                 case 'g':
1525                         qctl.qc_type |= 0x02;
1526                         break;
1527                 case 'f':
1528                         qctl.qc_cmd = LUSTRE_Q_FINVALIDATE;
1529                         break;
1530                 default:
1531                         fprintf(stderr, "error: %s: option '-%c' "
1532                                         "unrecognized\n", argv[0], c);
1533                         return CMD_HELP;
1534                 }
1535         }
1536
1537         if (qctl.qc_type)
1538                 qctl.qc_type--;
1539         else /* by default, invalidate quota for both user & group */
1540                 qctl.qc_type = 0x02;
1541
1542         if (argc == optind)
1543                 return CMD_HELP;
1544
1545         mnt = argv[optind];
1546
1547         rc = llapi_quotactl(mnt, &qctl);
1548         if (rc) {
1549                 fprintf(stderr, "quotainv failed: %s\n", strerror(errno));
1550                 return rc;
1551         }
1552
1553         return 0;
1554 }
1555
1556 #define ARG2INT(nr, str, msg)                                           \
1557 do {                                                                    \
1558         char *endp;                                                     \
1559         nr = strtol(str, &endp, 0);                                     \
1560         if (*endp) {                                                    \
1561                 fprintf(stderr, "error: bad %s: %s\n", msg, str);       \
1562                 return CMD_HELP;                                        \
1563         }                                                               \
1564 } while (0)
1565
1566 #define ADD_OVERFLOW(a,b) ((a + b) < a) ? (a = ULONG_MAX) : (a = a + b)
1567
1568 /* Convert format time string "XXwXXdXXhXXmXXs" into seconds value
1569  * returns the value or ULONG_MAX on integer overflow or incorrect format
1570  * Notes:
1571  *        1. the order of specifiers is arbitrary (may be: 5w3s or 3s5w)
1572  *        2. specifiers may be encountered multiple times (2s3s is 5 seconds)
1573  *        3. empty integer value is interpreted as 0
1574  */
1575 static unsigned long str2sec(const char* timestr)
1576 {
1577         const char spec[] = "smhdw";
1578         const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
1579         unsigned long val = 0;
1580         char *tail;
1581
1582         if (strpbrk(timestr, spec) == NULL) {
1583                 /* no specifiers inside the time string,
1584                    should treat it as an integer value */
1585                 val = strtoul(timestr, &tail, 10);
1586                 return *tail ? ULONG_MAX : val;
1587         }
1588
1589         /* format string is XXwXXdXXhXXmXXs */
1590         while (*timestr) {
1591                 unsigned long v;
1592                 int ind;
1593                 char* ptr;
1594
1595                 v = strtoul(timestr, &tail, 10);
1596                 if (v == ULONG_MAX || *tail == '\0')
1597                         /* value too large (ULONG_MAX or more)
1598                            or missing specifier */
1599                         goto error;
1600
1601                 ptr = strchr(spec, *tail);
1602                 if (ptr == NULL)
1603                         /* unknown specifier */
1604                         goto error;
1605
1606                 ind = ptr - spec;
1607
1608                 /* check if product will overflow the type */
1609                 if (!(v < ULONG_MAX / mult[ind]))
1610                         goto error;
1611
1612                 ADD_OVERFLOW(val, mult[ind] * v);
1613                 if (val == ULONG_MAX)
1614                         goto error;
1615
1616                 timestr = tail + 1;
1617         }
1618
1619         return val;
1620
1621 error:
1622         return ULONG_MAX;
1623 }
1624
1625 #define ARG2ULL(nr, str, defscale)                                      \
1626 do {                                                                    \
1627         unsigned long long limit, units = 0;                            \
1628         int rc;                                                         \
1629                                                                         \
1630         rc = parse_size(str, &limit, &units, 1);                        \
1631         if (rc < 0) {                                                   \
1632                 fprintf(stderr, "error: bad limit value %s\n", str);    \
1633                 return CMD_HELP;                                        \
1634         }                                                               \
1635         nr = ((units == 0) ? (defscale) : 1) * limit;                   \
1636 } while (0)
1637
1638 static inline int has_times_option(int argc, char **argv)
1639 {
1640         int i;
1641
1642         for (i = 1; i < argc; i++)
1643                 if (!strcmp(argv[i], "-t"))
1644                         return 1;
1645
1646         return 0;
1647 }
1648
1649 int lfs_setquota_times(int argc, char **argv)
1650 {
1651         int c, rc;
1652         struct if_quotactl qctl;
1653         char *mnt, *obd_type = (char *)qctl.obd_type;
1654         struct obd_dqblk *dqb = &qctl.qc_dqblk;
1655         struct obd_dqinfo *dqi = &qctl.qc_dqinfo;
1656         struct option long_opts[] = {
1657                 {"user",            no_argument,       0, 'u'},
1658                 {"group",           no_argument,       0, 'g'},
1659                 {"block-grace",     required_argument, 0, 'b'},
1660                 {"inode-grace",     required_argument, 0, 'i'},
1661                 {"times",           no_argument,       0, 't'},
1662                 {0, 0, 0, 0}
1663         };
1664
1665         memset(&qctl, 0, sizeof(qctl));
1666         qctl.qc_cmd  = LUSTRE_Q_SETINFO;
1667         qctl.qc_type = UGQUOTA;
1668
1669 #if 1
1670         /* compatibility syntax: setquota -t -[u|g] t1 t2 mnt */
1671         if (argc == 6 && !strcmp(argv[1], "-t") &&
1672             (!strcmp(argv[2], "-u") || !strcmp(argv[2], "-g")) &&
1673             argv[3][0] != '-' && argv[4][0] != '-') {
1674                 fprintf(stderr, "warning: using compatibility syntax, it may not"
1675                                 " be available in future releases!\n");
1676
1677                 qctl.qc_type = !strcmp(argv[2], "-u") ? USRQUOTA : GRPQUOTA;
1678
1679                 if ((dqi->dqi_bgrace = str2sec(argv[3])) == ULONG_MAX) {
1680                         fprintf(stderr, "error: bad block-grace: %s\n", argv[3]);
1681                         return CMD_HELP;
1682                 }
1683                 if ((dqi->dqi_igrace = str2sec(argv[4])) == ULONG_MAX) {
1684                         fprintf(stderr, "error: bad inode-grace: %s\n", argv[4]);
1685                         return CMD_HELP;
1686                 }
1687                 dqb->dqb_valid = QIF_TIMES;
1688                 mnt = argv[argc - 1];
1689                 goto quotactl;
1690         }
1691 #endif
1692
1693         optind = 0;
1694         while ((c = getopt_long(argc, argv, "ugb:i:t", long_opts, NULL)) != -1) {
1695                 switch (c) {
1696                 case 'u':
1697                 case 'g':
1698                         if (qctl.qc_type != UGQUOTA) {
1699                                 fprintf(stderr, "error: -u and -g can't be used "
1700                                                 "more than once\n");
1701                                 return CMD_HELP;
1702                         }
1703                         qctl.qc_type = (c == 'u') ? USRQUOTA : GRPQUOTA;
1704                         break;
1705                 case 'b':
1706                         if ((dqi->dqi_bgrace = str2sec(optarg)) == ULONG_MAX) {
1707                                 fprintf(stderr, "error: bad block-grace: %s\n",
1708                                         optarg);
1709                                 return CMD_HELP;
1710                         }
1711                         dqb->dqb_valid |= QIF_BTIME;
1712                         break;
1713                 case 'i':
1714                         if ((dqi->dqi_igrace = str2sec(optarg)) == ULONG_MAX) {
1715                                 fprintf(stderr, "error: bad inode-grace: %s\n",
1716                                         optarg);
1717                                 return CMD_HELP;
1718                         }
1719                         dqb->dqb_valid |= QIF_ITIME;
1720                         break;
1721                 case 't': /* Yes, of course! */
1722                         break;
1723                 default: /* getopt prints error message for us when opterr != 0 */
1724                         return CMD_HELP;
1725                 }
1726         }
1727
1728         if (qctl.qc_type == UGQUOTA) {
1729                 fprintf(stderr, "error: neither -u nor -g specified\n");
1730                 return CMD_HELP;
1731         }
1732
1733         if (optind != argc - 1) {
1734                 fprintf(stderr, "error: unexpected parameters encountered\n");
1735                 return CMD_HELP;
1736         }
1737
1738         mnt = argv[optind];
1739
1740 #if 1
1741 quotactl:
1742 #endif
1743         rc = llapi_quotactl(mnt, &qctl);
1744         if (rc) {
1745                 if (*obd_type)
1746                         fprintf(stderr, "%s %s ", obd_type,
1747                                 obd_uuid2str(&qctl.obd_uuid));
1748                 fprintf(stderr, "setquota failed: %s\n", strerror(errno));
1749                 return rc;
1750         }
1751
1752         return 0;
1753 }
1754
1755 #define BSLIMIT (1 << 0)
1756 #define BHLIMIT (1 << 1)
1757 #define ISLIMIT (1 << 2)
1758 #define IHLIMIT (1 << 3)
1759
1760 int lfs_setquota(int argc, char **argv)
1761 {
1762         int c, rc;
1763         struct if_quotactl qctl;
1764         char *mnt, *obd_type = (char *)qctl.obd_type;
1765         struct obd_dqblk *dqb = &qctl.qc_dqblk;
1766         struct option long_opts[] = {
1767                 {"user",            required_argument, 0, 'u'},
1768                 {"group",           required_argument, 0, 'g'},
1769                 {"block-softlimit", required_argument, 0, 'b'},
1770                 {"block-hardlimit", required_argument, 0, 'B'},
1771                 {"inode-softlimit", required_argument, 0, 'i'},
1772                 {"inode-hardlimit", required_argument, 0, 'I'},
1773                 {0, 0, 0, 0}
1774         };
1775         unsigned limit_mask = 0;
1776         char *endptr;
1777
1778         if (has_times_option(argc, argv))
1779                 return lfs_setquota_times(argc, argv);
1780
1781         memset(&qctl, 0, sizeof(qctl));
1782         qctl.qc_cmd  = LUSTRE_Q_SETQUOTA;
1783         qctl.qc_type = UGQUOTA; /* UGQUOTA makes no sense for setquota,
1784                                  * so it can be used as a marker that qc_type
1785                                  * isn't reinitialized from command line */
1786
1787 #if 1
1788         /* compatibility syntax: [-u|-g] <user|group> b B i I mount
1789          * will be removed in the future */
1790         if (argc == 8 && (!strcmp(argv[1], "-u") || !strcmp(argv[1], "-g")) &&
1791             argv[3][0] != '-' && argv[4][0] != '-' && argv[5][0] != '-' &&
1792             argv[6][0] != '-') {
1793                 fprintf(stderr, "warning: using compatibility syntax, it may not"
1794                                 " be available in future releases!\n");
1795
1796                 qctl.qc_type = !strcmp(argv[1], "-u") ? USRQUOTA : GRPQUOTA;
1797                 rc = name2id(&qctl.qc_id, argv[2],
1798                              (qctl.qc_type == USRQUOTA) ? USER : GROUP);
1799                 if (rc) {
1800                         fprintf(stderr, "error: unknown id %s\n", argv[2]);
1801                         return CMD_HELP;
1802                 }
1803
1804                 ARG2ULL(dqb->dqb_bsoftlimit, argv[3], 1024);
1805                 dqb->dqb_bsoftlimit >>= 10;
1806                 ARG2ULL(dqb->dqb_bhardlimit, argv[4], 1024);
1807                 dqb->dqb_bhardlimit >>= 10;
1808                 ARG2ULL(dqb->dqb_isoftlimit, argv[5], 1);
1809                 ARG2ULL(dqb->dqb_ihardlimit, argv[6], 1);
1810
1811                 dqb->dqb_valid = QIF_LIMITS;
1812                 mnt = argv[argc - 1];
1813                 goto quotactl;
1814         }
1815 #endif
1816
1817         optind = 0;
1818         while ((c = getopt_long(argc, argv, "u:g:b:B:i:I:", long_opts, NULL)) != -1) {
1819                 switch (c) {
1820                 case 'u':
1821                 case 'g':
1822                         if (qctl.qc_type != UGQUOTA) {
1823                                 fprintf(stderr, "error: -u and -g can't be used"
1824                                                 " more than once\n");
1825                                 return CMD_HELP;
1826                         }
1827                         qctl.qc_type = (c == 'u') ? USRQUOTA : GRPQUOTA;
1828                         rc = name2id(&qctl.qc_id, optarg,
1829                                      (qctl.qc_type == USRQUOTA) ? USER : GROUP);
1830                         if (rc) {
1831                                 qctl.qc_id = strtoul(optarg, &endptr, 10);
1832                                 if (*endptr != '\0') {
1833                                         fprintf(stderr, "error: can't find id "
1834                                                 "for name %s\n", optarg); 
1835                                         return CMD_HELP;
1836                                 }
1837                         }
1838                         break;
1839                 case 'b':
1840                         ARG2ULL(dqb->dqb_bsoftlimit, optarg, 1024);
1841                         dqb->dqb_bsoftlimit >>= 10;
1842                         limit_mask |= BSLIMIT;
1843                         break;
1844                 case 'B':
1845                         ARG2ULL(dqb->dqb_bhardlimit, optarg, 1024);
1846                         dqb->dqb_bhardlimit >>= 10;
1847                         limit_mask |= BHLIMIT;
1848                         break;
1849                 case 'i':
1850                         ARG2ULL(dqb->dqb_isoftlimit, optarg, 1);
1851                         limit_mask |= ISLIMIT;
1852                         break;
1853                 case 'I':
1854                         ARG2ULL(dqb->dqb_ihardlimit, optarg, 1);
1855                         limit_mask |= IHLIMIT;
1856                         break;
1857                 default: /* getopt prints error message for us when opterr != 0 */
1858                         return CMD_HELP;
1859                 }
1860         }
1861
1862         if (qctl.qc_type == UGQUOTA) {
1863                 fprintf(stderr, "error: neither -u nor -g was specified\n");
1864                 return CMD_HELP;
1865         }
1866
1867         if (limit_mask == 0) {
1868                 fprintf(stderr, "error: at least one limit must be specified\n");
1869                 return CMD_HELP;
1870         }
1871
1872         if (optind != argc - 1) {
1873                 fprintf(stderr, "error: unexpected parameters encountered\n");
1874                 return CMD_HELP;
1875         }
1876
1877         mnt = argv[optind];
1878
1879         if ((!(limit_mask & BHLIMIT) ^ !(limit_mask & BSLIMIT)) ||
1880             (!(limit_mask & IHLIMIT) ^ !(limit_mask & ISLIMIT))) {
1881                 /* sigh, we can't just set blimits/ilimits */
1882                 struct if_quotactl tmp_qctl = {.qc_cmd  = LUSTRE_Q_GETQUOTA,
1883                                                .qc_type = qctl.qc_type,
1884                                                .qc_id   = qctl.qc_id};
1885
1886                 rc = llapi_quotactl(mnt, &tmp_qctl);
1887                 if (rc < 0) {
1888                         fprintf(stderr, "error: setquota failed while retrieving"
1889                                         " current quota settings (%s)\n",
1890                                         strerror(errno));
1891                         return rc;
1892                 }
1893
1894                 if (!(limit_mask & BHLIMIT))
1895                         dqb->dqb_bhardlimit = tmp_qctl.qc_dqblk.dqb_bhardlimit;
1896                 if (!(limit_mask & BSLIMIT))
1897                         dqb->dqb_bsoftlimit = tmp_qctl.qc_dqblk.dqb_bsoftlimit;
1898                 if (!(limit_mask & IHLIMIT))
1899                         dqb->dqb_ihardlimit = tmp_qctl.qc_dqblk.dqb_ihardlimit;
1900                 if (!(limit_mask & ISLIMIT))
1901                         dqb->dqb_isoftlimit = tmp_qctl.qc_dqblk.dqb_isoftlimit;
1902
1903                 /* Keep grace times if we have got no softlimit arguments */
1904                 if ((limit_mask & BHLIMIT) && !(limit_mask & BSLIMIT)) {
1905                         dqb->dqb_valid |= QIF_BTIME;
1906                         dqb->dqb_btime = tmp_qctl.qc_dqblk.dqb_btime;
1907                 }
1908
1909                 if ((limit_mask & IHLIMIT) && !(limit_mask & ISLIMIT)) {
1910                         dqb->dqb_valid |= QIF_ITIME;
1911                         dqb->dqb_itime = tmp_qctl.qc_dqblk.dqb_itime;
1912                 }
1913         }
1914
1915         dqb->dqb_valid |= (limit_mask & (BHLIMIT | BSLIMIT)) ? QIF_BLIMITS : 0;
1916         dqb->dqb_valid |= (limit_mask & (IHLIMIT | ISLIMIT)) ? QIF_ILIMITS : 0;
1917
1918 #if 1
1919 quotactl:
1920 #endif
1921         rc = llapi_quotactl(mnt, &qctl);
1922         if (rc) {
1923                 if (*obd_type)
1924                         fprintf(stderr, "%s %s ", obd_type,
1925                                 obd_uuid2str(&qctl.obd_uuid));
1926                 fprintf(stderr, "setquota failed: %s\n", strerror(errno));
1927                 return rc;
1928         }
1929
1930         return 0;
1931 }
1932
1933 static inline char *type2name(int check_type)
1934 {
1935         if (check_type == USRQUOTA)
1936                 return "user";
1937         else if (check_type == GRPQUOTA)
1938                 return "group";
1939         else
1940                 return "unknown";
1941 }
1942
1943
1944 /* Converts seconds value into format string
1945  * result is returned in buf
1946  * Notes:
1947  *        1. result is in descenting order: 1w2d3h4m5s
1948  *        2. zero fields are not filled (except for p. 3): 5d1s
1949  *        3. zero seconds value is presented as "0s"
1950  */
1951 static void sec2str(time_t seconds, char *buf)
1952 {
1953         const char spec[] = "smhdw";
1954         const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
1955         unsigned long c;
1956         char* tail = buf;
1957         int i;
1958
1959         for (i = sizeof(mult) / sizeof(mult[0]) - 1 ; i >= 0; i--) {
1960                 c = seconds / mult[i];
1961
1962                 if (c > 0 || (i == 0 && buf == tail))
1963                         tail += snprintf(tail, 40-(tail-buf), "%lu%c", c, spec[i]);
1964
1965                 seconds %= mult[i];
1966         }
1967 }
1968
1969
1970 static void diff2str(time_t seconds, char *buf, time_t now)
1971 {
1972
1973         buf[0] = 0;
1974         if (!seconds)
1975                 return;
1976         if (seconds <= now) {
1977                 strcpy(buf, "none");
1978                 return;
1979         }
1980         sec2str(seconds - now, buf);
1981 }
1982
1983 static void print_quota_title(char *name, struct if_quotactl *qctl)
1984 {
1985         printf("Disk quotas for %s %s (%cid %u):\n",
1986                type2name(qctl->qc_type), name,
1987                *type2name(qctl->qc_type), qctl->qc_id);
1988         printf("%15s%8s %7s%8s%8s%8s %7s%8s%8s\n",
1989                "Filesystem",
1990                "kbytes", "quota", "limit", "grace",
1991                "files", "quota", "limit", "grace");
1992 }
1993
1994 #define GENERAL_QUOTA_INFO 1
1995 #define MDS_QUOTA_INFO     2
1996 #define OST_QUOTA_INFO     3
1997
1998 static void print_quota(char *mnt, struct if_quotactl *qctl, int type)
1999 {
2000         time_t now;
2001
2002         time(&now);
2003
2004         if (qctl->qc_cmd == LUSTRE_Q_GETQUOTA || qctl->qc_cmd == Q_GETOQUOTA) {
2005                 int bover = 0, iover = 0;
2006                 struct obd_dqblk *dqb = &qctl->qc_dqblk;
2007
2008                 if (dqb->dqb_bhardlimit &&
2009                     toqb(dqb->dqb_curspace) >= dqb->dqb_bhardlimit) {
2010                         bover = 1;
2011                 } else if (dqb->dqb_bsoftlimit &&
2012                            toqb(dqb->dqb_curspace) >= dqb->dqb_bsoftlimit) {
2013                         if (dqb->dqb_btime > now) {
2014                                 bover = 2;
2015                         } else {
2016                                 bover = 3;
2017                         }
2018                 }
2019
2020                 if (dqb->dqb_ihardlimit &&
2021                     dqb->dqb_curinodes >= dqb->dqb_ihardlimit) {
2022                         iover = 1;
2023                 } else if (dqb->dqb_isoftlimit &&
2024                            dqb->dqb_curinodes >= dqb->dqb_isoftlimit) {
2025                         if (dqb->dqb_btime > now) {
2026                                 iover = 2;
2027                         } else {
2028                                 iover = 3;
2029                         }
2030                 }
2031
2032 #if 0           /* XXX: always print quotas even when no usages */
2033                 if (dqb->dqb_curspace || dqb->dqb_curinodes)
2034 #endif
2035                 {
2036                         char numbuf[3][32];
2037                         char timebuf[40];
2038
2039                         if (strlen(mnt) > 15)
2040                                 printf("%s\n%15s", mnt, "");
2041                         else
2042                                 printf("%15s", mnt);
2043
2044                         if (bover)
2045                                 diff2str(dqb->dqb_btime, timebuf, now);
2046                         sprintf(numbuf[0], (dqb->dqb_valid & QIF_SPACE) ?
2047                                 LPU64 : "["LPU64"]", toqb(dqb->dqb_curspace));
2048                         if (type == GENERAL_QUOTA_INFO)
2049                                 sprintf(numbuf[1], (dqb->dqb_valid & QIF_BLIMITS)
2050                                         ? LPU64 : "["LPU64"]",
2051                                         dqb->dqb_bsoftlimit);
2052                         else
2053                                 sprintf(numbuf[1], "%s", "-");
2054                         sprintf(numbuf[2], (dqb->dqb_valid & QIF_BLIMITS)
2055                                 ? LPU64 : "["LPU64"]", dqb->dqb_bhardlimit);
2056                         printf(" %7s%c %6s %7s %7s",
2057                                numbuf[0], bover ? '*' : ' ', numbuf[1],
2058                                numbuf[2], bover > 1 ? timebuf : "-");
2059
2060                         if (iover)
2061                                 diff2str(dqb->dqb_itime, timebuf, now);
2062
2063                         sprintf(numbuf[0], (dqb->dqb_valid & QIF_INODES) ?
2064                                 LPU64 : "["LPU64"]", dqb->dqb_curinodes);
2065                        if (type == GENERAL_QUOTA_INFO)
2066                                 sprintf(numbuf[1], (dqb->dqb_valid & QIF_ILIMITS)
2067                                         ? LPU64 : "["LPU64"]",
2068                                         dqb->dqb_isoftlimit);
2069                         else
2070                                 sprintf(numbuf[1], "%s", "-");
2071                         sprintf(numbuf[2], (dqb->dqb_valid & QIF_ILIMITS) ?
2072                                 LPU64 : "["LPU64"]", dqb->dqb_ihardlimit);
2073                         if (type != OST_QUOTA_INFO)
2074                                 printf(" %7s%c %6s %7s %7s",
2075                                        numbuf[0], iover ? '*' : ' ', numbuf[1],
2076                                        numbuf[2], iover > 1 ? timebuf : "-");
2077                         else
2078                                 printf(" %7s %7s %7s %7s", "-", "-", "-", "-");
2079                         printf("\n");
2080                 }
2081         } else if (qctl->qc_cmd == LUSTRE_Q_GETINFO ||
2082                    qctl->qc_cmd == Q_GETOINFO) {
2083                 char bgtimebuf[40];
2084                 char igtimebuf[40];
2085
2086                 sec2str(qctl->qc_dqinfo.dqi_bgrace, bgtimebuf);
2087                 sec2str(qctl->qc_dqinfo.dqi_igrace, igtimebuf);
2088                 printf("Block grace time: %s; Inode grace time: %s\n",
2089                        bgtimebuf, igtimebuf);
2090         }
2091 }
2092
2093 static int print_mds_quota(char *mnt, struct if_quotactl *qctl)
2094 {
2095         int rc;
2096
2097         /* XXX: this is a flag to mark that only mds quota is wanted */
2098         qctl->qc_dqblk.dqb_valid = 1;
2099         rc = llapi_quotactl(mnt, qctl);
2100         if (rc) {
2101                 fprintf(stderr, "quotactl failed: %s\n", strerror(errno));
2102                 return rc;
2103         }
2104
2105         print_quota(obd_uuid2str(&qctl->obd_uuid), qctl, MDS_QUOTA_INFO);
2106         return 0;
2107 }
2108
2109 static int print_lov_quota(char *mnt, struct if_quotactl *qctl)
2110 {
2111         DIR *dir;
2112         struct obd_uuid *uuids = NULL, *uuidp;
2113         int obdcount = 1024;
2114         int i, rc = 0, rc1 = 0;
2115
2116         dir = opendir(mnt);
2117         if (!dir) {
2118                 fprintf(stderr, "open %s failed: %s\n", mnt, strerror(errno));
2119                 return -ENOENT;
2120         }
2121
2122         uuids = (struct obd_uuid *)malloc(INIT_ALLOC_NUM_OSTS *
2123                                           sizeof(struct obd_uuid));
2124         if (uuids == NULL)
2125                 goto out;
2126
2127 retry_get_uuids:
2128         rc = llapi_lov_get_uuids(dirfd(dir), uuids, &obdcount);
2129         if (rc != 0) {
2130                 struct obd_uuid *uuids_temp;
2131
2132                 if (rc == -EOVERFLOW) {
2133                         uuids_temp = realloc(uuids, obdcount *
2134                                              sizeof(struct obd_uuid));
2135                         if (uuids_temp != NULL)
2136                                 goto retry_get_uuids;
2137                         else
2138                                 rc = -ENOMEM;
2139                 }
2140
2141                 fprintf(stderr, "get ost uuid failed: %s\n", strerror(rc));
2142                 goto out;
2143         }
2144
2145         for (i = 0, uuidp = uuids; i < obdcount; i++, uuidp++) {
2146                 memcpy(&qctl->obd_uuid, uuidp, sizeof(*uuidp));
2147
2148                 /* XXX clear this flag to get quota from osts */
2149                 qctl->qc_dqblk.dqb_valid = 0;
2150                 rc = llapi_quotactl(mnt, qctl);
2151                 if (rc) {
2152                         if (!rc1)
2153                                 rc1 = rc;
2154                         fprintf(stderr, "%s quotactl failed: %s\n",
2155                                 uuidp->uuid, strerror(errno));
2156                         continue;
2157                 }
2158
2159                 print_quota((char *)uuidp->uuid, qctl, OST_QUOTA_INFO);
2160         }
2161
2162 out:
2163         closedir(dir);
2164         if (!rc)
2165                 rc = rc1;
2166         return rc;
2167 }
2168
2169 static int lfs_quota(int argc, char **argv)
2170 {
2171         int c;
2172         char *mnt, *name = NULL;
2173         struct if_quotactl qctl = { .qc_cmd = LUSTRE_Q_GETQUOTA,
2174                                     .qc_type = UGQUOTA };
2175         char *obd_type = (char *)qctl.obd_type;
2176         char *obd_uuid = (char *)qctl.obd_uuid.uuid;
2177         int rc, rc1 = 0, rc2 = 0, rc3 = 0, verbose = 0, inacc, quiet = 0;
2178         int pass = 0;
2179         char *endptr;
2180
2181         optind = 0;
2182         while ((c = getopt(argc, argv, "ugto:qv")) != -1) {
2183                 switch (c) {
2184                 case 'u':
2185                         if (qctl.qc_type != UGQUOTA) {
2186                                 fprintf(stderr, "error: use either -u or -g\n");
2187                                 return CMD_HELP;
2188                         }
2189                         qctl.qc_type = USRQUOTA;
2190                         break;
2191                 case 'g':
2192                         if (qctl.qc_type != UGQUOTA) {
2193                                 fprintf(stderr, "error: use either -u or -g\n");
2194                                 return CMD_HELP;
2195                         }
2196                         qctl.qc_type = GRPQUOTA;
2197                         break;
2198                 case 't':
2199                         qctl.qc_cmd = LUSTRE_Q_GETINFO;
2200                         break;
2201                 case 'o':
2202                         strncpy(obd_uuid, optarg, sizeof(qctl.obd_uuid));
2203                         break;
2204                 case 'v':
2205                         verbose = 1;
2206                         break;
2207                 case 'q':
2208                         quiet = 1;
2209                         break;
2210                 default:
2211                         fprintf(stderr, "error: %s: option '-%c' "
2212                                         "unrecognized\n", argv[0], c);
2213                         return CMD_HELP;
2214                 }
2215         }
2216
2217         /* current uid/gid info for "lfs quota /path/to/lustre/mount" */
2218         if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA && qctl.qc_type == UGQUOTA &&
2219             optind == argc - 1) {
2220 ug_output:
2221                 memset(&qctl, 0, sizeof(qctl)); /* spoiled by print_*_quota */
2222                 qctl.qc_cmd = LUSTRE_Q_GETQUOTA;
2223                 if (pass++ == 0) {
2224                         qctl.qc_type = USRQUOTA;
2225                         qctl.qc_id = geteuid();
2226                 } else {
2227                         qctl.qc_type = GRPQUOTA;
2228                         qctl.qc_id = getegid();
2229                 }
2230                 rc = id2name(&name, qctl.qc_id,
2231                              (qctl.qc_type == USRQUOTA) ? USER : GROUP);
2232                 if (rc)
2233                         name = "<unknown>";
2234         /* lfs quota -u username /path/to/lustre/mount */
2235         } else if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA) {
2236                 /* options should be followed by u/g-name and mntpoint */
2237                 if (optind + 2 != argc || qctl.qc_type == UGQUOTA) {
2238                         fprintf(stderr, "error: missing quota argument(s)\n");
2239                         return CMD_HELP;
2240                 }
2241
2242                 name = argv[optind++];
2243                 rc = name2id(&qctl.qc_id, name,
2244                              (qctl.qc_type == USRQUOTA) ? USER : GROUP);
2245                 if (rc) {
2246                         qctl.qc_id = strtoul(name, &endptr, 10);
2247                         if (*endptr != '\0') {
2248                                 fprintf(stderr, "error: can't find id for name "
2249                                         "%s\n", name);
2250                                 return CMD_HELP;
2251                         }
2252                 }
2253         } else if (optind + 1 != argc || qctl.qc_type == UGQUOTA) {
2254                 fprintf(stderr, "error: missing quota info argument(s)\n");
2255                 return CMD_HELP;
2256         }
2257
2258         mnt = argv[optind];
2259
2260         rc1 = llapi_quotactl(mnt, &qctl);
2261         if (rc1 == -1) {
2262                 switch (errno) {
2263                 case EPERM:
2264                         fprintf(stderr, "Permission denied.\n");
2265                 case ENOENT:
2266                         /* We already got a "No such file..." message. */
2267                         goto out;
2268                 case ESRCH: {
2269                         fprintf(stderr, "%s quotas are not enabled.\n",
2270                                 qctl.qc_type == USRQUOTA?"user":"group");
2271                         goto out;
2272                 }
2273                 default:
2274                         fprintf(stderr, "Unexpected quotactl error: %s\n",
2275                                 strerror(errno));
2276                 }
2277         }
2278
2279         if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA && !quiet)
2280                 print_quota_title(name, &qctl);
2281
2282         if (rc1 && *obd_type)
2283                 fprintf(stderr, "%s %s ", obd_type, obd_uuid);
2284
2285         if (*obd_uuid)
2286                 mnt = "";
2287
2288         inacc = (qctl.qc_cmd == LUSTRE_Q_GETQUOTA) &&
2289                 ((qctl.qc_dqblk.dqb_valid & (QIF_LIMITS|QIF_USAGE)) != (QIF_LIMITS|QIF_USAGE));
2290
2291         print_quota(mnt, &qctl, GENERAL_QUOTA_INFO);
2292
2293         if (!*obd_uuid && qctl.qc_cmd != LUSTRE_Q_GETINFO && verbose) {
2294                 rc2 = print_mds_quota(mnt, &qctl);
2295                 rc3 = print_lov_quota(mnt, &qctl);
2296         }
2297
2298         if (rc1 || rc2 || rc3 || inacc)
2299                 printf("Some errors happened when getting quota info. "
2300                        "Some devices may be not working or deactivated. "
2301                        "The data in \"[]\" is inaccurate.\n");
2302
2303 out:
2304         if (pass == 1)
2305                 goto ug_output;
2306
2307         return rc1;
2308 }
2309 #endif /* HAVE_SYS_QUOTA_H! */
2310
2311 int main(int argc, char **argv)
2312 {
2313         int rc;
2314
2315         setlinebuf(stdout);
2316
2317         ptl_initialize(argc, argv);
2318         if (obd_initialize(argc, argv) < 0)
2319                 exit(2);
2320         if (dbg_initialize(argc, argv) < 0)
2321                 exit(3);
2322
2323         Parser_init("lfs > ", cmdlist);
2324
2325         if (argc > 1) {
2326                 rc = Parser_execarg(argc - 1, argv + 1, cmdlist);
2327         } else {
2328                 rc = Parser_commands();
2329         }
2330
2331         obd_finalize(argc, argv);
2332         return rc < 0 ? -rc : rc;
2333 }