Whamcloud - gitweb
iam: add lvar format
[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
40 #include <lnet/api-support.h>
41 #include <lnet/lnetctl.h>
42
43 #include <liblustre.h>
44 #include <lustre/lustre_idl.h>
45 #include <lustre/liblustreapi.h>
46 #include <lustre/lustre_user.h>
47
48 #include "parser.h"
49 #include "obdctl.h"
50
51 unsigned int libcfs_subsystem_debug = 0;
52
53 /* all functions */
54 static int lfs_setstripe(int argc, char **argv);
55 static int lfs_find(int argc, char **argv);
56 static int lfs_getstripe(int argc, char **argv);
57 static int lfs_osts(int argc, char **argv);
58 static int lfs_df(int argc, char **argv);
59 static int lfs_check(int argc, char **argv);
60 static int lfs_catinfo(int argc, char **argv);
61 #ifdef HAVE_QUOTA_SUPPORT
62 static int lfs_quotachown(int argc, char **argv);
63 static int lfs_quotacheck(int argc, char **argv);
64 static int lfs_quotaon(int argc, char **argv);
65 static int lfs_quotaoff(int argc, char **argv);
66 static int lfs_setquota(int argc, char **argv);
67 static int lfs_quota(int argc, char **argv);
68 #endif
69 static int lfs_join(int argc, char **argv);
70
71 /* all avaialable commands */
72 command_t cmdlist[] = {
73         {"setstripe", lfs_setstripe, 0,
74          "Create a new file with a specific striping pattern or\n"
75          "set the default striping pattern on an existing directory or\n"
76          "delete the default striping pattern from an existing directory\n"
77          "usage: setstripe <filename|dirname> <stripe size> <stripe start> <stripe count>\n"
78          "       or \n"
79          "       setstripe -d <dirname>   (to delete default striping)\n"
80          "\tstripe size:  Number of bytes on each OST (0 filesystem default)\n"
81          "\tstripe start: OST index of first stripe (-1 filesystem default)\n"
82          "\tstripe count: Number of OSTs to stripe over (0 default, -1 all)"},
83         {"find", lfs_find, 0,
84          "To list the extended attributes for a given filename or files in a\n"
85          "directory or recursively for all files in a directory tree.\n"
86          "usage: find [--obd <uuid>] [--quiet | --verbose] [--recursive] <dir|file> ..."},
87         {"getstripe", lfs_getstripe, 0,
88          "To list the striping pattern for given filename.\n"
89          "usage:getstripe <filename>"},
90         {"check", lfs_check, 0,
91          "Display the status of MDS or OSTs (as specified in the command)\n"
92          "or all the servers (MDS and OSTs).\n"
93          "usage: check <osts|mds|servers>"},
94         {"catinfo", lfs_catinfo, 0,
95          "Show information of specified type logs.\n"
96          "usage: catinfo {keyword} [node name]\n"
97          "\tkeywords are one of followings: config, deletions.\n"
98          "\tnode name must be provided when use keyword config."},
99         {"join", lfs_join, 0,
100          "join two lustre files into one - join A, B, will be like cat B >> A & del B\n"
101          "usage: join <filename_A> <filename_B>\n"},
102         {"osts", lfs_osts, 0, "osts"},
103         {"df", lfs_df, 0,
104          "report filesystem disk space usage or inodes usage"
105          "of each MDS/OSD.\n"
106          "Usage: df [-i] [-h] [path]"},
107 #ifdef HAVE_QUOTA_SUPPORT
108         {"quotachown",lfs_quotachown, 0,
109          "Change files' owner or group on the specified filesystem.\n"
110          "usage: quotachown [-i] <filesystem>\n"
111          "\t-i: ignore error if file is not exist\n"},
112         {"quotacheck", lfs_quotacheck, 0,
113          "Scan the specified filesystem for disk usage, and create,\n"
114          "or update quota files.\n"
115          "usage: quotacheck [ -ug ] <filesystem>"},
116         {"quotaon", lfs_quotaon, 0, "Turn filesystem quotas on.\n"
117          "usage: quotaon [ -ugf ] <filesystem>"},
118         {"quotaoff", lfs_quotaoff, 0, "Turn filesystem quotas off.\n"
119          "usage: quotaoff [ -ug ] <filesystem>"},
120         {"setquota", lfs_setquota, 0, "Set filesystem quotas.\n"
121          "usage: setquota [ -u | -g ] <name> <block-softlimit> <block-hardlimit> <inode-softlimit> <inode-hardlimit> <filesystem>\n"
122          "       setquota -t [ -u | -g ] <block-grace> <inode-grace> <filesystem>"},
123         {"quota", lfs_quota, 0, "Display disk usage and limits.\n"
124          "usage: quota [ -o obd_uuid ] [ -u | -g ] [name] <filesystem>"},
125 #endif
126         {"help", Parser_help, 0, "help"},
127         {"exit", Parser_quit, 0, "quit"},
128         {"quit", Parser_quit, 0, "quit"},
129         { 0, 0, 0, NULL }
130 };
131
132 /* functions */
133 static int lfs_setstripe(int argc, char **argv)
134 {
135         char *fname;
136         int result;
137         long st_size;
138         int  st_offset, st_count;
139         char *end;
140
141         if (argc != 5 && argc != 3)
142                 return CMD_HELP;
143
144
145         if (argc == 3) {
146                 if (strcmp(argv[1], "-d") != 0)
147                         return CMD_HELP;
148
149                 fname = argv[2];
150                 st_size = 0;
151                 st_offset = -1;
152                 st_count = 0;
153         } else {
154                 fname = argv[1];
155
156                 /* get the stripe size */
157                 st_size = strtoul(argv[2], &end, 0);
158                 if (*end != '\0') {
159                         fprintf(stderr, "error: %s: bad stripe size '%s'\n",
160                                 argv[0], argv[2]);
161                         return CMD_HELP;
162                 }
163
164                 /* get the stripe offset */
165                 st_offset = strtoul(argv[3], &end, 0);
166                 if (*end != '\0') {
167                         fprintf(stderr, "error: %s: bad stripe offset '%s'\n",
168                                 argv[0], argv[3]);
169                         return CMD_HELP;
170                 }
171                 /* get the stripe count */
172                 st_count = strtoul(argv[4], &end, 0);
173                 if (*end != '\0') {
174                         fprintf(stderr, "error: %s: bad stripe count '%s'\n",
175                                 argv[0], argv[4]);
176                         return CMD_HELP;
177                 }
178         }
179
180         result = llapi_file_create(fname, st_size, st_offset, st_count, 0);
181         if (result)
182                 fprintf(stderr, "error: %s: create stripe file failed\n",
183                                 argv[0]);
184
185         return result;
186 }
187
188 static int lfs_find(int argc, char **argv)
189 {
190         struct option long_opts[] = {
191                 {"obd", 1, 0, 'o'},
192                 {"quiet", 0, 0, 'q'},
193                 {"recursive", 0, 0, 'r'},
194                 {"verbose", 0, 0, 'v'},
195                 {0, 0, 0, 0}
196         };
197         char short_opts[] = "ho:qrv";
198         int quiet, verbose, recursive, c, rc;
199         struct obd_uuid *obduuid = NULL;
200
201         optind = 0;
202         quiet = verbose = recursive = 0;
203         while ((c = getopt_long(argc, argv, short_opts,
204                                         long_opts, NULL)) != -1) {
205                 switch (c) {
206                 case 'o':
207                         if (obduuid) {
208                                 fprintf(stderr,
209                                         "error: %s: only one obduuid allowed",
210                                         argv[0]);
211                                 return CMD_HELP;
212                         }
213                         obduuid = (struct obd_uuid *)optarg;
214                         break;
215                 case 'q':
216                         quiet++;
217                         verbose = 0;
218                         break;
219                 case 'r':
220                         recursive = 1;
221                         break;
222                 case 'v':
223                         verbose++;
224                         quiet = 0;
225                         break;
226                 case '?':
227                         return CMD_HELP;
228                         break;
229                 default:
230                         fprintf(stderr, "error: %s: option '%s' unrecognized\n",
231                                 argv[0], argv[optind - 1]);
232                         return CMD_HELP;
233                         break;
234                 }
235         }
236
237         if (optind >= argc)
238                 return CMD_HELP;
239
240         do {
241                 rc = llapi_find(argv[optind], obduuid, recursive,verbose,quiet);
242         } while (++optind < argc && !rc);
243
244         if (rc)
245                 fprintf(stderr, "error: %s: find failed\n", argv[0]);
246         return rc;
247 }
248
249 static int lfs_getstripe(int argc, char **argv)
250 {
251         struct option long_opts[] = {
252                 {"quiet", 0, 0, 'q'},
253                 {"verbose", 0, 0, 'v'},
254                 {0, 0, 0, 0}
255         };
256         char short_opts[] = "qv";
257         int quiet, verbose, recursive, c, rc;
258         struct obd_uuid *obduuid = NULL;
259
260         optind = 0;
261         quiet = verbose = recursive = 0;
262         while ((c = getopt_long(argc, argv, short_opts,
263                                         long_opts, NULL)) != -1) {
264                 switch (c) {
265                 case 'o':
266                         if (obduuid) {
267                                 fprintf(stderr,
268                                         "error: %s: only one obduuid allowed",
269                                         argv[0]);
270                                 return CMD_HELP;
271                         }
272                         obduuid = (struct obd_uuid *)optarg;
273                         break;
274                 case 'q':
275                         quiet++;
276                         verbose = 0;
277                         break;
278                 case 'v':
279                         verbose++;
280                         quiet = 0;
281                         break;
282                 case '?':
283                         return CMD_HELP;
284                         break;
285                 default:
286                         fprintf(stderr, "error: %s: option '%s' unrecognized\n",
287                                 argv[0], argv[optind - 1]);
288                         return CMD_HELP;
289                         break;
290                 }
291         }
292
293         if (optind >= argc)
294                 return CMD_HELP;
295
296         do {
297                 rc = llapi_find(argv[optind], obduuid, recursive,verbose,quiet);
298         } while (++optind < argc && !rc);
299
300         if (rc)
301                 fprintf(stderr, "error: %s: getstripe failed for %s\n",
302                         argv[0], argv[1]);
303
304         return rc;
305 }
306
307 static int lfs_osts(int argc, char **argv)
308 {
309         FILE *fp;
310         struct mntent *mnt = NULL;
311         struct obd_uuid *obduuid = NULL;
312         int rc=0;
313
314         if (argc != 1)
315                 return CMD_HELP;
316
317         fp = setmntent(MOUNTED, "r");
318
319         if (fp == NULL) {
320                  fprintf(stderr, "%s: setmntent(%s): %s:", argv[0], MOUNTED,
321                         strerror (errno));
322         } else {
323                 mnt = getmntent(fp);
324                 while (feof(fp) == 0 && ferror(fp) ==0) {
325                         if (llapi_is_lustre_mnttype(mnt)) {
326                                 rc = llapi_find(mnt->mnt_dir, obduuid, 0, 0, 0);
327                                 if (rc)
328                                         fprintf(stderr,
329                                                "error: %s: failed on %s\n",
330                                                argv[0], mnt->mnt_dir);
331                         }
332                         mnt = getmntent(fp);
333                 }
334                 endmntent(fp);
335         }
336
337         return rc;
338 }
339
340 #define COOK(value)                                                     \
341 ({                                                                      \
342         int radix = 0;                                                  \
343         while (value > 1024) {                                          \
344                 value /= 1024;                                          \
345                 radix++;                                                \
346         }                                                               \
347         radix;                                                          \
348 })
349 #define UUF     "%-20s"
350 #define CSF     "%9s"
351 #define CDF     "%9llu"
352 #define HSF     "%8s"
353 #define HDF     "%6.1f"
354 #define RSF     "%5s"
355 #define RDF     "%5d"
356
357 static int path2mnt(char *path, FILE *fp, char *mntdir, int dir_len)
358 {
359         char rpath[PATH_MAX] = {'\0'};
360         struct mntent *mnt;
361         int rc, len, out_len = 0;
362
363         if (!realpath(path, rpath)) {
364                 rc = -errno;
365                 fprintf(stderr, "error: lfs df: invalid path '%s': %s\n",
366                         path, strerror(-rc));
367                 return rc;
368         }
369
370         len = 0;
371         mnt = getmntent(fp);
372         while (feof(fp) == 0 && ferror(fp) == 0) {
373                 if (llapi_is_lustre_mnttype(mnt)) {
374                         len = strlen(mnt->mnt_dir);
375                         if (len > out_len &&
376                             !strncmp(rpath, mnt->mnt_dir, len)) {
377                                 out_len = len;
378                                 memset(mntdir, 0, dir_len);
379                                 strncpy(mntdir, mnt->mnt_dir, dir_len);
380                         }
381                 }
382                 mnt = getmntent(fp);
383         }
384
385         if (out_len > 0)
386                 return 0;
387
388         fprintf(stderr, "error: lfs df: %s isn't mounted on lustre\n", path);
389         return -EINVAL;
390 }
391
392 static int showdf(char *mntdir, struct obd_statfs *stat,
393                   char *uuid, int ishow, int cooked,
394                   char *type, int index, int rc)
395 {
396         __u64 avail, used, total;
397         double ratio = 0;
398         char *suffix = "KMGTPEZY";
399         char tbuf[10], ubuf[10], abuf[10], rbuf[10];
400
401         if (!uuid || !stat)
402                 return -EINVAL;
403
404         switch (rc) {
405         case 0:
406                 if (ishow) {
407                         avail = stat->os_ffree;
408                         used = stat->os_files - stat->os_ffree;
409                         total = stat->os_files;
410                 } else {
411                         int shift = cooked ? 0 : 10;
412
413                         avail = (stat->os_bavail * stat->os_bsize) >> shift;
414                         used = stat->os_blocks - stat->os_bavail;
415                         used = (used * stat->os_bsize) >> shift;
416                         total = (stat->os_blocks * stat->os_bsize) >> shift;
417                 }
418
419                 if (total > 0)
420                         ratio = (double)used / (double)total;
421
422                 if (cooked) {
423                         int i;
424                         double cook_val;
425
426                         cook_val = (double)total;
427                         i = COOK(cook_val);
428                         if (i > 0)
429                                 sprintf(tbuf, HDF"%c", cook_val, suffix[i - 1]);
430                         else
431                                 sprintf(tbuf, CDF, total);
432
433                         cook_val = (double)used;
434                         i = COOK(cook_val);
435                         if (i > 0)
436                                 sprintf(ubuf, HDF"%c", cook_val, suffix[i - 1]);
437                         else
438                                 sprintf(ubuf, CDF, used);
439
440                         cook_val = (double)avail;
441                         i = COOK(cook_val);
442                         if (i > 0)
443                                 sprintf(abuf, HDF"%c", cook_val, suffix[i - 1]);
444                         else
445                                 sprintf(abuf, CDF, avail);
446                 } else {
447                         sprintf(tbuf, CDF, total);
448                         sprintf(ubuf, CDF, used);
449                         sprintf(abuf, CDF, avail);
450                 }
451
452                 sprintf(rbuf, RDF, (int)(ratio * 100));
453                 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s",
454                        uuid, tbuf, ubuf, abuf, rbuf, mntdir);
455                 if (type)
456                         printf("[%s:%d]\n", type, index);
457                 else
458                         printf("\n");
459
460                 break;
461         case -ENODATA:
462                 printf(UUF": inactive device\n", uuid);
463                 break;
464         default:
465                 printf(UUF": %s\n", uuid, strerror(-rc));
466                 break;
467         }
468
469         return 0;
470 }
471
472 static int mntdf(char *mntdir, int ishow, int cooked)
473 {
474         struct obd_statfs stat_buf, sum = { .os_bsize = 1 };
475         struct obd_uuid uuid_buf;
476         __u32 index;
477         int rc;
478
479         if (ishow)
480                 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
481                        "UUID", "Inodes", "IUsed", "IFree",
482                        "IUse%", "Mounted on");
483         else
484                 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
485                        "UUID", cooked ? "bytes" : "1K-blocks",
486                        "Used", "Available", "Use%", "Mounted on");
487
488         for (index = 0; ; index++) {
489                 memset(&stat_buf, 0, sizeof(struct obd_statfs));
490                 memset(&uuid_buf, 0, sizeof(struct obd_uuid));
491                 rc = llapi_obd_statfs(mntdir, LL_STATFS_MDC, index,
492                                       &stat_buf, &uuid_buf);
493                 if (rc == -ENODEV)
494                         break;
495
496                 if (rc == -ENOTCONN || rc == -ETIMEDOUT || rc == -EIO ||
497                     rc == -ENODATA || rc == 0) {
498                         showdf(mntdir, &stat_buf, uuid_buf.uuid, ishow, cooked,
499                                "MDT", index, rc);
500                 } else {
501                         fprintf(stderr,
502                                 "error: llapi_obd_statfs(%s): %s (%d)\n",
503                                 uuid_buf.uuid, strerror(-rc), rc);
504                         return rc;
505                 }
506                 if (rc == 0) {
507                         sum.os_ffree += stat_buf.os_ffree;
508                         sum.os_files += stat_buf.os_files;
509                 }
510         }
511
512         for (index = 0; ; index++) {
513                 memset(&stat_buf, 0, sizeof(struct obd_statfs));
514                 memset(&uuid_buf, 0, sizeof(struct obd_uuid));
515                 rc = llapi_obd_statfs(mntdir, LL_STATFS_LOV, index,
516                                       &stat_buf, &uuid_buf);
517                 if (rc == -ENODEV)
518                         break;
519
520                 if (rc == -ENOTCONN || rc == -ETIMEDOUT || rc == -EIO ||
521                     rc == -ENODATA || rc == 0) {
522                         showdf(mntdir, &stat_buf, uuid_buf.uuid, ishow, cooked,
523                                "OST", index, rc);
524                 } else {
525                         fprintf(stderr,
526                                 "error: llapi_obd_statfs failed: %s (%d)\n",
527                                 strerror(-rc), rc);
528                         return rc;
529                 }
530                 if (rc == 0) {
531                         sum.os_blocks += stat_buf.os_blocks * stat_buf.os_bsize;
532                         sum.os_bfree  += stat_buf.os_bfree * stat_buf.os_bsize;
533                         sum.os_bavail += stat_buf.os_bavail * stat_buf.os_bsize;
534                 }
535         }
536
537         printf("\n");
538         showdf(mntdir, &sum, "filesystem summary:", ishow, cooked, NULL, 0,0);
539
540         return 0;
541 }
542
543 static int lfs_df(int argc, char **argv)
544 {
545         FILE *fp;
546         char *path = NULL;
547         struct mntent *mnt = NULL;
548         char mntdir[PATH_MAX] = {'\0'};
549         int ishow = 0, cooked = 0;
550         int c, rc = 0;
551
552         optind = 0;
553         while ((c = getopt(argc, argv, "ih")) != -1) {
554                 switch (c) {
555                 case 'i':
556                         ishow = 1;
557                         break;
558                 case 'h':
559                         cooked = 1;
560                         break;
561                 default:
562                         return CMD_HELP;
563                 }
564         }
565         if (optind < argc )
566                 path = argv[optind];
567
568         fp = setmntent(MOUNTED, "r");
569         if (fp == NULL) {
570                 rc = -errno;
571                 fprintf(stderr, "error: %s: open %s failed( %s )\n",
572                         argv[0], MOUNTED, strerror(errno));
573                 return rc;
574         }
575         if (path) {
576                 rc = path2mnt(path, fp, mntdir, sizeof(mntdir));
577                 if (rc) {
578                         endmntent(fp);
579                         return rc;
580                 }
581
582                 rc = mntdf(mntdir, ishow, cooked);
583                 printf("\n");
584                 endmntent(fp);
585         } else {
586                 mnt = getmntent(fp);
587                 while (feof(fp) == 0 && ferror(fp) == 0) {
588                         if (llapi_is_lustre_mnttype(mnt)) {
589                                 rc = mntdf(mnt->mnt_dir, ishow, cooked);
590                                 if (rc)
591                                         break;
592                                 printf("\n");
593                         }
594                         mnt = getmntent(fp);
595                 }
596                 endmntent(fp);
597         }
598
599         return rc;
600 }
601
602 static int lfs_check(int argc, char **argv)
603 {
604         int rc;
605         FILE *fp;
606         struct mntent *mnt = NULL;
607         int num_types = 1;
608         char *obd_types[2];
609         char obd_type1[4];
610         char obd_type2[4];
611
612         if (argc != 2)
613                 return CMD_HELP;
614
615         obd_types[0] = obd_type1;
616         obd_types[1] = obd_type2;
617
618         if (strcmp(argv[1], "osts") == 0) {
619                 strcpy(obd_types[0], "osc");
620         } else if (strcmp(argv[1], "mds") == 0) {
621                 strcpy(obd_types[0], "mdc");
622         } else if (strcmp(argv[1], "servers") == 0) {
623                 num_types = 2;
624                 strcpy(obd_types[0], "osc");
625                 strcpy(obd_types[1], "mdc");
626         } else {
627                 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
628                                 argv[0], argv[1]);
629                         return CMD_HELP;
630         }
631
632         fp = setmntent(MOUNTED, "r");
633         if (fp == NULL) {
634                  fprintf(stderr, "setmntent(%s): %s:", MOUNTED,
635                         strerror (errno));
636         } else {
637                 mnt = getmntent(fp);
638                 while (feof(fp) == 0 && ferror(fp) ==0) {
639                         if (llapi_is_lustre_mnttype(mnt))
640                                 break;
641                         mnt = getmntent(fp);
642                 }
643                 endmntent(fp);
644         }
645
646         if (!mnt) {
647                 fprintf(stderr, "No suitable Lustre mount found\n");
648                 return -1;
649         }
650
651         rc = llapi_target_check(num_types, obd_types, mnt->mnt_dir);
652
653         if (rc)
654                 fprintf(stderr, "error: %s: %s status failed\n",
655                                 argv[0],argv[1]);
656
657         return rc;
658
659 }
660
661 static int lfs_catinfo(int argc, char **argv)
662 {
663         FILE *fp;
664         struct mntent *mnt = NULL;
665         int rc;
666
667         if (argc < 2 || (!strcmp(argv[1],"config") && argc < 3))
668                 return CMD_HELP;
669
670         if (strcmp(argv[1], "config") && strcmp(argv[1], "deletions"))
671                 return CMD_HELP;
672
673         fp = setmntent(MOUNTED, "r");
674         if (fp == NULL) {
675                  fprintf(stderr, "setmntent(%s): %s:", MOUNTED,
676                          strerror(errno));
677         } else {
678                 mnt = getmntent(fp);
679                 while (feof(fp) == 0 && ferror(fp) == 0) {
680                         if (llapi_is_lustre_mnttype(mnt))
681                                 break;
682                         mnt = getmntent(fp);
683                 }
684                 endmntent(fp);
685         }
686
687         if (mnt) {
688                 if (argc == 3)
689                         rc = llapi_catinfo(mnt->mnt_dir, argv[1], argv[2]);
690                 else
691                         rc = llapi_catinfo(mnt->mnt_dir, argv[1], NULL);
692         } else {
693                 fprintf(stderr, "no lustre_lite mounted.\n");
694                 rc = -1;
695         }
696
697         return rc;
698 }
699
700 int lfs_join(int argc, char **argv)
701 {
702         char *name_head, *name_tail;
703         int fd, rc;
704         loff_t size;
705
706         if (argc != 3)
707                 return CMD_HELP;
708         name_head = argv[1];
709         fd = open(name_head, O_WRONLY);
710         if (fd < 0) {
711                 fprintf(stderr, "Can not open name_head %s rc=%d\n",
712                         name_head, fd);
713                 return fd;
714         }
715         size = lseek(fd, 0, SEEK_END);
716         if (size % JOIN_FILE_ALIGN) {
717                 fprintf(stderr,"head file %s size %llu must be mutiple of %d\n",
718                         name_head, size, JOIN_FILE_ALIGN);
719                 rc = -EINVAL;
720                 goto out;
721         }
722         name_tail = argv[2];
723         rc = ioctl(fd, LL_IOC_JOIN, name_tail);
724 out:
725         close(fd);
726         if (rc) {
727                 fprintf(stderr, "Lustre joining files: %s, %s, failed\n",
728                         argv[1], argv[2]);
729         }
730         return rc;
731 }
732
733 #ifdef HAVE_QUOTA_SUPPORT
734 static int lfs_quotachown(int argc, char **argv)
735 {
736
737         int c,rc;
738         int flag = 0;
739
740         while ((c = getopt(argc, argv, "i")) != -1) {
741                 switch (c) {
742                 case 'i':
743                         flag++;
744                         break;
745                 default:
746                         fprintf(stderr, "error: %s: option '-%c' "
747                                         "unrecognized\n", argv[0], c);
748                         return CMD_HELP;
749                 }
750         }
751         if (optind == argc)
752                 return CMD_HELP;
753         rc = llapi_quotachown(argv[optind], flag);
754         if(rc)
755                 fprintf(stderr,"error: change file owner/group failed.\n");
756         return rc;
757 }
758
759
760 static int lfs_quotacheck(int argc, char **argv)
761 {
762         int c, check_type = 0;
763         char *mnt;
764         struct if_quotacheck qchk;
765         struct if_quotactl qctl;
766         char *obd_type = qchk.obd_type;
767         char *obd_uuid = qchk.obd_uuid.uuid;
768         int rc;
769
770         memset(&qchk, 0, sizeof(qchk));
771
772         optind = 0;
773         while ((c = getopt(argc, argv, "ug")) != -1) {
774                 switch (c) {
775                 case 'u':
776                         check_type |= 0x01;
777                         break;
778                 case 'g':
779                         check_type |= 0x02;
780                         break;
781                 default:
782                         fprintf(stderr, "error: %s: option '-%c' "
783                                         "unrecognized\n", argv[0], c);
784                         return CMD_HELP;
785                 }
786         }
787
788         if (check_type)
789                 check_type--;
790         else    /* do quotacheck for both user & group quota by default */
791                 check_type = 0x02;
792
793         if (argc == optind)
794                 return CMD_HELP;
795
796         mnt = argv[optind];
797
798         memset(&qctl, 0, sizeof(qctl));
799         qctl.qc_cmd = LUSTRE_Q_QUOTAOFF;
800         qctl.qc_id = QFMT_LDISKFS;
801         qctl.qc_type = check_type;
802         rc = llapi_quotactl(mnt, &qctl);
803         if (rc) {
804                 fprintf(stderr, "quota off failed: %s\n", strerror(errno));
805                 return rc;
806         }
807
808         rc = llapi_quotacheck(mnt, check_type);
809         if (rc) {
810                 fprintf(stderr, "quotacheck failed: %s\n", strerror(errno));
811                 return rc;
812         }
813
814         rc = llapi_poll_quotacheck(mnt, &qchk);
815         if (rc) {
816                 if (*obd_type)
817                         fprintf(stderr, "%s %s ", obd_type, obd_uuid);
818                 fprintf(stderr, "quota check failed: %s\n", strerror(errno));
819                 return rc;
820         }
821
822         memset(&qctl, 0, sizeof(qctl));
823         qctl.qc_cmd = LUSTRE_Q_QUOTAON;
824         qctl.qc_id = QFMT_LDISKFS;
825         qctl.qc_type = check_type;
826         rc = llapi_quotactl(mnt, &qctl);
827         if (rc) {
828                 if (*obd_type)
829                         fprintf(stderr, "%s %s ",
830                                 qctl.obd_type, qctl.obd_uuid.uuid);
831                 fprintf(stderr, "%s turn on quota failed: %s\n",
832                         argv[0], strerror(errno));
833                 return rc;
834         }
835
836         return 0;
837 }
838
839 static int lfs_quotaon(int argc, char **argv)
840 {
841         int c;
842         char *mnt;
843         struct if_quotactl qctl;
844         char *obd_type = qctl.obd_type;
845         char *obd_uuid = qctl.obd_uuid.uuid;
846         int rc;
847
848         memset(&qctl, 0, sizeof(qctl));
849         qctl.qc_cmd = LUSTRE_Q_QUOTAON;
850         qctl.qc_id = QFMT_LDISKFS;
851
852         optind = 0;
853         while ((c = getopt(argc, argv, "ugf")) != -1) {
854                 switch (c) {
855                 case 'u':
856                         qctl.qc_type |= 0x01;
857                         break;
858                 case 'g':
859                         qctl.qc_type |= 0x02;
860                         break;
861                 case 'f':
862                         qctl.qc_cmd = LUSTRE_Q_QUOTAOFF;
863                         break;
864                 default:
865                         fprintf(stderr, "error: %s: option '-%c' "
866                                         "unrecognized\n", argv[0], c);
867                         return CMD_HELP;
868                 }
869         }
870
871         if (qctl.qc_type)
872                 qctl.qc_type--;
873
874         if (argc == optind)
875                 return CMD_HELP;
876
877         mnt = argv[optind];
878
879         rc = llapi_quotactl(mnt, &qctl);
880         if (rc) {
881                 if (*obd_type)
882                         fprintf(stderr, "%s %s ", obd_type, obd_uuid);
883                 fprintf(stderr, "%s failed: %s\n", argv[0], strerror(errno));
884                 return rc;
885         }
886
887         return 0;
888 }
889
890 static int lfs_quotaoff(int argc, char **argv)
891 {
892         int c;
893         char *mnt;
894         struct if_quotactl qctl;
895         char *obd_type = qctl.obd_type;
896         char *obd_uuid = qctl.obd_uuid.uuid;
897         int rc;
898
899         memset(&qctl, 0, sizeof(qctl));
900         qctl.qc_cmd = LUSTRE_Q_QUOTAOFF;
901
902         optind = 0;
903         while ((c = getopt(argc, argv, "ug")) != -1) {
904                 switch (c) {
905                 case 'u':
906                         qctl.qc_type |= 0x01;
907                         break;
908                 case 'g':
909                         qctl.qc_type |= 0x02;
910                         break;
911                 default:
912                         fprintf(stderr, "error: %s: option '-%c' "
913                                         "unrecognized\n", argv[0], c);
914                         return CMD_HELP;
915                 }
916         }
917
918         if (qctl.qc_type)
919                 qctl.qc_type--;
920
921         if (argc == optind)
922                 return CMD_HELP;
923
924         mnt = argv[optind];
925
926         rc = llapi_quotactl(mnt, &qctl);
927         if (rc) {
928                 if (*obd_type)
929                         fprintf(stderr, "%s %s ", obd_type, obd_uuid);
930                 fprintf(stderr, "quotaoff failed: %s\n", strerror(errno));
931                 return rc;
932         }
933
934         return 0;
935 }
936
937 static int name2id(unsigned int *id, char *name, int type)
938 {
939         if (type == USRQUOTA) {
940                 struct passwd *entry;
941
942                 if (!(entry = getpwnam(name))) {
943                         if (!errno)
944                                 errno = ENOENT;
945                         return -1;
946                 }
947
948                 *id = entry->pw_uid;
949         } else {
950                 struct group *entry;
951
952                 if (!(entry = getgrnam(name))) {
953                         if (!errno)
954                                 errno = ENOENT;
955                         return -1;
956                 }
957
958                 *id = entry->gr_gid;
959         }
960
961         return 0;
962 }
963
964 static int id2name(char **name, unsigned int id, int type)
965 {
966         if (type == USRQUOTA) {
967                 struct passwd *entry;
968
969                 if (!(entry = getpwuid(id))) {
970                         if (!errno)
971                                 errno = ENOENT;
972                         return -1;
973                 }
974
975                 *name = entry->pw_name;
976         } else {
977                 struct group *entry;
978
979                 if (!(entry = getgrgid(id))) {
980                         if (!errno)
981                                 errno = ENOENT;
982                         return -1;
983                 }
984
985                 *name = entry->gr_name;
986         }
987
988         return 0;
989 }
990
991 #define ARG2INT(nr, str, msg)                                           \
992 do {                                                                    \
993         char *endp;                                                     \
994         nr = strtol(str, &endp, 0);                                     \
995         if (*endp) {                                                    \
996                 fprintf(stderr, "error: bad %s: %s\n", msg, str);       \
997                 return CMD_HELP;                                        \
998         }                                                               \
999 } while (0)
1000
1001 int lfs_setquota(int argc, char **argv)
1002 {
1003         int c;
1004         char *mnt;
1005         struct if_quotactl qctl;
1006         char *obd_type = qctl.obd_type;
1007         char *obd_uuid = qctl.obd_uuid.uuid;
1008         int rc;
1009
1010         memset(&qctl, 0, sizeof(qctl));
1011         qctl.qc_cmd = LUSTRE_Q_SETQUOTA;
1012
1013         optind = 0;
1014         while ((c = getopt(argc, argv, "ugt")) != -1) {
1015                 switch (c) {
1016                 case 'u':
1017                         qctl.qc_type |= 0x01;
1018                         break;
1019                 case 'g':
1020                         qctl.qc_type |= 0x02;
1021                         break;
1022                 case 't':
1023                         qctl.qc_cmd = LUSTRE_Q_SETINFO;
1024                         break;
1025                 default:
1026                         fprintf(stderr, "error: %s: option '-%c' "
1027                                         "unrecognized\n", argv[0], c);
1028                         return CMD_HELP;
1029                 }
1030         }
1031
1032         if (qctl.qc_type)
1033                 qctl.qc_type--;
1034
1035         if (qctl.qc_type == UGQUOTA) {
1036                 fprintf(stderr, "error: user and group quotas can't be set "
1037                                 "both\n");
1038                 return CMD_HELP;
1039         }
1040
1041         if (qctl.qc_cmd == LUSTRE_Q_SETQUOTA) {
1042                 struct obd_dqblk *dqb = &qctl.qc_dqblk;
1043
1044                 if (optind + 6 != argc)
1045                         return CMD_HELP;
1046
1047                 rc = name2id(&qctl.qc_id, argv[optind++], qctl.qc_type);
1048                 if (rc) {
1049                         fprintf(stderr, "error: find id for name %s failed: %s\n",
1050                                 argv[optind - 1], strerror(errno));
1051                         return CMD_HELP;
1052                 }
1053
1054                 ARG2INT(dqb->dqb_bsoftlimit, argv[optind++], "block-softlimit");
1055                 ARG2INT(dqb->dqb_bhardlimit, argv[optind++], "block-hardlimit");
1056                 ARG2INT(dqb->dqb_isoftlimit, argv[optind++], "inode-softlimit");
1057                 ARG2INT(dqb->dqb_ihardlimit, argv[optind++], "inode-hardlimit");
1058
1059                 dqb->dqb_valid = QIF_LIMITS;
1060         } else {
1061                 struct obd_dqinfo *dqi = &qctl.qc_dqinfo;
1062
1063                 if (optind + 3 != argc)
1064                         return CMD_HELP;
1065
1066                 ARG2INT(dqi->dqi_bgrace, argv[optind++], "block-grace");
1067                 ARG2INT(dqi->dqi_igrace, argv[optind++], "inode-grace");
1068         }
1069
1070         mnt = argv[optind];
1071
1072         rc = llapi_quotactl(mnt, &qctl);
1073         if (rc) {
1074                 if (*obd_type)
1075                         fprintf(stderr, "%s %s ", obd_type, obd_uuid);
1076                 fprintf(stderr, "setquota failed: %s\n", strerror(errno));
1077                 return rc;
1078         }
1079
1080         return 0;
1081 }
1082
1083 static inline char *type2name(int check_type)
1084 {
1085         if (check_type == USRQUOTA)
1086                 return "user";
1087         else if (check_type == GRPQUOTA)
1088                 return "group";
1089         else
1090                 return "unknown";
1091 }
1092
1093
1094 static void grace2str(time_t seconds,char *buf)
1095 {
1096         uint minutes, hours, days;
1097
1098         minutes = (seconds + 30) / 60;
1099         hours = minutes / 60;
1100         minutes %= 60;
1101         days = hours / 24;
1102         hours %= 24;
1103         if (days >= 2)
1104                 snprintf(buf, 40, "%ddays", days);
1105         else
1106                 snprintf(buf, 40, "%02d:%02d", hours + days * 24, minutes);
1107 }
1108
1109
1110 static void diff2str(time_t seconds, char *buf, time_t now)
1111 {
1112
1113         buf[0] = 0;
1114         if (!seconds)
1115                 return;
1116         if (seconds <= now) {
1117                 strcpy(buf, "none");
1118                 return;
1119         }
1120         grace2str(seconds - now, buf);
1121 }
1122
1123 static void print_quota_title(char *name, struct if_quotactl *qctl)
1124 {
1125         printf("Disk quotas for %s %s (%cid %u):\n",
1126                type2name(qctl->qc_type), name,
1127                *type2name(qctl->qc_type), qctl->qc_id);
1128         printf("%15s%8s %7s%8s%8s%8s %7s%8s%8s\n",
1129                "Filesystem",
1130                "blocks", "quota", "limit", "grace",
1131                "files", "quota", "limit", "grace");
1132 }
1133
1134 static void print_quota(char *mnt, struct if_quotactl *qctl, int ost_only)
1135 {
1136         time_t now;
1137
1138         time(&now);
1139
1140         if (qctl->qc_cmd == LUSTRE_Q_GETQUOTA || qctl->qc_cmd == Q_GETOQUOTA) {
1141                 int bover = 0, iover = 0;
1142                 struct obd_dqblk *dqb = &qctl->qc_dqblk;
1143
1144                 if (dqb->dqb_bhardlimit &&
1145                     toqb(dqb->dqb_curspace) > dqb->dqb_bhardlimit) {
1146                         bover = 1;
1147                 } else if (dqb->dqb_bsoftlimit &&
1148                            toqb(dqb->dqb_curspace) > dqb->dqb_bsoftlimit) {
1149                         if (dqb->dqb_btime > now) {
1150                                 bover = 2;
1151                         } else {
1152                                 bover = 3;
1153                         }
1154                 }
1155
1156                 if (dqb->dqb_ihardlimit &&
1157                     dqb->dqb_curinodes > dqb->dqb_ihardlimit) {
1158                         iover = 1;
1159                 } else if (dqb->dqb_isoftlimit &&
1160                            dqb->dqb_curinodes > dqb->dqb_isoftlimit) {
1161                         if (dqb->dqb_btime > now) {
1162                                 iover = 2;
1163                         } else {
1164                                 iover = 3;
1165                         }
1166                 }
1167
1168 #if 0           /* XXX: always print quotas even when no usages */
1169                 if (dqb->dqb_curspace || dqb->dqb_curinodes)
1170 #endif
1171                 {
1172                         char numbuf[3][32];
1173                         char timebuf[40];
1174
1175                         if (strlen(mnt) > 15)
1176                                 printf("%s\n%15s", mnt, "");
1177                         else
1178                                 printf("%15s", mnt);
1179
1180                         if (bover)
1181                                 diff2str(dqb->dqb_btime, timebuf, now);
1182
1183                         sprintf(numbuf[0], "%llu", toqb(dqb->dqb_curspace));
1184                         sprintf(numbuf[1], "%llu", dqb->dqb_bsoftlimit);
1185                         sprintf(numbuf[2], "%llu", dqb->dqb_bhardlimit);
1186                         printf(" %7s%c %6s %7s %7s",
1187                                numbuf[0], bover ? '*' : ' ', numbuf[1],
1188                                numbuf[2], bover > 1 ? timebuf : "");
1189
1190                         if (iover)
1191                                 diff2str(dqb->dqb_itime, timebuf, now);
1192
1193                         sprintf(numbuf[0], "%llu", dqb->dqb_curinodes);
1194                         sprintf(numbuf[1], "%llu", dqb->dqb_isoftlimit);
1195                         sprintf(numbuf[2], "%llu", dqb->dqb_ihardlimit);
1196                         if (!ost_only)
1197                                 printf(" %7s%c %6s %7s %7s",
1198                                        numbuf[0], iover ? '*' : ' ', numbuf[1],
1199                                        numbuf[2], iover > 1 ? timebuf : "");
1200                         printf("\n");
1201                 }
1202         } else if (qctl->qc_cmd == LUSTRE_Q_GETINFO ||
1203                    qctl->qc_cmd == Q_GETOINFO) {
1204                 char bgtimebuf[40];
1205                 char igtimebuf[40];
1206
1207                 grace2str(qctl->qc_dqinfo.dqi_bgrace, bgtimebuf);
1208                 grace2str(qctl->qc_dqinfo.dqi_igrace, igtimebuf);
1209                 printf("Block grace time: %s; Inode grace time: %s\n",
1210                        bgtimebuf, igtimebuf);
1211         }
1212 }
1213
1214 static void print_mds_quota(char *mnt, struct if_quotactl *qctl)
1215 {
1216         int rc;
1217
1218         /* XXX: this is a flag to mark that only mds quota is wanted */
1219         qctl->qc_dqblk.dqb_valid = 1;
1220         rc = llapi_quotactl(mnt, qctl);
1221         if (rc) {
1222                 fprintf(stderr, "quotactl failed: %s\n", strerror(errno));
1223                 return;
1224         }
1225         qctl->qc_dqblk.dqb_valid = 0;
1226
1227         print_quota(qctl->obd_uuid.uuid, qctl, 0);
1228 }
1229
1230 static void print_lov_quota(char *mnt, struct if_quotactl *qctl)
1231 {
1232         DIR *dir;
1233         struct obd_uuid uuids[1024], *uuidp;
1234         int obdcount = 1024;
1235         int i, rc;
1236
1237         dir = opendir(mnt);
1238         if (!dir) {
1239                 fprintf(stderr, "open %s failed: %s\n", mnt, strerror(errno));
1240                 return;
1241         }
1242
1243         rc = llapi_lov_get_uuids(dirfd(dir), uuids, &obdcount);
1244         if (rc != 0) {
1245                 fprintf(stderr, "get ost uuid failed: %s\n", strerror(errno));
1246                 goto out;
1247         }
1248
1249         for (i = 0, uuidp = uuids; i < obdcount; i++, uuidp++) {
1250                 memcpy(&qctl->obd_uuid, uuidp, sizeof(*uuidp));
1251
1252                 /* XXX clear this flag to get quota from osts */
1253                 qctl->qc_dqblk.dqb_valid = 0;
1254                 rc = llapi_quotactl(mnt, qctl);
1255                 if (rc) {
1256                         fprintf(stderr, "%s quotactl failed: %s\n",
1257                                 uuidp->uuid, strerror(errno));
1258                         continue;
1259                 }
1260
1261                 print_quota(uuidp->uuid, qctl, 1);
1262         }
1263
1264 out:
1265         closedir(dir);
1266         return;
1267 }
1268
1269 static int lfs_quota(int argc, char **argv)
1270 {
1271         int c;
1272         char *name = NULL, *mnt;
1273         struct if_quotactl qctl;
1274         char *obd_type = qctl.obd_type;
1275         char *obd_uuid = qctl.obd_uuid.uuid;
1276         int rc;
1277
1278         memset(&qctl, 0, sizeof(qctl));
1279         qctl.qc_cmd = LUSTRE_Q_GETQUOTA;
1280
1281         optind = 0;
1282         while ((c = getopt(argc, argv, "ugto:")) != -1) {
1283                 switch (c) {
1284                 case 'u':
1285                         qctl.qc_type |= 0x01;
1286                         break;
1287                 case 'g':
1288                         qctl.qc_type |= 0x02;
1289                         break;
1290                 case 't':
1291                         qctl.qc_cmd = LUSTRE_Q_GETINFO;
1292                         break;
1293                 case 'o':
1294                         strncpy(obd_uuid, optarg, sizeof(qctl.obd_uuid));
1295                         break;
1296                 default:
1297                         fprintf(stderr, "error: %s: option '-%c' "
1298                                         "unrecognized\n", argv[0], c);
1299                         return CMD_HELP;
1300                 }
1301         }
1302
1303         if (qctl.qc_type)
1304                 qctl.qc_type--;
1305
1306         if (qctl.qc_type == UGQUOTA) {
1307                 fprintf(stderr, "error: user or group can't be specified"
1308                                 "both\n");
1309                 return CMD_HELP;
1310         }
1311
1312         if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA) {
1313                 if (optind + 2 != argc)
1314                         return CMD_HELP;
1315
1316                 name = argv[optind++];
1317                 rc = name2id(&qctl.qc_id, name, qctl.qc_type);
1318                 if (rc) {
1319                         fprintf(stderr, "error: find id for name %s failed: %s\n",
1320                                 name, strerror(errno));
1321                         return CMD_HELP;
1322                 }
1323                 print_quota_title(name, &qctl);
1324         } else if (optind + 1 != argc) {
1325                 return CMD_HELP;
1326         }
1327
1328         mnt = argv[optind];
1329
1330         rc = llapi_quotactl(mnt, &qctl);
1331         if (rc) {
1332                 if (*obd_type)
1333                         fprintf(stderr, "%s %s ", obd_type, obd_uuid);
1334                 fprintf(stderr, "quota failed: %s\n", strerror(errno));
1335                 return rc;
1336         }
1337
1338         if (!name)
1339                 rc = id2name(&name, getuid(), qctl.qc_type);
1340
1341         if (*obd_uuid) {
1342                 mnt = "";
1343                 name = obd_uuid;
1344         }
1345
1346         print_quota(mnt, &qctl, 0);
1347
1348         if (!*obd_uuid && qctl.qc_cmd != LUSTRE_Q_GETINFO) {
1349                 print_mds_quota(mnt, &qctl);
1350                 print_lov_quota(mnt, &qctl);
1351         }
1352
1353         return 0;
1354 }
1355 #endif /* HAVE_QUOTA_SUPPORT */
1356
1357 int main(int argc, char **argv)
1358 {
1359         int rc;
1360
1361         setlinebuf(stdout);
1362
1363         ptl_initialize(argc, argv);
1364         if (obd_initialize(argc, argv) < 0)
1365                 exit(2);
1366         if (dbg_initialize(argc, argv) < 0)
1367                 exit(3);
1368
1369         Parser_init("lfs > ", cmdlist);
1370
1371         if (argc > 1) {
1372                 rc = Parser_execarg(argc - 1, argv + 1, cmdlist);
1373         } else {
1374                 rc = Parser_commands();
1375         }
1376
1377         obd_finalize(argc, argv);
1378         return rc;
1379 }