Whamcloud - gitweb
Branch b1_6
[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  *  Copyright (C) 2002 Cluster File Systems, Inc.
5  *   Author: Peter J. Braam <braam@clusterfs.com>
6  *   Author: Phil Schwan <phil@clusterfs.com>
7  *   Author: Robert Read <rread@clusterfs.com>
8  *
9  *   This file is part of Lustre, http://www.lustre.org.
10  *
11  *   Lustre is free software; you can redistribute it and/or
12  *   modify it under the terms of version 2 of the GNU General Public
13  *   License as published by the Free Software Foundation.
14  *
15  *   Lustre is distributed in the hope that it will be useful,
16  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
17  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  *   GNU General Public License for more details.
19  *
20  *   You should have received a copy of the GNU General Public License
21  *   along with Lustre; if not, write to the Free Software
22  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23  *
24  */
25
26
27 #include <stdlib.h>
28 #include <stdio.h>
29 #include <getopt.h>
30 #include <string.h>
31 #include <mntent.h>
32 #include <errno.h>
33 #include <pwd.h>
34 #include <grp.h>
35 #include <sys/types.h>
36 #include <sys/stat.h>
37 #include <fcntl.h>
38 #include <dirent.h>
39 #include <time.h>
40 #include <ctype.h>
41
42 #include <lnet/api-support.h>
43 #include <lnet/lnetctl.h>
44
45 #include <liblustre.h>
46 #include <lustre/lustre_idl.h>
47 #include <lustre/liblustreapi.h>
48 #include <lustre/lustre_user.h>
49
50 #include "parser.h"
51 #include "obdctl.h"
52
53 unsigned int libcfs_subsystem_debug = 0;
54
55 /* all functions */
56 static int lfs_setstripe(int argc, char **argv);
57 static int lfs_find(int argc, char **argv);
58 static int lfs_getstripe(int argc, char **argv);
59 static int lfs_osts(int argc, char **argv);
60 static int lfs_df(int argc, char **argv);
61 static int lfs_check(int argc, char **argv);
62 static int lfs_catinfo(int argc, char **argv);
63 #ifdef HAVE_QUOTA_SUPPORT
64 static int lfs_quotachown(int argc, char **argv);
65 static int lfs_quotacheck(int argc, char **argv);
66 static int lfs_quotaon(int argc, char **argv);
67 static int lfs_quotaoff(int argc, char **argv);
68 static int lfs_setquota(int argc, char **argv);
69 static int lfs_quota(int argc, char **argv);
70 #endif
71 static int lfs_join(int argc, char **argv);
72
73 /* all avaialable commands */
74 command_t cmdlist[] = {
75         {"setstripe", lfs_setstripe, 0,
76          "Create a new file with a specific striping pattern or\n"
77          "set the default striping pattern on an existing directory or\n"
78          "delete the default striping pattern from an existing directory\n"
79          "usage: setstripe <filename|dirname> <stripe_size> <stripe_index> <stripe_count>\n"
80          "       or \n"
81          "       setstripe <filename|dirname> [--size|-s stripe_size]\n"
82          "                                    [--index|-i stripe_index]\n"
83          "                                    [--count|-c stripe_count]\n"
84          "       or \n"
85          "       setstripe -d <dirname>   (to delete default striping)\n"
86          "\tstripe_size:  Number of bytes on each OST (0 filesystem default)\n"
87          "\tstripe_index: OST index of first stripe (-1 filesystem default)\n"
88          "\tstripe_count: Number of OSTs to stripe over (0 default, -1 all)"},
89         {"getstripe", lfs_getstripe, 0,
90          "To list the striping info for a given filename or files in a\n"
91          "directory or recursively for all files in a directory tree.\n"
92          "usage: getstripe [--obd|-O <uuid>] [--quiet | -q] [--verbose | -v]\n"
93          "                 [--recursive | -r] <dir|file> ..."},
94         {"find", lfs_find, 0,
95          "To find files that match given parameters recursively in a directory tree.\n"
96          "usage: find <dir/file> ... \n"
97          "     [[!] --atime|-A N] [[!] --mtime|-M N] [[!] --ctime|-C N] [--maxdepth|-D N]\n"
98          "     [[!] --name|-n <pattern>] [--print0|-P] [--print|-p] [--obd|-O <uuid>]\n"
99          "\t !: used before --atime, --mtime, --ctime specifies the negative value\n"
100          "\t !: used before --name means find exclude the regular expression pattern\n"
101          "If one of the options below is provided, find works the same as 'getstripe':\n"
102          "To list the striping info for a given filename or files in a directory or\n"
103          "recursively.\n"
104          "OBSOLETE usage: find [--quiet | -q] [--verbose | -v]\n"
105          "                     [--recursive | -r] <dir|file> ..."},
106         {"check", lfs_check, 0,
107          "Display the status of MDS or OSTs (as specified in the command)\n"
108          "or all the servers (MDS and OSTs).\n"
109          "usage: check <osts|mds|servers>"},
110         {"catinfo", lfs_catinfo, 0,
111          "Show information of specified type logs.\n"
112          "usage: catinfo {keyword} [node name]\n"
113          "\tkeywords are one of followings: config, deletions.\n"
114          "\tnode name must be provided when use keyword config."},
115         {"join", lfs_join, 0,
116          "join two lustre files into one - join A, B, will be like cat B >> A & del B\n"
117          "usage: join <filename_A> <filename_B>\n"},
118         {"osts", lfs_osts, 0, "osts"},
119         {"df", lfs_df, 0,
120          "report filesystem disk space usage or inodes usage"
121          "of each MDS/OSD.\n"
122          "Usage: df [-i] [-h] [path]"},
123 #ifdef HAVE_QUOTA_SUPPORT
124         {"quotachown",lfs_quotachown, 0,
125          "Change files' owner or group on the specified filesystem.\n"
126          "usage: quotachown [-i] <filesystem>\n"
127          "\t-i: ignore error if file is not exist\n"},
128         {"quotacheck", lfs_quotacheck, 0,
129          "Scan the specified filesystem for disk usage, and create,\n"
130          "or update quota files.\n"
131          "usage: quotacheck [ -ug ] <filesystem>"},
132         {"quotaon", lfs_quotaon, 0, "Turn filesystem quotas on.\n"
133          "usage: quotaon [ -ugf ] <filesystem>"},
134         {"quotaoff", lfs_quotaoff, 0, "Turn filesystem quotas off.\n"
135          "usage: quotaoff [ -ug ] <filesystem>"},
136         {"setquota", lfs_setquota, 0, "Set filesystem quotas.\n"
137          "usage: setquota [ -u | -g ] <name> <block-softlimit> <block-hardlimit> <inode-softlimit> <inode-hardlimit> <filesystem>\n"
138          "       setquota -t [ -u | -g ] <block-grace> <inode-grace> <filesystem>"},
139         {"quota", lfs_quota, 0, "Display disk usage and limits.\n"
140          "usage: quota [ -o obd_uuid ] [ -u | -g ] [name] <filesystem>"},
141 #endif
142         {"help", Parser_help, 0, "help"},
143         {"exit", Parser_quit, 0, "quit"},
144         {"quit", Parser_quit, 0, "quit"},
145         { 0, 0, 0, NULL }
146 };
147
148 /* functions */
149 static int lfs_setstripe(int argc, char **argv)
150 {
151         char *fname;
152         int result;
153         long st_size;
154         int  st_offset, st_count;
155         char *end;
156         int c;
157         int delete = 0;
158         char *stripe_size_arg = NULL;
159         char *stripe_off_arg = NULL;
160         char *stripe_count_arg = NULL;
161
162         struct option long_opts[] = {
163                 {"size",        required_argument, 0, 's'},
164                 {"count",       required_argument, 0, 'c'},
165                 {"index",       required_argument, 0, 'i'},
166                 {"delete",      no_argument,       0, 'd'},
167                 {0, 0, 0, 0}
168         };
169
170         st_size = 0;
171         st_offset = -1;
172         st_count = 0;
173         if (argc == 3 && strcmp(argv[1], "-d") == 0) {
174                 /* for compatibility with the existing positional parameter
175                  * usage */
176                 fname = argv[2];
177                 optind = 2;
178         } else if (argc == 5  && 
179                    (argv[2][0] != '-' || isdigit(argv[2][1])) &&
180                    (argv[3][0] != '-' || isdigit(argv[3][1])) &&
181                    (argv[4][0] != '-' || isdigit(argv[4][1])) ) {
182                 /* for compatibility with the existing positional parameter
183                  * usage */
184                 fname = argv[1];
185                 stripe_size_arg = argv[2];
186                 stripe_off_arg = argv[3];
187                 stripe_count_arg = argv[4];
188                 optind = 4;
189         } else {
190                 while ((c = getopt_long(argc, argv, "c:di:s:",
191                                                 long_opts, NULL)) >= 0) 
192                 {
193                         switch (c) {
194                         case 0:
195                                 /* Long options. */
196                                 break;
197                         case 'c':
198                                 stripe_count_arg = optarg;
199                                 break;
200                         case 'd':
201                                 /* delete the default striping pattern */
202                                 delete = 1;
203                                 break;
204                         case 'i':
205                                 stripe_off_arg = optarg;
206                                 break;
207                         case 's':
208                                 stripe_size_arg = optarg;
209                                 break;
210                         case '?':
211                                 return CMD_HELP;
212                         default:
213                                 fprintf(stderr, "error: %s: option '%s' "
214                                                 "unrecognized\n",
215                                                 argv[0], argv[optind - 1]);
216                                 return CMD_HELP;
217                         }
218                 }
219
220                 if (optind < argc)
221                         fname = argv[optind];
222                 else
223                         return CMD_HELP;
224
225                 if (delete && 
226                     (stripe_size_arg != NULL || stripe_off_arg != NULL || 
227                      stripe_count_arg != NULL)) {
228                         fprintf(stderr, "error: %s: cannot specify -d with "
229                                         "-s, -c or -i options\n",
230                                         argv[0]);
231                         return CMD_HELP;
232                 }
233         }
234
235         if (optind != argc - 1) {
236                 fprintf(stderr, "error: %s: only 1 filename|dirname can be "
237                                 "specified: '%s'\n",
238                                 argv[0], argv[argc-1]);
239                 return CMD_HELP;
240         }
241
242         /* get the stripe size */
243         if (stripe_size_arg != NULL) {
244                 st_size = strtoul(stripe_size_arg, &end, 0);
245                 if (*end != '\0') {
246                         fprintf(stderr, "error: %s: bad stripe size '%s'\n",
247                                         argv[0], stripe_size_arg);
248                         return CMD_HELP;
249                 }
250         }
251         /* get the stripe offset */
252         if (stripe_off_arg != NULL) {
253                 st_offset = strtoul(stripe_off_arg, &end, 0);
254                 if (*end != '\0') {
255                         fprintf(stderr, "error: %s: bad stripe offset '%s'\n",
256                                         argv[0], stripe_off_arg);
257                         return CMD_HELP;
258                 }
259         }
260         /* get the stripe count */
261         if (stripe_count_arg != NULL) {
262                 st_count = strtoul(stripe_count_arg, &end, 0);
263                 if (*end != '\0') {
264                         fprintf(stderr, "error: %s: bad stripe count '%s'\n",
265                                         argv[0], stripe_count_arg);
266                         return CMD_HELP;
267                 }
268         }
269
270         result = llapi_file_create(fname, st_size, st_offset, st_count, 0);
271         if (result)
272                 fprintf(stderr, "error: %s: create stripe file failed\n",
273                                 argv[0]);
274
275         return result;
276 }
277
278 static int set_time(time_t *time, time_t *set, char *str)
279 {
280         time_t t;
281         int res = 0;
282         
283         if (str[0] == '+')
284                 res = 1;
285         else if (str[0] == '-')
286                 res = -1;
287
288         if (res)
289                 str++;
290
291         t = strtol(str, NULL, 0);
292         if (*time < t * 24 * 60 * 60) {
293                 if (res)
294                         str--;
295                 fprintf(stderr, "Wrong time '%s' is specified.\n", str);
296                 return INT_MAX;
297         }
298
299         *set = *time - t * 24 * 60 * 60;
300         return res;
301 }
302
303 static int lfs_find(int argc, char **argv)
304 {
305         int new_fashion = 1;
306         int c, ret;
307         int zeroend;
308         time_t t;
309         unsigned int depth;
310         int quiet, verbose, recursive;
311         struct find_param param;
312         struct obd_uuid *obduuid = NULL;
313         char timestr[1024];
314         struct option long_opts[] = {
315                 /* New find options. */
316                 {"atime",     required_argument, 0, 'A'},
317                 {"ctime",     required_argument, 0, 'C'},
318                 {"mtime",     required_argument, 0, 'M'},
319                 {"maxdepth",  required_argument, 0, 'D'},
320                 {"name",      required_argument, 0, 'n'},
321                 /* --obd is considered as a new option. */
322                 {"obd",       required_argument, 0, 'O'},
323                 {"ost",       required_argument, 0, 'O'},
324                 {"print",     no_argument,       0, 'P'},
325                 {"print0",    no_argument,       0, 'p'},
326                 /* Old find options. */
327                 {"quiet",     no_argument,       0, 'q'},
328                 {"recursive", no_argument,       0, 'r'},
329                 {"verbose",   no_argument,       0, 'v'},
330                 {0, 0, 0, 0}
331         };
332         int pathstart = -1;
333         int pathend = -1;
334         int neg_opt = 0;
335         time_t *xtime;
336         int *xsign;
337         int isoption;
338
339         time(&t);
340         zeroend = 0;
341         depth = -1;
342         quiet = verbose = recursive = 0;
343
344         memset(&param, 0, sizeof(param));
345
346         while ((c = getopt_long_only(argc, argv, "-A:C:D:M:n:PpOqrv",
347                                      long_opts, NULL)) >= 0)
348         {
349                 xtime = NULL;
350                 xsign = NULL;
351                 if (neg_opt)
352                         --neg_opt;
353                 /* '!' is part of option */
354                 isoption = (c != 1) || (strcmp(optarg, "!") == 0);
355                 if (!isoption && pathend != -1) {
356                         fprintf(stderr, "err: %s: filename|dirname must either "
357                                         "precede options or follow options\n",
358                                         argv[0]);
359                         return CMD_HELP;
360                 }
361                 if (!isoption && pathstart == -1)
362                         pathstart = optind - 1;
363                 if (isoption && pathstart != -1 && pathend == -1) {
364                         pathend = optind - 2;
365                         if ((c == 1 && strcmp(optarg, "!") == 0) ||
366                             c == 'P' || c == 'p' || c == 'O' ||
367                             c == 'q' || c == 'r' || c == 'v')
368                                 pathend = optind - 1;
369                 }
370                 switch (c) {
371                 case 0:
372                         /* Long options. */
373                         break;
374                 case 1:
375                         if (strcmp(optarg, "!") == 0)
376                                 neg_opt = 2;
377                       break;
378                 case 'A':
379                         xtime = &param.atime;
380                         xsign = &param.asign;
381                 case 'C':
382                         if (c == 'C') {
383                                 xtime = &param.ctime;
384                                 xsign = &param.csign;
385                         }
386                 case 'M':
387                         if (c == 'M') {
388                                 xtime = &param.mtime;
389                                 xsign = &param.msign;
390                         }
391                         new_fashion = 1;
392                         if (neg_opt) {
393                                 if (optarg[0] == '-')
394                                         optarg[0] = '+';
395                                 else if (optarg[0] == '+')
396                                         optarg[0] = '-';
397                                 else {
398                                         timestr[0] = '-';
399                                         timestr[1] = '\0';
400                                         strcat(timestr, optarg);
401                                         optarg = timestr;
402                                 }
403                         }
404                         ret = set_time(&t, xtime, optarg);
405                         if (ret == INT_MAX)
406                                 return -1;
407                         if (ret)
408                                 *xsign = ret;
409                         break;
410                 case 'D':
411                         depth = strtol(optarg, 0, 0);
412                         break;
413                 case 'n':
414                         new_fashion = 1;
415                         param.pattern = (char *)optarg;
416                         if (neg_opt)
417                                 param.exclude_pattern = 1;
418                         else
419                                 param.exclude_pattern = 0;
420                         break;
421                 case 'O':
422                         if (obduuid) {
423                                 fprintf(stderr,
424                                         "error: %s: only one obduuid allowed",
425                                         argv[0]);
426                                 return CMD_HELP;
427                         }
428                         obduuid = (struct obd_uuid *)optarg;
429                         break;
430                 case 'p':
431                         zeroend = 1;
432                         break;
433                 case 'P':
434                         break;
435                 case 'q':
436                         new_fashion = 0;
437                         quiet++;
438                         verbose = 0;
439                         break;
440                 case 'r':
441                         new_fashion = 0;
442                         recursive = 1;
443                         break;
444                 case 'v':
445                         new_fashion = 0;
446                         verbose++;
447                         quiet = 0;
448                         break;
449                 case '?':
450                         return CMD_HELP;
451                 default:
452                         fprintf(stderr, "error: %s: option '%s' unrecognized\n",
453                                 argv[0], argv[optind - 1]);
454                         return CMD_HELP;
455                 };
456         }
457
458         if (pathstart == -1) {
459                 fprintf(stderr, "error: %s: no filename|pathname\n",
460                                 argv[0]);
461                 return CMD_HELP;
462         } else if (pathend == -1) {
463                 /* no options */
464                 pathend = argc;
465         }
466
467         param.obduuid = obduuid;
468         if (new_fashion) {
469                 param.maxdepth = depth;
470                 param.zeroend = zeroend;
471                 param.quiet = 1;
472         } else {
473                 param.recursive = recursive;
474                 param.verbose = verbose;
475                 param.quiet = quiet;
476                 param.maxdepth = recursive ? -1 : 1;
477         }
478
479         do {
480                 if (new_fashion)
481                         ret = llapi_find(argv[pathstart], &param);
482                 else
483                         ret = llapi_getstripe(argv[pathstart], &param);
484         } while (++pathstart < pathend && !ret);
485
486         if (ret)
487                 fprintf(stderr, "error: %s failed for %s.\n",
488                         argv[0], argv[optind - 1]);
489
490         return ret;
491 }
492
493 static int lfs_getstripe(int argc, char **argv)
494 {
495         struct option long_opts[] = {
496                 {"obd", 1, 0, 'O'},
497                 {"quiet", 0, 0, 'q'},
498                 {"recursive", 0, 0, 'r'},
499                 {"verbose", 0, 0, 'v'},
500                 {0, 0, 0, 0}
501         };
502         char short_opts[] = "hO:qrv";
503         int quiet, verbose, recursive, c, rc;
504         struct obd_uuid *obduuid = NULL;
505         struct find_param param;
506
507         optind = 0;
508         quiet = verbose = recursive = 0;
509         while ((c = getopt_long(argc, argv, short_opts,
510                                 long_opts, NULL)) != -1) {
511                 switch (c) {
512                 case 'O':
513                         if (obduuid) {
514                                 fprintf(stderr,
515                                         "error: %s: only one obduuid allowed",
516                                         argv[0]);
517                                 return CMD_HELP;
518                         }
519                         obduuid = (struct obd_uuid *)optarg;
520                         break;
521                 case 'q':
522                         quiet++;
523                         verbose = 0;
524                         break;
525                 case 'r':
526                         recursive = 1;
527                         break;
528                 case 'v':
529                         verbose++;
530                         quiet = 0;
531                         break;
532                 case '?':
533                         return CMD_HELP;
534                 default:
535                         fprintf(stderr, "error: %s: option '%s' unrecognized\n",
536                                 argv[0], argv[optind - 1]);
537                         return CMD_HELP;
538                 }
539         }
540
541         if (optind >= argc)
542                 return CMD_HELP;
543
544         memset(&param, 0, sizeof(param));
545         param.recursive = recursive;
546         param.verbose = verbose;
547         param.quiet = quiet;
548         param.obduuid = obduuid;
549         param.maxdepth = recursive ? -1 : 1;
550
551         do {
552                 rc = llapi_getstripe(argv[optind], &param);
553         } while (++optind < argc && !rc);
554
555         if (rc)
556                 fprintf(stderr, "error: %s failed for %s.\n", 
557                         argv[0], argv[optind - 1]);
558         return rc;
559 }
560
561 static int lfs_osts(int argc, char **argv)
562 {
563         FILE *fp;
564         struct mntent *mnt = NULL;
565         struct obd_uuid *obduuid = NULL;
566         struct find_param param;
567         int rc=0;
568
569         if (argc != 1)
570                 return CMD_HELP;
571
572         fp = setmntent(MOUNTED, "r");
573
574         if (fp == NULL) {
575                  fprintf(stderr, "%s: setmntent(%s): %s:", argv[0], MOUNTED,
576                         strerror (errno));
577         } else {
578                 mnt = getmntent(fp);
579                 memset(&param, 0, sizeof(param));
580                 param.obduuid = obduuid;
581                 while (feof(fp) == 0 && ferror(fp) ==0) {
582                         if (llapi_is_lustre_mnt(mnt)) {
583                                 rc = llapi_getstripe(mnt->mnt_dir, &param);
584                                 if (rc)
585                                         fprintf(stderr,
586                                                "error: %s: failed on %s\n",
587                                                argv[0], mnt->mnt_dir);
588                         }
589                         mnt = getmntent(fp);
590                 }
591                 endmntent(fp);
592         }
593
594         return rc;
595 }
596
597 #define COOK(value)                                                     \
598 ({                                                                      \
599         int radix = 0;                                                  \
600         while (value > 1024) {                                          \
601                 value /= 1024;                                          \
602                 radix++;                                                \
603         }                                                               \
604         radix;                                                          \
605 })
606 #define UUF     "%-20s"
607 #define CSF     "%9s"
608 #define CDF     "%9llu"
609 #define HSF     "%8s"
610 #define HDF     "%6.1f"
611 #define RSF     "%5s"
612 #define RDF     "%4d%%"
613
614 static int path2mnt(char *path, FILE *fp, char *mntdir, int dir_len)
615 {
616         char rpath[PATH_MAX] = {'\0'};
617         struct mntent *mnt;
618         int rc, len, out_len = 0;
619
620         if (!realpath(path, rpath)) {
621                 rc = -errno;
622                 fprintf(stderr, "error: lfs df: invalid path '%s': %s\n",
623                         path, strerror(-rc));
624                 return rc;
625         }
626
627         len = 0;
628         mnt = getmntent(fp);
629         while (feof(fp) == 0 && ferror(fp) == 0) {
630                 if (llapi_is_lustre_mnt(mnt)) {
631                         len = strlen(mnt->mnt_dir);
632                         if (len > out_len &&
633                             !strncmp(rpath, mnt->mnt_dir, len)) {
634                                 out_len = len;
635                                 memset(mntdir, 0, dir_len);
636                                 strncpy(mntdir, mnt->mnt_dir, dir_len);
637                         }
638                 }
639                 mnt = getmntent(fp);
640         }
641
642         if (out_len > 0)
643                 return 0;
644
645         fprintf(stderr, "error: lfs df: %s isn't mounted on lustre\n", path);
646         return -EINVAL;
647 }
648
649 static int showdf(char *mntdir, struct obd_statfs *stat,
650                   char *uuid, int ishow, int cooked,
651                   char *type, int index, int rc)
652 {
653         long long avail, used, total;
654         double ratio = 0;
655         char *suffix = "KMGTPEZY";
656         char tbuf[10], ubuf[10], abuf[10], rbuf[10];
657
658         if (!uuid || !stat)
659                 return -EINVAL;
660
661         switch (rc) {
662         case 0:
663                 if (ishow) {
664                         avail = stat->os_ffree;
665                         used = stat->os_files - stat->os_ffree;
666                         total = stat->os_files;
667                 } else {
668                         int shift = cooked ? 0 : 10;
669
670                         avail = (stat->os_bavail * stat->os_bsize) >> shift;
671                         used = stat->os_blocks - stat->os_bavail;
672                         used = (used * stat->os_bsize) >> shift;
673                         total = (stat->os_blocks * stat->os_bsize) >> shift;
674                 }
675
676                 if (total > 0)
677                         ratio = (double)used / (double)total;
678
679                 if (cooked) {
680                         int i;
681                         double cook_val;
682
683                         cook_val = (double)total;
684                         i = COOK(cook_val);
685                         if (i > 0)
686                                 sprintf(tbuf, HDF"%c", cook_val, suffix[i - 1]);
687                         else
688                                 sprintf(tbuf, CDF, total);
689
690                         cook_val = (double)used;
691                         i = COOK(cook_val);
692                         if (i > 0)
693                                 sprintf(ubuf, HDF"%c", cook_val, suffix[i - 1]);
694                         else
695                                 sprintf(ubuf, CDF, used);
696
697                         cook_val = (double)avail;
698                         i = COOK(cook_val);
699                         if (i > 0)
700                                 sprintf(abuf, HDF"%c", cook_val, suffix[i - 1]);
701                         else
702                                 sprintf(abuf, CDF, avail);
703                 } else {
704                         sprintf(tbuf, CDF, total);
705                         sprintf(ubuf, CDF, used);
706                         sprintf(abuf, CDF, avail);
707                 }
708
709                 sprintf(rbuf, RDF, (int)(ratio * 100));
710                 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s",
711                        uuid, tbuf, ubuf, abuf, rbuf, mntdir);
712                 if (type)
713                         printf("[%s:%d]\n", type, index);
714                 else
715                         printf("\n");
716
717                 break;
718         case -ENODATA:
719                 printf(UUF": inactive device\n", uuid);
720                 break;
721         default:
722                 printf(UUF": %s\n", uuid, strerror(-rc));
723                 break;
724         }
725
726         return 0;
727 }
728
729 static int mntdf(char *mntdir, int ishow, int cooked)
730 {
731         struct obd_statfs stat_buf, sum = { .os_bsize = 1 };
732         struct obd_uuid uuid_buf;
733         __u32 index;
734         int rc;
735
736         if (ishow)
737                 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
738                        "UUID", "Inodes", "IUsed", "IFree",
739                        "IUse%", "Mounted on");
740         else
741                 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
742                        "UUID", cooked ? "bytes" : "1K-blocks",
743                        "Used", "Available", "Use%", "Mounted on");
744
745         for (index = 0; ; index++) {
746                 memset(&stat_buf, 0, sizeof(struct obd_statfs));
747                 memset(&uuid_buf, 0, sizeof(struct obd_uuid));
748                 rc = llapi_obd_statfs(mntdir, LL_STATFS_MDC, index,
749                                       &stat_buf, &uuid_buf);
750                 if (rc == -ENODEV)
751                         break;
752
753                 if (rc == -EAGAIN)
754                         continue;
755
756                 if (rc == -ENOTCONN || rc == -ETIMEDOUT || rc == -EIO ||
757                     rc == -ENODATA || rc == 0) {
758                         showdf(mntdir, &stat_buf, obd_uuid2str(&uuid_buf),
759                                ishow, cooked, "MDT", index, rc);
760                 } else {
761                         fprintf(stderr,
762                                 "error: llapi_obd_statfs(%s): %s (%d)\n",
763                                 obd_uuid2str(&uuid_buf), strerror(-rc), rc);
764                         return rc;
765                 }
766                 if (rc == 0) {
767                         sum.os_ffree += stat_buf.os_ffree;
768                         sum.os_files += stat_buf.os_files;
769                 }
770         }
771
772         for (index = 0; ; index++) {
773                 memset(&stat_buf, 0, sizeof(struct obd_statfs));
774                 memset(&uuid_buf, 0, sizeof(struct obd_uuid));
775                 rc = llapi_obd_statfs(mntdir, LL_STATFS_LOV, index,
776                                       &stat_buf, &uuid_buf);
777                 if (rc == -ENODEV)
778                         break;
779
780                 if (rc == -EAGAIN)
781                         continue;
782
783                 if (rc == -ENOTCONN || rc == -ETIMEDOUT || rc == -EIO ||
784                     rc == -ENODATA || rc == 0) {
785                         showdf(mntdir, &stat_buf, obd_uuid2str(&uuid_buf),
786                                ishow, cooked, "OST", index, rc);
787                 } else {
788                         fprintf(stderr,
789                                 "error: llapi_obd_statfs failed: %s (%d)\n",
790                                 strerror(-rc), rc);
791                         return rc;
792                 }
793                 if (rc == 0) {
794                         sum.os_blocks += stat_buf.os_blocks * stat_buf.os_bsize;
795                         sum.os_bfree  += stat_buf.os_bfree * stat_buf.os_bsize;
796                         sum.os_bavail += stat_buf.os_bavail * stat_buf.os_bsize;
797                 }
798         }
799
800         printf("\n");
801         showdf(mntdir, &sum, "filesystem summary:", ishow, cooked, NULL, 0,0);
802
803         return 0;
804 }
805
806 static int lfs_df(int argc, char **argv)
807 {
808         FILE *fp;
809         char *path = NULL;
810         struct mntent *mnt = NULL;
811         char mntdir[PATH_MAX] = {'\0'};
812         int ishow = 0, cooked = 0;
813         int c, rc = 0;
814
815         optind = 0;
816         while ((c = getopt(argc, argv, "ih")) != -1) {
817                 switch (c) {
818                 case 'i':
819                         ishow = 1;
820                         break;
821                 case 'h':
822                         cooked = 1;
823                         break;
824                 default:
825                         return CMD_HELP;
826                 }
827         }
828         if (optind < argc )
829                 path = argv[optind];
830
831         fp = setmntent(MOUNTED, "r");
832         if (fp == NULL) {
833                 rc = -errno;
834                 fprintf(stderr, "error: %s: open %s failed( %s )\n",
835                         argv[0], MOUNTED, strerror(errno));
836                 return rc;
837         }
838         if (path) {
839                 rc = path2mnt(path, fp, mntdir, sizeof(mntdir));
840                 if (rc) {
841                         endmntent(fp);
842                         return rc;
843                 }
844
845                 rc = mntdf(mntdir, ishow, cooked);
846                 printf("\n");
847                 endmntent(fp);
848         } else {
849                 mnt = getmntent(fp);
850                 while (feof(fp) == 0 && ferror(fp) == 0) {
851                         if (llapi_is_lustre_mnt(mnt)) {
852                                 rc = mntdf(mnt->mnt_dir, ishow, cooked);
853                                 if (rc)
854                                         break;
855                                 printf("\n");
856                         }
857                         mnt = getmntent(fp);
858                 }
859                 endmntent(fp);
860         }
861
862         return rc;
863 }
864
865 static int lfs_check(int argc, char **argv)
866 {
867         int rc;
868         FILE *fp;
869         struct mntent *mnt = NULL;
870         int num_types = 1;
871         char *obd_types[2];
872         char obd_type1[4];
873         char obd_type2[4];
874
875         if (argc != 2)
876                 return CMD_HELP;
877
878         obd_types[0] = obd_type1;
879         obd_types[1] = obd_type2;
880
881         if (strcmp(argv[1], "osts") == 0) {
882                 strcpy(obd_types[0], "osc");
883         } else if (strcmp(argv[1], "mds") == 0) {
884                 strcpy(obd_types[0], "mdc");
885         } else if (strcmp(argv[1], "servers") == 0) {
886                 num_types = 2;
887                 strcpy(obd_types[0], "osc");
888                 strcpy(obd_types[1], "mdc");
889         } else {
890                 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
891                                 argv[0], argv[1]);
892                         return CMD_HELP;
893         }
894
895         fp = setmntent(MOUNTED, "r");
896         if (fp == NULL) {
897                  fprintf(stderr, "setmntent(%s): %s:", MOUNTED,
898                         strerror (errno));
899         } else {
900                 mnt = getmntent(fp);
901                 while (feof(fp) == 0 && ferror(fp) ==0) {
902                         if (llapi_is_lustre_mnt(mnt))
903                                 break;
904                         mnt = getmntent(fp);
905                 }
906                 endmntent(fp);
907         }
908
909         if (!mnt) {
910                 fprintf(stderr, "No suitable Lustre mount found\n");
911                 return -1;
912         }
913
914         rc = llapi_target_check(num_types, obd_types, mnt->mnt_dir);
915
916         if (rc)
917                 fprintf(stderr, "error: %s: %s status failed\n",
918                                 argv[0],argv[1]);
919
920         return rc;
921
922 }
923
924 static int lfs_catinfo(int argc, char **argv)
925 {
926         FILE *fp;
927         struct mntent *mnt = NULL;
928         int rc;
929
930         if (argc < 2 || (!strcmp(argv[1],"config") && argc < 3))
931                 return CMD_HELP;
932
933         if (strcmp(argv[1], "config") && strcmp(argv[1], "deletions"))
934                 return CMD_HELP;
935
936         fp = setmntent(MOUNTED, "r");
937         if (fp == NULL) {
938                  fprintf(stderr, "setmntent(%s): %s:", MOUNTED,
939                          strerror(errno));
940         } else {
941                 mnt = getmntent(fp);
942                 while (feof(fp) == 0 && ferror(fp) == 0) {
943                         if (llapi_is_lustre_mnt(mnt))
944                                 break;
945                         mnt = getmntent(fp);
946                 }
947                 endmntent(fp);
948         }
949
950         if (mnt) {
951                 if (argc == 3)
952                         rc = llapi_catinfo(mnt->mnt_dir, argv[1], argv[2]);
953                 else
954                         rc = llapi_catinfo(mnt->mnt_dir, argv[1], NULL);
955         } else {
956                 fprintf(stderr, "no lustre_lite mounted.\n");
957                 rc = -1;
958         }
959
960         return rc;
961 }
962
963 int lfs_join(int argc, char **argv)
964 {
965         char *name_head, *name_tail;
966         int fd, rc;
967         loff_t size;
968
969         if (argc != 3)
970                 return CMD_HELP;
971         name_head = argv[1];
972         fd = open(name_head, O_WRONLY);
973         if (fd < 0) {
974                 fprintf(stderr, "Can not open name_head %s rc=%d\n",
975                         name_head, fd);
976                 return fd;
977         }
978         size = lseek(fd, 0, SEEK_END);
979         if (size % JOIN_FILE_ALIGN) {
980                 fprintf(stderr,"head file %s size %llu must be mutiple of %d\n",
981                         name_head, (long long)size, JOIN_FILE_ALIGN);
982                 rc = -EINVAL;
983                 goto out;
984         }
985         name_tail = argv[2];
986         rc = ioctl(fd, LL_IOC_JOIN, name_tail);
987 out:
988         close(fd);
989         if (rc) {
990                 fprintf(stderr, "Lustre joining files: %s, %s, failed\n",
991                         argv[1], argv[2]);
992         }
993         return rc;
994 }
995
996 #ifdef HAVE_QUOTA_SUPPORT
997 static int lfs_quotachown(int argc, char **argv)
998 {
999
1000         int c,rc;
1001         int flag = 0;
1002
1003         while ((c = getopt(argc, argv, "i")) != -1) {
1004                 switch (c) {
1005                 case 'i':
1006                         flag++;
1007                         break;
1008                 default:
1009                         fprintf(stderr, "error: %s: option '-%c' "
1010                                         "unrecognized\n", argv[0], c);
1011                         return CMD_HELP;
1012                 }
1013         }
1014         if (optind == argc)
1015                 return CMD_HELP;
1016         rc = llapi_quotachown(argv[optind], flag);
1017         if(rc)
1018                 fprintf(stderr,"error: change file owner/group failed.\n");
1019         return rc;
1020 }
1021
1022
1023 static int lfs_quotacheck(int argc, char **argv)
1024 {
1025         int c, check_type = 0;
1026         char *mnt;
1027         struct if_quotacheck qchk;
1028         struct if_quotactl qctl;
1029         char *obd_type = (char *)qchk.obd_type;
1030         int rc;
1031
1032         memset(&qchk, 0, sizeof(qchk));
1033
1034         optind = 0;
1035         while ((c = getopt(argc, argv, "ug")) != -1) {
1036                 switch (c) {
1037                 case 'u':
1038                         check_type |= 0x01;
1039                         break;
1040                 case 'g':
1041                         check_type |= 0x02;
1042                         break;
1043                 default:
1044                         fprintf(stderr, "error: %s: option '-%c' "
1045                                         "unrecognized\n", argv[0], c);
1046                         return CMD_HELP;
1047                 }
1048         }
1049
1050         if (check_type)
1051                 check_type--;
1052         else    /* do quotacheck for both user & group quota by default */
1053                 check_type = 0x02;
1054
1055         if (argc == optind)
1056                 return CMD_HELP;
1057
1058         mnt = argv[optind];
1059
1060         memset(&qctl, 0, sizeof(qctl));
1061         qctl.qc_cmd = LUSTRE_Q_QUOTAOFF;
1062         qctl.qc_id = QFMT_LDISKFS;
1063         qctl.qc_type = check_type;
1064         rc = llapi_quotactl(mnt, &qctl);
1065         if (rc) {
1066                 fprintf(stderr, "quota off failed: %s\n", strerror(errno));
1067                 return rc;
1068         }
1069
1070         rc = llapi_quotacheck(mnt, check_type);
1071         if (rc) {
1072                 fprintf(stderr, "quotacheck failed: %s\n", strerror(errno));
1073                 return rc;
1074         }
1075
1076         rc = llapi_poll_quotacheck(mnt, &qchk);
1077         if (rc) {
1078                 if (*obd_type)
1079                         fprintf(stderr, "%s %s ", obd_type,
1080                                 obd_uuid2str(&qchk.obd_uuid));
1081                 fprintf(stderr, "quota check failed: %s\n", strerror(errno));
1082                 return rc;
1083         }
1084
1085         memset(&qctl, 0, sizeof(qctl));
1086         qctl.qc_cmd = LUSTRE_Q_QUOTAON;
1087         qctl.qc_id = QFMT_LDISKFS;
1088         qctl.qc_type = check_type;
1089         rc = llapi_quotactl(mnt, &qctl);
1090         if (rc) {
1091                 if (*obd_type)
1092                         fprintf(stderr, "%s %s ", (char *)qctl.obd_type,
1093                                 obd_uuid2str(&qctl.obd_uuid));
1094                 fprintf(stderr, "%s turn on quota failed: %s\n",
1095                         argv[0], strerror(errno));
1096                 return rc;
1097         }
1098
1099         return 0;
1100 }
1101
1102 static int lfs_quotaon(int argc, char **argv)
1103 {
1104         int c;
1105         char *mnt;
1106         struct if_quotactl qctl;
1107         char *obd_type = (char *)qctl.obd_type;
1108         int rc;
1109
1110         memset(&qctl, 0, sizeof(qctl));
1111         qctl.qc_cmd = LUSTRE_Q_QUOTAON;
1112         qctl.qc_id = QFMT_LDISKFS;
1113
1114         optind = 0;
1115         while ((c = getopt(argc, argv, "ugf")) != -1) {
1116                 switch (c) {
1117                 case 'u':
1118                         qctl.qc_type |= 0x01;
1119                         break;
1120                 case 'g':
1121                         qctl.qc_type |= 0x02;
1122                         break;
1123                 case 'f':
1124                         qctl.qc_cmd = LUSTRE_Q_QUOTAOFF;
1125                         break;
1126                 default:
1127                         fprintf(stderr, "error: %s: option '-%c' "
1128                                         "unrecognized\n", argv[0], c);
1129                         return CMD_HELP;
1130                 }
1131         }
1132
1133         if (qctl.qc_type)
1134                 qctl.qc_type--;
1135
1136         if (argc == optind)
1137                 return CMD_HELP;
1138
1139         mnt = argv[optind];
1140
1141         rc = llapi_quotactl(mnt, &qctl);
1142         if (rc) {
1143                 if (*obd_type)
1144                         fprintf(stderr, "%s %s ", obd_type,
1145                                 obd_uuid2str(&qctl.obd_uuid));
1146                 fprintf(stderr, "%s failed: %s\n", argv[0], strerror(errno));
1147                 return rc;
1148         }
1149
1150         return 0;
1151 }
1152
1153 static int lfs_quotaoff(int argc, char **argv)
1154 {
1155         int c;
1156         char *mnt;
1157         struct if_quotactl qctl;
1158         char *obd_type = (char *)qctl.obd_type;
1159         int rc;
1160
1161         memset(&qctl, 0, sizeof(qctl));
1162         qctl.qc_cmd = LUSTRE_Q_QUOTAOFF;
1163
1164         optind = 0;
1165         while ((c = getopt(argc, argv, "ug")) != -1) {
1166                 switch (c) {
1167                 case 'u':
1168                         qctl.qc_type |= 0x01;
1169                         break;
1170                 case 'g':
1171                         qctl.qc_type |= 0x02;
1172                         break;
1173                 default:
1174                         fprintf(stderr, "error: %s: option '-%c' "
1175                                         "unrecognized\n", argv[0], c);
1176                         return CMD_HELP;
1177                 }
1178         }
1179
1180         if (qctl.qc_type)
1181                 qctl.qc_type--;
1182
1183         if (argc == optind)
1184                 return CMD_HELP;
1185
1186         mnt = argv[optind];
1187
1188         rc = llapi_quotactl(mnt, &qctl);
1189         if (rc) {
1190                 if (*obd_type)
1191                         fprintf(stderr, "%s %s ", obd_type,
1192                                 obd_uuid2str(&qctl.obd_uuid));
1193                 fprintf(stderr, "quotaoff failed: %s\n", strerror(errno));
1194                 return rc;
1195         }
1196
1197         return 0;
1198 }
1199
1200 static int name2id(unsigned int *id, char *name, int type)
1201 {
1202         if (type == USRQUOTA) {
1203                 struct passwd *entry;
1204
1205                 if (!(entry = getpwnam(name))) {
1206                         if (!errno)
1207                                 errno = ENOENT;
1208                         return -1;
1209                 }
1210
1211                 *id = entry->pw_uid;
1212         } else {
1213                 struct group *entry;
1214
1215                 if (!(entry = getgrnam(name))) {
1216                         if (!errno)
1217                                 errno = ENOENT;
1218                         return -1;
1219                 }
1220
1221                 *id = entry->gr_gid;
1222         }
1223
1224         return 0;
1225 }
1226
1227 static int id2name(char **name, unsigned int id, int type)
1228 {
1229         if (type == USRQUOTA) {
1230                 struct passwd *entry;
1231
1232                 if (!(entry = getpwuid(id))) {
1233                         if (!errno)
1234                                 errno = ENOENT;
1235                         return -1;
1236                 }
1237
1238                 *name = entry->pw_name;
1239         } else {
1240                 struct group *entry;
1241
1242                 if (!(entry = getgrgid(id))) {
1243                         if (!errno)
1244                                 errno = ENOENT;
1245                         return -1;
1246                 }
1247
1248                 *name = entry->gr_name;
1249         }
1250
1251         return 0;
1252 }
1253
1254 #define ARG2INT(nr, str, msg)                                           \
1255 do {                                                                    \
1256         char *endp;                                                     \
1257         nr = strtol(str, &endp, 0);                                     \
1258         if (*endp) {                                                    \
1259                 fprintf(stderr, "error: bad %s: %s\n", msg, str);       \
1260                 return CMD_HELP;                                        \
1261         }                                                               \
1262 } while (0)
1263
1264 int lfs_setquota(int argc, char **argv)
1265 {
1266         int c;
1267         char *mnt;
1268         struct if_quotactl qctl;
1269         char *obd_type = (char *)qctl.obd_type;
1270         int rc;
1271
1272         memset(&qctl, 0, sizeof(qctl));
1273         qctl.qc_cmd = LUSTRE_Q_SETQUOTA;
1274
1275         optind = 0;
1276         while ((c = getopt(argc, argv, "ugt")) != -1) {
1277                 switch (c) {
1278                 case 'u':
1279                         qctl.qc_type |= 0x01;
1280                         break;
1281                 case 'g':
1282                         qctl.qc_type |= 0x02;
1283                         break;
1284                 case 't':
1285                         qctl.qc_cmd = LUSTRE_Q_SETINFO;
1286                         break;
1287                 default:
1288                         fprintf(stderr, "error: %s: option '-%c' "
1289                                         "unrecognized\n", argv[0], c);
1290                         return CMD_HELP;
1291                 }
1292         }
1293
1294         if (qctl.qc_type)
1295                 qctl.qc_type--;
1296
1297         if (qctl.qc_type == UGQUOTA) {
1298                 fprintf(stderr, "error: user and group quotas can't be set "
1299                                 "both\n");
1300                 return CMD_HELP;
1301         }
1302
1303         if (qctl.qc_cmd == LUSTRE_Q_SETQUOTA) {
1304                 struct obd_dqblk *dqb = &qctl.qc_dqblk;
1305
1306                 if (optind + 6 != argc)
1307                         return CMD_HELP;
1308
1309                 rc = name2id(&qctl.qc_id, argv[optind++], qctl.qc_type);
1310                 if (rc) {
1311                         fprintf(stderr, "error: find id for name %s failed: %s\n",
1312                                 argv[optind - 1], strerror(errno));
1313                         return CMD_HELP;
1314                 }
1315
1316                 ARG2INT(dqb->dqb_bsoftlimit, argv[optind++], "block-softlimit");
1317                 ARG2INT(dqb->dqb_bhardlimit, argv[optind++], "block-hardlimit");
1318                 ARG2INT(dqb->dqb_isoftlimit, argv[optind++], "inode-softlimit");
1319                 ARG2INT(dqb->dqb_ihardlimit, argv[optind++], "inode-hardlimit");
1320
1321                 dqb->dqb_valid = QIF_LIMITS;
1322         } else {
1323                 struct obd_dqinfo *dqi = &qctl.qc_dqinfo;
1324
1325                 if (optind + 3 != argc)
1326                         return CMD_HELP;
1327
1328                 ARG2INT(dqi->dqi_bgrace, argv[optind++], "block-grace");
1329                 ARG2INT(dqi->dqi_igrace, argv[optind++], "inode-grace");
1330         }
1331
1332         mnt = argv[optind];
1333
1334         rc = llapi_quotactl(mnt, &qctl);
1335         if (rc) {
1336                 if (*obd_type)
1337                         fprintf(stderr, "%s %s ", obd_type,
1338                                 obd_uuid2str(&qctl.obd_uuid));
1339                 fprintf(stderr, "setquota failed: %s\n", strerror(errno));
1340                 return rc;
1341         }
1342
1343         return 0;
1344 }
1345
1346 static inline char *type2name(int check_type)
1347 {
1348         if (check_type == USRQUOTA)
1349                 return "user";
1350         else if (check_type == GRPQUOTA)
1351                 return "group";
1352         else
1353                 return "unknown";
1354 }
1355
1356
1357 static void grace2str(time_t seconds,char *buf)
1358 {
1359         uint minutes, hours, days;
1360
1361         minutes = (seconds + 30) / 60;
1362         hours = minutes / 60;
1363         minutes %= 60;
1364         days = hours / 24;
1365         hours %= 24;
1366         if (days >= 2)
1367                 snprintf(buf, 40, "%ddays", days);
1368         else
1369                 snprintf(buf, 40, "%02d:%02d", hours + days * 24, minutes);
1370 }
1371
1372
1373 static void diff2str(time_t seconds, char *buf, time_t now)
1374 {
1375
1376         buf[0] = 0;
1377         if (!seconds)
1378                 return;
1379         if (seconds <= now) {
1380                 strcpy(buf, "none");
1381                 return;
1382         }
1383         grace2str(seconds - now, buf);
1384 }
1385
1386 static void print_quota_title(char *name, struct if_quotactl *qctl)
1387 {
1388         printf("Disk quotas for %s %s (%cid %u):\n",
1389                type2name(qctl->qc_type), name,
1390                *type2name(qctl->qc_type), qctl->qc_id);
1391         printf("%15s%8s %7s%8s%8s%8s %7s%8s%8s\n",
1392                "Filesystem",
1393                "blocks", "quota", "limit", "grace",
1394                "files", "quota", "limit", "grace");
1395 }
1396
1397 static void print_quota(char *mnt, struct if_quotactl *qctl, int ost_only)
1398 {
1399         time_t now;
1400
1401         time(&now);
1402
1403         if (qctl->qc_cmd == LUSTRE_Q_GETQUOTA || qctl->qc_cmd == Q_GETOQUOTA) {
1404                 int bover = 0, iover = 0;
1405                 struct obd_dqblk *dqb = &qctl->qc_dqblk;
1406
1407                 if (dqb->dqb_bhardlimit &&
1408                     toqb(dqb->dqb_curspace) > dqb->dqb_bhardlimit) {
1409                         bover = 1;
1410                 } else if (dqb->dqb_bsoftlimit &&
1411                            toqb(dqb->dqb_curspace) > dqb->dqb_bsoftlimit) {
1412                         if (dqb->dqb_btime > now) {
1413                                 bover = 2;
1414                         } else {
1415                                 bover = 3;
1416                         }
1417                 }
1418
1419                 if (dqb->dqb_ihardlimit &&
1420                     dqb->dqb_curinodes > dqb->dqb_ihardlimit) {
1421                         iover = 1;
1422                 } else if (dqb->dqb_isoftlimit &&
1423                            dqb->dqb_curinodes > dqb->dqb_isoftlimit) {
1424                         if (dqb->dqb_btime > now) {
1425                                 iover = 2;
1426                         } else {
1427                                 iover = 3;
1428                         }
1429                 }
1430
1431 #if 0           /* XXX: always print quotas even when no usages */
1432                 if (dqb->dqb_curspace || dqb->dqb_curinodes)
1433 #endif
1434                 {
1435                         char numbuf[3][32];
1436                         char timebuf[40];
1437
1438                         if (strlen(mnt) > 15)
1439                                 printf("%s\n%15s", mnt, "");
1440                         else
1441                                 printf("%15s", mnt);
1442
1443                         if (bover)
1444                                 diff2str(dqb->dqb_btime, timebuf, now);
1445
1446                         sprintf(numbuf[0], LPU64, toqb(dqb->dqb_curspace));
1447                         sprintf(numbuf[1], LPU64, dqb->dqb_bsoftlimit);
1448                         sprintf(numbuf[2], LPU64, dqb->dqb_bhardlimit);
1449                         printf(" %7s%c %6s %7s %7s",
1450                                numbuf[0], bover ? '*' : ' ', numbuf[1],
1451                                numbuf[2], bover > 1 ? timebuf : "");
1452
1453                         if (iover)
1454                                 diff2str(dqb->dqb_itime, timebuf, now);
1455
1456                         sprintf(numbuf[0], LPU64, dqb->dqb_curinodes);
1457                         sprintf(numbuf[1], LPU64, dqb->dqb_isoftlimit);
1458                         sprintf(numbuf[2], LPU64, dqb->dqb_ihardlimit);
1459                         if (!ost_only)
1460                                 printf(" %7s%c %6s %7s %7s",
1461                                        numbuf[0], iover ? '*' : ' ', numbuf[1],
1462                                        numbuf[2], iover > 1 ? timebuf : "");
1463                         printf("\n");
1464                 }
1465         } else if (qctl->qc_cmd == LUSTRE_Q_GETINFO ||
1466                    qctl->qc_cmd == Q_GETOINFO) {
1467                 char bgtimebuf[40];
1468                 char igtimebuf[40];
1469
1470                 grace2str(qctl->qc_dqinfo.dqi_bgrace, bgtimebuf);
1471                 grace2str(qctl->qc_dqinfo.dqi_igrace, igtimebuf);
1472                 printf("Block grace time: %s; Inode grace time: %s\n",
1473                        bgtimebuf, igtimebuf);
1474         }
1475 }
1476
1477 static void print_mds_quota(char *mnt, struct if_quotactl *qctl)
1478 {
1479         int rc;
1480
1481         /* XXX: this is a flag to mark that only mds quota is wanted */
1482         qctl->qc_dqblk.dqb_valid = 1;
1483         rc = llapi_quotactl(mnt, qctl);
1484         if (rc) {
1485                 fprintf(stderr, "quotactl failed: %s\n", strerror(errno));
1486                 return;
1487         }
1488         qctl->qc_dqblk.dqb_valid = 0;
1489
1490         print_quota(obd_uuid2str(&qctl->obd_uuid), qctl, 0);
1491 }
1492
1493 static void print_lov_quota(char *mnt, struct if_quotactl *qctl)
1494 {
1495         DIR *dir;
1496         struct obd_uuid uuids[1024], *uuidp;
1497         int obdcount = 1024;
1498         int i, rc;
1499
1500         dir = opendir(mnt);
1501         if (!dir) {
1502                 fprintf(stderr, "open %s failed: %s\n", mnt, strerror(errno));
1503                 return;
1504         }
1505
1506         rc = llapi_lov_get_uuids(dirfd(dir), uuids, &obdcount);
1507         if (rc != 0) {
1508                 fprintf(stderr, "get ost uuid failed: %s\n", strerror(errno));
1509                 goto out;
1510         }
1511
1512         for (i = 0, uuidp = uuids; i < obdcount; i++, uuidp++) {
1513                 memcpy(&qctl->obd_uuid, uuidp, sizeof(*uuidp));
1514
1515                 /* XXX clear this flag to get quota from osts */
1516                 qctl->qc_dqblk.dqb_valid = 0;
1517                 rc = llapi_quotactl(mnt, qctl);
1518                 if (rc) {
1519                         fprintf(stderr, "%s quotactl failed: %s\n",
1520                                 uuidp->uuid, strerror(errno));
1521                         continue;
1522                 }
1523
1524                 print_quota((char *)uuidp->uuid, qctl, 1);
1525         }
1526
1527 out:
1528         closedir(dir);
1529         return;
1530 }
1531
1532 static int lfs_quota(int argc, char **argv)
1533 {
1534         int c;
1535         char *name = NULL, *mnt;
1536         struct if_quotactl qctl;
1537         char *obd_type = (char *)qctl.obd_type;
1538         char *obd_uuid = (char *)qctl.obd_uuid.uuid;
1539         int rc;
1540
1541         memset(&qctl, 0, sizeof(qctl));
1542         qctl.qc_cmd = LUSTRE_Q_GETQUOTA;
1543
1544         optind = 0;
1545         while ((c = getopt(argc, argv, "ugto:")) != -1) {
1546                 switch (c) {
1547                 case 'u':
1548                         qctl.qc_type |= 0x01;
1549                         break;
1550                 case 'g':
1551                         qctl.qc_type |= 0x02;
1552                         break;
1553                 case 't':
1554                         qctl.qc_cmd = LUSTRE_Q_GETINFO;
1555                         break;
1556                 case 'o':
1557                         strncpy(obd_uuid, optarg, sizeof(qctl.obd_uuid));
1558                         break;
1559                 default:
1560                         fprintf(stderr, "error: %s: option '-%c' "
1561                                         "unrecognized\n", argv[0], c);
1562                         return CMD_HELP;
1563                 }
1564         }
1565
1566         if (qctl.qc_type)
1567                 qctl.qc_type--;
1568
1569         if (qctl.qc_type == UGQUOTA) {
1570                 fprintf(stderr, "error: user or group can't be specified"
1571                                 "both\n");
1572                 return CMD_HELP;
1573         }
1574
1575         if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA) {
1576                 if (optind + 2 != argc)
1577                         return CMD_HELP;
1578
1579                 name = argv[optind++];
1580                 rc = name2id(&qctl.qc_id, name, qctl.qc_type);
1581                 if (rc) {
1582                         fprintf(stderr, "error: find id for name %s failed: %s\n",
1583                                 name, strerror(errno));
1584                         return CMD_HELP;
1585                 }
1586                 print_quota_title(name, &qctl);
1587         } else if (optind + 1 != argc) {
1588                 return CMD_HELP;
1589         }
1590
1591         mnt = argv[optind];
1592
1593         rc = llapi_quotactl(mnt, &qctl);
1594         if (rc) {
1595                 if (*obd_type)
1596                         fprintf(stderr, "%s %s ", obd_type, obd_uuid);
1597                 fprintf(stderr, "quota failed: %s\n", strerror(errno));
1598                 return rc;
1599         }
1600
1601         if (!name)
1602                 rc = id2name(&name, getuid(), qctl.qc_type);
1603
1604         if (*obd_uuid) {
1605                 mnt = "";
1606                 name = obd_uuid;
1607         }
1608
1609         print_quota(mnt, &qctl, 0);
1610
1611         if (!*obd_uuid && qctl.qc_cmd != LUSTRE_Q_GETINFO) {
1612                 print_mds_quota(mnt, &qctl);
1613                 print_lov_quota(mnt, &qctl);
1614         }
1615
1616         return 0;
1617 }
1618 #endif /* HAVE_QUOTA_SUPPORT */
1619
1620 int main(int argc, char **argv)
1621 {
1622         int rc;
1623
1624         setlinebuf(stdout);
1625
1626         ptl_initialize(argc, argv);
1627         if (obd_initialize(argc, argv) < 0)
1628                 exit(2);
1629         if (dbg_initialize(argc, argv) < 0)
1630                 exit(3);
1631
1632         Parser_init("lfs > ", cmdlist);
1633
1634         if (argc > 1) {
1635                 rc = Parser_execarg(argc - 1, argv + 1, cmdlist);
1636         } else {
1637                 rc = Parser_commands();
1638         }
1639
1640         obd_finalize(argc, argv);
1641         return rc;
1642 }