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