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