Whamcloud - gitweb
e180ffb7067ef8ae3a75e03c4c73aa89e6edc0c4
[fs/lustre-release.git] / lustre / utils / lfs.c
1 /*
2  * GPL HEADER START
3  *
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 only,
8  * as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License version 2 for more details (a copy is included
14  * in the LICENSE file that accompanied this code).
15  *
16  * You should have received a copy of the GNU General Public License
17  * version 2 along with this program; If not, see
18  * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
19  *
20  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
21  * CA 95054 USA or visit www.sun.com if you need additional information or
22  * have any questions.
23  *
24  * GPL HEADER END
25  */
26 /*
27  * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
28  * Use is subject to license terms.
29  *
30  * Copyright (c) 2011, 2012, Intel Corporation.
31  */
32 /*
33  * This file is part of Lustre, http://www.lustre.org/
34  * Lustre is a trademark of Sun Microsystems, Inc.
35  *
36  * lustre/utils/lfs.c
37  *
38  * Author: Peter J. Braam <braam@clusterfs.com>
39  * Author: Phil Schwan <phil@clusterfs.com>
40  * Author: Robert Read <rread@clusterfs.com>
41  */
42
43 /* for O_DIRECTORY */
44 #ifndef _GNU_SOURCE
45 #define _GNU_SOURCE
46 #endif
47
48 #include <stdlib.h>
49 #include <stdio.h>
50 #include <getopt.h>
51 #include <string.h>
52 #include <mntent.h>
53 #include <errno.h>
54 #include <pwd.h>
55 #include <grp.h>
56 #include <sys/types.h>
57 #include <sys/stat.h>
58 #include <fcntl.h>
59 #include <dirent.h>
60 #include <time.h>
61 #include <ctype.h>
62 #ifdef HAVE_SYS_QUOTA_H
63 # include <sys/quota.h>
64 #endif
65
66 /* For dirname() */
67 #include <libgen.h>
68
69 #include <lnet/lnetctl.h>
70
71 #include <liblustre.h>
72 #include <lustre/lustreapi.h>
73
74 #include <libcfs/libcfsutil.h>
75 #include "obdctl.h"
76
77 /* all functions */
78 static int lfs_setstripe(int argc, char **argv);
79 static int lfs_find(int argc, char **argv);
80 static int lfs_getstripe(int argc, char **argv);
81 static int lfs_getdirstripe(int argc, char **argv);
82 static int lfs_setdirstripe(int argc, char **argv);
83 static int lfs_rmentry(int argc, char **argv);
84 static int lfs_osts(int argc, char **argv);
85 static int lfs_mdts(int argc, char **argv);
86 static int lfs_df(int argc, char **argv);
87 static int lfs_getname(int argc, char **argv);
88 static int lfs_check(int argc, char **argv);
89 #ifdef HAVE_SYS_QUOTA_H
90 static int lfs_quotacheck(int argc, char **argv);
91 static int lfs_quotaon(int argc, char **argv);
92 static int lfs_quotaoff(int argc, char **argv);
93 static int lfs_setquota(int argc, char **argv);
94 static int lfs_quota(int argc, char **argv);
95 #endif
96 static int lfs_flushctx(int argc, char **argv);
97 static int lfs_join(int argc, char **argv);
98 static int lfs_lsetfacl(int argc, char **argv);
99 static int lfs_lgetfacl(int argc, char **argv);
100 static int lfs_rsetfacl(int argc, char **argv);
101 static int lfs_rgetfacl(int argc, char **argv);
102 static int lfs_cp(int argc, char **argv);
103 static int lfs_ls(int argc, char **argv);
104 static int lfs_poollist(int argc, char **argv);
105 static int lfs_changelog(int argc, char **argv);
106 static int lfs_changelog_clear(int argc, char **argv);
107 static int lfs_fid2path(int argc, char **argv);
108 static int lfs_path2fid(int argc, char **argv);
109 static int lfs_data_version(int argc, char **argv);
110 static int lfs_hsm_state(int argc, char **argv);
111 static int lfs_hsm_set(int argc, char **argv);
112 static int lfs_hsm_clear(int argc, char **argv);
113 static int lfs_hsm_action(int argc, char **argv);
114 static int lfs_hsm_archive(int argc, char **argv);
115 static int lfs_hsm_restore(int argc, char **argv);
116 static int lfs_hsm_release(int argc, char **argv);
117 static int lfs_hsm_remove(int argc, char **argv);
118 static int lfs_hsm_cancel(int argc, char **argv);
119
120
121 /* all avaialable commands */
122 command_t cmdlist[] = {
123         {"setstripe", lfs_setstripe, 0,
124          "Create a new file with a specific striping pattern or\n"
125          "set the default striping pattern on an existing directory or\n"
126          "delete the default striping pattern from an existing directory\n"
127          "usage: setstripe [--stripe-count|-c <stripe_count>]\n"
128          "                 [--stripe-index|-i <start_ost_idx>]\n"
129          "                 [--stripe-size|-S <stripe_size>]\n"
130          "                 [--pool|-p <pool_name>] <directory|filename>\n"
131          " or\n"
132          "       setstripe -d <directory>   (to delete default striping)\n"
133          "\tstripe_size:  Number of bytes on each OST (0 filesystem default)\n"
134          "\t              Can be specified with k, m or g (in KB, MB and GB\n"
135          "\t              respectively)\n"
136          "\tstart_ost_idx: OST index of first stripe (-1 default)\n"
137          "\tstripe_count: Number of OSTs to stripe over (0 default, -1 all)\n"
138          "\tpool_name:    Name of OST pool to use (default none)"},
139         {"getstripe", lfs_getstripe, 0,
140          "To list the striping info for a given file or files in a\n"
141          "directory or recursively for all files in a directory tree.\n"
142          "usage: getstripe [--ost|-O <uuid>] [--quiet | -q] [--verbose | -v]\n"
143          "                 [--stripe-count|-c] [--stripe-index|-i]\n"
144          "                 [--pool|-p] [--stripe-size|-S] [--directory|-d]\n"
145          "                 [--mdt-index|-M] [--recursive|-r] [--raw|-R]\n"
146          "                 <directory|filename> ..."},
147         {"setdirstripe", lfs_setdirstripe, 0,
148          "To create a remote directory on a specified MDT.\n"
149          "usage: setdirstripe <--index|-i mdt_index> <dir>\n"
150          "\tmdt_index:    MDT index of first stripe\n"},
151         {"getdirstripe", lfs_getdirstripe, 0,
152          "To list the striping info for a given directory\n"
153          "or recursively for all directories in a directory tree.\n"
154          "usage: getdirstripe [--obd|-O <uuid>] [--quiet|-q] [--verbose|-v]\n"
155          "               [--count|-c ] [--index|-i ] [--raw|-R]\n"
156          "               [--recursive | -r] <dir> ..."},
157         {"mkdir", lfs_setdirstripe, 0,
158          "To create a remote directory on a specified MDT. And this can only\n"
159          "be done on MDT0 by administrator.\n"
160          "usage: mkdir <--index|-i mdt_index> <dir>\n"
161          "\tmdt_index:    MDT index of the remote directory.\n"},
162         {"rm_entry", lfs_rmentry, 0,
163          "To remove the name entry of the remote directory. Note: This\n"
164          "command will only delete the name entry, i.e. the remote directory\n"
165          "will become inaccessable after this command. This can only be done\n"
166          "by the administrator\n"
167          "usage: rm_entry <dir>\n"},
168         {"pool_list", lfs_poollist, 0,
169          "List pools or pool OSTs\n"
170          "usage: pool_list <fsname>[.<pool>] | <pathname>\n"},
171         {"find", lfs_find, 0,
172          "find files matching given attributes recursively in directory tree.\n"
173          "usage: find <directory|filename> ...\n"
174          "     [[!] --atime|-A [+-]N] [[!] --ctime|-C [+-]N]\n"
175          "     [[!] --mtime|-M [+-]N] [[!] --mdt|-m <uuid|index,...>]\n"
176          "     [--maxdepth|-D N] [[!] --name|-n <pattern>]\n"
177          "     [[!] --ost|-O <uuid|index,...>] [--print|-p] [--print0|-P]\n"
178          "     [[!] --size|-s [+-]N[bkMGTPE]]\n"
179          "     [[!] --stripe-count|-c [+-]<stripes>]\n"
180          "     [[!] --stripe-index|-i <index,...>]\n"
181          "     [[!] --stripe-size|-S [+-]N[kMGT]] [[!] --type|-t <filetype>]\n"
182          "     [[!] --gid|-g|--group|-G <gid>|<gname>]\n"
183          "     [[!] --uid|-u|--user|-U <uid>|<uname>] [[!] --pool <pool>]\n"
184          "\t !: used before an option indicates 'NOT' requested attribute\n"
185          "\t -: used before a value indicates 'AT MOST' requested value\n"
186          "\t +: used before a value indicates 'AT LEAST' requested value\n"},
187         {"check", lfs_check, 0,
188          "Display the status of MDS or OSTs (as specified in the command)\n"
189          "or all the servers (MDS and OSTs).\n"
190          "usage: check <osts|mds|servers>"},
191         {"join", lfs_join, 0,
192          "join two lustre files into one.\n"
193          "obsolete, HEAD does not support it anymore.\n"},
194         {"osts", lfs_osts, 0, "list OSTs connected to client "
195          "[for specified path only]\n" "usage: osts [path]"},
196         {"mdts", lfs_mdts, 0, "list MDTs connected to client "
197          "[for specified path only]\n" "usage: mdts [path]"},
198         {"df", lfs_df, 0,
199          "report filesystem disk space usage or inodes usage"
200          "of each MDS and all OSDs or a batch belonging to a specific pool .\n"
201          "Usage: df [-i] [-h] [--lazy|-l] [--pool|-p <fsname>[.<pool>] [path]"},
202         {"getname", lfs_getname, 0, "list instances and specified mount points "
203          "[for specified path only]\n"
204          "Usage: getname [-h]|[path ...] "},
205 #ifdef HAVE_SYS_QUOTA_H
206         {"quotacheck", lfs_quotacheck, 0,
207          "Scan the specified filesystem for disk usage, and create,\n"
208          "or update quota files. Deprecated as of 2.4.0.\n"
209          "usage: quotacheck [ -ug ] <filesystem>"},
210         {"quotaon", lfs_quotaon, 0, "Turn filesystem"
211          " quotas on. Deprecated as of 2.4.0.\n"
212          "usage: quotaon [ -ugf ] <filesystem>"},
213         {"quotaoff", lfs_quotaoff, 0, "Turn filesystem"
214          " quotas off. Deprecated as of 2.4.0.\n"
215          "usage: quotaoff [ -ug ] <filesystem>"},
216         {"setquota", lfs_setquota, 0, "Set filesystem quotas.\n"
217          "usage: setquota <-u|-g> <uname>|<uid>|<gname>|<gid>\n"
218          "                -b <block-softlimit> -B <block-hardlimit>\n"
219          "                -i <inode-softlimit> -I <inode-hardlimit> <filesystem>\n"
220          "       setquota <-u|--user|-g|--group> <uname>|<uid>|<gname>|<gid>\n"
221          "                [--block-softlimit <block-softlimit>]\n"
222          "                [--block-hardlimit <block-hardlimit>]\n"
223          "                [--inode-softlimit <inode-softlimit>]\n"
224          "                [--inode-hardlimit <inode-hardlimit>] <filesystem>\n"
225          "       setquota [-t] <-u|--user|-g|--group>\n"
226          "                [--block-grace <block-grace>]\n"
227          "                [--inode-grace <inode-grace>] <filesystem>\n"
228          "       -b can be used instead of --block-softlimit/--block-grace\n"
229          "       -B can be used instead of --block-hardlimit\n"
230          "       -i can be used instead of --inode-softlimit/--inode-grace\n"
231          "       -I can be used instead of --inode-hardlimit"},
232         {"quota", lfs_quota, 0, "Display disk usage and limits.\n"
233          "usage: quota [-q] [-v] [-o <obd_uuid>|-i <mdt_idx>|-I <ost_idx>]\n"
234          "             [<-u|-g> <uname>|<uid>|<gname>|<gid>] <filesystem>\n"
235          "       quota [-o <obd_uuid>|-i <mdt_idx>|-I <ost_idx>] -t <-u|-g> <filesystem>"},
236 #endif
237         {"flushctx", lfs_flushctx, 0, "Flush security context for current user.\n"
238          "usage: flushctx [-k] [mountpoint...]"},
239         {"lsetfacl", lfs_lsetfacl, 0,
240          "Remote user setfacl for user/group on the same remote client.\n"
241          "usage: lsetfacl [-bkndRLPvh] [{-m|-x} acl_spec] [{-M|-X} acl_file] file ..."},
242         {"lgetfacl", lfs_lgetfacl, 0,
243          "Remote user getfacl for user/group on the same remote client.\n"
244          "usage: lgetfacl [-dRLPvh] file ..."},
245         {"rsetfacl", lfs_rsetfacl, 0,
246          "Remote user setfacl for user/group on other clients.\n"
247          "usage: rsetfacl [-bkndRLPvh] [{-m|-x} acl_spec] [{-M|-X} acl_file] file ..."},
248         {"rgetfacl", lfs_rgetfacl, 0,
249          "Remote user getfacl for user/group on other clients.\n"
250          "usage: rgetfacl [-dRLPvh] file ..."},
251         {"cp", lfs_cp, 0,
252          "Remote user copy files and directories.\n"
253          "usage: cp [OPTION]... [-T] SOURCE DEST\n\tcp [OPTION]... SOURCE... DIRECTORY\n\tcp [OPTION]... -t DIRECTORY SOURCE..."},
254         {"ls", lfs_ls, 0,
255          "Remote user list directory contents.\n"
256          "usage: ls [OPTION]... [FILE]..."},
257         {"changelog", lfs_changelog, 0,
258          "Show the metadata changes on an MDT."
259          "\nusage: changelog <mdtname> [startrec [endrec]]"},
260         {"changelog_clear", lfs_changelog_clear, 0,
261          "Indicate that old changelog records up to <endrec> are no longer of "
262          "interest to consumer <id>, allowing the system to free up space.\n"
263          "An <endrec> of 0 means all records.\n"
264          "usage: changelog_clear <mdtname> <id> <endrec>"},
265         {"fid2path", lfs_fid2path, 0,
266          "Resolve the full path to a given FID. For a specific hardlink "
267          "specify link number <linkno>.\n"
268          /* "For a historical name, specify changelog record <recno>.\n" */
269          "usage: fid2path <fsname|rootpath> <fid> [--link <linkno>]"
270                 /*[--rec <recno>]*/},
271         {"path2fid", lfs_path2fid, 0, "Display the fid for a given path.\n"
272          "usage: path2fid <path>"},
273         {"data_version", lfs_data_version, 0, "Display file data version for "
274          "a given path.\n" "usage: data_version [-n] <path>"},
275         {"hsm_state", lfs_hsm_state, 0, "Display the HSM information (states, "
276          "undergoing actions) for given files.\n usage: hsm_state <file> ..."},
277         {"hsm_set", lfs_hsm_set, 0, "Set HSM user flag on specified files.\n"
278          "usage: hsm_set [--norelease] [--noarchive] [--dirty] [--exists] "
279          "[--archived] [--lost] <file> ..."},
280         {"hsm_clear", lfs_hsm_clear, 0, "Clear HSM user flag on specified "
281          "files.\n"
282          "usage: hsm_clear [--norelease] [--noarchive] [--dirty] [--exists] "
283          "[--archived] [--lost] <file> ..."},
284         {"hsm_action", lfs_hsm_action, 0, "Display current HSM request for "
285          "given files.\n" "usage: hsm_action <file> ..."},
286         {"hsm_archive", lfs_hsm_archive, 0,
287          "Archive file to external storage.\n"
288          "usage: hsm_archive [--filelist FILELIST] [--data DATA] [--archive NUM] "
289          "<file> ..."},
290         {"hsm_restore", lfs_hsm_restore, 0,
291          "Restore file from external storage.\n"
292          "usage: hsm_restore [--filelist FILELIST] [--data DATA] <file> ..."},
293         {"hsm_release", lfs_hsm_release, 0,
294          "Release files from Lustre.\n"
295          "usage: hsm_release [--filelist FILELIST] [--data DATA] <file> ..."},
296         {"hsm_remove", lfs_hsm_remove, 0,
297          "Remove file copy from external storage.\n"
298          "usage: hsm_remove [--filelist FILELIST] [--data DATA] <file> ..."},
299         {"hsm_cancel", lfs_hsm_cancel, 0,
300          "Cancel requests related to specified files.\n"
301          "usage: hsm_cancel [--filelist FILELIST] [--data DATA] <file> ..."},
302         {"help", Parser_help, 0, "help"},
303         {"exit", Parser_quit, 0, "quit"},
304         {"quit", Parser_quit, 0, "quit"},
305         { 0, 0, 0, NULL }
306 };
307
308 static int isnumber(const char *str)
309 {
310         const char *ptr;
311
312         if (str[0] != '-' && !isdigit(str[0]))
313                 return 0;
314
315         for (ptr = str + 1; *ptr != '\0'; ptr++) {
316                 if (!isdigit(*ptr))
317                         return 0;
318         }
319
320         return 1;
321 }
322
323 /* functions */
324 static int lfs_setstripe(int argc, char **argv)
325 {
326         char *fname;
327         int result;
328         unsigned long long st_size;
329         int  st_offset, st_count;
330         char *end;
331         int c;
332         int delete = 0;
333         char *stripe_size_arg = NULL;
334         char *stripe_off_arg = NULL;
335         char *stripe_count_arg = NULL;
336         char *pool_name_arg = NULL;
337         unsigned long long size_units = 1;
338
339         struct option long_opts[] = {
340 #if LUSTRE_VERSION >= OBD_OCD_VERSION(2,9,50,0)
341 #warning "remove deprecated --count option"
342 #else
343                 /* This formerly implied "stripe-count", but was explicitly
344                  * made "stripe-count" for consistency with other options,
345                  * and to separate it from "mdt-count" when DNE arrives. */
346                 {"count",        required_argument, 0, 'c'},
347 #endif
348                 {"stripe-count", required_argument, 0, 'c'},
349                 {"stripe_count", required_argument, 0, 'c'},
350                 {"delete",       no_argument,       0, 'd'},
351 #if LUSTRE_VERSION >= OBD_OCD_VERSION(2,9,50,0)
352 #warning "remove deprecated --index option"
353 #else
354                 /* This formerly implied "stripe-index", but was explicitly
355                  * made "stripe-index" for consistency with other options,
356                  * and to separate it from "mdt-index" when DNE arrives. */
357                 {"index",        required_argument, 0, 'i'},
358 #endif
359                 {"stripe-index", required_argument, 0, 'i'},
360                 {"stripe_index", required_argument, 0, 'i'},
361 #if LUSTRE_VERSION >= OBD_OCD_VERSION(2,9,50,0)
362 #warning "remove deprecated --offset option"
363 #else
364                 /* This formerly implied "stripe-index", but was confusing
365                  * with "file offset" (which will eventually be needed for
366                  * with different layouts by offset), so deprecate it. */
367                 {"offset",       required_argument, 0, 'o'},
368 #endif
369                 {"pool",         required_argument, 0, 'p'},
370 #if LUSTRE_VERSION >= OBD_OCD_VERSION(2,9,50,0)
371 #warning "remove deprecated --size option"
372 #else
373                 /* This formerly implied "--stripe-size", but was confusing
374                  * with "lfs find --size|-s", which means "file size", so use
375                  * the consistent "--stripe-size|-S" for all commands. */
376                 {"size",         required_argument, 0, 's'},
377 #endif
378                 {"stripe-size",  required_argument, 0, 'S'},
379                 {"stripe_size",  required_argument, 0, 'S'},
380                 {0, 0, 0, 0}
381         };
382
383         st_size = 0;
384         st_offset = -1;
385         st_count = 0;
386
387 #if LUSTRE_VERSION < OBD_OCD_VERSION(2,4,50,0)
388         if (argc == 5 && argv[1][0] != '-' &&
389             isnumber(argv[2]) && isnumber(argv[3]) && isnumber(argv[4])) {
390                 fprintf(stderr, "error: obsolete usage of setstripe "
391                         "positional parameters.  Use -c, -i, -S instead.\n");
392                 return CMD_HELP;
393         } else
394 #else
395 #warning "remove obsolete positional parameter error"
396 #endif
397         {
398                 optind = 0;
399                 while ((c = getopt_long(argc, argv, "c:di:o:p:s:S:",
400                                         long_opts, NULL)) >= 0) {
401                 switch (c) {
402                 case 0:
403                         /* Long options. */
404                         break;
405                 case 'c':
406 #if LUSTRE_VERSION >= OBD_OCD_VERSION(2,9,50,0)
407 #warning "remove deprecated --count option"
408 #elif LUSTRE_VERSION >= OBD_OCD_VERSION(2,6,50,0)
409                         if (strcmp(argv[optind - 1], "--count") == 0)
410                                 fprintf(stderr, "warning: '--count' deprecated"
411                                         ", use '--stripe-count' instead\n");
412 #endif
413                         stripe_count_arg = optarg;
414                         break;
415                 case 'd':
416                         /* delete the default striping pattern */
417                         delete = 1;
418                         break;
419                 case 'o':
420 #if LUSTRE_VERSION >= OBD_OCD_VERSION(2,4,50,0)
421                         fprintf(stderr, "warning: '--offset|-o' deprecated, "
422                                 "use '--stripe-index|-i' instead\n");
423 #else
424                         if (strcmp(argv[optind - 1], "--offset") == 0)
425                                 /* need --stripe-index established first */
426                                 fprintf(stderr, "warning: '--offset' deprecated"
427                                         ", use '--index' instead\n");
428 #endif
429                 case 'i':
430 #if LUSTRE_VERSION >= OBD_OCD_VERSION(2,9,50,0)
431 #warning "remove deprecated --offset and --index options"
432 #elif LUSTRE_VERSION >= OBD_OCD_VERSION(2,6,50,0)
433                         if (strcmp(argv[optind - 1], "--index") == 0)
434                                 fprintf(stderr, "warning: '--index' deprecated"
435                                         ", use '--stripe-index' instead\n");
436 #endif
437                         stripe_off_arg = optarg;
438                         break;
439                 case 's':
440 #if LUSTRE_VERSION >= OBD_OCD_VERSION(2,9,50,0)
441 #warning "remove deprecated --size option"
442 #elif LUSTRE_VERSION >= OBD_OCD_VERSION(2,6,50,0)
443                         fprintf(stderr, "warning: '--size|-s' deprecated, "
444                                 "use '--stripe-size|-S' instead\n");
445 #endif
446                 case 'S':
447                         stripe_size_arg = optarg;
448                         break;
449                 case 'p':
450                         pool_name_arg = optarg;
451                         break;
452                 default:
453                         return CMD_HELP;
454                 }
455                 }
456
457                 fname = argv[optind];
458
459                 if (delete &&
460                     (stripe_size_arg != NULL || stripe_off_arg != NULL ||
461                      stripe_count_arg != NULL || pool_name_arg != NULL)) {
462                         fprintf(stderr, "error: %s: cannot specify -d with "
463                                         "-s, -c, -o, or -p options\n",
464                                         argv[0]);
465                         return CMD_HELP;
466                 }
467         }
468
469         if (optind == argc) {
470                 fprintf(stderr, "error: %s: missing filename|dirname\n",
471                         argv[0]);
472                 return CMD_HELP;
473         }
474
475         /* get the stripe size */
476         if (stripe_size_arg != NULL) {
477                 result = parse_size(stripe_size_arg, &st_size, &size_units, 0);
478                 if (result) {
479                         fprintf(stderr, "error: %s: bad stripe size '%s'\n",
480                                 argv[0], stripe_size_arg);
481                         return result;
482                 }
483         }
484         /* get the stripe offset */
485         if (stripe_off_arg != NULL) {
486                 st_offset = strtol(stripe_off_arg, &end, 0);
487                 if (*end != '\0') {
488                         fprintf(stderr, "error: %s: bad stripe offset '%s'\n",
489                                 argv[0], stripe_off_arg);
490                         return CMD_HELP;
491                 }
492         }
493         /* get the stripe count */
494         if (stripe_count_arg != NULL) {
495                 st_count = strtoul(stripe_count_arg, &end, 0);
496                 if (*end != '\0') {
497                         fprintf(stderr, "error: %s: bad stripe count '%s'\n",
498                                 argv[0], stripe_count_arg);
499                         return CMD_HELP;
500                 }
501         }
502
503         do {
504                 result = llapi_file_create_pool(fname, st_size, st_offset,
505                                                 st_count, 0, pool_name_arg);
506                 if (result) {
507                         fprintf(stderr,"error: %s: create stripe file '%s' "
508                                 "failed\n", argv[0], fname);
509                         break;
510                 }
511                 fname = argv[++optind];
512         } while (fname != NULL);
513
514         return result;
515 }
516
517 static int lfs_poollist(int argc, char **argv)
518 {
519         if (argc != 2)
520                 return CMD_HELP;
521
522         return llapi_poollist(argv[1]);
523 }
524
525 static int set_time(time_t *time, time_t *set, char *str)
526 {
527         time_t t;
528         int res = 0;
529
530         if (str[0] == '+')
531                 res = 1;
532         else if (str[0] == '-')
533                 res = -1;
534
535         if (res)
536                 str++;
537
538         t = strtol(str, NULL, 0);
539         if (*time < t * 24 * 60 * 60) {
540                 if (res)
541                         str--;
542                 fprintf(stderr, "Wrong time '%s' is specified.\n", str);
543                 return INT_MAX;
544         }
545
546         *set = *time - t * 24 * 60 * 60;
547         return res;
548 }
549
550 #define USER 0
551 #define GROUP 1
552
553 static int name2id(unsigned int *id, char *name, int type)
554 {
555         if (type == USER) {
556                 struct passwd *entry;
557
558                 if (!(entry = getpwnam(name))) {
559                         if (!errno)
560                                 errno = ENOENT;
561                         return -1;
562                 }
563
564                 *id = entry->pw_uid;
565         } else {
566                 struct group *entry;
567
568                 if (!(entry = getgrnam(name))) {
569                         if (!errno)
570                                 errno = ENOENT;
571                         return -1;
572                 }
573
574                 *id = entry->gr_gid;
575         }
576
577         return 0;
578 }
579
580 static int id2name(char **name, unsigned int id, int type)
581 {
582         if (type == USER) {
583                 struct passwd *entry;
584
585                 if (!(entry = getpwuid(id))) {
586                         if (!errno)
587                                 errno = ENOENT;
588                         return -1;
589                 }
590
591                 *name = entry->pw_name;
592         } else {
593                 struct group *entry;
594
595                 if (!(entry = getgrgid(id))) {
596                         if (!errno)
597                                 errno = ENOENT;
598                         return -1;
599                 }
600
601                 *name = entry->gr_name;
602         }
603
604         return 0;
605 }
606
607 #define FIND_POOL_OPT 3
608 static int lfs_find(int argc, char **argv)
609 {
610         int c, ret;
611         time_t t;
612         struct find_param param = { .maxdepth = -1, .quiet = 1 };
613         struct option long_opts[] = {
614                 {"atime",        required_argument, 0, 'A'},
615                 {"stripe-count", required_argument, 0, 'c'},
616                 {"stripe_count", required_argument, 0, 'c'},
617                 {"ctime",        required_argument, 0, 'C'},
618                 {"maxdepth",     required_argument, 0, 'D'},
619                 {"gid",          required_argument, 0, 'g'},
620                 {"group",        required_argument, 0, 'G'},
621                 {"stripe-index", required_argument, 0, 'i'},
622                 {"stripe_index", required_argument, 0, 'i'},
623                 {"mdt",          required_argument, 0, 'm'},
624                 {"mtime",        required_argument, 0, 'M'},
625                 {"name",         required_argument, 0, 'n'},
626      /* reserve {"or",           no_argument,     , 0, 'o'}, to match find(1) */
627                 {"obd",          required_argument, 0, 'O'},
628                 {"ost",          required_argument, 0, 'O'},
629                 /* no short option for pool, p/P already used */
630                 {"pool",         required_argument, 0, FIND_POOL_OPT},
631                 {"print0",       no_argument,       0, 'p'},
632                 {"print",        no_argument,       0, 'P'},
633                 {"size",         required_argument, 0, 's'},
634                 {"stripe-size",  required_argument, 0, 'S'},
635                 {"stripe_size",  required_argument, 0, 'S'},
636                 {"type",         required_argument, 0, 't'},
637                 {"uid",          required_argument, 0, 'u'},
638                 {"user",         required_argument, 0, 'U'},
639                 {0, 0, 0, 0}
640         };
641         int pathstart = -1;
642         int pathend = -1;
643         int neg_opt = 0;
644         time_t *xtime;
645         int *xsign;
646         int isoption;
647         char *endptr;
648
649         time(&t);
650
651         optind = 0;
652         /* when getopt_long_only() hits '!' it returns 1, puts "!" in optarg */
653         while ((c = getopt_long_only(argc, argv,
654                                      "-A:c:C:D:g:G:i:m:M:n:O:Ppqrs:S:t:u:U:v",
655                                      long_opts, NULL)) >= 0) {
656                 xtime = NULL;
657                 xsign = NULL;
658                 if (neg_opt)
659                         --neg_opt;
660                 /* '!' is part of option */
661                 /* when getopt_long_only() finds a string which is not
662                  * an option nor a known option argument it returns 1
663                  * in that case if we already have found pathstart and pathend
664                  * (i.e. we have the list of pathnames),
665                  * the only supported value is "!"
666                  */
667                 isoption = (c != 1) || (strcmp(optarg, "!") == 0);
668                 if (!isoption && pathend != -1) {
669                         fprintf(stderr, "err: %s: filename|dirname must either "
670                                         "precede options or follow options\n",
671                                         argv[0]);
672                         ret = CMD_HELP;
673                         goto err;
674                 }
675                 if (!isoption && pathstart == -1)
676                         pathstart = optind - 1;
677                 if (isoption && pathstart != -1 && pathend == -1)
678                         pathend = optind - 2;
679                 switch (c) {
680                 case 0:
681                         /* Long options. */
682                         break;
683                 case 1:
684                         /* unknown; opt is "!" or path component,
685                          * checking done above.
686                          */
687                         if (strcmp(optarg, "!") == 0)
688                                 neg_opt = 2;
689                         break;
690                 case 'A':
691                         xtime = &param.atime;
692                         xsign = &param.asign;
693                         param.exclude_atime = !!neg_opt;
694                         /* no break, this falls through to 'C' for ctime */
695                 case 'C':
696                         if (c == 'C') {
697                                 xtime = &param.ctime;
698                                 xsign = &param.csign;
699                                 param.exclude_ctime = !!neg_opt;
700                         }
701                         /* no break, this falls through to 'M' for mtime */
702                 case 'M':
703                         if (c == 'M') {
704                                 xtime = &param.mtime;
705                                 xsign = &param.msign;
706                                 param.exclude_mtime = !!neg_opt;
707                         }
708                         ret = set_time(&t, xtime, optarg);
709                         if (ret == INT_MAX) {
710                                 ret = -1;
711                                 goto err;
712                         }
713                         if (ret)
714                                 *xsign = ret;
715                         break;
716                 case 'c':
717                         if (optarg[0] == '+') {
718                                 param.stripecount_sign = -1;
719                                 optarg++;
720                         } else if (optarg[0] == '-') {
721                                 param.stripecount_sign =  1;
722                                 optarg++;
723                         }
724
725                         param.stripecount = strtoul(optarg, &endptr, 0);
726                         if (*endptr != '\0') {
727                                 fprintf(stderr,"error: bad stripe_count '%s'\n",
728                                         optarg);
729                                 ret = -1;
730                                 goto err;
731                         }
732                         param.check_stripecount = 1;
733                         param.exclude_stripecount = !!neg_opt;
734                         break;
735                 case 'D':
736                         param.maxdepth = strtol(optarg, 0, 0);
737                         break;
738                 case 'g':
739                 case 'G':
740                         ret = name2id(&param.gid, optarg, GROUP);
741                         if (ret) {
742                                 param.gid = strtoul(optarg, &endptr, 10);
743                                 if (*endptr != '\0') {
744                                         fprintf(stderr, "Group/GID: %s cannot "
745                                                 "be found.\n", optarg);
746                                         ret = -1;
747                                         goto err;
748                                 }
749                         }
750                         param.exclude_gid = !!neg_opt;
751                         param.check_gid = 1;
752                         break;
753                 case 'u':
754                 case 'U':
755                         ret = name2id(&param.uid, optarg, USER);
756                         if (ret) {
757                                 param.uid = strtoul(optarg, &endptr, 10);
758                                 if (*endptr != '\0') {
759                                         fprintf(stderr, "User/UID: %s cannot "
760                                                 "be found.\n", optarg);
761                                         ret = -1;
762                                         goto err;
763                                 }
764                         }
765                         param.exclude_uid = !!neg_opt;
766                         param.check_uid = 1;
767                         break;
768                 case FIND_POOL_OPT:
769                         if (strlen(optarg) > LOV_MAXPOOLNAME) {
770                                 fprintf(stderr,
771                                         "Pool name %s is too long"
772                                         " (max is %d)\n", optarg,
773                                         LOV_MAXPOOLNAME);
774                                 ret = -1;
775                                 goto err;
776                         }
777                         /* we do check for empty pool because empty pool
778                          * is used to find V1 lov attributes */
779                         strncpy(param.poolname, optarg, LOV_MAXPOOLNAME);
780                         param.poolname[LOV_MAXPOOLNAME] = '\0';
781                         param.exclude_pool = !!neg_opt;
782                         param.check_pool = 1;
783                         break;
784                 case 'n':
785                         param.pattern = (char *)optarg;
786                         param.exclude_pattern = !!neg_opt;
787                         break;
788                 case 'm':
789                 case 'i':
790                 case 'O': {
791                         char *buf, *token, *next, *p;
792                         int len = 1;
793                         void *tmp;
794
795                         buf = strdup(optarg);
796                         if (buf == NULL) {
797                                 ret = -ENOMEM;
798                                 goto err;
799                         }
800
801                         param.exclude_obd = !!neg_opt;
802
803                         token = buf;
804                         while (token && *token) {
805                                 token = strchr(token, ',');
806                                 if (token) {
807                                         len++;
808                                         token++;
809                                 }
810                         }
811                         if (c == 'm') {
812                                 param.exclude_mdt = !!neg_opt;
813                                 param.num_alloc_mdts += len;
814                                 tmp = realloc(param.mdtuuid,
815                                               param.num_alloc_mdts *
816                                               sizeof(*param.mdtuuid));
817                                 if (tmp == NULL)
818                                         GOTO(err_free, ret = -ENOMEM);
819                                 param.mdtuuid = tmp;
820                         } else {
821                                 param.exclude_obd = !!neg_opt;
822                                 param.num_alloc_obds += len;
823                                 tmp = realloc(param.obduuid,
824                                               param.num_alloc_obds *
825                                               sizeof(*param.obduuid));
826                                 if (tmp == NULL)
827                                         GOTO(err_free, ret = -ENOMEM);
828                                 param.obduuid = tmp;
829                         }
830                         for (token = buf; token && *token; token = next) {
831                                 char *uuid;
832                                 if (c == 'm')
833                                         uuid =
834                                           param.mdtuuid[param.num_mdts++].uuid;
835                                 else
836                                         uuid =
837                                           param.obduuid[param.num_obds++].uuid;
838                                 p = strchr(token, ',');
839                                 next = 0;
840                                 if (p) {
841                                         *p = 0;
842                                         next = p+1;
843                                 }
844                                 strcpy((char *)uuid, token);
845                         }
846 err_free:
847                         if (buf)
848                                 free(buf);
849                         break;
850                 }
851                 case 'p':
852                         param.zeroend = 1;
853                         break;
854                 case 'P':
855                         break;
856                 case 's':
857                         if (optarg[0] == '+') {
858                                 param.size_sign = -1;
859                                 optarg++;
860                         } else if (optarg[0] == '-') {
861                                 param.size_sign =  1;
862                                 optarg++;
863                         }
864
865                         ret = parse_size(optarg, &param.size,
866                                          &param.size_units, 0);
867                         if (ret) {
868                                 fprintf(stderr, "error: bad file size '%s'\n",
869                                         optarg);
870                                 goto err;
871                         }
872                         param.check_size = 1;
873                         param.exclude_size = !!neg_opt;
874                         break;
875                 case 'S':
876                         if (optarg[0] == '+') {
877                                 param.stripesize_sign = -1;
878                                 optarg++;
879                         } else if (optarg[0] == '-') {
880                                 param.stripesize_sign =  1;
881                                 optarg++;
882                         }
883
884                         ret = parse_size(optarg, &param.stripesize,
885                                          &param.stripesize_units, 0);
886                         if (ret) {
887                                 fprintf(stderr, "error: bad stripe_size '%s'\n",
888                                         optarg);
889                                 goto err;
890                         }
891                         param.check_stripesize = 1;
892                         param.exclude_stripesize = !!neg_opt;
893                         break;
894                 case 't':
895                         param.exclude_type = !!neg_opt;
896                         switch(optarg[0]) {
897                         case 'b': param.type = S_IFBLK; break;
898                         case 'c': param.type = S_IFCHR; break;
899                         case 'd': param.type = S_IFDIR; break;
900                         case 'f': param.type = S_IFREG; break;
901                         case 'l': param.type = S_IFLNK; break;
902                         case 'p': param.type = S_IFIFO; break;
903                         case 's': param.type = S_IFSOCK; break;
904 #ifdef S_IFDOOR /* Solaris only */
905                         case 'D': param.type = S_IFDOOR; break;
906 #endif
907                         default: fprintf(stderr, "error: %s: bad type '%s'\n",
908                                          argv[0], optarg);
909                                  ret = CMD_HELP;
910                                  goto err;
911                         };
912                         break;
913                 default:
914                         ret = CMD_HELP;
915                         goto err;
916                 };
917         }
918
919         if (pathstart == -1) {
920                 fprintf(stderr, "error: %s: no filename|pathname\n",
921                         argv[0]);
922                 ret = CMD_HELP;
923                 goto err;
924         } else if (pathend == -1) {
925                 /* no options */
926                 pathend = argc;
927         }
928
929         do {
930                 ret = llapi_find(argv[pathstart], &param);
931         } while (++pathstart < pathend && !ret);
932
933         if (ret)
934                 fprintf(stderr, "error: %s failed for %s.\n",
935                         argv[0], argv[optind - 1]);
936 err:
937         if (param.obduuid && param.num_alloc_obds)
938                 free(param.obduuid);
939
940         if (param.mdtuuid && param.num_alloc_mdts)
941                 free(param.mdtuuid);
942
943         return ret;
944 }
945
946 static int lfs_getstripe_internal(int argc, char **argv,
947                                   struct find_param *param)
948 {
949         struct option long_opts[] = {
950 #if LUSTRE_VERSION >= OBD_OCD_VERSION(2,9,50,0)
951 #warning "remove deprecated --count option"
952 #else
953                 /* This formerly implied "stripe-count", but was explicitly
954                  * made "stripe-count" for consistency with other options,
955                  * and to separate it from "mdt-count" when DNE arrives. */
956                 {"count",        no_argument,       0, 'c'},
957 #endif
958                 {"stripe-count", no_argument,       0, 'c'},
959                 {"stripe_count", no_argument,       0, 'c'},
960                 {"directory",    no_argument,       0, 'd'},
961                 {"generation",   no_argument,       0, 'g'},
962 #if LUSTRE_VERSION >= OBD_OCD_VERSION(2,9,50,0)
963 #warning "remove deprecated --index option"
964 #else
965                 /* This formerly implied "stripe-index", but was explicitly
966                  * made "stripe-index" for consistency with other options,
967                  * and to separate it from "mdt-index" when DNE arrives. */
968                 {"index",        no_argument,       0, 'i'},
969 #endif
970                 {"stripe-index", no_argument,       0, 'i'},
971                 {"stripe_index", no_argument,       0, 'i'},
972                 {"mdt-index",    no_argument,       0, 'M'},
973                 {"mdt_index",    no_argument,       0, 'M'},
974 #if LUSTRE_VERSION >= OBD_OCD_VERSION(2,9,50,0)
975 #warning "remove deprecated --offset option"
976 #else
977                 /* This formerly implied "stripe-index", but was confusing
978                  * with "file offset" (which will eventually be needed for
979                  * with different layouts by offset), so deprecate it. */
980                 {"offset",       no_argument,       0, 'o'},
981 #endif
982                 {"obd",          required_argument, 0, 'O'},
983                 {"ost",          required_argument, 0, 'O'},
984                 {"pool",         no_argument,       0, 'p'},
985                 {"quiet",        no_argument,       0, 'q'},
986                 {"recursive",    no_argument,       0, 'r'},
987                 {"raw",          no_argument,       0, 'R'},
988 #if LUSTRE_VERSION >= OBD_OCD_VERSION(2,9,50,0)
989 #warning "remove deprecated --size option"
990 #else
991                 /* This formerly implied "--stripe-size", but was confusing
992                  * with "lfs find --size|-s", which means "file size", so use
993                  * the consistent "--stripe-size|-S" for all commands. */
994                 {"size",         no_argument,       0, 's'},
995 #endif
996                 {"stripe-size",  no_argument,       0, 'S'},
997                 {"stripe_size",  no_argument,       0, 'S'},
998                 {"verbose",      no_argument,       0, 'v'},
999                 {0, 0, 0, 0}
1000         };
1001         int c, rc;
1002
1003         param->maxdepth = 1;
1004         optind = 0;
1005         while ((c = getopt_long(argc, argv, "cdghiMoO:pqrRsSv",
1006                                 long_opts, NULL)) != -1) {
1007                 switch (c) {
1008                 case 'O':
1009                         if (param->obduuid) {
1010                                 fprintf(stderr,
1011                                         "error: %s: only one obduuid allowed",
1012                                         argv[0]);
1013                                 return CMD_HELP;
1014                         }
1015                         param->obduuid = (struct obd_uuid *)optarg;
1016                         break;
1017                 case 'q':
1018                         param->quiet++;
1019                         break;
1020                 case 'd':
1021                         param->maxdepth = 0;
1022                         break;
1023                 case 'r':
1024                         param->recursive = 1;
1025                         break;
1026                 case 'v':
1027                         param->verbose = VERBOSE_ALL | VERBOSE_DETAIL;
1028                         break;
1029                 case 'c':
1030 #if LUSTRE_VERSION >= OBD_OCD_VERSION(2,9,50,0)
1031 #warning "remove deprecated --count option"
1032 #elif LUSTRE_VERSION >= OBD_OCD_VERSION(2,6,50,0)
1033                         if (strcmp(argv[optind - 1], "--count") == 0)
1034                                 fprintf(stderr, "warning: '--count' deprecated,"
1035                                         " use '--stripe-count' instead\n");
1036 #endif
1037                         if (!(param->verbose & VERBOSE_DETAIL)) {
1038                                 param->verbose |= VERBOSE_COUNT;
1039                                 param->maxdepth = 0;
1040                         }
1041                         break;
1042                 case 's':
1043 #if LUSTRE_VERSION >= OBD_OCD_VERSION(2,9,50,0)
1044 #warning "remove deprecated --size option"
1045 #elif LUSTRE_VERSION >= OBD_OCD_VERSION(2,6,50,0)
1046                         fprintf(stderr, "warning: '--size|-s' deprecated, "
1047                                 "use '--stripe-size|-S' instead\n");
1048 #endif
1049                 case 'S':
1050                         if (!(param->verbose & VERBOSE_DETAIL)) {
1051                                 param->verbose |= VERBOSE_SIZE;
1052                                 param->maxdepth = 0;
1053                         }
1054                         break;
1055                 case 'o':
1056 #if LUSTRE_VERSION >= OBD_OCD_VERSION(2,4,50,0)
1057                         fprintf(stderr, "warning: '--offset|-o' deprecated, "
1058                                 "use '--stripe-index|-i' instead\n");
1059 #else
1060                         if (strcmp(argv[optind - 1], "--offset") == 0)
1061                                 /* need --stripe-index established first */
1062                                 fprintf(stderr, "warning: '--offset' deprecated"
1063                                         ", use '--index' instead\n");
1064 #endif
1065                 case 'i':
1066 #if LUSTRE_VERSION >= OBD_OCD_VERSION(2,9,50,0)
1067 #warning "remove deprecated --offset and --index options"
1068 #elif LUSTRE_VERSION >= OBD_OCD_VERSION(2,6,50,0)
1069                         if (strcmp(argv[optind - 1], "--index") == 0)
1070                                 fprintf(stderr, "warning: '--index' deprecated"
1071                                         ", use '--stripe-index' instead\n");
1072 #endif
1073                         if (!(param->verbose & VERBOSE_DETAIL)) {
1074                                 param->verbose |= VERBOSE_OFFSET;
1075                                 param->maxdepth = 0;
1076                         }
1077                         break;
1078                 case 'p':
1079                         if (!(param->verbose & VERBOSE_DETAIL)) {
1080                                 param->verbose |= VERBOSE_POOL;
1081                                 param->maxdepth = 0;
1082                         }
1083                         break;
1084                 case 'g':
1085                         if (!(param->verbose & VERBOSE_DETAIL)) {
1086                                 param->verbose |= VERBOSE_GENERATION;
1087                                 param->maxdepth = 0;
1088                         }
1089                         break;
1090                 case 'M':
1091                         if (!(param->verbose & VERBOSE_DETAIL))
1092                                 param->maxdepth = 0;
1093                         param->verbose |= VERBOSE_MDTINDEX;
1094                         break;
1095                 case 'R':
1096                         param->raw = 1;
1097                         break;
1098                 default:
1099                         return CMD_HELP;
1100                 }
1101         }
1102
1103         if (optind >= argc)
1104                 return CMD_HELP;
1105
1106         if (param->recursive)
1107                 param->maxdepth = -1;
1108
1109         if (!param->verbose)
1110                 param->verbose = VERBOSE_ALL;
1111         if (param->quiet)
1112                 param->verbose = VERBOSE_OBJID;
1113
1114         do {
1115                 rc = llapi_getstripe(argv[optind], param);
1116         } while (++optind < argc && !rc);
1117
1118         if (rc)
1119                 fprintf(stderr, "error: %s failed for %s.\n",
1120                         argv[0], argv[optind - 1]);
1121         return rc;
1122 }
1123
1124 static int lfs_tgts(int argc, char **argv)
1125 {
1126         char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
1127         struct find_param param;
1128         int index = 0, rc=0;
1129
1130         if (argc > 2)
1131                 return CMD_HELP;
1132
1133         if (argc == 2 && !realpath(argv[1], path)) {
1134                 rc = -errno;
1135                 fprintf(stderr, "error: invalid path '%s': %s\n",
1136                         argv[1], strerror(-rc));
1137                 return rc;
1138         }
1139
1140         while (!llapi_search_mounts(path, index++, mntdir, NULL)) {
1141                 /* Check if we have a mount point */
1142                 if (mntdir[0] == '\0')
1143                         continue;
1144
1145                 memset(&param, 0, sizeof(param));
1146                 if (!strcmp(argv[0], "mdts"))
1147                         param.get_lmv = 1;
1148
1149                 rc = llapi_ostlist(mntdir, &param);
1150                 if (rc) {
1151                         fprintf(stderr, "error: %s: failed on %s\n",
1152                                 argv[0], mntdir);
1153                 }
1154                 if (path[0] != '\0')
1155                         break;
1156                 memset(mntdir, 0, PATH_MAX);
1157         }
1158
1159         return rc;
1160 }
1161
1162 static int lfs_getstripe(int argc, char **argv)
1163 {
1164         struct find_param param = { 0 };
1165         return lfs_getstripe_internal(argc, argv, &param);
1166 }
1167
1168 /* functions */
1169 static int lfs_getdirstripe(int argc, char **argv)
1170 {
1171         struct find_param param = { 0 };
1172
1173         param.get_lmv = 1;
1174         return lfs_getstripe_internal(argc, argv, &param);
1175 }
1176
1177 /* functions */
1178 static int lfs_setdirstripe(int argc, char **argv)
1179 {
1180         char *dname;
1181         int result;
1182         int  st_offset, st_count;
1183         char *end;
1184         int c;
1185         char *stripe_off_arg = NULL;
1186         int  flags = 0;
1187
1188         struct option long_opts[] = {
1189                 {"index",    required_argument, 0, 'i'},
1190                 {0, 0, 0, 0}
1191         };
1192
1193         st_offset = -1;
1194         st_count = 1;
1195         optind = 0;
1196         while ((c = getopt_long(argc, argv, "i:o",
1197                                 long_opts, NULL)) >= 0) {
1198                 switch (c) {
1199                 case 0:
1200                         /* Long options. */
1201                         break;
1202                 case 'i':
1203                         stripe_off_arg = optarg;
1204                         break;
1205                 default:
1206                         fprintf(stderr, "error: %s: option '%s' "
1207                                         "unrecognized\n",
1208                                         argv[0], argv[optind - 1]);
1209                         return CMD_HELP;
1210                 }
1211         }
1212
1213         if (optind == argc) {
1214                 fprintf(stderr, "error: %s: missing dirname\n",
1215                         argv[0]);
1216                 return CMD_HELP;
1217         }
1218
1219         dname = argv[optind];
1220         if (stripe_off_arg == NULL) {
1221                 fprintf(stderr, "error: %s: missing stripe_off.\n",
1222                         argv[0]);
1223                 return CMD_HELP;
1224         }
1225         /* get the stripe offset */
1226         st_offset = strtoul(stripe_off_arg, &end, 0);
1227         if (*end != '\0') {
1228                 fprintf(stderr, "error: %s: bad stripe offset '%s'\n",
1229                         argv[0], stripe_off_arg);
1230                 return CMD_HELP;
1231         }
1232         do {
1233                 result = llapi_dir_create_pool(dname, flags, st_offset,
1234                                                st_count, 0, NULL);
1235                 if (result) {
1236                         fprintf(stderr, "error: %s: create stripe dir '%s' "
1237                                 "failed\n", argv[0], dname);
1238                         break;
1239                 }
1240                 dname = argv[++optind];
1241         } while (dname != NULL);
1242
1243         return result;
1244 }
1245
1246 /* functions */
1247 static int lfs_rmentry(int argc, char **argv)
1248 {
1249         char *dname;
1250         int   index;
1251         int   result = 0;
1252
1253         if (argc <= 1) {
1254                 fprintf(stderr, "error: %s: missing dirname\n",
1255                         argv[0]);
1256                 return CMD_HELP;
1257         }
1258
1259         index = 1;
1260         dname = argv[index];
1261         while (dname != NULL) {
1262                 result = llapi_direntry_remove(dname);
1263                 if (result) {
1264                         fprintf(stderr, "error: %s: remove dir entry '%s' "
1265                                 "failed\n", argv[0], dname);
1266                         break;
1267                 }
1268                 dname = argv[++index];
1269         }
1270         return result;
1271 }
1272
1273 static int lfs_osts(int argc, char **argv)
1274 {
1275         return lfs_tgts(argc, argv);
1276 }
1277
1278 static int lfs_mdts(int argc, char **argv)
1279 {
1280         return lfs_tgts(argc, argv);
1281 }
1282
1283 #define COOK(value)                                                     \
1284 ({                                                                      \
1285         int radix = 0;                                                  \
1286         while (value > 1024) {                                          \
1287                 value /= 1024;                                          \
1288                 radix++;                                                \
1289         }                                                               \
1290         radix;                                                          \
1291 })
1292 #define UUF     "%-20s"
1293 #define CSF     "%11s"
1294 #define CDF     "%11llu"
1295 #define HDF     "%8.1f%c"
1296 #define RSF     "%4s"
1297 #define RDF     "%3d%%"
1298
1299 static int showdf(char *mntdir, struct obd_statfs *stat,
1300                   char *uuid, int ishow, int cooked,
1301                   char *type, int index, int rc)
1302 {
1303         long long avail, used, total;
1304         double ratio = 0;
1305         char *suffix = "KMGTPEZY";
1306         /* Note if we have >2^64 bytes/fs these buffers will need to be grown */
1307         char tbuf[20], ubuf[20], abuf[20], rbuf[20];
1308
1309         if (!uuid || !stat)
1310                 return -EINVAL;
1311
1312         switch (rc) {
1313         case 0:
1314                 if (ishow) {
1315                         avail = stat->os_ffree;
1316                         used = stat->os_files - stat->os_ffree;
1317                         total = stat->os_files;
1318                 } else {
1319                         int shift = cooked ? 0 : 10;
1320
1321                         avail = (stat->os_bavail * stat->os_bsize) >> shift;
1322                         used  = ((stat->os_blocks - stat->os_bfree) *
1323                                  stat->os_bsize) >> shift;
1324                         total = (stat->os_blocks * stat->os_bsize) >> shift;
1325                 }
1326
1327                 if ((used + avail) > 0)
1328                         ratio = (double)used / (double)(used + avail);
1329
1330                 if (cooked) {
1331                         int i;
1332                         double cook_val;
1333
1334                         cook_val = (double)total;
1335                         i = COOK(cook_val);
1336                         if (i > 0)
1337                                 sprintf(tbuf, HDF, cook_val, suffix[i - 1]);
1338                         else
1339                                 sprintf(tbuf, CDF, total);
1340
1341                         cook_val = (double)used;
1342                         i = COOK(cook_val);
1343                         if (i > 0)
1344                                 sprintf(ubuf, HDF, cook_val, suffix[i - 1]);
1345                         else
1346                                 sprintf(ubuf, CDF, used);
1347
1348                         cook_val = (double)avail;
1349                         i = COOK(cook_val);
1350                         if (i > 0)
1351                                 sprintf(abuf, HDF, cook_val, suffix[i - 1]);
1352                         else
1353                                 sprintf(abuf, CDF, avail);
1354                 } else {
1355                         sprintf(tbuf, CDF, total);
1356                         sprintf(ubuf, CDF, used);
1357                         sprintf(abuf, CDF, avail);
1358                 }
1359
1360                 sprintf(rbuf, RDF, (int)(ratio * 100 + 0.5));
1361                 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s",
1362                        uuid, tbuf, ubuf, abuf, rbuf, mntdir);
1363                 if (type)
1364                         printf("[%s:%d]\n", type, index);
1365                 else
1366                         printf("\n");
1367
1368                 break;
1369         case -ENODATA:
1370                 printf(UUF": inactive device\n", uuid);
1371                 break;
1372         default:
1373                 printf(UUF": %s\n", uuid, strerror(-rc));
1374                 break;
1375         }
1376
1377         return 0;
1378 }
1379
1380 struct ll_stat_type {
1381         int   st_op;
1382         char *st_name;
1383 };
1384
1385 static int mntdf(char *mntdir, char *fsname, char *pool, int ishow,
1386                 int cooked, int lazy)
1387 {
1388         struct obd_statfs stat_buf, sum = { .os_bsize = 1 };
1389         struct obd_uuid uuid_buf;
1390         char *poolname = NULL;
1391         struct ll_stat_type types[] = { { LL_STATFS_LMV, "MDT" },
1392                                         { LL_STATFS_LOV, "OST" },
1393                                         { 0, NULL } };
1394         struct ll_stat_type *tp;
1395         __u32 index;
1396         __u32 type;
1397         int rc;
1398
1399         if (pool) {
1400                 poolname = strchr(pool, '.');
1401                 if (poolname != NULL) {
1402                         if (strncmp(fsname, pool, strlen(fsname))) {
1403                                 fprintf(stderr, "filesystem name incorrect\n");
1404                                 return -ENODEV;
1405                         }
1406                         poolname++;
1407                 } else
1408                         poolname = pool;
1409         }
1410
1411         if (ishow)
1412                 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
1413                        "UUID", "Inodes", "IUsed", "IFree",
1414                        "IUse%", "Mounted on");
1415         else
1416                 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
1417                        "UUID", cooked ? "bytes" : "1K-blocks",
1418                        "Used", "Available", "Use%", "Mounted on");
1419
1420         for (tp = types; tp->st_name != NULL; tp++) {
1421                 for (index = 0; ; index++) {
1422                         memset(&stat_buf, 0, sizeof(struct obd_statfs));
1423                         memset(&uuid_buf, 0, sizeof(struct obd_uuid));
1424                         type = lazy ? tp->st_op | LL_STATFS_NODELAY : tp->st_op;
1425                         rc = llapi_obd_statfs(mntdir, type, index,
1426                                               &stat_buf, &uuid_buf);
1427                         if (rc == -ENODEV)
1428                                 break;
1429
1430                         if (poolname && tp->st_op == LL_STATFS_LOV &&
1431                             llapi_search_ost(fsname, poolname,
1432                                              obd_uuid2str(&uuid_buf)) != 1)
1433                                 continue;
1434
1435                         /* the llapi_obd_statfs() call may have returned with
1436                          * an error, but if it filled in uuid_buf we will at
1437                          * lease use that to print out a message for that OBD.
1438                          * If we didn't get anything in the uuid_buf, then fill
1439                          * it in so that we can print an error message. */
1440                         if (uuid_buf.uuid[0] == '\0')
1441                                 sprintf(uuid_buf.uuid, "%s%04x",
1442                                         tp->st_name, index);
1443                         showdf(mntdir, &stat_buf, obd_uuid2str(&uuid_buf),
1444                                ishow, cooked, tp->st_name, index, rc);
1445
1446                         if (rc == 0) {
1447                                 if (tp->st_op == LL_STATFS_LMV) {
1448                                         sum.os_ffree += stat_buf.os_ffree;
1449                                         sum.os_files += stat_buf.os_files;
1450                                 } else /* if (tp->st_op == LL_STATFS_LOV) */ {
1451                                         sum.os_blocks += stat_buf.os_blocks *
1452                                                 stat_buf.os_bsize;
1453                                         sum.os_bfree  += stat_buf.os_bfree *
1454                                                 stat_buf.os_bsize;
1455                                         sum.os_bavail += stat_buf.os_bavail *
1456                                                 stat_buf.os_bsize;
1457                                 }
1458                         } else if (rc == -EINVAL || rc == -EFAULT) {
1459                                 break;
1460                         }
1461                 }
1462         }
1463
1464         printf("\n");
1465         showdf(mntdir, &sum, "filesystem summary:", ishow, cooked, NULL, 0,0);
1466         printf("\n");
1467         return 0;
1468 }
1469
1470 static int lfs_df(int argc, char **argv)
1471 {
1472         char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
1473         int ishow = 0, cooked = 0;
1474         int lazy = 0;
1475         int c, rc = 0, index = 0;
1476         char fsname[PATH_MAX] = "", *pool_name = NULL;
1477         struct option long_opts[] = {
1478                 {"pool", required_argument, 0, 'p'},
1479                 {"lazy", 0, 0, 'l'},
1480                 {0, 0, 0, 0}
1481         };
1482
1483         optind = 0;
1484         while ((c = getopt_long(argc, argv, "hilp:", long_opts, NULL)) != -1) {
1485                 switch (c) {
1486                 case 'i':
1487                         ishow = 1;
1488                         break;
1489                 case 'h':
1490                         cooked = 1;
1491                         break;
1492                 case 'l':
1493                         lazy = 1;
1494                 case 'p':
1495                         pool_name = optarg;
1496                         break;
1497                 default:
1498                         return CMD_HELP;
1499                 }
1500         }
1501         if (optind < argc && !realpath(argv[optind], path)) {
1502                 rc = -errno;
1503                 fprintf(stderr, "error: invalid path '%s': %s\n",
1504                         argv[optind], strerror(-rc));
1505                 return rc;
1506         }
1507
1508         while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
1509                 /* Check if we have a mount point */
1510                 if (mntdir[0] == '\0')
1511                         continue;
1512
1513                 rc = mntdf(mntdir, fsname, pool_name, ishow, cooked, lazy);
1514                 if (rc || path[0] != '\0')
1515                         break;
1516                 fsname[0] = '\0'; /* avoid matching in next loop */
1517                 mntdir[0] = '\0'; /* avoid matching in next loop */
1518         }
1519
1520         return rc;
1521 }
1522
1523 static int lfs_getname(int argc, char **argv)
1524 {
1525         char mntdir[PATH_MAX] = "", path[PATH_MAX] = "", fsname[PATH_MAX] = "";
1526         int rc = 0, index = 0, c;
1527         char buf[sizeof(struct obd_uuid)];
1528
1529         optind = 0;
1530         while ((c = getopt(argc, argv, "h")) != -1)
1531                 return CMD_HELP;
1532
1533         if (optind == argc) { /* no paths specified, get all paths. */
1534                 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
1535                         rc = llapi_getname(mntdir, buf, sizeof(buf));
1536                         if (rc < 0) {
1537                                 fprintf(stderr,
1538                                         "cannot get name for `%s': %s\n",
1539                                         mntdir, strerror(-rc));
1540                                 break;
1541                         }
1542
1543                         printf("%s %s\n", buf, mntdir);
1544
1545                         path[0] = fsname[0] = mntdir[0] = 0;
1546                 }
1547         } else { /* paths specified, only attempt to search these. */
1548                 for (; optind < argc; optind++) {
1549                         rc = llapi_getname(argv[optind], buf, sizeof(buf));
1550                         if (rc < 0) {
1551                                 fprintf(stderr,
1552                                         "cannot get name for `%s': %s\n",
1553                                         argv[optind], strerror(-rc));
1554                                 break;
1555                         }
1556
1557                         printf("%s %s\n", buf, argv[optind]);
1558                 }
1559         }
1560         return rc;
1561 }
1562
1563 static int lfs_check(int argc, char **argv)
1564 {
1565         int rc;
1566         char mntdir[PATH_MAX] = {'\0'};
1567         int num_types = 1;
1568         char *obd_types[2];
1569         char obd_type1[4];
1570         char obd_type2[4];
1571
1572         if (argc != 2)
1573                 return CMD_HELP;
1574
1575         obd_types[0] = obd_type1;
1576         obd_types[1] = obd_type2;
1577
1578         if (strcmp(argv[1], "osts") == 0) {
1579                 strcpy(obd_types[0], "osc");
1580         } else if (strcmp(argv[1], "mds") == 0) {
1581                 strcpy(obd_types[0], "mdc");
1582         } else if (strcmp(argv[1], "servers") == 0) {
1583                 num_types = 2;
1584                 strcpy(obd_types[0], "osc");
1585                 strcpy(obd_types[1], "mdc");
1586         } else {
1587                 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
1588                                 argv[0], argv[1]);
1589                         return CMD_HELP;
1590         }
1591
1592         rc = llapi_search_mounts(NULL, 0, mntdir, NULL);
1593         if (rc < 0 || mntdir[0] == '\0') {
1594                 fprintf(stderr, "No suitable Lustre mount found\n");
1595                 return rc;
1596         }
1597
1598         rc = llapi_target_iterate(num_types, obd_types,
1599                                   mntdir, llapi_ping_target);
1600
1601         if (rc)
1602                 fprintf(stderr, "error: %s: %s status failed\n",
1603                                 argv[0],argv[1]);
1604
1605         return rc;
1606
1607 }
1608
1609 static int lfs_join(int argc, char **argv)
1610 {
1611         fprintf(stderr, "join two lustre files into one.\n"
1612                         "obsolete, HEAD does not support it anymore.\n");
1613         return 0;
1614 }
1615
1616 #ifdef HAVE_SYS_QUOTA_H
1617 static int lfs_quotacheck(int argc, char **argv)
1618 {
1619         int c, check_type = 0;
1620         char *mnt;
1621         struct if_quotacheck qchk;
1622         struct if_quotactl qctl;
1623         char *obd_type = (char *)qchk.obd_type;
1624         int rc;
1625
1626         memset(&qchk, 0, sizeof(qchk));
1627
1628         optind = 0;
1629         while ((c = getopt(argc, argv, "gu")) != -1) {
1630                 switch (c) {
1631                 case 'u':
1632                         check_type |= 0x01;
1633                         break;
1634                 case 'g':
1635                         check_type |= 0x02;
1636                         break;
1637                 default:
1638                         fprintf(stderr, "error: %s: option '-%c' "
1639                                         "unrecognized\n", argv[0], c);
1640                         return CMD_HELP;
1641                 }
1642         }
1643
1644         if (check_type)
1645                 check_type--;
1646         else    /* do quotacheck for both user & group quota by default */
1647                 check_type = 0x02;
1648
1649         if (argc == optind)
1650                 return CMD_HELP;
1651
1652         mnt = argv[optind];
1653
1654         rc = llapi_quotacheck(mnt, check_type);
1655         if (rc == -EOPNOTSUPP) {
1656                 fprintf(stderr, "error: quotacheck not supported by the quota "
1657                         "master.\nPlease note that quotacheck is deprecated as "
1658                         "of lustre 2.4.0 since space accounting is always "
1659                         "enabled.\nFilesystems not formatted with 2.4 utils or "
1660                         "beyond can be upgraded with tunefs.lustre --quota.\n");
1661                 return rc;
1662         } else if (rc) {
1663                 fprintf(stderr, "quotacheck failed: %s\n", strerror(-rc));
1664                 return rc;
1665         }
1666
1667         rc = llapi_poll_quotacheck(mnt, &qchk);
1668         if (rc) {
1669                 if (*obd_type)
1670                         fprintf(stderr, "%s %s ", obd_type,
1671                                 obd_uuid2str(&qchk.obd_uuid));
1672                 fprintf(stderr, "quota check failed: %s\n", strerror(-rc));
1673                 return rc;
1674         }
1675
1676         memset(&qctl, 0, sizeof(qctl));
1677         qctl.qc_cmd = LUSTRE_Q_QUOTAON;
1678         qctl.qc_type = check_type;
1679         rc = llapi_quotactl(mnt, &qctl);
1680         if (rc && rc != -EALREADY) {
1681                 if (*obd_type)
1682                         fprintf(stderr, "%s %s ", (char *)qctl.obd_type,
1683                                 obd_uuid2str(&qctl.obd_uuid));
1684                 fprintf(stderr, "%s turn on quota failed: %s\n",
1685                         argv[0], strerror(-rc));
1686                 return rc;
1687         }
1688
1689         return 0;
1690 }
1691
1692 static int lfs_quotaon(int argc, char **argv)
1693 {
1694         int c;
1695         char *mnt;
1696         struct if_quotactl qctl;
1697         char *obd_type = (char *)qctl.obd_type;
1698         int rc;
1699
1700         memset(&qctl, 0, sizeof(qctl));
1701         qctl.qc_cmd = LUSTRE_Q_QUOTAON;
1702
1703         optind = 0;
1704         while ((c = getopt(argc, argv, "fgu")) != -1) {
1705                 switch (c) {
1706                 case 'u':
1707                         qctl.qc_type |= 0x01;
1708                         break;
1709                 case 'g':
1710                         qctl.qc_type |= 0x02;
1711                         break;
1712                 case 'f':
1713                         qctl.qc_cmd = LUSTRE_Q_QUOTAOFF;
1714                         break;
1715                 default:
1716                         fprintf(stderr, "error: %s: option '-%c' "
1717                                         "unrecognized\n", argv[0], c);
1718                         return CMD_HELP;
1719                 }
1720         }
1721
1722         if (qctl.qc_type)
1723                 qctl.qc_type--;
1724         else /* by default, enable quota for both user & group */
1725                 qctl.qc_type = 0x02;
1726
1727         if (argc == optind)
1728                 return CMD_HELP;
1729
1730         mnt = argv[optind];
1731
1732         rc = llapi_quotactl(mnt, &qctl);
1733         if (rc) {
1734                 if (rc == -EOPNOTSUPP) {
1735                         fprintf(stderr, "error: quotaon not supported by the "
1736                                 "quota master.\nPlease note that quotaon/off is"
1737                                 " deprecated as of lustre 2.4.0.\nQuota "
1738                                 "enforcement should now be enabled on the MGS "
1739                                 "via:\nmgs# lctl conf_param ${FSNAME}.quota."
1740                                 "<ost|mdt>=<u|g|ug>\n(ost for block quota, mdt "
1741                                 "for inode quota, u for user and g for group"
1742                                 "\n");
1743                 } else if (rc == -EALREADY) {
1744                         rc = 0;
1745                 } else if (rc == -ENOENT) {
1746                         fprintf(stderr, "error: cannot find quota database, "
1747                                         "make sure you have run quotacheck\n");
1748                 } else {
1749                         if (*obd_type)
1750                                 fprintf(stderr, "%s %s ", obd_type,
1751                                         obd_uuid2str(&qctl.obd_uuid));
1752                         fprintf(stderr, "%s failed: %s\n", argv[0],
1753                                 strerror(-rc));
1754                 }
1755         }
1756
1757         return rc;
1758 }
1759
1760 static int lfs_quotaoff(int argc, char **argv)
1761 {
1762         int c;
1763         char *mnt;
1764         struct if_quotactl qctl;
1765         char *obd_type = (char *)qctl.obd_type;
1766         int rc;
1767
1768         memset(&qctl, 0, sizeof(qctl));
1769         qctl.qc_cmd = LUSTRE_Q_QUOTAOFF;
1770
1771         optind = 0;
1772         while ((c = getopt(argc, argv, "gu")) != -1) {
1773                 switch (c) {
1774                 case 'u':
1775                         qctl.qc_type |= 0x01;
1776                         break;
1777                 case 'g':
1778                         qctl.qc_type |= 0x02;
1779                         break;
1780                 default:
1781                         fprintf(stderr, "error: %s: option '-%c' "
1782                                         "unrecognized\n", argv[0], c);
1783                         return CMD_HELP;
1784                 }
1785         }
1786
1787         if (qctl.qc_type)
1788                 qctl.qc_type--;
1789         else /* by default, disable quota for both user & group */
1790                 qctl.qc_type = 0x02;
1791
1792         if (argc == optind)
1793                 return CMD_HELP;
1794
1795         mnt = argv[optind];
1796
1797         rc = llapi_quotactl(mnt, &qctl);
1798         if (rc) {
1799                 if (rc == -EOPNOTSUPP) {
1800                         fprintf(stderr, "error: quotaoff not supported by the "
1801                                 "quota master.\nPlease note that quotaon/off is"
1802                                 " deprecated as of lustre 2.4.0.\nQuota "
1803                                 "enforcement can be disabled on the MGS via:\n"
1804                                 "mgs# lctl conf_param ${FSNAME}.quota.<ost|mdt>"
1805                                 "=\"\"\n");
1806                 } else if (rc == -EALREADY) {
1807                         rc = 0;
1808                 } else {
1809                         if (*obd_type)
1810                                 fprintf(stderr, "%s %s ", obd_type,
1811                                         obd_uuid2str(&qctl.obd_uuid));
1812                         fprintf(stderr, "quotaoff failed: %s\n",
1813                                 strerror(-rc));
1814                 }
1815         }
1816
1817         return rc;
1818 }
1819
1820 #define ARG2INT(nr, str, msg)                                           \
1821 do {                                                                    \
1822         char *endp;                                                     \
1823         nr = strtol(str, &endp, 0);                                     \
1824         if (*endp) {                                                    \
1825                 fprintf(stderr, "error: bad %s: %s\n", msg, str);       \
1826                 return CMD_HELP;                                        \
1827         }                                                               \
1828 } while (0)
1829
1830 #define ADD_OVERFLOW(a,b) ((a + b) < a) ? (a = ULONG_MAX) : (a = a + b)
1831
1832 /* Convert format time string "XXwXXdXXhXXmXXs" into seconds value
1833  * returns the value or ULONG_MAX on integer overflow or incorrect format
1834  * Notes:
1835  *        1. the order of specifiers is arbitrary (may be: 5w3s or 3s5w)
1836  *        2. specifiers may be encountered multiple times (2s3s is 5 seconds)
1837  *        3. empty integer value is interpreted as 0
1838  */
1839 static unsigned long str2sec(const char* timestr)
1840 {
1841         const char spec[] = "smhdw";
1842         const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
1843         unsigned long val = 0;
1844         char *tail;
1845
1846         if (strpbrk(timestr, spec) == NULL) {
1847                 /* no specifiers inside the time string,
1848                    should treat it as an integer value */
1849                 val = strtoul(timestr, &tail, 10);
1850                 return *tail ? ULONG_MAX : val;
1851         }
1852
1853         /* format string is XXwXXdXXhXXmXXs */
1854         while (*timestr) {
1855                 unsigned long v;
1856                 int ind;
1857                 char* ptr;
1858
1859                 v = strtoul(timestr, &tail, 10);
1860                 if (v == ULONG_MAX || *tail == '\0')
1861                         /* value too large (ULONG_MAX or more)
1862                            or missing specifier */
1863                         goto error;
1864
1865                 ptr = strchr(spec, *tail);
1866                 if (ptr == NULL)
1867                         /* unknown specifier */
1868                         goto error;
1869
1870                 ind = ptr - spec;
1871
1872                 /* check if product will overflow the type */
1873                 if (!(v < ULONG_MAX / mult[ind]))
1874                         goto error;
1875
1876                 ADD_OVERFLOW(val, mult[ind] * v);
1877                 if (val == ULONG_MAX)
1878                         goto error;
1879
1880                 timestr = tail + 1;
1881         }
1882
1883         return val;
1884
1885 error:
1886         return ULONG_MAX;
1887 }
1888
1889 #define ARG2ULL(nr, str, def_units)                                     \
1890 do {                                                                    \
1891         unsigned long long limit, units = def_units;                    \
1892         int rc;                                                         \
1893                                                                         \
1894         rc = parse_size(str, &limit, &units, 1);                        \
1895         if (rc < 0) {                                                   \
1896                 fprintf(stderr, "error: bad limit value %s\n", str);    \
1897                 return CMD_HELP;                                        \
1898         }                                                               \
1899         nr = limit;                                                     \
1900 } while (0)
1901
1902 static inline int has_times_option(int argc, char **argv)
1903 {
1904         int i;
1905
1906         for (i = 1; i < argc; i++)
1907                 if (!strcmp(argv[i], "-t"))
1908                         return 1;
1909
1910         return 0;
1911 }
1912
1913 int lfs_setquota_times(int argc, char **argv)
1914 {
1915         int c, rc;
1916         struct if_quotactl qctl;
1917         char *mnt, *obd_type = (char *)qctl.obd_type;
1918         struct obd_dqblk *dqb = &qctl.qc_dqblk;
1919         struct obd_dqinfo *dqi = &qctl.qc_dqinfo;
1920         struct option long_opts[] = {
1921                 {"block-grace",     required_argument, 0, 'b'},
1922                 {"group",           no_argument,       0, 'g'},
1923                 {"inode-grace",     required_argument, 0, 'i'},
1924                 {"times",           no_argument,       0, 't'},
1925                 {"user",            no_argument,       0, 'u'},
1926                 {0, 0, 0, 0}
1927         };
1928
1929         memset(&qctl, 0, sizeof(qctl));
1930         qctl.qc_cmd  = LUSTRE_Q_SETINFO;
1931         qctl.qc_type = UGQUOTA;
1932
1933         optind = 0;
1934         while ((c = getopt_long(argc, argv, "b:gi:tu", long_opts, NULL)) != -1) {
1935                 switch (c) {
1936                 case 'u':
1937                 case 'g':
1938                         if (qctl.qc_type != UGQUOTA) {
1939                                 fprintf(stderr, "error: -u and -g can't be used "
1940                                                 "more than once\n");
1941                                 return CMD_HELP;
1942                         }
1943                         qctl.qc_type = (c == 'u') ? USRQUOTA : GRPQUOTA;
1944                         break;
1945                 case 'b':
1946                         if ((dqi->dqi_bgrace = str2sec(optarg)) == ULONG_MAX) {
1947                                 fprintf(stderr, "error: bad block-grace: %s\n",
1948                                         optarg);
1949                                 return CMD_HELP;
1950                         }
1951                         dqb->dqb_valid |= QIF_BTIME;
1952                         break;
1953                 case 'i':
1954                         if ((dqi->dqi_igrace = str2sec(optarg)) == ULONG_MAX) {
1955                                 fprintf(stderr, "error: bad inode-grace: %s\n",
1956                                         optarg);
1957                                 return CMD_HELP;
1958                         }
1959                         dqb->dqb_valid |= QIF_ITIME;
1960                         break;
1961                 case 't': /* Yes, of course! */
1962                         break;
1963                 default: /* getopt prints error message for us when opterr != 0 */
1964                         return CMD_HELP;
1965                 }
1966         }
1967
1968         if (qctl.qc_type == UGQUOTA) {
1969                 fprintf(stderr, "error: neither -u nor -g specified\n");
1970                 return CMD_HELP;
1971         }
1972
1973         if (optind != argc - 1) {
1974                 fprintf(stderr, "error: unexpected parameters encountered\n");
1975                 return CMD_HELP;
1976         }
1977
1978         mnt = argv[optind];
1979         rc = llapi_quotactl(mnt, &qctl);
1980         if (rc) {
1981                 if (*obd_type)
1982                         fprintf(stderr, "%s %s ", obd_type,
1983                                 obd_uuid2str(&qctl.obd_uuid));
1984                 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
1985                 return rc;
1986         }
1987
1988         return 0;
1989 }
1990
1991 #define BSLIMIT (1 << 0)
1992 #define BHLIMIT (1 << 1)
1993 #define ISLIMIT (1 << 2)
1994 #define IHLIMIT (1 << 3)
1995
1996 int lfs_setquota(int argc, char **argv)
1997 {
1998         int c, rc;
1999         struct if_quotactl qctl;
2000         char *mnt, *obd_type = (char *)qctl.obd_type;
2001         struct obd_dqblk *dqb = &qctl.qc_dqblk;
2002         struct option long_opts[] = {
2003                 {"block-softlimit", required_argument, 0, 'b'},
2004                 {"block-hardlimit", required_argument, 0, 'B'},
2005                 {"group",           required_argument, 0, 'g'},
2006                 {"inode-softlimit", required_argument, 0, 'i'},
2007                 {"inode-hardlimit", required_argument, 0, 'I'},
2008                 {"user",            required_argument, 0, 'u'},
2009                 {0, 0, 0, 0}
2010         };
2011         unsigned limit_mask = 0;
2012         char *endptr;
2013
2014         if (has_times_option(argc, argv))
2015                 return lfs_setquota_times(argc, argv);
2016
2017         memset(&qctl, 0, sizeof(qctl));
2018         qctl.qc_cmd  = LUSTRE_Q_SETQUOTA;
2019         qctl.qc_type = UGQUOTA; /* UGQUOTA makes no sense for setquota,
2020                                  * so it can be used as a marker that qc_type
2021                                  * isn't reinitialized from command line */
2022
2023         optind = 0;
2024         while ((c = getopt_long(argc, argv, "b:B:g:i:I:u:", long_opts, NULL)) != -1) {
2025                 switch (c) {
2026                 case 'u':
2027                 case 'g':
2028                         if (qctl.qc_type != UGQUOTA) {
2029                                 fprintf(stderr, "error: -u and -g can't be used"
2030                                                 " more than once\n");
2031                                 return CMD_HELP;
2032                         }
2033                         qctl.qc_type = (c == 'u') ? USRQUOTA : GRPQUOTA;
2034                         rc = name2id(&qctl.qc_id, optarg,
2035                                      (qctl.qc_type == USRQUOTA) ? USER : GROUP);
2036                         if (rc) {
2037                                 qctl.qc_id = strtoul(optarg, &endptr, 10);
2038                                 if (*endptr != '\0') {
2039                                         fprintf(stderr, "error: can't find id "
2040                                                 "for name %s\n", optarg);
2041                                         return CMD_HELP;
2042                                 }
2043                         }
2044                         break;
2045                 case 'b':
2046                         ARG2ULL(dqb->dqb_bsoftlimit, optarg, 1024);
2047                         dqb->dqb_bsoftlimit >>= 10;
2048                         limit_mask |= BSLIMIT;
2049                         break;
2050                 case 'B':
2051                         ARG2ULL(dqb->dqb_bhardlimit, optarg, 1024);
2052                         dqb->dqb_bhardlimit >>= 10;
2053                         limit_mask |= BHLIMIT;
2054                         break;
2055                 case 'i':
2056                         ARG2ULL(dqb->dqb_isoftlimit, optarg, 1);
2057                         limit_mask |= ISLIMIT;
2058                         break;
2059                 case 'I':
2060                         ARG2ULL(dqb->dqb_ihardlimit, optarg, 1);
2061                         limit_mask |= IHLIMIT;
2062                         break;
2063                 default: /* getopt prints error message for us when opterr != 0 */
2064                         return CMD_HELP;
2065                 }
2066         }
2067
2068         if (qctl.qc_type == UGQUOTA) {
2069                 fprintf(stderr, "error: neither -u nor -g was specified\n");
2070                 return CMD_HELP;
2071         }
2072
2073         if (limit_mask == 0) {
2074                 fprintf(stderr, "error: at least one limit must be specified\n");
2075                 return CMD_HELP;
2076         }
2077
2078         if (optind != argc - 1) {
2079                 fprintf(stderr, "error: unexpected parameters encountered\n");
2080                 return CMD_HELP;
2081         }
2082
2083         mnt = argv[optind];
2084
2085         if ((!(limit_mask & BHLIMIT) ^ !(limit_mask & BSLIMIT)) ||
2086             (!(limit_mask & IHLIMIT) ^ !(limit_mask & ISLIMIT))) {
2087                 /* sigh, we can't just set blimits/ilimits */
2088                 struct if_quotactl tmp_qctl = {.qc_cmd  = LUSTRE_Q_GETQUOTA,
2089                                                .qc_type = qctl.qc_type,
2090                                                .qc_id   = qctl.qc_id};
2091
2092                 rc = llapi_quotactl(mnt, &tmp_qctl);
2093                 if (rc < 0) {
2094                         fprintf(stderr, "error: setquota failed while retrieving"
2095                                         " current quota settings (%s)\n",
2096                                         strerror(-rc));
2097                         return rc;
2098                 }
2099
2100                 if (!(limit_mask & BHLIMIT))
2101                         dqb->dqb_bhardlimit = tmp_qctl.qc_dqblk.dqb_bhardlimit;
2102                 if (!(limit_mask & BSLIMIT))
2103                         dqb->dqb_bsoftlimit = tmp_qctl.qc_dqblk.dqb_bsoftlimit;
2104                 if (!(limit_mask & IHLIMIT))
2105                         dqb->dqb_ihardlimit = tmp_qctl.qc_dqblk.dqb_ihardlimit;
2106                 if (!(limit_mask & ISLIMIT))
2107                         dqb->dqb_isoftlimit = tmp_qctl.qc_dqblk.dqb_isoftlimit;
2108
2109                 /* Keep grace times if we have got no softlimit arguments */
2110                 if ((limit_mask & BHLIMIT) && !(limit_mask & BSLIMIT)) {
2111                         dqb->dqb_valid |= QIF_BTIME;
2112                         dqb->dqb_btime = tmp_qctl.qc_dqblk.dqb_btime;
2113                 }
2114
2115                 if ((limit_mask & IHLIMIT) && !(limit_mask & ISLIMIT)) {
2116                         dqb->dqb_valid |= QIF_ITIME;
2117                         dqb->dqb_itime = tmp_qctl.qc_dqblk.dqb_itime;
2118                 }
2119         }
2120
2121         dqb->dqb_valid |= (limit_mask & (BHLIMIT | BSLIMIT)) ? QIF_BLIMITS : 0;
2122         dqb->dqb_valid |= (limit_mask & (IHLIMIT | ISLIMIT)) ? QIF_ILIMITS : 0;
2123
2124         rc = llapi_quotactl(mnt, &qctl);
2125         if (rc) {
2126                 if (*obd_type)
2127                         fprintf(stderr, "%s %s ", obd_type,
2128                                 obd_uuid2str(&qctl.obd_uuid));
2129                 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
2130                 return rc;
2131         }
2132
2133         return 0;
2134 }
2135
2136 static inline char *type2name(int check_type)
2137 {
2138         if (check_type == USRQUOTA)
2139                 return "user";
2140         else if (check_type == GRPQUOTA)
2141                 return "group";
2142         else
2143                 return "unknown";
2144 }
2145
2146 /* Converts seconds value into format string
2147  * result is returned in buf
2148  * Notes:
2149  *        1. result is in descenting order: 1w2d3h4m5s
2150  *        2. zero fields are not filled (except for p. 3): 5d1s
2151  *        3. zero seconds value is presented as "0s"
2152  */
2153 static char * __sec2str(time_t seconds, char *buf)
2154 {
2155         const char spec[] = "smhdw";
2156         const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
2157         unsigned long c;
2158         char *tail = buf;
2159         int i;
2160
2161         for (i = sizeof(mult) / sizeof(mult[0]) - 1 ; i >= 0; i--) {
2162                 c = seconds / mult[i];
2163
2164                 if (c > 0 || (i == 0 && buf == tail))
2165                         tail += snprintf(tail, 40-(tail-buf), "%lu%c", c, spec[i]);
2166
2167                 seconds %= mult[i];
2168         }
2169
2170         return tail;
2171 }
2172
2173 static void sec2str(time_t seconds, char *buf, int rc)
2174 {
2175         char *tail = buf;
2176
2177         if (rc)
2178                 *tail++ = '[';
2179
2180         tail = __sec2str(seconds, tail);
2181
2182         if (rc && tail - buf < 39) {
2183                 *tail++ = ']';
2184                 *tail++ = 0;
2185         }
2186 }
2187
2188 static void diff2str(time_t seconds, char *buf, time_t now)
2189 {
2190
2191         buf[0] = 0;
2192         if (!seconds)
2193                 return;
2194         if (seconds <= now) {
2195                 strcpy(buf, "none");
2196                 return;
2197         }
2198         __sec2str(seconds - now, buf);
2199 }
2200
2201 static void print_quota_title(char *name, struct if_quotactl *qctl)
2202 {
2203         printf("Disk quotas for %s %s (%cid %u):\n",
2204                type2name(qctl->qc_type), name,
2205                *type2name(qctl->qc_type), qctl->qc_id);
2206         printf("%15s%8s %7s%8s%8s%8s %7s%8s%8s\n",
2207                "Filesystem",
2208                "kbytes", "quota", "limit", "grace",
2209                "files", "quota", "limit", "grace");
2210 }
2211
2212 static void print_quota(char *mnt, struct if_quotactl *qctl, int type, int rc)
2213 {
2214         time_t now;
2215
2216         time(&now);
2217
2218         if (qctl->qc_cmd == LUSTRE_Q_GETQUOTA || qctl->qc_cmd == Q_GETOQUOTA) {
2219                 int bover = 0, iover = 0;
2220                 struct obd_dqblk *dqb = &qctl->qc_dqblk;
2221
2222                 if (dqb->dqb_bhardlimit &&
2223                     toqb(dqb->dqb_curspace) >= dqb->dqb_bhardlimit) {
2224                         bover = 1;
2225                 } else if (dqb->dqb_bsoftlimit && dqb->dqb_btime) {
2226                         if (dqb->dqb_btime > now) {
2227                                 bover = 2;
2228                         } else {
2229                                 bover = 3;
2230                         }
2231                 }
2232
2233                 if (dqb->dqb_ihardlimit &&
2234                     dqb->dqb_curinodes >= dqb->dqb_ihardlimit) {
2235                         iover = 1;
2236                 } else if (dqb->dqb_isoftlimit && dqb->dqb_itime) {
2237                         if (dqb->dqb_btime > now) {
2238                                 iover = 2;
2239                         } else {
2240                                 iover = 3;
2241                         }
2242                 }
2243
2244 #if 0           /* XXX: always print quotas even when no usages */
2245                 if (dqb->dqb_curspace || dqb->dqb_curinodes)
2246 #endif
2247                 {
2248                         char numbuf[3][32];
2249                         char timebuf[40];
2250
2251                         if (strlen(mnt) > 15)
2252                                 printf("%s\n%15s", mnt, "");
2253                         else
2254                                 printf("%15s", mnt);
2255
2256                         if (bover)
2257                                 diff2str(dqb->dqb_btime, timebuf, now);
2258                         if (rc == -EREMOTEIO)
2259                                 sprintf(numbuf[0], LPU64"*",
2260                                         toqb(dqb->dqb_curspace));
2261                         else
2262                                 sprintf(numbuf[0],
2263                                         (dqb->dqb_valid & QIF_SPACE) ?
2264                                         LPU64 : "["LPU64"]",
2265                                         toqb(dqb->dqb_curspace));
2266                         if (type == QC_GENERAL)
2267                                 sprintf(numbuf[1], (dqb->dqb_valid & QIF_BLIMITS)
2268                                         ? LPU64 : "["LPU64"]",
2269                                         dqb->dqb_bsoftlimit);
2270                         else
2271                                 sprintf(numbuf[1], "%s", "-");
2272                         sprintf(numbuf[2], (dqb->dqb_valid & QIF_BLIMITS)
2273                                 ? LPU64 : "["LPU64"]", dqb->dqb_bhardlimit);
2274                         printf(" %7s%c %6s %7s %7s",
2275                                numbuf[0], bover ? '*' : ' ', numbuf[1],
2276                                numbuf[2], bover > 1 ? timebuf : "-");
2277
2278                         if (iover)
2279                                 diff2str(dqb->dqb_itime, timebuf, now);
2280
2281                         sprintf(numbuf[0], (dqb->dqb_valid & QIF_INODES) ?
2282                                 LPU64 : "["LPU64"]", dqb->dqb_curinodes);
2283                        if (type == QC_GENERAL)
2284                                 sprintf(numbuf[1], (dqb->dqb_valid & QIF_ILIMITS)
2285                                         ? LPU64 : "["LPU64"]",
2286                                         dqb->dqb_isoftlimit);
2287                         else
2288                                 sprintf(numbuf[1], "%s", "-");
2289                         sprintf(numbuf[2], (dqb->dqb_valid & QIF_ILIMITS) ?
2290                                 LPU64 : "["LPU64"]", dqb->dqb_ihardlimit);
2291                         if (type != QC_OSTIDX)
2292                                 printf(" %7s%c %6s %7s %7s",
2293                                        numbuf[0], iover ? '*' : ' ', numbuf[1],
2294                                        numbuf[2], iover > 1 ? timebuf : "-");
2295                         else
2296                                 printf(" %7s %7s %7s %7s", "-", "-", "-", "-");
2297                         printf("\n");
2298                 }
2299         } else if (qctl->qc_cmd == LUSTRE_Q_GETINFO ||
2300                    qctl->qc_cmd == Q_GETOINFO) {
2301                 char bgtimebuf[40];
2302                 char igtimebuf[40];
2303
2304                 sec2str(qctl->qc_dqinfo.dqi_bgrace, bgtimebuf, rc);
2305                 sec2str(qctl->qc_dqinfo.dqi_igrace, igtimebuf, rc);
2306                 printf("Block grace time: %s; Inode grace time: %s\n",
2307                        bgtimebuf, igtimebuf);
2308         }
2309 }
2310
2311 static int print_obd_quota(char *mnt, struct if_quotactl *qctl, int is_mdt)
2312 {
2313         int rc = 0, rc1 = 0, count = 0;
2314         __u32 valid = qctl->qc_valid;
2315
2316         rc = llapi_get_obd_count(mnt, &count, is_mdt);
2317         if (rc) {
2318                 fprintf(stderr, "can not get %s count: %s\n",
2319                         is_mdt ? "mdt": "ost", strerror(-rc));
2320                 return rc;
2321         }
2322
2323         for (qctl->qc_idx = 0; qctl->qc_idx < count; qctl->qc_idx++) {
2324                 qctl->qc_valid = is_mdt ? QC_MDTIDX : QC_OSTIDX;
2325                 rc = llapi_quotactl(mnt, qctl);
2326                 if (rc) {
2327                         /* It is remote client case. */
2328                         if (-rc == EOPNOTSUPP) {
2329                                 rc = 0;
2330                                 goto out;
2331                         }
2332
2333                         if (!rc1)
2334                                 rc1 = rc;
2335                         fprintf(stderr, "quotactl %s%d failed.\n",
2336                                 is_mdt ? "mdt": "ost", qctl->qc_idx);
2337                         continue;
2338                 }
2339
2340                 print_quota(obd_uuid2str(&qctl->obd_uuid), qctl, qctl->qc_valid, 0);
2341         }
2342
2343 out:
2344         qctl->qc_valid = valid;
2345         return rc ? : rc1;
2346 }
2347
2348 static int lfs_quota(int argc, char **argv)
2349 {
2350         int c;
2351         char *mnt, *name = NULL;
2352         struct if_quotactl qctl = { .qc_cmd = LUSTRE_Q_GETQUOTA,
2353                                     .qc_type = UGQUOTA };
2354         char *obd_type = (char *)qctl.obd_type;
2355         char *obd_uuid = (char *)qctl.obd_uuid.uuid;
2356         int rc, rc1 = 0, rc2 = 0, rc3 = 0,
2357             verbose = 0, pass = 0, quiet = 0, inacc;
2358         char *endptr;
2359         __u32 valid = QC_GENERAL, idx = 0;
2360
2361         optind = 0;
2362         while ((c = getopt(argc, argv, "gi:I:o:qtuv")) != -1) {
2363                 switch (c) {
2364                 case 'u':
2365                         if (qctl.qc_type != UGQUOTA) {
2366                                 fprintf(stderr, "error: use either -u or -g\n");
2367                                 return CMD_HELP;
2368                         }
2369                         qctl.qc_type = USRQUOTA;
2370                         break;
2371                 case 'g':
2372                         if (qctl.qc_type != UGQUOTA) {
2373                                 fprintf(stderr, "error: use either -u or -g\n");
2374                                 return CMD_HELP;
2375                         }
2376                         qctl.qc_type = GRPQUOTA;
2377                         break;
2378                 case 't':
2379                         qctl.qc_cmd = LUSTRE_Q_GETINFO;
2380                         break;
2381                 case 'o':
2382                         valid = qctl.qc_valid = QC_UUID;
2383                         strncpy(obd_uuid, optarg, sizeof(qctl.obd_uuid));
2384                         break;
2385                 case 'i':
2386                         valid = qctl.qc_valid = QC_MDTIDX;
2387                         idx = qctl.qc_idx = atoi(optarg);
2388                         break;
2389                 case 'I':
2390                         valid = qctl.qc_valid = QC_OSTIDX;
2391                         idx = qctl.qc_idx = atoi(optarg);
2392                         break;
2393                 case 'v':
2394                         verbose = 1;
2395                         break;
2396                 case 'q':
2397                         quiet = 1;
2398                         break;
2399                 default:
2400                         fprintf(stderr, "error: %s: option '-%c' "
2401                                         "unrecognized\n", argv[0], c);
2402                         return CMD_HELP;
2403                 }
2404         }
2405
2406         /* current uid/gid info for "lfs quota /path/to/lustre/mount" */
2407         if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA && qctl.qc_type == UGQUOTA &&
2408             optind == argc - 1) {
2409 ug_output:
2410                 memset(&qctl, 0, sizeof(qctl)); /* spoiled by print_*_quota */
2411                 qctl.qc_cmd = LUSTRE_Q_GETQUOTA;
2412                 qctl.qc_valid = valid;
2413                 qctl.qc_idx = idx;
2414                 if (pass++ == 0) {
2415                         qctl.qc_type = USRQUOTA;
2416                         qctl.qc_id = geteuid();
2417                 } else {
2418                         qctl.qc_type = GRPQUOTA;
2419                         qctl.qc_id = getegid();
2420                 }
2421                 rc = id2name(&name, qctl.qc_id,
2422                              (qctl.qc_type == USRQUOTA) ? USER : GROUP);
2423                 if (rc)
2424                         name = "<unknown>";
2425         /* lfs quota -u username /path/to/lustre/mount */
2426         } else if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA) {
2427                 /* options should be followed by u/g-name and mntpoint */
2428                 if (optind + 2 != argc || qctl.qc_type == UGQUOTA) {
2429                         fprintf(stderr, "error: missing quota argument(s)\n");
2430                         return CMD_HELP;
2431                 }
2432
2433                 name = argv[optind++];
2434                 rc = name2id(&qctl.qc_id, name,
2435                              (qctl.qc_type == USRQUOTA) ? USER : GROUP);
2436                 if (rc) {
2437                         qctl.qc_id = strtoul(name, &endptr, 10);
2438                         if (*endptr != '\0') {
2439                                 fprintf(stderr, "error: can't find id for name "
2440                                         "%s\n", name);
2441                                 return CMD_HELP;
2442                         }
2443                 }
2444         } else if (optind + 1 != argc || qctl.qc_type == UGQUOTA) {
2445                 fprintf(stderr, "error: missing quota info argument(s)\n");
2446                 return CMD_HELP;
2447         }
2448
2449         mnt = argv[optind];
2450
2451         rc1 = llapi_quotactl(mnt, &qctl);
2452         if (rc1 < 0) {
2453                 switch (rc1) {
2454                 case -ESRCH:
2455                         fprintf(stderr, "%s quotas are not enabled.\n",
2456                                 qctl.qc_type == USRQUOTA ? "user" : "group");
2457                         goto out;
2458                 case -EPERM:
2459                         fprintf(stderr, "Permission denied.\n");
2460                 case -ENOENT:
2461                         /* We already got a "No such file..." message. */
2462                         goto out;
2463                 default:
2464                         fprintf(stderr, "Unexpected quotactl error: %s\n",
2465                                 strerror(-rc1));
2466                 }
2467         }
2468
2469         if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA && !quiet)
2470                 print_quota_title(name, &qctl);
2471
2472         if (rc1 && *obd_type)
2473                 fprintf(stderr, "%s %s ", obd_type, obd_uuid);
2474
2475         if (qctl.qc_valid != QC_GENERAL)
2476                 mnt = "";
2477
2478         inacc = (qctl.qc_cmd == LUSTRE_Q_GETQUOTA) &&
2479                 ((qctl.qc_dqblk.dqb_valid&(QIF_LIMITS|QIF_USAGE))!=(QIF_LIMITS|QIF_USAGE));
2480
2481         print_quota(mnt, &qctl, QC_GENERAL, rc1);
2482
2483         if (qctl.qc_valid == QC_GENERAL && qctl.qc_cmd != LUSTRE_Q_GETINFO && verbose) {
2484                 rc2 = print_obd_quota(mnt, &qctl, 1);
2485                 rc3 = print_obd_quota(mnt, &qctl, 0);
2486         }
2487
2488         if (rc1 || rc2 || rc3 || inacc)
2489                 printf("Some errors happened when getting quota info. "
2490                        "Some devices may be not working or deactivated. "
2491                        "The data in \"[]\" is inaccurate.\n");
2492
2493 out:
2494         if (pass == 1)
2495                 goto ug_output;
2496
2497         return rc1;
2498 }
2499 #endif /* HAVE_SYS_QUOTA_H! */
2500
2501 static int flushctx_ioctl(char *mp)
2502 {
2503         int fd, rc;
2504
2505         fd = open(mp, O_RDONLY);
2506         if (fd == -1) {
2507                 fprintf(stderr, "flushctx: error open %s: %s\n",
2508                         mp, strerror(errno));
2509                 return -1;
2510         }
2511
2512         rc = ioctl(fd, LL_IOC_FLUSHCTX);
2513         if (rc == -1)
2514                 fprintf(stderr, "flushctx: error ioctl %s: %s\n",
2515                         mp, strerror(errno));
2516
2517         close(fd);
2518         return rc;
2519 }
2520
2521 static int lfs_flushctx(int argc, char **argv)
2522 {
2523         int     kdestroy = 0, c;
2524         FILE   *proc = NULL;
2525         char    procline[PATH_MAX], *line;
2526         int     rc = 0;
2527
2528         optind = 0;
2529         while ((c = getopt(argc, argv, "k")) != -1) {
2530                 switch (c) {
2531                 case 'k':
2532                         kdestroy = 1;
2533                         break;
2534                 default:
2535                         fprintf(stderr, "error: %s: option '-%c' "
2536                                         "unrecognized\n", argv[0], c);
2537                         return CMD_HELP;
2538                 }
2539         }
2540
2541         if (kdestroy) {
2542             int rc;
2543             if ((rc = system("kdestroy > /dev/null")) != 0) {
2544                 rc = WEXITSTATUS(rc);
2545                 fprintf(stderr, "error destroying tickets: %d, continuing\n", rc);
2546             }
2547         }
2548
2549         if (optind >= argc) {
2550                 /* flush for all mounted lustre fs. */
2551                 proc = fopen("/proc/mounts", "r");
2552                 if (!proc) {
2553                         fprintf(stderr, "error: %s: can't open /proc/mounts\n",
2554                                 argv[0]);
2555                         return -1;
2556                 }
2557
2558                 while ((line = fgets(procline, PATH_MAX, proc)) != NULL) {
2559                         char dev[PATH_MAX];
2560                         char mp[PATH_MAX];
2561                         char fs[PATH_MAX];
2562
2563                         if (sscanf(line, "%s %s %s", dev, mp, fs) != 3) {
2564                                 fprintf(stderr, "%s: unexpected format in "
2565                                                 "/proc/mounts\n",
2566                                         argv[0]);
2567                                 rc = -1;
2568                                 goto out;
2569                         }
2570
2571                         if (strcmp(fs, "lustre") != 0)
2572                                 continue;
2573                         /* we use '@' to determine it's a client. are there
2574                          * any other better way?
2575                          */
2576                         if (strchr(dev, '@') == NULL)
2577                                 continue;
2578
2579                         if (flushctx_ioctl(mp))
2580                                 rc = -1;
2581                 }
2582         } else {
2583                 /* flush fs as specified */
2584                 while (optind < argc) {
2585                         if (flushctx_ioctl(argv[optind++]))
2586                                 rc = -1;
2587                 }
2588         }
2589
2590 out:
2591         if (proc != NULL)
2592                 fclose(proc);
2593         return rc;
2594 }
2595
2596 static int lfs_lsetfacl(int argc, char **argv)
2597 {
2598         argv[0]++;
2599         return(llapi_lsetfacl(argc, argv));
2600 }
2601
2602 static int lfs_lgetfacl(int argc, char **argv)
2603 {
2604         argv[0]++;
2605         return(llapi_lgetfacl(argc, argv));
2606 }
2607
2608 static int lfs_rsetfacl(int argc, char **argv)
2609 {
2610         argv[0]++;
2611         return(llapi_rsetfacl(argc, argv));
2612 }
2613
2614 static int lfs_rgetfacl(int argc, char **argv)
2615 {
2616         argv[0]++;
2617         return(llapi_rgetfacl(argc, argv));
2618 }
2619
2620 static int lfs_cp(int argc, char **argv)
2621 {
2622         return(llapi_cp(argc, argv));
2623 }
2624
2625 static int lfs_ls(int argc, char **argv)
2626 {
2627         return(llapi_ls(argc, argv));
2628 }
2629
2630 static int lfs_changelog(int argc, char **argv)
2631 {
2632         void *changelog_priv;
2633         struct changelog_ext_rec *rec;
2634         long long startrec = 0, endrec = 0;
2635         char *mdd;
2636         struct option long_opts[] = {
2637                 {"follow", no_argument, 0, 'f'},
2638                 {0, 0, 0, 0}
2639         };
2640         char short_opts[] = "f";
2641         int rc, follow = 0;
2642
2643         optind = 0;
2644         while ((rc = getopt_long(argc, argv, short_opts,
2645                                 long_opts, NULL)) != -1) {
2646                 switch (rc) {
2647                 case 'f':
2648                         follow++;
2649                         break;
2650                 case '?':
2651                         return CMD_HELP;
2652                 default:
2653                         fprintf(stderr, "error: %s: option '%s' unrecognized\n",
2654                                 argv[0], argv[optind - 1]);
2655                         return CMD_HELP;
2656                 }
2657         }
2658         if (optind >= argc)
2659                 return CMD_HELP;
2660
2661         mdd = argv[optind++];
2662         if (argc > optind)
2663                 startrec = strtoll(argv[optind++], NULL, 10);
2664         if (argc > optind)
2665                 endrec = strtoll(argv[optind++], NULL, 10);
2666
2667         rc = llapi_changelog_start(&changelog_priv,
2668                                    CHANGELOG_FLAG_BLOCK |
2669                                    (follow ? CHANGELOG_FLAG_FOLLOW : 0),
2670                                    mdd, startrec);
2671         if (rc < 0) {
2672                 fprintf(stderr, "Can't start changelog: %s\n",
2673                         strerror(errno = -rc));
2674                 return rc;
2675         }
2676
2677         while ((rc = llapi_changelog_recv(changelog_priv, &rec)) == 0) {
2678                 time_t secs;
2679                 struct tm ts;
2680
2681                 if (endrec && rec->cr_index > endrec) {
2682                         llapi_changelog_free(&rec);
2683                         break;
2684                 }
2685                 if (rec->cr_index < startrec) {
2686                         llapi_changelog_free(&rec);
2687                         continue;
2688                 }
2689
2690                 secs = rec->cr_time >> 30;
2691                 gmtime_r(&secs, &ts);
2692                 printf(LPU64" %02d%-5s %02d:%02d:%02d.%06d %04d.%02d.%02d "
2693                        "0x%x t="DFID, rec->cr_index, rec->cr_type,
2694                        changelog_type2str(rec->cr_type),
2695                        ts.tm_hour, ts.tm_min, ts.tm_sec,
2696                        (int)(rec->cr_time & ((1<<30) - 1)),
2697                        ts.tm_year + 1900, ts.tm_mon + 1, ts.tm_mday,
2698                        rec->cr_flags & CLF_FLAGMASK, PFID(&rec->cr_tfid));
2699                 if (rec->cr_namelen)
2700                         /* namespace rec includes parent and filename */
2701                         printf(" p="DFID" %.*s", PFID(&rec->cr_pfid),
2702                                 rec->cr_namelen, rec->cr_name);
2703                 if (fid_is_sane(&rec->cr_sfid))
2704                         printf(" s="DFID" sp="DFID" %.*s",
2705                                 PFID(&rec->cr_sfid), PFID(&rec->cr_spfid),
2706                                 changelog_rec_snamelen(rec),
2707                                 changelog_rec_sname(rec));
2708                 printf("\n");
2709
2710                 llapi_changelog_free(&rec);
2711         }
2712
2713         llapi_changelog_fini(&changelog_priv);
2714
2715         if (rc < 0)
2716                 fprintf(stderr, "Changelog: %s\n", strerror(errno = -rc));
2717
2718         return (rc == 1 ? 0 : rc);
2719 }
2720
2721 static int lfs_changelog_clear(int argc, char **argv)
2722 {
2723         long long endrec;
2724         int rc;
2725
2726         if (argc != 4)
2727                 return CMD_HELP;
2728
2729         endrec = strtoll(argv[3], NULL, 10);
2730
2731         rc = llapi_changelog_clear(argv[1], argv[2], endrec);
2732         if (rc)
2733                 fprintf(stderr, "%s error: %s\n", argv[0],
2734                         strerror(errno = -rc));
2735         return rc;
2736 }
2737
2738 static int lfs_fid2path(int argc, char **argv)
2739 {
2740         struct option long_opts[] = {
2741                 {"cur", no_argument, 0, 'c'},
2742                 {"link", required_argument, 0, 'l'},
2743                 {"rec", required_argument, 0, 'r'},
2744                 {0, 0, 0, 0}
2745         };
2746         char  short_opts[] = "cl:r:";
2747         char *device, *fid, *path;
2748         long long recno = -1;
2749         int linkno = -1;
2750         int lnktmp;
2751         int printcur = 0;
2752         int rc;
2753
2754         optind = 0;
2755
2756         while ((rc = getopt_long(argc, argv, short_opts,
2757                                 long_opts, NULL)) != -1) {
2758                 switch (rc) {
2759                 case 'c':
2760                         printcur++;
2761                         break;
2762                 case 'l':
2763                         linkno = strtol(optarg, NULL, 10);
2764                         break;
2765                 case 'r':
2766                         recno = strtoll(optarg, NULL, 10);
2767                         break;
2768                 case '?':
2769                         return CMD_HELP;
2770                 default:
2771                         fprintf(stderr, "error: %s: option '%s' unrecognized\n",
2772                                 argv[0], argv[optind - 1]);
2773                         return CMD_HELP;
2774                 }
2775         }
2776         device = argv[optind++];
2777         fid = argv[optind++];
2778         if (optind != argc)
2779                 return CMD_HELP;
2780
2781         path = calloc(1, PATH_MAX);
2782
2783         lnktmp = (linkno >= 0) ? linkno : 0;
2784         while (1) {
2785                 int oldtmp = lnktmp;
2786                 long long rectmp = recno;
2787                 rc = llapi_fid2path(device, fid, path, PATH_MAX, &rectmp,
2788                                     &lnktmp);
2789                 if (rc < 0) {
2790                         fprintf(stderr, "%s error: %s\n", argv[0],
2791                                 strerror(errno = -rc));
2792                         break;
2793                 }
2794
2795                 if (printcur)
2796                         fprintf(stdout, "%lld ", rectmp);
2797                 if (device[0] == '/') {
2798                         fprintf(stdout, "%s", device);
2799                         if (device[strlen(device) - 1] != '/')
2800                                 fprintf(stdout, "/");
2801                 } else if (path[0] == '\0') {
2802                         fprintf(stdout, "/");
2803                 }
2804                 fprintf(stdout, "%s\n", path);
2805
2806                 if (linkno >= 0)
2807                         /* specified linkno */
2808                         break;
2809                 if (oldtmp == lnktmp)
2810                         /* no more links */
2811                         break;
2812         }
2813
2814         free(path);
2815         return rc;
2816 }
2817
2818 static int lfs_path2fid(int argc, char **argv)
2819 {
2820         char *path;
2821         lustre_fid fid;
2822         int rc;
2823
2824         if (argc != 2)
2825                 return CMD_HELP;
2826
2827         path = argv[1];
2828         rc = llapi_path2fid(path, &fid);
2829         if (rc) {
2830                 fprintf(stderr, "can't get fid for %s: %s\n", path,
2831                         strerror(errno = -rc));
2832                 return rc;
2833         }
2834
2835         printf(DFID"\n", PFID(&fid));
2836
2837         return 0;
2838 }
2839
2840 static int lfs_data_version(int argc, char **argv)
2841 {
2842         char *path;
2843         __u64 data_version;
2844         int fd;
2845         int rc;
2846         int c;
2847         int nolock = 0;
2848
2849         if (argc < 2)
2850                 return CMD_HELP;
2851
2852         optind = 0;
2853         while ((c = getopt(argc, argv, "n")) != -1) {
2854                 switch (c) {
2855                 case 'n':
2856                         nolock = LL_DV_NOFLUSH;
2857                         break;
2858                 default:
2859                         return CMD_HELP;
2860                 }
2861         }
2862         if (optind == argc)
2863                 return CMD_HELP;
2864
2865         path = argv[optind];
2866         fd = open(path, O_RDONLY);
2867         if (fd < 0) {
2868                 fprintf(stderr, "can't open %s: %s\n", path,
2869                         strerror(errno));
2870                 return errno;
2871         }
2872
2873         rc = llapi_get_data_version(fd, &data_version, nolock);
2874         if (rc) {
2875                 fprintf(stderr, "can't get version for %s: %s\n", path,
2876                         strerror(errno = -rc));
2877         } else
2878                 printf(LPU64 "\n", data_version);
2879
2880         close(fd);
2881
2882         return rc;
2883 }
2884
2885 static int lfs_hsm_state(int argc, char **argv)
2886 {
2887         int rc;
2888         int i = 1;
2889         char *path;
2890         struct hsm_user_state hus;
2891
2892         if (argc < 2)
2893                 return CMD_HELP;
2894
2895         do {
2896                 path = argv[i];
2897
2898                 rc = llapi_hsm_state_get(path, &hus);
2899                 if (rc) {
2900                         fprintf(stderr, "can't get hsm state for %s: %s\n",
2901                                 path, strerror(errno = -rc));
2902                         return rc;
2903                 }
2904
2905                 /* Display path name and status flags */
2906                 printf("%s: (0x%08x)", path, hus.hus_states);
2907
2908                 if (hus.hus_states & HS_RELEASED)
2909                         printf(" released");
2910                 if (hus.hus_states & HS_EXISTS)
2911                         printf(" exists");
2912                 if (hus.hus_states & HS_DIRTY)
2913                         printf(" dirty");
2914                 if (hus.hus_states & HS_ARCHIVED)
2915                         printf(" archived");
2916                 /* Display user-settable flags */
2917                 if (hus.hus_states & HS_NORELEASE)
2918                         printf(" never_release");
2919                 if (hus.hus_states & HS_NOARCHIVE)
2920                         printf(" never_archive");
2921                 if (hus.hus_states & HS_LOST)
2922                         printf(" lost_from_hsm");
2923
2924                 if (hus.hus_archive_id != 0)
2925                         printf(", archive_id:%d", hus.hus_archive_id);
2926                 printf("\n");
2927
2928         } while (++i < argc);
2929
2930         return 0;
2931 }
2932
2933 #define LFS_HSM_SET   0
2934 #define LFS_HSM_CLEAR 1
2935
2936 /**
2937  * Generic function to set or clear HSM flags.
2938  * Used by hsm_set and hsm_clear.
2939  *
2940  * @mode  if LFS_HSM_SET, set the flags, if LFS_HSM_CLEAR, clear the flags.
2941  */
2942 static int lfs_hsm_change_flags(int argc, char **argv, int mode)
2943 {
2944         struct option long_opts[] = {
2945                 {"lost", 0, 0, 'l'},
2946                 {"norelease", 0, 0, 'r'},
2947                 {"noarchive", 0, 0, 'a'},
2948                 {"archived", 0, 0, 'A'},
2949                 {"dirty", 0, 0, 'd'},
2950                 {"exists", 0, 0, 'e'},
2951                 {0, 0, 0, 0}
2952         };
2953         char short_opts[] = "lraAde";
2954         __u64 mask = 0;
2955         int c, rc;
2956         char *path;
2957
2958         if (argc < 3)
2959                 return CMD_HELP;
2960
2961         optind = 0;
2962         while ((c = getopt_long(argc, argv, short_opts,
2963                                 long_opts, NULL)) != -1) {
2964                 switch (c) {
2965                 case 'l':
2966                         mask |= HS_LOST;
2967                         break;
2968                 case 'a':
2969                         mask |= HS_NOARCHIVE;
2970                         break;
2971                 case 'A':
2972                         mask |= HS_ARCHIVED;
2973                         break;
2974                 case 'r':
2975                         mask |= HS_NORELEASE;
2976                         break;
2977                 case 'd':
2978                         mask |= HS_DIRTY;
2979                         break;
2980                 case 'e':
2981                         mask |= HS_EXISTS;
2982                         break;
2983                 case '?':
2984                         return CMD_HELP;
2985                 default:
2986                         fprintf(stderr, "error: %s: option '%s' unrecognized\n",
2987                                 argv[0], argv[optind - 1]);
2988                         return CMD_HELP;
2989                 }
2990         }
2991
2992         /* User should have specified a flag */
2993         if (mask == 0)
2994                 return CMD_HELP;
2995
2996         while (optind < argc) {
2997
2998                 path = argv[optind];
2999
3000                 /* If mode == 0, this means we apply the mask. */
3001                 if (mode == LFS_HSM_SET)
3002                         rc = llapi_hsm_state_set(path, mask, 0, 0);
3003                 else
3004                         rc = llapi_hsm_state_set(path, 0, mask, 0);
3005
3006                 if (rc != 0) {
3007                         fprintf(stderr, "Can't change hsm flags for %s: %s\n",
3008                                 path, strerror(errno = -rc));
3009                         return rc;
3010                 }
3011                 optind++;
3012         }
3013
3014         return 0;
3015 }
3016
3017 static int lfs_hsm_action(int argc, char **argv)
3018 {
3019         int                              rc;
3020         int                              i = 1;
3021         char                            *path;
3022         struct hsm_current_action        hca;
3023         struct hsm_extent                he;
3024         enum hsm_user_action             hua;
3025         enum hsm_progress_states         hps;
3026
3027         if (argc < 2)
3028                 return CMD_HELP;
3029
3030         do {
3031                 path = argv[i];
3032
3033                 rc = llapi_hsm_current_action(path, &hca);
3034                 if (rc) {
3035                         fprintf(stderr, "can't get hsm action for %s: %s\n",
3036                                 path, strerror(errno = -rc));
3037                         return rc;
3038                 }
3039                 he = hca.hca_location;
3040                 hua = hca.hca_action;
3041                 hps = hca.hca_state;
3042
3043                 printf("%s: %s", path, hsm_user_action2name(hua));
3044
3045                 /* Skip file without action */
3046                 if (hca.hca_action == HUA_NONE) {
3047                         printf("\n");
3048                         continue;
3049                 }
3050
3051                 printf(" %s ", hsm_progress_state2name(hps));
3052
3053                 if ((hps == HPS_RUNNING) &&
3054                     (hua == HUA_ARCHIVE || hua == HUA_RESTORE))
3055                         printf("("LPX64 " bytes moved)\n", he.length);
3056                 else if ((he.offset + he.length) == OBD_OBJECT_EOF)
3057                         printf("(from "LPX64 " to EOF)\n", he.offset);
3058                 else
3059                         printf("(from "LPX64 " to "LPX64")\n",
3060                                he.offset, he.offset + he.length);
3061
3062         } while (++i < argc);
3063
3064         return 0;
3065 }
3066
3067 static int lfs_hsm_set(int argc, char **argv)
3068 {
3069         return lfs_hsm_change_flags(argc, argv, LFS_HSM_SET);
3070 }
3071
3072 static int lfs_hsm_clear(int argc, char **argv)
3073 {
3074         return lfs_hsm_change_flags(argc, argv, LFS_HSM_CLEAR);
3075 }
3076
3077 /**
3078  * Check file state and return its fid, to be used by lfs_hsm_request().
3079  *
3080  * \param[in]     file      Path to file to check
3081  * \param[in,out] fid       Pointer to allocated lu_fid struct.
3082  * \param[in,out] last_dev  Pointer to last device id used.
3083  *
3084  * \return 0 on success.
3085  */
3086 static int lfs_hsm_prepare_file(char *file, struct lu_fid *fid,
3087                                 dev_t *last_dev)
3088 {
3089         struct stat     st;
3090         int             rc;
3091
3092         rc = lstat(file, &st);
3093         if (rc) {
3094                 fprintf(stderr, "Cannot stat %s: %s\n", file, strerror(-errno));
3095                 return -errno;
3096         }
3097         /* A request should be ... */
3098         if (*last_dev != st.st_dev && *last_dev != 0) {
3099                 fprintf(stderr, "All files should be "
3100                         "on the same filesystem: %s\n", file);
3101                 return -EINVAL;
3102         }
3103         *last_dev = st.st_dev;
3104
3105         rc = llapi_path2fid(file, fid);
3106         if (rc) {
3107                 fprintf(stderr, "Cannot read FID of %s: %s\n",
3108                         file, strerror(-rc));
3109                 return rc;
3110         }
3111         return 0;
3112 }
3113
3114 static int lfs_hsm_request(int argc, char **argv, int action)
3115 {
3116         struct option            long_opts[] = {
3117                 {"filelist", 1, 0, 'l'},
3118                 {"data", 1, 0, 'D'},
3119                 {"archive", 1, 0, 'a'},
3120                 {0, 0, 0, 0}
3121         };
3122         dev_t                    last_dev = 0;
3123         char                     short_opts[] = "l:D:a:";
3124         struct hsm_user_request *hur, *oldhur;
3125         int                      c, i;
3126         size_t                   len;
3127         int                      nbfile;
3128         char                    *line = NULL;
3129         char                    *filelist = NULL;
3130         char                     fullpath[PATH_MAX];
3131         char                    *opaque = NULL;
3132         int                      opaque_len = 0;
3133         int                      archive_id = 0;
3134         FILE                    *fp;
3135         int                      nbfile_alloc = 0;
3136         char                     some_file[PATH_MAX+1] = "";
3137         int                      rc;
3138
3139         if (argc < 2)
3140                 return CMD_HELP;
3141
3142         optind = 0;
3143         while ((c = getopt_long(argc, argv, short_opts,
3144                                 long_opts, NULL)) != -1) {
3145                 switch (c) {
3146                 case 'l':
3147                         filelist = optarg;
3148                         break;
3149                 case 'D':
3150                         opaque = optarg;
3151                         break;
3152                 case 'a':
3153                         if (action != HUA_ARCHIVE) {
3154                                 fprintf(stderr,
3155                                         "error: -a is supported only "
3156                                         "when archiving\n");
3157                                 return CMD_HELP;
3158                         }
3159                         archive_id = atoi(optarg);
3160                         break;
3161                 case '?':
3162                         return CMD_HELP;
3163                 default:
3164                         fprintf(stderr, "error: %s: option '%s' unrecognized\n",
3165                                 argv[0], argv[optind - 1]);
3166                         return CMD_HELP;
3167                 }
3168         }
3169
3170         /* All remaining args are files, so we have at least nbfile */
3171         nbfile = argc - optind;
3172
3173         if ((nbfile == 0) && (filelist == NULL))
3174                 return CMD_HELP;
3175
3176         if (opaque != NULL)
3177                 opaque_len = strlen(opaque);
3178
3179         /* Alloc the request structure with enough place to store all files
3180          * from command line. */
3181         hur = llapi_hsm_user_request_alloc(nbfile, opaque_len);
3182         if (hur == NULL) {
3183                 fprintf(stderr, "Cannot create the request: %s\n",
3184                         strerror(errno));
3185                 return errno;
3186         }
3187         nbfile_alloc = nbfile;
3188
3189         hur->hur_request.hr_action = action;
3190         hur->hur_request.hr_archive_id = archive_id;
3191         hur->hur_request.hr_flags = 0;
3192
3193         /* All remaining args are files, add them */
3194         if (nbfile != 0)
3195                 strcpy(some_file, argv[optind]);
3196
3197         for (i = 0; i < nbfile; i++) {
3198                 hur->hur_user_item[i].hui_extent.length = -1;
3199                 rc = lfs_hsm_prepare_file(argv[optind + i],
3200                                           &hur->hur_user_item[i].hui_fid,
3201                                           &last_dev);
3202                 hur->hur_request.hr_itemcount++;
3203                 if (rc)
3204                         goto out_free;
3205         }
3206
3207         /* from here stop using nb_file, use hur->hur_request.hr_itemcount */
3208
3209         /* If a filelist was specified, read the filelist from it. */
3210         if (filelist != NULL) {
3211                 fp = fopen(filelist, "r");
3212                 if (fp == NULL) {
3213                         fprintf(stderr, "Cannot read the file list %s: %s\n",
3214                                 filelist, strerror(errno));
3215                         rc = -errno;
3216                         goto out_free;
3217                 }
3218
3219                 while ((rc = getline(&line, &len, fp)) != -1) {
3220                         struct hsm_user_item *hui;
3221
3222                         /* If allocated buffer was too small, gets something
3223                          * bigger */
3224                         if (nbfile_alloc <= hur->hur_request.hr_itemcount) {
3225                                 nbfile_alloc = nbfile_alloc * 2 + 1;
3226                                 oldhur = hur;
3227                                 hur = llapi_hsm_user_request_alloc(nbfile_alloc,
3228                                                                    opaque_len);
3229                                 if (hur == NULL) {
3230                                         fprintf(stderr, "Cannot allocate "
3231                                                 "the request: %s\n",
3232                                                 strerror(errno));
3233                                         hur = oldhur;
3234                                         rc = -errno;
3235                                         goto out_free;
3236                                 }
3237                                 memcpy(hur, oldhur, hur_len(oldhur));
3238                                 free(oldhur);
3239                         }
3240
3241                         /* Chop CR */
3242                         if (line[strlen(line) - 1] == '\n')
3243                                 line[strlen(line) - 1] = '\0';
3244
3245                         hui =
3246                              &hur->hur_user_item[hur->hur_request.hr_itemcount];
3247                         hui->hui_extent.length = -1;
3248                         rc = lfs_hsm_prepare_file(line, &hui->hui_fid,
3249                                                   &last_dev);
3250                         hur->hur_request.hr_itemcount++;
3251                         if (rc)
3252                                 goto out_free;
3253
3254                         if ((some_file[0] == '\0') &&
3255                             (strlen(line) < sizeof(some_file)))
3256                                 strcpy(some_file, line);
3257                 }
3258
3259                 rc = fclose(fp);
3260                 if (line)
3261                         free(line);
3262         }
3263
3264         /* If a --data was used, add it to the request */
3265         hur->hur_request.hr_data_len = opaque_len;
3266         if (opaque != NULL)
3267                 memcpy(hur_data(hur), opaque, opaque_len);
3268
3269         /* Send the HSM request */
3270         if (realpath(some_file, fullpath) == NULL) {
3271                 fprintf(stderr, "Could not find path '%s': %s\n",
3272                         some_file, strerror(errno));
3273         }
3274         rc = llapi_hsm_request(fullpath, hur);
3275         if (rc) {
3276                 fprintf(stderr, "Cannot send HSM request (use of %s): %s\n",
3277                         some_file, strerror(-rc));
3278                 goto out_free;
3279         }
3280
3281 out_free:
3282         free(hur);
3283         return rc;
3284 }
3285
3286 static int lfs_hsm_archive(int argc, char **argv)
3287 {
3288         return lfs_hsm_request(argc, argv, HUA_ARCHIVE);
3289 }
3290
3291 static int lfs_hsm_restore(int argc, char **argv)
3292 {
3293         return lfs_hsm_request(argc, argv, HUA_RESTORE);
3294 }
3295
3296 static int lfs_hsm_release(int argc, char **argv)
3297 {
3298         return lfs_hsm_request(argc, argv, HUA_RELEASE);
3299 }
3300
3301 static int lfs_hsm_remove(int argc, char **argv)
3302 {
3303         return lfs_hsm_request(argc, argv, HUA_REMOVE);
3304 }
3305
3306 static int lfs_hsm_cancel(int argc, char **argv)
3307 {
3308         return lfs_hsm_request(argc, argv, HUA_CANCEL);
3309 }
3310
3311 int main(int argc, char **argv)
3312 {
3313         int rc;
3314
3315         setlinebuf(stdout);
3316
3317         ptl_initialize(argc, argv);
3318         if (obd_initialize(argc, argv) < 0)
3319                 exit(2);
3320
3321         Parser_init("lfs > ", cmdlist);
3322
3323         if (argc > 1) {
3324                 rc = Parser_execarg(argc - 1, argv + 1, cmdlist);
3325         } else {
3326                 rc = Parser_commands();
3327         }
3328
3329         obd_finalize(argc, argv);
3330         return rc < 0 ? -rc : rc;
3331 }
3332