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