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