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