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