Whamcloud - gitweb
LU-9430 utils: fix logic errors and putchar in sk_name2hmac()
[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.gnu.org/licenses/gpl-2.0.html
19  *
20  * GPL HEADER END
21  */
22 /*
23  * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
24  * Use is subject to license terms.
25  *
26  * Copyright (c) 2011, 2016, Intel Corporation.
27  */
28 /*
29  * This file is part of Lustre, http://www.lustre.org/
30  * Lustre is a trademark of Sun Microsystems, Inc.
31  *
32  * lustre/utils/lfs.c
33  *
34  * Author: Peter J. Braam <braam@clusterfs.com>
35  * Author: Phil Schwan <phil@clusterfs.com>
36  * Author: Robert Read <rread@clusterfs.com>
37  */
38
39 /* for O_DIRECTORY */
40 #ifndef _GNU_SOURCE
41 #define _GNU_SOURCE
42 #endif
43
44 #include <stdlib.h>
45 #include <stdio.h>
46 #include <getopt.h>
47 #include <string.h>
48 #include <mntent.h>
49 #include <unistd.h>
50 #include <errno.h>
51 #include <err.h>
52 #include <pwd.h>
53 #include <grp.h>
54 #include <sys/ioctl.h>
55 #include <sys/quota.h>
56 #include <sys/time.h>
57 #include <sys/types.h>
58 #include <sys/stat.h>
59 #include <fcntl.h>
60 #include <dirent.h>
61 #include <time.h>
62 #include <ctype.h>
63
64 #include <libcfs/util/string.h>
65 #include <libcfs/util/ioctl.h>
66 #include <libcfs/util/parser.h>
67 #include <lustre/lustreapi.h>
68 #include <lustre_ver.h>
69 #include <lustre_param.h>
70
71 #ifndef ARRAY_SIZE
72 # define ARRAY_SIZE(a) ((sizeof(a)) / (sizeof((a)[0])))
73 #endif /* !ARRAY_SIZE */
74
75 /* all functions */
76 static int lfs_setstripe(int argc, char **argv);
77 static int lfs_find(int argc, char **argv);
78 static int lfs_getstripe(int argc, char **argv);
79 static int lfs_getdirstripe(int argc, char **argv);
80 static int lfs_setdirstripe(int argc, char **argv);
81 static int lfs_rmentry(int argc, char **argv);
82 static int lfs_osts(int argc, char **argv);
83 static int lfs_mdts(int argc, char **argv);
84 static int lfs_df(int argc, char **argv);
85 static int lfs_getname(int argc, char **argv);
86 static int lfs_check(int argc, char **argv);
87 #ifdef HAVE_SYS_QUOTA_H
88 static int lfs_setquota(int argc, char **argv);
89 static int lfs_quota(int argc, char **argv);
90 #endif
91 static int lfs_flushctx(int argc, char **argv);
92 static int lfs_cp(int argc, char **argv);
93 static int lfs_ls(int argc, char **argv);
94 static int lfs_poollist(int argc, char **argv);
95 static int lfs_changelog(int argc, char **argv);
96 static int lfs_changelog_clear(int argc, char **argv);
97 static int lfs_fid2path(int argc, char **argv);
98 static int lfs_path2fid(int argc, char **argv);
99 static int lfs_data_version(int argc, char **argv);
100 static int lfs_hsm_state(int argc, char **argv);
101 static int lfs_hsm_set(int argc, char **argv);
102 static int lfs_hsm_clear(int argc, char **argv);
103 static int lfs_hsm_action(int argc, char **argv);
104 static int lfs_hsm_archive(int argc, char **argv);
105 static int lfs_hsm_restore(int argc, char **argv);
106 static int lfs_hsm_release(int argc, char **argv);
107 static int lfs_hsm_remove(int argc, char **argv);
108 static int lfs_hsm_cancel(int argc, char **argv);
109 static int lfs_swap_layouts(int argc, char **argv);
110 static int lfs_mv(int argc, char **argv);
111 static int lfs_ladvise(int argc, char **argv);
112 static int lfs_list_commands(int argc, char **argv);
113
114 /* Setstripe and migrate share mostly the same parameters */
115 #define SSM_CMD_COMMON(cmd) \
116         "usage: "cmd" [--stripe-count|-c <stripe_count>]\n"             \
117         "                 [--stripe-index|-i <start_ost_idx>]\n"        \
118         "                 [--stripe-size|-S <stripe_size>]\n"           \
119         "                 [--pool|-p <pool_name>]\n"                    \
120         "                 [--ost|-o <ost_indices>]\n"                   \
121         "                 [--component-end|-E <comp_end>]\n"
122
123 #define SSM_HELP_COMMON \
124         "\tstripe_size:  Number of bytes on each OST (0 filesystem default)\n" \
125         "\t              Can be specified with k, m or g (in KB, MB and GB\n" \
126         "\t              respectively)\n"                               \
127         "\tstart_ost_idx: OST index of first stripe (-1 default)\n"     \
128         "\tstripe_count: Number of OSTs to stripe over (0 default, -1 all)\n" \
129         "\tpool_name:    Name of OST pool to use (default none)\n"      \
130         "\tost_indices:  List of OST indices, can be repeated multiple times\n"\
131         "\t              Indices be specified in a format of:\n"        \
132         "\t                -o <ost_1>,<ost_i>-<ost_j>,<ost_n>\n"        \
133         "\t              Or:\n"                                         \
134         "\t                -o <ost_1> -o <ost_i>-<ost_j> -o <ost_n>\n"  \
135         "\t              If --pool is set with --ost, then the OSTs\n"  \
136         "\t              must be the members of the pool."              \
137         "\tcomp_end:     Extent end of the component\n"                 \
138         "\t              Can be specified with k, m or g (in KB, MB and GB\n" \
139         "\t              respectively, -1 for EOF), it must be aligned with\n"\
140         "\t              the stripe_size\n"
141
142 #define SETSTRIPE_USAGE                                         \
143         SSM_CMD_COMMON("setstripe")                             \
144         "                 <directory|filename>\n"               \
145         SSM_HELP_COMMON                                         \
146
147 #define MIGRATE_USAGE                                                   \
148         SSM_CMD_COMMON("migrate  ")                                     \
149         "                 [--block|-b]\n"                               \
150         "                 [--non-block|-n]\n"                           \
151         "                 <filename>\n"                                 \
152         SSM_HELP_COMMON                                                 \
153         "\n"                                                            \
154         "\tblock:        Block file access during data migration (default)\n" \
155         "\tnon-block:    Abort migrations if concurrent access is detected\n" \
156
157 #define SETDIRSTRIPE_USAGE                                      \
158         "               [--mdt-count|-c stripe_count>\n"        \
159         "               [--mdt-index|-i mdt_index]\n"           \
160         "               [--mdt-hash|-H mdt_hash]\n"             \
161         "               [--default|-D] [--mode|-m mode] <dir>\n"        \
162         "\tstripe_count: stripe count of the striped directory\n"       \
163         "\tmdt_index: MDT index of first stripe\n"                      \
164         "\tmdt_hash:  hash type of the striped directory. mdt types:\n" \
165         "       fnv_1a_64 FNV-1a hash algorithm (default)\n"            \
166         "       all_char  sum of characters % MDT_COUNT (not recommended)\n" \
167         "\tdefault_stripe: set default dirstripe of the directory\n"    \
168         "\tmode: the mode of the directory\n"
169
170 static const char       *progname;
171 static bool              file_lease_supported = true;
172
173 /* all available commands */
174 command_t cmdlist[] = {
175         {"setstripe", lfs_setstripe, 0,
176          "Create a new file with a specific striping pattern or\n"
177          "set the default striping pattern on an existing directory or\n"
178          "delete the default striping pattern from an existing directory or\n"
179          "add layout component(s) to an existing composite file or\n"
180          "delete specified component(s) from an existing composite file\n\n"
181          "To delete default striping from an existing directory:\n"
182          "usage: setstripe -d <directory>\n"
183          " or\n"
184          "To delete component(s) from an existing composite file:\n"
185          "usage: setstripe --component-del [--component-id|-I <comp_id>]\n"
186          "                               [--component-flags|-F <comp_flags>]\n"
187          "                               <filename>\n"
188          "\tcomp_id:     Unique component ID\n"
189          "\tcomp_flags:  'init' indicating all instantiated components\n"
190          "\t-I and -F can't be specified at the same time\n"
191          " or\n"
192          "To add component(s) to an existing composite file:\n"
193          SSM_CMD_COMMON("setstripe --component-add")
194          " or\n"
195          "To create a file with specified striping/composite layout:\n"
196          SETSTRIPE_USAGE},
197         {"getstripe", lfs_getstripe, 0,
198          "To list the striping info for a given file or files in a\n"
199          "directory or recursively for all files in a directory tree.\n"
200          "usage: getstripe [--ost|-O <uuid>] [--quiet|-q] [--verbose|-v]\n"
201          "                 [--stripe-count|-c] [--stripe-index|-i]\n"
202          "                 [--pool|-p] [--stripe-size|-S] [--directory|-d]\n"
203          "                 [--mdt|-m] [--recursive|-r] [--raw|-R]\n"
204          "                 [--layout|-L] [--fid|-F] [--generation|-g]\n"
205          "                 [--component-id|-I [comp_id]]\n"
206          "                 [--component-flags [comp_flags]]\n"
207          "                 [--component-count [comp_count]]\n"
208          "                 [--component-start [comp_start]]\n"
209          "                 [--component-end|-E [comp_end]]\n"
210          "                 <directory|filename> ..."},
211         {"setdirstripe", lfs_setdirstripe, 0,
212          "To create a striped directory on a specified MDT. This can only\n"
213          "be done on MDT0 with the right of administrator.\n"
214          "usage: setdirstripe [OPTION] <directory>\n"
215          SETDIRSTRIPE_USAGE},
216         {"getdirstripe", lfs_getdirstripe, 0,
217          "To list the striping info for a given directory\n"
218          "or recursively for all directories in a directory tree.\n"
219          "usage: getdirstripe [--obd|-O <uuid>] [--mdt-count|-c]\n"
220          "                    [--mdt-index|-i] [--mdt-hash|-H]\n"
221          "                    [--recursive|-r] [--default|-D] <dir> ..."},
222         {"mkdir", lfs_setdirstripe, 0,
223          "To create a striped directory on a specified MDT. This can only\n"
224          "be done on MDT0 with the right of administrator.\n"
225          "usage: mkdir [OPTION] <directory>\n"
226          SETDIRSTRIPE_USAGE},
227         {"rm_entry", lfs_rmentry, 0,
228          "To remove the name entry of the remote directory. Note: This\n"
229          "command will only delete the name entry, i.e. the remote directory\n"
230          "will become inaccessable after this command. This can only be done\n"
231          "by the administrator\n"
232          "usage: rm_entry <dir>\n"},
233         {"pool_list", lfs_poollist, 0,
234          "List pools or pool OSTs\n"
235          "usage: pool_list <fsname>[.<pool>] | <pathname>\n"},
236         {"find", lfs_find, 0,
237          "find files matching given attributes recursively in directory tree.\n"
238          "usage: find <directory|filename> ...\n"
239          "     [[!] --atime|-A [+-]N] [[!] --ctime|-C [+-]N]\n"
240          "     [[!] --mtime|-M [+-]N] [[!] --mdt|-m <uuid|index,...>]\n"
241          "     [--maxdepth|-D N] [[!] --name|-n <pattern>]\n"
242          "     [[!] --ost|-O <uuid|index,...>] [--print|-p] [--print0|-P]\n"
243          "     [[!] --size|-s [+-]N[bkMGTPE]]\n"
244          "     [[!] --stripe-count|-c [+-]<stripes>]\n"
245          "     [[!] --stripe-index|-i <index,...>]\n"
246          "     [[!] --stripe-size|-S [+-]N[kMGT]] [[!] --type|-t <filetype>]\n"
247          "     [[!] --gid|-g|--group|-G <gid>|<gname>]\n"
248          "     [[!] --uid|-u|--user|-U <uid>|<uname>] [[!] --pool <pool>]\n"
249          "     [[!] --projid <projid>]\n"
250          "     [[!] --layout|-L released,raid0]\n"
251          "     [[!] --component-count [+-]<comp_cnt>]\n"
252          "     [[!] --component-start [+-]N[kMGTPE]]\n"
253          "     [[!] --component-end|-E [+-]N[kMGTPE]]\n"
254          "     [[!] --component-flags <comp_flags>]\n"
255          "     [[!] --mdt-count|-T [+-]<stripes>]\n"
256          "     [[!] --mdt-hash|-H <hashtype>\n"
257          "\t !: used before an option indicates 'NOT' requested attribute\n"
258          "\t -: used before a value indicates 'AT MOST' requested value\n"
259          "\t +: used before a value indicates 'AT LEAST' requested value\n"
260          "\tmdt-hash:   hash type of the striped directory.\n"
261          "\t            fnv_1a_64 FNV-1a hash algorithm\n"
262          "\t            all_char  sum of characters % MDT_COUNT\n"},
263         {"check", lfs_check, 0,
264          "Display the status of MDS or OSTs (as specified in the command)\n"
265          "or all the servers (MDS and OSTs).\n"
266          "usage: check <osts|mds|servers>"},
267         {"osts", lfs_osts, 0, "list OSTs connected to client "
268          "[for specified path only]\n" "usage: osts [path]"},
269         {"mdts", lfs_mdts, 0, "list MDTs connected to client "
270          "[for specified path only]\n" "usage: mdts [path]"},
271         {"df", lfs_df, 0,
272          "report filesystem disk space usage or inodes usage"
273          "of each MDS and all OSDs or a batch belonging to a specific pool .\n"
274          "Usage: df [-i] [-h] [--lazy|-l] [--pool|-p <fsname>[.<pool>] [path]"},
275         {"getname", lfs_getname, 0, "list instances and specified mount points "
276          "[for specified path only]\n"
277          "Usage: getname [-h]|[path ...] "},
278 #ifdef HAVE_SYS_QUOTA_H
279         {"setquota", lfs_setquota, 0, "Set filesystem quotas.\n"
280          "usage: setquota <-u|-g|-p> <uname>|<uid>|<gname>|<gid>|<projid>\n"
281          "                -b <block-softlimit> -B <block-hardlimit>\n"
282          "                -i <inode-softlimit> -I <inode-hardlimit> <filesystem>\n"
283          "       setquota <-u|--user|-g|--group|-p|--project> <uname>|<uid>|<gname>|<gid>|<projid>\n"
284          "                [--block-softlimit <block-softlimit>]\n"
285          "                [--block-hardlimit <block-hardlimit>]\n"
286          "                [--inode-softlimit <inode-softlimit>]\n"
287          "                [--inode-hardlimit <inode-hardlimit>] <filesystem>\n"
288          "       setquota [-t] <-u|--user|-g|--group|-p|--project>\n"
289          "                [--block-grace <block-grace>]\n"
290          "                [--inode-grace <inode-grace>] <filesystem>\n"
291          "       -b can be used instead of --block-softlimit/--block-grace\n"
292          "       -B can be used instead of --block-hardlimit\n"
293          "       -i can be used instead of --inode-softlimit/--inode-grace\n"
294          "       -I can be used instead of --inode-hardlimit\n\n"
295          "Note: The total quota space will be split into many qunits and\n"
296          "      balanced over all server targets, the minimal qunit size is\n"
297          "      1M bytes for block space and 1K inodes for inode space.\n\n"
298          "      Quota space rebalancing process will stop when this mininum\n"
299          "      value is reached. As a result, quota exceeded can be returned\n"
300          "      while many targets still have 1MB or 1K inodes of spare\n"
301          "      quota space."},
302         {"quota", lfs_quota, 0, "Display disk usage and limits.\n"
303          "usage: quota [-q] [-v] [-h] [-o <obd_uuid>|-i <mdt_idx>|-I "
304                        "<ost_idx>]\n"
305          "             [<-u|-g|-p> <uname>|<uid>|<gname>|<gid>|<projid>] <filesystem>\n"
306          "       quota [-o <obd_uuid>|-i <mdt_idx>|-I <ost_idx>] -t <-u|-g|-p> <filesystem>"},
307 #endif
308         {"flushctx", lfs_flushctx, 0, "Flush security context for current user.\n"
309          "usage: flushctx [-k] [mountpoint...]"},
310         {"cp", lfs_cp, 0,
311          "Remote user copy files and directories.\n"
312          "usage: cp [OPTION]... [-T] SOURCE DEST\n\tcp [OPTION]... SOURCE... DIRECTORY\n\tcp [OPTION]... -t DIRECTORY SOURCE..."},
313         {"ls", lfs_ls, 0,
314          "Remote user list directory contents.\n"
315          "usage: ls [OPTION]... [FILE]..."},
316         {"changelog", lfs_changelog, 0,
317          "Show the metadata changes on an MDT."
318          "\nusage: changelog <mdtname> [startrec [endrec]]"},
319         {"changelog_clear", lfs_changelog_clear, 0,
320          "Indicate that old changelog records up to <endrec> are no longer of "
321          "interest to consumer <id>, allowing the system to free up space.\n"
322          "An <endrec> of 0 means all records.\n"
323          "usage: changelog_clear <mdtname> <id> <endrec>"},
324         {"fid2path", lfs_fid2path, 0,
325          "Resolve the full path(s) for given FID(s). For a specific hardlink "
326          "specify link number <linkno>.\n"
327         /* "For a historical link name, specify changelog record <recno>.\n" */
328          "usage: fid2path [--link <linkno>] <fsname|rootpath> <fid> ..."
329                 /* [ --rec <recno> ] */ },
330         {"path2fid", lfs_path2fid, 0, "Display the fid(s) for a given path(s).\n"
331          "usage: path2fid [--parents] <path> ..."},
332         {"data_version", lfs_data_version, 0, "Display file data version for "
333          "a given path.\n" "usage: data_version -[n|r|w] <path>"},
334         {"hsm_state", lfs_hsm_state, 0, "Display the HSM information (states, "
335          "undergoing actions) for given files.\n usage: hsm_state <file> ..."},
336         {"hsm_set", lfs_hsm_set, 0, "Set HSM user flag on specified files.\n"
337          "usage: hsm_set [--norelease] [--noarchive] [--dirty] [--exists] "
338          "[--archived] [--lost] <file> ..."},
339         {"hsm_clear", lfs_hsm_clear, 0, "Clear HSM user flag on specified "
340          "files.\n"
341          "usage: hsm_clear [--norelease] [--noarchive] [--dirty] [--exists] "
342          "[--archived] [--lost] <file> ..."},
343         {"hsm_action", lfs_hsm_action, 0, "Display current HSM request for "
344          "given files.\n" "usage: hsm_action <file> ..."},
345         {"hsm_archive", lfs_hsm_archive, 0,
346          "Archive file to external storage.\n"
347          "usage: hsm_archive [--filelist FILELIST] [--data DATA] [--archive NUM] "
348          "<file> ..."},
349         {"hsm_restore", lfs_hsm_restore, 0,
350          "Restore file from external storage.\n"
351          "usage: hsm_restore [--filelist FILELIST] [--data DATA] <file> ..."},
352         {"hsm_release", lfs_hsm_release, 0,
353          "Release files from Lustre.\n"
354          "usage: hsm_release [--filelist FILELIST] [--data DATA] <file> ..."},
355         {"hsm_remove", lfs_hsm_remove, 0,
356          "Remove file copy from external storage.\n"
357          "usage: hsm_remove [--filelist FILELIST] [--data DATA]\n"
358          "                  [--mntpath MOUNTPATH] [--archive NUM] <file|FID> ...\n"
359          "\n"
360          "Note: To remove files from the archive that have been deleted on\n"
361          "Lustre, set mntpath and optionally archive. In that case, all the\n"
362          "positional arguments and entries in the file list must be FIDs."
363         },
364         {"hsm_cancel", lfs_hsm_cancel, 0,
365          "Cancel requests related to specified files.\n"
366          "usage: hsm_cancel [--filelist FILELIST] [--data DATA] <file> ..."},
367         {"swap_layouts", lfs_swap_layouts, 0, "Swap layouts between 2 files.\n"
368          "usage: swap_layouts <path1> <path2>"},
369         {"migrate", lfs_setstripe, 0,
370          "migrate a directory between MDTs.\n"
371          "usage: migrate --mdt-index <mdt_idx> [--verbose|-v] "
372          "<directory>\n"
373          "\tmdt_idx:      index of the destination MDT\n"
374          "\n"
375          "migrate file objects from one OST "
376          "layout\nto another (may be not safe with concurent writes).\n"
377          "usage: migrate  "
378          "[--stripe-count|-c] <stripe_count>\n"
379          "              [--stripe-index|-i] <start_ost_index>\n"
380          "              [--stripe-size|-S] <stripe_size>\n"
381          "              [--pool|-p] <pool_name>\n"
382          "              [--ost-list|-o] <ost_indices>\n"
383          "              [--block|-b]\n"
384          "              [--non-block|-n]\n"
385          "              <file|directory>\n"
386          "\tstripe_count:     number of OSTs to stripe a file over\n"
387          "\tstripe_ost_index: index of the first OST to stripe a file over\n"
388          "\tstripe_size:      number of bytes to store before moving to the next OST\n"
389          "\tpool_name:        name of the predefined pool of OSTs\n"
390          "\tost_indices:      OSTs to stripe over, in order\n"
391          "\tblock:            wait for the operation to return before continuing\n"
392          "\tnon-block:        do not wait for the operation to return.\n"},
393         {"mv", lfs_mv, 0,
394          "To move directories between MDTs. This command is deprecated, "
395          "use \"migrate\" instead.\n"
396          "usage: mv <directory|filename> [--mdt-index|-M] <mdt_index> "
397          "[--verbose|-v]\n"},
398         {"ladvise", lfs_ladvise, 0,
399          "Provide servers with advice about access patterns for a file.\n"
400          "usage: ladvise [--advice|-a ADVICE] [--start|-s START[kMGT]]\n"
401          "               [--background|-b]\n"
402          "               {[--end|-e END[kMGT]] | [--length|-l LENGTH[kMGT]]}\n"
403          "               <file> ...\n"},
404         {"help", Parser_help, 0, "help"},
405         {"exit", Parser_quit, 0, "quit"},
406         {"quit", Parser_quit, 0, "quit"},
407         {"--version", Parser_version, 0,
408          "output build version of the utility and exit"},
409         {"--list-commands", lfs_list_commands, 0,
410          "list commands supported by the utility and exit"},
411         { 0, 0, 0, NULL }
412 };
413
414
415 #define MIGRATION_NONBLOCK      1
416
417 static int check_hashtype(const char *hashtype)
418 {
419         int i;
420
421         for (i = LMV_HASH_TYPE_ALL_CHARS; i < LMV_HASH_TYPE_MAX; i++)
422                 if (strcmp(hashtype, mdt_hash_name[i]) == 0)
423                         return i;
424
425         return 0;
426 }
427
428 /**
429  * Internal helper for migrate_copy_data(). Check lease and report error if
430  * need be.
431  *
432  * \param[in]  fd           File descriptor on which to check the lease.
433  * \param[out] lease_broken Set to true if the lease was broken.
434  * \param[in]  group_locked Whether a group lock was taken or not.
435  * \param[in]  path         Name of the file being processed, for error
436  *                          reporting
437  *
438  * \retval 0       Migration can keep on going.
439  * \retval -errno  Error occurred, abort migration.
440  */
441 static int check_lease(int fd, bool *lease_broken, bool group_locked,
442                        const char *path)
443 {
444         int rc;
445
446         if (!file_lease_supported)
447                 return 0;
448
449         rc = llapi_lease_check(fd);
450         if (rc > 0)
451                 return 0; /* llapi_check_lease returns > 0 on success. */
452
453         if (!group_locked) {
454                 fprintf(stderr, "%s: cannot migrate '%s': file busy\n",
455                         progname, path);
456                 rc = rc ? rc : -EAGAIN;
457         } else {
458                 fprintf(stderr, "%s: external attempt to access file '%s' "
459                         "blocked until migration ends.\n", progname, path);
460                 rc = 0;
461         }
462         *lease_broken = true;
463         return rc;
464 }
465
466 static int migrate_copy_data(int fd_src, int fd_dst, size_t buf_size,
467                              bool group_locked, const char *fname)
468 {
469         void    *buf = NULL;
470         ssize_t  rsize = -1;
471         ssize_t  wsize = 0;
472         size_t   rpos = 0;
473         size_t   wpos = 0;
474         off_t    bufoff = 0;
475         int      rc;
476         bool     lease_broken = false;
477
478         /* Use a page-aligned buffer for direct I/O */
479         rc = posix_memalign(&buf, getpagesize(), buf_size);
480         if (rc != 0)
481                 return -rc;
482
483         while (1) {
484                 /* read new data only if we have written all
485                  * previously read data */
486                 if (wpos == rpos) {
487                         if (!lease_broken) {
488                                 rc = check_lease(fd_src, &lease_broken,
489                                                  group_locked, fname);
490                                 if (rc < 0)
491                                         goto out;
492                         }
493                         rsize = read(fd_src, buf, buf_size);
494                         if (rsize < 0) {
495                                 rc = -errno;
496                                 fprintf(stderr, "%s: %s: read failed: %s\n",
497                                         progname, fname, strerror(-rc));
498                                 goto out;
499                         }
500                         rpos += rsize;
501                         bufoff = 0;
502                 }
503                 /* eof ? */
504                 if (rsize == 0)
505                         break;
506
507                 wsize = write(fd_dst, buf + bufoff, rpos - wpos);
508                 if (wsize < 0) {
509                         rc = -errno;
510                         fprintf(stderr,
511                                 "%s: %s: write failed on volatile: %s\n",
512                                 progname, fname, strerror(-rc));
513                         goto out;
514                 }
515                 wpos += wsize;
516                 bufoff += wsize;
517         }
518
519         rc = fsync(fd_dst);
520         if (rc < 0) {
521                 rc = -errno;
522                 fprintf(stderr, "%s: %s: fsync failed: %s\n",
523                         progname, fname, strerror(-rc));
524         }
525
526 out:
527         free(buf);
528         return rc;
529 }
530
531 static int migrate_copy_timestamps(int fdv, const struct stat *st)
532 {
533         struct timeval  tv[2] = {
534                 {.tv_sec = st->st_atime},
535                 {.tv_sec = st->st_mtime}
536         };
537
538         return futimes(fdv, tv);
539 }
540
541 static int migrate_block(int fd, int fdv, const struct stat *st,
542                          size_t buf_size, const char *name)
543 {
544         __u64   dv1;
545         int     gid;
546         int     rc;
547         int     rc2;
548
549         rc = llapi_get_data_version(fd, &dv1, LL_DV_RD_FLUSH);
550         if (rc < 0) {
551                 fprintf(stderr, "%s: %s: cannot get dataversion: %s\n",
552                         progname, name, strerror(-rc));
553                 return rc;
554         }
555
556         do
557                 gid = random();
558         while (gid == 0);
559
560         /* The grouplock blocks all concurrent accesses to the file.
561          * It has to be taken after llapi_get_data_version as it would
562          * block it too. */
563         rc = llapi_group_lock(fd, gid);
564         if (rc < 0) {
565                 fprintf(stderr, "%s: %s: cannot get group lock: %s\n",
566                         progname, name, strerror(-rc));
567                 return rc;
568         }
569
570         rc = migrate_copy_data(fd, fdv, buf_size, true, name);
571         if (rc < 0) {
572                 fprintf(stderr, "%s: %s: data copy failed\n", progname, name);
573                 goto out_unlock;
574         }
575
576         /* Make sure we keep original atime/mtime values */
577         rc = migrate_copy_timestamps(fdv, st);
578         if (rc < 0) {
579                 fprintf(stderr, "%s: %s: timestamp copy failed\n",
580                         progname, name);
581                 goto out_unlock;
582         }
583
584         /* swap layouts
585          * for a migration we need to check data version on file did
586          * not change.
587          *
588          * Pass in gid=0 since we already own grouplock. */
589         rc = llapi_fswap_layouts_grouplock(fd, fdv, dv1, 0, 0,
590                                            SWAP_LAYOUTS_CHECK_DV1);
591         if (rc == -EAGAIN) {
592                 fprintf(stderr, "%s: %s: dataversion changed during copy, "
593                         "migration aborted\n", progname, name);
594                 goto out_unlock;
595         } else if (rc < 0) {
596                 fprintf(stderr, "%s: %s: cannot swap layouts: %s\n", progname,
597                         name, strerror(-rc));
598                 goto out_unlock;
599         }
600
601 out_unlock:
602         rc2 = llapi_group_unlock(fd, gid);
603         if (rc2 < 0 && rc == 0) {
604                 fprintf(stderr, "%s: %s: putting group lock failed: %s\n",
605                         progname, name, strerror(-rc2));
606                 rc = rc2;
607         }
608
609         return rc;
610 }
611
612 static int migrate_nonblock(int fd, int fdv, const struct stat *st,
613                             size_t buf_size, const char *name)
614 {
615         __u64   dv1;
616         __u64   dv2;
617         int     rc;
618
619         rc = llapi_get_data_version(fd, &dv1, LL_DV_RD_FLUSH);
620         if (rc < 0) {
621                 fprintf(stderr, "%s: %s: cannot get data version: %s\n",
622                         progname, name, strerror(-rc));
623                 return rc;
624         }
625
626         rc = migrate_copy_data(fd, fdv, buf_size, false, name);
627         if (rc < 0) {
628                 fprintf(stderr, "%s: %s: data copy failed\n", progname, name);
629                 return rc;
630         }
631
632         rc = llapi_get_data_version(fd, &dv2, LL_DV_RD_FLUSH);
633         if (rc != 0) {
634                 fprintf(stderr, "%s: %s: cannot get data version: %s\n",
635                         progname, name, strerror(-rc));
636                 return rc;
637         }
638
639         if (dv1 != dv2) {
640                 rc = -EAGAIN;
641                 fprintf(stderr, "%s: %s: data version changed during "
642                                 "migration\n",
643                         progname, name);
644                 return rc;
645         }
646
647         /* Make sure we keep original atime/mtime values */
648         rc = migrate_copy_timestamps(fdv, st);
649         if (rc < 0) {
650                 fprintf(stderr, "%s: %s: timestamp copy failed\n",
651                         progname, name);
652                 return rc;
653         }
654
655         /* Atomically put lease, swap layouts and close.
656          * for a migration we need to check data version on file did
657          * not change. */
658         rc = llapi_fswap_layouts(fd, fdv, 0, 0, SWAP_LAYOUTS_CLOSE);
659         if (rc < 0) {
660                 fprintf(stderr, "%s: %s: cannot swap layouts: %s\n",
661                         progname, name, strerror(-rc));
662                 return rc;
663         }
664
665         return 0;
666 }
667
668 static int lfs_component_set(char *fname, int comp_id, __u32 flags)
669 {
670         return -ENOTSUP;
671 }
672
673 static int lfs_component_del(char *fname, __u32 comp_id, __u32 flags)
674 {
675         int     rc = 0;
676
677         if (flags != 0 && comp_id != 0)
678                 return -EINVAL;
679
680         /* LCME_FL_INIT is the only supported flag in PFL */
681         if (flags != 0) {
682                 if (flags & ~LCME_KNOWN_FLAGS) {
683                         fprintf(stderr, "Invalid component flags %#x\n", flags);
684                         return -EINVAL;
685                 }
686                 comp_id = LCME_ID_NONE | flags;
687         } else if (comp_id > LCME_ID_MAX) {
688                 fprintf(stderr, "Invalid component id %u\n", comp_id);
689                 return -EINVAL;
690         }
691
692         rc = llapi_layout_file_comp_del(fname, comp_id);
693         if (rc)
694                 fprintf(stderr, "Delete component %#x from %s failed. %s\n",
695                         comp_id, fname, strerror(errno));
696         return rc;
697 }
698
699 static int lfs_component_add(char *fname, struct llapi_layout *layout)
700 {
701         int     rc;
702
703         if (layout == NULL)
704                 return -EINVAL;
705
706         rc = llapi_layout_file_comp_add(fname, layout);
707         if (rc)
708                 fprintf(stderr, "Add layout component(s) to %s failed. %s\n",
709                         fname, strerror(errno));
710         return rc;
711 }
712
713 static int lfs_component_create(char *fname, int open_flags, mode_t open_mode,
714                                 struct llapi_layout *layout)
715 {
716         struct stat     st;
717         int     fd;
718
719         if (layout == NULL)
720                 return -EINVAL;
721
722         fd = lstat(fname, &st);
723         if (fd == 0 && S_ISDIR(st.st_mode))
724                 open_flags = O_DIRECTORY | O_RDONLY;
725
726         fd = llapi_layout_file_open(fname, open_flags, open_mode, layout);
727         if (fd < 0)
728                 fprintf(stderr, "%s %s failed. %s\n",
729                         S_ISDIR(st.st_mode) ?
730                                 "Set default composite layout to " :
731                                 "Create composite file",
732                         fname, strerror(errno));
733         return fd;
734 }
735
736 static int lfs_migrate(char *name, __u64 migration_flags,
737                        struct llapi_stripe_param *param,
738                        struct llapi_layout *layout)
739 {
740         int                      fd = -1;
741         int                      fdv = -1;
742         char                     parent[PATH_MAX];
743         int                      mdt_index;
744         int                      random_value;
745         char                     volatile_file[sizeof(parent) +
746                                                LUSTRE_VOLATILE_HDR_LEN +
747                                                2 * sizeof(mdt_index) +
748                                                2 * sizeof(random_value) + 4];
749         char                    *ptr;
750         int                      rc;
751         struct lov_user_md      *lum = NULL;
752         int                      lum_size;
753         int                      buf_size = 1024 * 1024 * 4;
754         bool                     have_lease_rdlck = false;
755         struct stat              st;
756         struct stat              stv;
757
758         /* find the right size for the IO and allocate the buffer */
759         lum_size = lov_user_md_size(LOV_MAX_STRIPE_COUNT, LOV_USER_MAGIC_V3);
760         lum = malloc(lum_size);
761         if (lum == NULL) {
762                 rc = -ENOMEM;
763                 goto free;
764         }
765
766         rc = llapi_file_get_stripe(name, lum);
767         /* failure can happen for many reasons and some may be not real errors
768          * (eg: no stripe)
769          * in case of a real error, a later call will fail with better
770          * error management */
771         if (rc == 0) {
772                 if ((lum->lmm_magic == LOV_USER_MAGIC_V1 ||
773                      lum->lmm_magic == LOV_USER_MAGIC_V3) &&
774                     lum->lmm_stripe_size != 0)
775                         buf_size = lum->lmm_stripe_size;
776         }
777
778         /* open file, direct io */
779         /* even if the file is only read, WR mode is nedeed to allow
780          * layout swap on fd */
781         fd = open(name, O_RDWR | O_DIRECT);
782         if (fd == -1) {
783                 rc = -errno;
784                 fprintf(stderr, "%s: %s: cannot open: %s\n", progname, name,
785                         strerror(-rc));
786                 goto free;
787         }
788
789         if (file_lease_supported) {
790                 rc = llapi_lease_get(fd, LL_LEASE_RDLCK);
791                 if (rc == -EOPNOTSUPP) {
792                         /* Older servers do not support file lease.
793                          * Disable related checks. This opens race conditions
794                          * as explained in LU-4840 */
795                         file_lease_supported = false;
796                 } else if (rc < 0) {
797                         fprintf(stderr, "%s: %s: cannot get open lease: %s\n",
798                                 progname, name, strerror(-rc));
799                         goto error;
800                 } else {
801                         have_lease_rdlck = true;
802                 }
803         }
804
805         /* search for file directory pathname */
806         if (strlen(name) > sizeof(parent)-1) {
807                 rc = -E2BIG;
808                 goto error;
809         }
810         strncpy(parent, name, sizeof(parent));
811         ptr = strrchr(parent, '/');
812         if (ptr == NULL) {
813                 if (getcwd(parent, sizeof(parent)) == NULL) {
814                         rc = -errno;
815                         goto error;
816                 }
817         } else {
818                 if (ptr == parent)
819                         strcpy(parent, "/");
820                 else
821                         *ptr = '\0';
822         }
823
824         rc = llapi_file_fget_mdtidx(fd, &mdt_index);
825         if (rc < 0) {
826                 fprintf(stderr, "%s: %s: cannot get MDT index: %s\n",
827                         progname, name, strerror(-rc));
828                 goto error;
829         }
830
831         do {
832                 int open_flags = O_WRONLY | O_CREAT | O_EXCL | O_NOFOLLOW;
833                 mode_t open_mode = S_IRUSR | S_IWUSR;
834
835                 random_value = random();
836                 rc = snprintf(volatile_file, sizeof(volatile_file),
837                               "%s/%s:%.4X:%.4X", parent, LUSTRE_VOLATILE_HDR,
838                               mdt_index, random_value);
839                 if (rc >= sizeof(volatile_file)) {
840                         rc = -E2BIG;
841                         goto error;
842                 }
843
844                 /* create, open a volatile file, use caching (ie no directio) */
845                 if (param != NULL)
846                         fdv = llapi_file_open_param(volatile_file, open_flags,
847                                                     open_mode, param);
848                 else if (layout != NULL)
849                         fdv = lfs_component_create(volatile_file, open_flags,
850                                                    open_mode, layout);
851                 else
852                         fdv = -EINVAL;
853         } while (fdv == -EEXIST);
854
855         if (fdv < 0) {
856                 rc = fdv;
857                 fprintf(stderr, "%s: %s: cannot create volatile file in"
858                                 " directory: %s\n",
859                         progname, parent, strerror(-rc));
860                 goto error;
861         }
862
863         /* In case the MDT does not support creation of volatile files
864          * we should try to unlink it. */
865         (void)unlink(volatile_file);
866
867         /* Not-owner (root?) special case.
868          * Need to set owner/group of volatile file like original.
869          * This will allow to pass related check during layout_swap.
870          */
871         rc = fstat(fd, &st);
872         if (rc != 0) {
873                 rc = -errno;
874                 fprintf(stderr, "%s: %s: cannot stat: %s\n", progname, name,
875                         strerror(errno));
876                 goto error;
877         }
878         rc = fstat(fdv, &stv);
879         if (rc != 0) {
880                 rc = -errno;
881                 fprintf(stderr, "%s: %s: cannot stat: %s\n", progname,
882                         volatile_file, strerror(errno));
883                 goto error;
884         }
885         if (st.st_uid != stv.st_uid || st.st_gid != stv.st_gid) {
886                 rc = fchown(fdv, st.st_uid, st.st_gid);
887                 if (rc != 0) {
888                         rc = -errno;
889                         fprintf(stderr, "%s: %s: cannot chown: %s\n", progname,
890                                 name, strerror(errno));
891                         goto error;
892                 }
893         }
894
895         if (migration_flags & MIGRATION_NONBLOCK && file_lease_supported) {
896                 rc = migrate_nonblock(fd, fdv, &st, buf_size, name);
897                 if (rc == 0) {
898                         have_lease_rdlck = false;
899                         fdv = -1; /* The volatile file is closed as we put the
900                                    * lease in non-blocking mode. */
901                 }
902         } else {
903                 /* Blocking mode (forced if servers do not support file lease).
904                  * It is also the default mode, since we cannot distinguish
905                  * between a broken lease and a server that does not support
906                  * atomic swap/close (LU-6785) */
907                 rc = migrate_block(fd, fdv, &st, buf_size, name);
908         }
909
910 error:
911         if (have_lease_rdlck)
912                 llapi_lease_put(fd);
913
914         if (fd >= 0)
915                 close(fd);
916
917         if (fdv >= 0)
918                 close(fdv);
919
920 free:
921         if (lum)
922                 free(lum);
923
924         return rc;
925 }
926
927 /**
928  * Parse a string containing an OST index list into an array of integers.
929  *
930  * The input string contains a comma delimited list of individual
931  * indices and ranges, for example "1,2-4,7". Add the indices into the
932  * \a osts array and remove duplicates.
933  *
934  * \param[out] osts    array to store indices in
935  * \param[in] size     size of \a osts array
936  * \param[in] offset   starting index in \a osts
937  * \param[in] arg      string containing OST index list
938  *
939  * \retval positive    number of indices in \a osts
940  * \retval -EINVAL     unable to parse \a arg
941  */
942 static int parse_targets(__u32 *osts, int size, int offset, char *arg)
943 {
944         int rc;
945         int nr = offset;
946         int slots = size - offset;
947         char *ptr = NULL;
948         bool end_of_loop;
949
950         if (arg == NULL)
951                 return -EINVAL;
952
953         end_of_loop = false;
954         while (!end_of_loop) {
955                 int start_index;
956                 int end_index;
957                 int i;
958                 char *endptr = NULL;
959
960                 rc = -EINVAL;
961
962                 ptr = strchrnul(arg, ',');
963
964                 end_of_loop = *ptr == '\0';
965                 *ptr = '\0';
966
967                 start_index = strtol(arg, &endptr, 0);
968                 if (endptr == arg) /* no data at all */
969                         break;
970                 if (*endptr != '-' && *endptr != '\0') /* has invalid data */
971                         break;
972                 if (start_index < 0)
973                         break;
974
975                 end_index = start_index;
976                 if (*endptr == '-') {
977                         end_index = strtol(endptr + 1, &endptr, 0);
978                         if (*endptr != '\0')
979                                 break;
980                         if (end_index < start_index)
981                                 break;
982                 }
983
984                 for (i = start_index; i <= end_index && slots > 0; i++) {
985                         int j;
986
987                         /* remove duplicate */
988                         for (j = 0; j < offset; j++) {
989                                 if (osts[j] == i)
990                                         break;
991                         }
992                         if (j == offset) { /* no duplicate */
993                                 osts[nr++] = i;
994                                 --slots;
995                         }
996                 }
997                 if (slots == 0 && i < end_index)
998                         break;
999
1000                 *ptr = ',';
1001                 arg = ++ptr;
1002                 offset = nr;
1003                 rc = 0;
1004         }
1005         if (!end_of_loop && ptr != NULL)
1006                 *ptr = ',';
1007
1008         return rc < 0 ? rc : nr;
1009 }
1010
1011 static int verify_pool_name(char *prog_name, char *pool_name)
1012 {
1013         char    *ptr;
1014         int      rc;
1015
1016         if (pool_name == NULL)
1017                 return 0;
1018
1019         ptr = strchr(pool_name, '.');
1020         if (ptr == NULL) {
1021                 ptr = pool_name;
1022         } else {
1023                 if (ptr == pool_name) {
1024                         fprintf(stderr, "error: %s: fsname is empty "
1025                                 "in pool name '%s'\n",
1026                                 prog_name, pool_name);
1027                         return -EINVAL;
1028                 }
1029                 ++ptr;
1030         }
1031
1032         rc = lustre_is_poolname_valid(ptr, 1, LOV_MAXPOOLNAME);
1033         if (rc == -1) {
1034                 fprintf(stderr, "error: %s: poolname '%s' is empty\n",
1035                         prog_name, pool_name);
1036                 return -EINVAL;
1037         } else if (rc == -2) {
1038                 fprintf(stderr, "error: %s: pool name '%s' is too long "
1039                         "(max is %d characters)\n",
1040                         prog_name, pool_name, LOV_MAXPOOLNAME);
1041                 return -EINVAL;
1042         } else if (rc > 0) {
1043                 fprintf(stderr, "error: %s: char '%c' not allowed in "
1044                         "pool name '%s'\n",
1045                         prog_name, rc, pool_name);
1046                 return -EINVAL;
1047         }
1048         return rc;
1049 }
1050
1051 struct lfs_setstripe_args {
1052         unsigned long long       lsa_comp_end;
1053         unsigned long long       lsa_stripe_size;
1054         int                      lsa_stripe_count;
1055         int                      lsa_stripe_off;
1056         __u32                    lsa_comp_flags;
1057         int                      lsa_nr_osts;
1058         __u32                   *lsa_osts;
1059         char                    *lsa_pool_name;
1060 };
1061
1062 static inline void setstripe_args_init(struct lfs_setstripe_args *lsa)
1063 {
1064         memset(lsa, 0, sizeof(*lsa));
1065         lsa->lsa_stripe_off = -1;
1066 }
1067
1068 static inline bool setstripe_args_specified(struct lfs_setstripe_args *lsa)
1069 {
1070         return (lsa->lsa_stripe_size != 0 || lsa->lsa_stripe_count != 0 ||
1071                 lsa->lsa_stripe_off != -1 || lsa->lsa_pool_name != NULL ||
1072                 lsa->lsa_comp_end != 0);
1073 }
1074
1075 static int comp_args_to_layout(struct llapi_layout **composite,
1076                                struct lfs_setstripe_args *lsa)
1077 {
1078         struct llapi_layout *layout = *composite;
1079         uint64_t prev_end = 0;
1080         int i = 0, rc;
1081
1082         if (layout == NULL) {
1083                 layout = llapi_layout_alloc();
1084                 if (layout == NULL) {
1085                         fprintf(stderr, "Alloc llapi_layout failed. %s\n",
1086                                 strerror(errno));
1087                         return -ENOMEM;
1088                 }
1089                 *composite = layout;
1090         } else {
1091                 uint64_t start;
1092
1093                 /* Get current component extent, current component
1094                  * must be the tail component. */
1095                 rc = llapi_layout_comp_extent_get(layout, &start, &prev_end);
1096                 if (rc) {
1097                         fprintf(stderr, "Get comp extent failed. %s\n",
1098                                 strerror(errno));
1099                         return rc;
1100                 }
1101
1102                 rc = llapi_layout_comp_add(layout);
1103                 if (rc) {
1104                         fprintf(stderr, "Add component failed. %s\n",
1105                                 strerror(errno));
1106                         return rc;
1107                 }
1108         }
1109
1110         rc = llapi_layout_comp_extent_set(layout, prev_end, lsa->lsa_comp_end);
1111         if (rc) {
1112                 fprintf(stderr, "Set extent [%lu, %llu) failed. %s\n",
1113                         prev_end, lsa->lsa_comp_end, strerror(errno));
1114                 return rc;
1115         }
1116
1117         if (lsa->lsa_stripe_size != 0) {
1118                 rc = llapi_layout_stripe_size_set(layout,
1119                                                   lsa->lsa_stripe_size);
1120                 if (rc) {
1121                         fprintf(stderr, "Set stripe size %llu failed. %s\n",
1122                                 lsa->lsa_stripe_size, strerror(errno));
1123                         return rc;
1124                 }
1125         }
1126
1127         if (lsa->lsa_stripe_count != 0) {
1128                 rc = llapi_layout_stripe_count_set(layout,
1129                                                    lsa->lsa_stripe_count == -1 ?
1130                                                    LLAPI_LAYOUT_WIDE :
1131                                                    lsa->lsa_stripe_count);
1132                 if (rc) {
1133                         fprintf(stderr, "Set stripe count %d failed. %s\n",
1134                                 lsa->lsa_stripe_count, strerror(errno));
1135                         return rc;
1136                 }
1137         }
1138
1139         if (lsa->lsa_pool_name != NULL) {
1140                 rc = llapi_layout_pool_name_set(layout, lsa->lsa_pool_name);
1141                 if (rc) {
1142                         fprintf(stderr, "Set pool name: %s failed. %s\n",
1143                                 lsa->lsa_pool_name, strerror(errno));
1144                         return rc;
1145                 }
1146         }
1147
1148         if (lsa->lsa_nr_osts > 0) {
1149                 if (lsa->lsa_stripe_count > 0 &&
1150                     lsa->lsa_nr_osts != lsa->lsa_stripe_count) {
1151                         fprintf(stderr, "stripe_count(%d) != nr_osts(%d)\n",
1152                                 lsa->lsa_stripe_count, lsa->lsa_nr_osts);
1153                         return -EINVAL;
1154                 }
1155                 for (i = 0; i < lsa->lsa_nr_osts; i++) {
1156                         rc = llapi_layout_ost_index_set(layout, i,
1157                                                         lsa->lsa_osts[i]);
1158                         if (rc)
1159                                 break;
1160                 }
1161         } else if (lsa->lsa_stripe_off != -1) {
1162                 rc = llapi_layout_ost_index_set(layout, 0, lsa->lsa_stripe_off);
1163         }
1164         if (rc) {
1165                 fprintf(stderr, "Set ost index %d failed. %s\n",
1166                         i, strerror(errno));
1167                 return rc;
1168         }
1169
1170         return 0;
1171 }
1172
1173 /* In 'lfs setstripe --component-add' mode, we need to fetch the extent
1174  * end of the last component in the existing file, and adjust the
1175  * first extent start of the components to be added accordingly. */
1176 static int adjust_first_extent(char *fname, struct llapi_layout *layout)
1177 {
1178         struct llapi_layout *head;
1179         uint64_t start, end, stripe_size, prev_end = 0;
1180         int rc;
1181
1182         if (layout == NULL)
1183                 return -EINVAL;
1184
1185         head = llapi_layout_get_by_path(fname, 0);
1186         if (head == NULL) {
1187                 fprintf(stderr, "Read layout from %s failed. %s\n",
1188                         fname, strerror(errno));
1189                 return -EINVAL;
1190         }
1191
1192         /* Current component of 'head' should be tail of component list. */
1193         rc = llapi_layout_comp_extent_get(head, &start, &prev_end);
1194         if (rc) {
1195                 fprintf(stderr, "Get prev extent failed. %s\n",
1196                         strerror(errno));
1197                 llapi_layout_free(head);
1198                 return rc;
1199         }
1200
1201         llapi_layout_free(head);
1202
1203         /* Make sure we use the first component of the layout to be added. */
1204         rc = llapi_layout_comp_use(layout, LLAPI_LAYOUT_COMP_USE_FIRST);
1205         if (rc < 0) {
1206                 fprintf(stderr, "Move component cursor failed. %s\n",
1207                         strerror(errno));
1208                 return rc;
1209         }
1210
1211         rc = llapi_layout_comp_extent_get(layout, &start, &end);
1212         if (rc) {
1213                 fprintf(stderr, "Get extent failed. %s\n", strerror(errno));
1214                 return rc;
1215         }
1216
1217         if (start > prev_end || end <= prev_end) {
1218                 fprintf(stderr, "First extent to be set [%lu, %lu) isn't "
1219                         "adjacent with the existing file extent end: %lu\n",
1220                         start, end, prev_end);
1221                 return -EINVAL;
1222         }
1223
1224         rc = llapi_layout_stripe_size_get(layout, &stripe_size);
1225         if (rc) {
1226                 fprintf(stderr, "Get stripe size failed. %s\n",
1227                         strerror(errno));
1228                 return rc;
1229         }
1230
1231         if (stripe_size != LLAPI_LAYOUT_DEFAULT &&
1232             (prev_end & (stripe_size - 1))) {
1233                 fprintf(stderr, "Stripe size %lu not aligned with %lu\n",
1234                         stripe_size, prev_end);
1235                 return -EINVAL;
1236         }
1237
1238         rc = llapi_layout_comp_extent_set(layout, prev_end, end);
1239         if (rc) {
1240                 fprintf(stderr, "Set component extent [%lu, %lu) failed. %s\n",
1241                         prev_end, end, strerror(errno));
1242                 return rc;
1243         }
1244
1245         return 0;
1246 }
1247
1248 static int comp_name2flags(__u32 *flags, char *name)
1249 {
1250         char *ptr;
1251
1252         if (name == NULL)
1253                 return -EINVAL;
1254
1255         *flags = 0;
1256         for (ptr = name; ; ptr = NULL) {
1257                 char *flg = strtok(ptr, ",");
1258                 if (flg == NULL)
1259                         break;
1260                 if (strcmp(flg, "init") == 0)
1261                         *flags |= LCME_FL_INIT;
1262                 else
1263                         return -EINVAL;
1264         }
1265         return (*flags == 0) ? -EINVAL : 0;
1266 }
1267
1268 enum {
1269         LFS_POOL_OPT = 3,
1270         LFS_COMP_COUNT_OPT,
1271         LFS_COMP_START_OPT,
1272         LFS_COMP_FLAGS_OPT,
1273         LFS_COMP_DEL_OPT,
1274         LFS_COMP_SET_OPT,
1275         LFS_COMP_ADD_OPT,
1276         LFS_PROJID_OPT,
1277 };
1278
1279 /* functions */
1280 static int lfs_setstripe(int argc, char **argv)
1281 {
1282         struct lfs_setstripe_args        lsa;
1283         struct llapi_stripe_param       *param = NULL;
1284         struct find_param                migrate_mdt_param = {
1285                 .fp_max_depth = -1,
1286                 .fp_mdt_index = -1,
1287         };
1288         char                            *fname;
1289         int                              result;
1290         int                              result2 = 0;
1291         char                            *end;
1292         int                              c;
1293         int                              delete = 0;
1294         char                            *mdt_idx_arg = NULL;
1295         unsigned long long               size_units = 1;
1296         bool                             migrate_mode = false;
1297         bool                             migration_block = false;
1298         __u64                            migration_flags = 0;
1299         __u32                            osts[LOV_MAX_STRIPE_COUNT] = { 0 };
1300         int                              comp_del = 0, comp_set = 0;
1301         int                              comp_add = 0;
1302         __u32                            comp_id = 0;
1303         struct llapi_layout             *layout = NULL;
1304
1305         struct option            long_opts[] = {
1306                 /* --block is only valid in migrate mode */
1307                 {"block",        no_argument,       0, 'b'},
1308                 {"comp-add",     no_argument,       0, LFS_COMP_ADD_OPT},
1309                 {"component-add", no_argument,      0, LFS_COMP_ADD_OPT},
1310                 {"comp-del",     no_argument,       0, LFS_COMP_DEL_OPT},
1311                 {"component-del", no_argument,      0, LFS_COMP_DEL_OPT},
1312                 {"comp-flags",   required_argument, 0, LFS_COMP_FLAGS_OPT},
1313                 {"component-flags", required_argument, 0, LFS_COMP_FLAGS_OPT},
1314                 {"comp-set",     no_argument,       0, LFS_COMP_SET_OPT},
1315                 {"component-set", no_argument,      0, LFS_COMP_SET_OPT},
1316 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
1317                 /* This formerly implied "stripe-count", but was explicitly
1318                  * made "stripe-count" for consistency with other options,
1319                  * and to separate it from "mdt-count" when DNE arrives. */
1320                 {"count",        required_argument, 0, 'c'},
1321 #endif
1322                 {"stripe-count", required_argument, 0, 'c'},
1323                 {"stripe_count", required_argument, 0, 'c'},
1324                 {"delete",       no_argument,       0, 'd'},
1325                 {"comp-end",     required_argument, 0, 'E'},
1326                 {"component-end", required_argument, 0, 'E'},
1327                 /* dirstripe {"mdt-hash",     required_argument, 0, 'H'}, */
1328 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
1329                 /* This formerly implied "stripe-index", but was explicitly
1330                  * made "stripe-index" for consistency with other options,
1331                  * and to separate it from "mdt-index" when DNE arrives. */
1332                 {"index",        required_argument, 0, 'i'},
1333 #endif
1334                 {"stripe-index", required_argument, 0, 'i'},
1335                 {"stripe_index", required_argument, 0, 'i'},
1336                 {"comp-id",      required_argument, 0, 'I'},
1337                 {"component-id", required_argument, 0, 'I'},
1338                 {"mdt",          required_argument, 0, 'm'},
1339                 {"mdt-index",    required_argument, 0, 'm'},
1340                 {"mdt_index",    required_argument, 0, 'm'},
1341                 /* --non-block is only valid in migrate mode */
1342                 {"non-block",    no_argument,       0, 'n'},
1343                 {"ost",          required_argument, 0, 'o'},
1344 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
1345                 {"ost-list",     required_argument, 0, 'o'},
1346                 {"ost_list",     required_argument, 0, 'o'},
1347 #endif
1348                 {"pool",         required_argument, 0, 'p'},
1349 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
1350                 /* This formerly implied "--stripe-size", but was confusing
1351                  * with "lfs find --size|-s", which means "file size", so use
1352                  * the consistent "--stripe-size|-S" for all commands. */
1353                 {"size",         required_argument, 0, 's'},
1354 #endif
1355                 {"stripe-size",  required_argument, 0, 'S'},
1356                 {"stripe_size",  required_argument, 0, 'S'},
1357                 /* dirstripe {"mdt-count",    required_argument, 0, 'T'}, */
1358                 /* --verbose is only valid in migrate mode */
1359                 {"verbose",      no_argument,       0, 'v'},
1360                 {0, 0, 0, 0}
1361         };
1362
1363         setstripe_args_init(&lsa);
1364
1365         if (strcmp(argv[0], "migrate") == 0)
1366                 migrate_mode = true;
1367
1368         while ((c = getopt_long(argc, argv, "bc:dE:i:I:m:no:p:s:S:v",
1369                                 long_opts, NULL)) >= 0) {
1370                 switch (c) {
1371                 case 0:
1372                         /* Long options. */
1373                         break;
1374                 case LFS_COMP_ADD_OPT:
1375                         comp_add = 1;
1376                         break;
1377                 case LFS_COMP_DEL_OPT:
1378                         comp_del = 1;
1379                         break;
1380                 case LFS_COMP_FLAGS_OPT:
1381                         result = comp_name2flags(&lsa.lsa_comp_flags, optarg);
1382                         if (result != 0) {
1383                                 fprintf(stderr, "error: %s: bad comp flags "
1384                                         "'%s'\n", argv[0], optarg);
1385                                 goto error;
1386                         }
1387                         break;
1388                 case LFS_COMP_SET_OPT:
1389                         comp_set = 1;
1390                         break;
1391                 case 'b':
1392                         if (!migrate_mode) {
1393                                 fprintf(stderr, "--block is valid only for"
1394                                                 " migrate mode\n");
1395                                 goto error;
1396                         }
1397                         migration_block = true;
1398                         break;
1399                 case 'c':
1400 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1401                         if (strcmp(argv[optind - 1], "--count") == 0)
1402                                 fprintf(stderr, "warning: '--count' deprecated"
1403                                         ", use '--stripe-count' instead\n");
1404 #endif
1405                         lsa.lsa_stripe_count = strtoul(optarg, &end, 0);
1406                         if (*end != '\0') {
1407                                 fprintf(stderr, "error: %s: bad stripe count "
1408                                         "'%s'\n", argv[0], optarg);
1409                                 goto error;
1410                         }
1411                         break;
1412                 case 'd':
1413                         /* delete the default striping pattern */
1414                         delete = 1;
1415                         break;
1416                 case 'E':
1417                         if (lsa.lsa_comp_end != 0) {
1418                                 result = comp_args_to_layout(&layout, &lsa);
1419                                 if (result)
1420                                         goto error;
1421
1422                                 setstripe_args_init(&lsa);
1423                         }
1424
1425                         if (!strncmp(optarg, "-1", strlen("-1")) ||
1426                             !strncmp(optarg, "EOF", strlen("EOF")) ||
1427                             !strncmp(optarg, "eof", strlen("eof"))) {
1428                                 lsa.lsa_comp_end = LUSTRE_EOF;
1429                         } else {
1430                                 result = llapi_parse_size(optarg,
1431                                                         &lsa.lsa_comp_end,
1432                                                         &size_units, 0);
1433                                 if (result) {
1434                                         fprintf(stderr, "error: %s: "
1435                                                 "bad component end '%s'\n",
1436                                                 argv[0], optarg);
1437                                         goto error;
1438                                 }
1439                         }
1440                         break;
1441                 case 'i':
1442                         if (strcmp(argv[optind - 1], "--index") == 0)
1443                                 fprintf(stderr, "warning: '--index' deprecated"
1444                                         ", use '--stripe-index' instead\n");
1445                         lsa.lsa_stripe_off = strtol(optarg, &end, 0);
1446                         if (*end != '\0') {
1447                                 fprintf(stderr, "error: %s: bad stripe offset "
1448                                         "'%s'\n", argv[0], optarg);
1449                                 goto error;
1450                         }
1451                         break;
1452                 case 'I':
1453                         comp_id = strtoul(optarg, &end, 0);
1454                         if (*end != '\0' || comp_id == 0) {
1455                                 fprintf(stderr, "error: %s: bad comp ID "
1456                                         "'%s'\n", argv[0], optarg);
1457                                 goto error;
1458                         }
1459                         break;
1460                 case 'm':
1461                         if (!migrate_mode) {
1462                                 fprintf(stderr, "--mdt-index is valid only for"
1463                                                 " migrate mode\n");
1464                                 goto error;
1465                         }
1466                         mdt_idx_arg = optarg;
1467                         break;
1468                 case 'n':
1469                         if (!migrate_mode) {
1470                                 fprintf(stderr, "--non-block is valid only for"
1471                                                 " migrate mode\n");
1472                                 goto error;
1473                         }
1474                         migration_flags |= MIGRATION_NONBLOCK;
1475                         break;
1476                 case 'o':
1477                         lsa.lsa_nr_osts = parse_targets(osts,
1478                                                 sizeof(osts) / sizeof(__u32),
1479                                                 lsa.lsa_nr_osts, optarg);
1480                         if (lsa.lsa_nr_osts < 0) {
1481                                 fprintf(stderr,
1482                                         "error: %s: bad OST indices '%s'\n",
1483                                         argv[0], optarg);
1484                                 goto error;
1485                         }
1486
1487                         lsa.lsa_osts = osts;
1488                         if (lsa.lsa_stripe_off == -1)
1489                                 lsa.lsa_stripe_off = osts[0];
1490                         break;
1491                 case 'p':
1492                         result = verify_pool_name(argv[0], optarg);
1493                         if (result)
1494                                 goto error;
1495                         lsa.lsa_pool_name = optarg;
1496                         break;
1497 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
1498                 case 's':
1499 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1500                         fprintf(stderr, "warning: '--size|-s' deprecated, "
1501                                 "use '--stripe-size|-S' instead\n");
1502 #endif
1503 #endif /* LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0) */
1504                 case 'S':
1505                         result = llapi_parse_size(optarg, &lsa.lsa_stripe_size,
1506                                                   &size_units, 0);
1507                         if (result) {
1508                                 fprintf(stderr, "error: %s: bad stripe size "
1509                                         "'%s'\n", argv[0], optarg);
1510                                 goto error;
1511                         }
1512                         break;
1513                 case 'v':
1514                         if (!migrate_mode) {
1515                                 fprintf(stderr, "--verbose is valid only for"
1516                                                 " migrate mode\n");
1517                                 goto error;
1518                         }
1519                         migrate_mdt_param.fp_verbose = VERBOSE_DETAIL;
1520                         break;
1521                 default:
1522                         goto error;
1523                 }
1524         }
1525
1526         fname = argv[optind];
1527
1528         if (lsa.lsa_comp_end != 0) {
1529                 result = comp_args_to_layout(&layout, &lsa);
1530                 if (result)
1531                         goto error;
1532         }
1533
1534         if (optind == argc) {
1535                 fprintf(stderr, "error: %s: missing filename|dirname\n",
1536                         argv[0]);
1537                 goto error;
1538         }
1539
1540         /* Only LCME_FL_INIT flags is used in PFL, and it shouldn't be
1541          * altered by user space tool, so we don't need to support the
1542          * --component-set for this moment. */
1543         if (comp_set != 0) {
1544                 fprintf(stderr, "error: %s: --component-set isn't supported.\n",
1545                         argv[0]);
1546                 goto error;
1547         }
1548
1549         if ((delete + comp_set + comp_del + comp_add) > 1) {
1550                 fprintf(stderr, "error: %s: can't specify --component-set, "
1551                         "--component-del, --component-add or -d together\n",
1552                         argv[0]);
1553                 goto error;
1554         }
1555
1556         if (delete && (setstripe_args_specified(&lsa) || comp_id != 0 ||
1557                        lsa.lsa_comp_flags != 0 || layout != NULL)) {
1558                 fprintf(stderr, "error: %s: can't specify -d with "
1559                         "-s, -c, -o, -p, -I, -F or -E options\n",
1560                         argv[0]);
1561                 goto error;
1562         }
1563
1564         if ((comp_set || comp_del) &&
1565             (setstripe_args_specified(&lsa) || layout != NULL)) {
1566                 fprintf(stderr, "error: %s: can't specify --component-del or "
1567                         "--component-set with -s, -c, -o, -p or -E options.\n",
1568                         argv[0]);
1569                 goto error;
1570         }
1571
1572         if (comp_del && comp_id != 0 && lsa.lsa_comp_flags != 0) {
1573                 fprintf(stderr, "error: %s: can't specify both -I and -F for "
1574                         "--component-del option.\n", argv[0]);
1575                 goto error;
1576         }
1577
1578         if (comp_add) {
1579                 if (layout == NULL) {
1580                         fprintf(stderr, "error: %s: -E option must be present"
1581                                 "in --component-add mode.\n", argv[0]);
1582                         goto error;
1583                 }
1584                 result = adjust_first_extent(fname, layout);
1585                 if (result != 0)
1586                         goto error;
1587         }
1588
1589         if (mdt_idx_arg != NULL && optind > 3) {
1590                 fprintf(stderr, "error: %s: cannot specify -m with other "
1591                         "options\n", argv[0]);
1592                 goto error;
1593         }
1594
1595         if ((migration_flags & MIGRATION_NONBLOCK) && migration_block) {
1596                 fprintf(stderr,
1597                         "error: %s: cannot specify --non-block and --block\n",
1598                         argv[0]);
1599                 goto error;
1600         }
1601
1602         /* support --component-id option for migrate later. */
1603         if (migrate_mode && comp_id != 0) {
1604                 fprintf(stderr, "error: %s: -I isn't supported yet.\n",
1605                         argv[0]);
1606                 goto error;
1607         }
1608
1609         if (mdt_idx_arg != NULL) {
1610                 /* initialize migrate mdt parameters */
1611                 migrate_mdt_param.fp_mdt_index = strtoul(mdt_idx_arg, &end, 0);
1612                 if (*end != '\0') {
1613                         fprintf(stderr, "error: %s: bad MDT index '%s'\n",
1614                                 argv[0], mdt_idx_arg);
1615                         goto error;
1616                 }
1617                 migrate_mdt_param.fp_migrate = 1;
1618         } else if (layout == NULL) {
1619                 /* initialize stripe parameters */
1620                 param = calloc(1, offsetof(typeof(*param),
1621                                lsp_osts[lsa.lsa_nr_osts]));
1622                 if (param == NULL) {
1623                         fprintf(stderr, "error: %s: %s\n", argv[0],
1624                                 strerror(ENOMEM));
1625                         goto error;
1626                 }
1627
1628                 param->lsp_stripe_size = lsa.lsa_stripe_size;
1629                 param->lsp_stripe_offset = lsa.lsa_stripe_off;
1630                 param->lsp_stripe_count = lsa.lsa_stripe_count;
1631                 param->lsp_stripe_pattern = 0;
1632                 param->lsp_pool = lsa.lsa_pool_name;
1633                 param->lsp_is_specific = false;
1634                 if (lsa.lsa_nr_osts > 0) {
1635                         if (lsa.lsa_stripe_count > 0 &&
1636                             lsa.lsa_nr_osts != lsa.lsa_stripe_count) {
1637                                 fprintf(stderr, "error: %s: stripe count '%d' "
1638                                         "doesn't match the number of OSTs: %d\n"
1639                                         , argv[0], lsa.lsa_stripe_count,
1640                                         lsa.lsa_nr_osts);
1641                                 free(param);
1642                                 goto error;
1643                         }
1644
1645                         param->lsp_is_specific = true;
1646                         param->lsp_stripe_count = lsa.lsa_nr_osts;
1647                         memcpy(param->lsp_osts, osts,
1648                                sizeof(*osts) * lsa.lsa_nr_osts);
1649                 }
1650         }
1651
1652         for (fname = argv[optind]; fname != NULL; fname = argv[++optind]) {
1653                 char *op;
1654                 if (mdt_idx_arg != NULL) {
1655                         result = llapi_migrate_mdt(fname, &migrate_mdt_param);
1656                         op = "migrate mdt objects of";
1657                 } else if (migrate_mode) {
1658                         result = lfs_migrate(fname, migration_flags, param,
1659                                              layout);
1660                         op = "migrate ost objects of";
1661                 } else if (comp_set != 0) {
1662                         result = lfs_component_set(fname, comp_id,
1663                                                    lsa.lsa_comp_flags);
1664                         op = "modify component flags of";
1665                 } else if (comp_del != 0) {
1666                         result = lfs_component_del(fname, comp_id,
1667                                                    lsa.lsa_comp_flags);
1668                         op = "delete component of";
1669                 } else if (comp_add != 0) {
1670                         result = lfs_component_add(fname, layout);
1671                         op = "add component to";
1672                 } else if (layout != NULL) {
1673                         result = lfs_component_create(fname, O_CREAT | O_WRONLY,
1674                                                       0644, layout);
1675                         if (result >= 0) {
1676                                 close(result);
1677                                 result = 0;
1678                         }
1679                         op = "create composite";
1680                 } else {
1681                         result = llapi_file_open_param(fname,
1682                                                        O_CREAT | O_WRONLY,
1683                                                        0644, param);
1684                         if (result >= 0) {
1685                                 close(result);
1686                                 result = 0;
1687                         }
1688                         op = "create striped";
1689                 }
1690                 if (result) {
1691                         /* Save the first error encountered. */
1692                         if (result2 == 0)
1693                                 result2 = result;
1694                         fprintf(stderr, "error: %s: %s file '%s' failed: %s\n",
1695                                 argv[0], op, fname,
1696                                 lsa.lsa_pool_name != NULL && result == EINVAL ?
1697                                 "OST not in pool?" : strerror(errno));
1698                         continue;
1699                 }
1700         }
1701
1702         free(param);
1703         llapi_layout_free(layout);
1704         return result2;
1705 error:
1706         llapi_layout_free(layout);
1707         return CMD_HELP;
1708 }
1709
1710 static int lfs_poollist(int argc, char **argv)
1711 {
1712         if (argc != 2)
1713                 return CMD_HELP;
1714
1715         return llapi_poollist(argv[1]);
1716 }
1717
1718 static int set_time(time_t *time, time_t *set, char *str)
1719 {
1720         time_t t;
1721         int res = 0;
1722
1723         if (str[0] == '+')
1724                 res = 1;
1725         else if (str[0] == '-')
1726                 res = -1;
1727
1728         if (res)
1729                 str++;
1730
1731         t = strtol(str, NULL, 0);
1732         if (*time < t * 24 * 60 * 60) {
1733                 if (res)
1734                         str--;
1735                 fprintf(stderr, "Wrong time '%s' is specified.\n", str);
1736                 return INT_MAX;
1737         }
1738
1739         *set = *time - t * 24 * 60 * 60;
1740         return res;
1741 }
1742 static int name2uid(unsigned int *id, const char *name)
1743 {
1744         struct passwd *passwd;
1745
1746         passwd = getpwnam(name);
1747         if (passwd == NULL)
1748                 return -ENOENT;
1749         *id = passwd->pw_uid;
1750
1751         return 0;
1752 }
1753
1754 static int name2gid(unsigned int *id, const char *name)
1755 {
1756         struct group *group;
1757
1758         group = getgrnam(name);
1759         if (group == NULL)
1760                 return -ENOENT;
1761         *id = group->gr_gid;
1762
1763         return 0;
1764 }
1765
1766 static inline int name2projid(unsigned int *id, const char *name)
1767 {
1768         return -ENOTSUP;
1769 }
1770
1771 static int uid2name(char **name, unsigned int id)
1772 {
1773         struct passwd *passwd;
1774
1775         passwd = getpwuid(id);
1776         if (passwd == NULL)
1777                 return -ENOENT;
1778         *name = passwd->pw_name;
1779
1780         return 0;
1781 }
1782
1783 static inline int gid2name(char **name, unsigned int id)
1784 {
1785         struct group *group;
1786
1787         group = getgrgid(id);
1788         if (group == NULL)
1789                 return -ENOENT;
1790         *name = group->gr_name;
1791
1792         return 0;
1793 }
1794
1795 static int name2layout(__u32 *layout, char *name)
1796 {
1797         char *ptr, *lyt;
1798
1799         *layout = 0;
1800         for (ptr = name; ; ptr = NULL) {
1801                 lyt = strtok(ptr, ",");
1802                 if (lyt == NULL)
1803                         break;
1804                 if (strcmp(lyt, "released") == 0)
1805                         *layout |= LOV_PATTERN_F_RELEASED;
1806                 else if (strcmp(lyt, "raid0") == 0)
1807                         *layout |= LOV_PATTERN_RAID0;
1808                 else
1809                         return -1;
1810         }
1811         return 0;
1812 }
1813
1814 static int lfs_find(int argc, char **argv)
1815 {
1816         int c, rc;
1817         int ret = 0;
1818         time_t t;
1819         struct find_param param = {
1820                 .fp_max_depth = -1,
1821                 .fp_quiet = 1,
1822         };
1823         struct option long_opts[] = {
1824                 {"atime",        required_argument, 0, 'A'},
1825                 {"comp-count",   required_argument, 0, LFS_COMP_COUNT_OPT},
1826                 {"component-count", required_argument, 0, LFS_COMP_COUNT_OPT},
1827                 {"comp-flags",   required_argument, 0, LFS_COMP_FLAGS_OPT},
1828                 {"component-flags", required_argument, 0, LFS_COMP_FLAGS_OPT},
1829                 {"comp-start",   required_argument, 0, LFS_COMP_START_OPT},
1830                 {"component-start", required_argument, 0, LFS_COMP_START_OPT},
1831                 {"stripe-count", required_argument, 0, 'c'},
1832                 {"stripe_count", required_argument, 0, 'c'},
1833                 {"ctime",        required_argument, 0, 'C'},
1834                 {"maxdepth",     required_argument, 0, 'D'},
1835                 {"comp-end",     required_argument, 0, 'E'},
1836                 {"component-end", required_argument, 0, 'E'},
1837                 {"gid",          required_argument, 0, 'g'},
1838                 {"group",        required_argument, 0, 'G'},
1839                 {"mdt-hash",     required_argument, 0, 'H'},
1840                 {"stripe-index", required_argument, 0, 'i'},
1841                 {"stripe_index", required_argument, 0, 'i'},
1842                 /*{"component-id", required_argument, 0, 'I'},*/
1843                 {"layout",       required_argument, 0, 'L'},
1844                 {"mdt",          required_argument, 0, 'm'},
1845                 {"mdt-index",    required_argument, 0, 'm'},
1846                 {"mdt_index",    required_argument, 0, 'm'},
1847                 {"mtime",        required_argument, 0, 'M'},
1848                 {"name",         required_argument, 0, 'n'},
1849      /* reserve {"or",           no_argument,     , 0, 'o'}, to match find(1) */
1850                 {"obd",          required_argument, 0, 'O'},
1851                 {"ost",          required_argument, 0, 'O'},
1852                 /* no short option for pool, p/P already used */
1853                 {"pool",         required_argument, 0, LFS_POOL_OPT},
1854                 {"print0",       no_argument,       0, 'p'},
1855                 {"print",        no_argument,       0, 'P'},
1856                 {"projid",       required_argument, 0, LFS_PROJID_OPT},
1857                 {"size",         required_argument, 0, 's'},
1858                 {"stripe-size",  required_argument, 0, 'S'},
1859                 {"stripe_size",  required_argument, 0, 'S'},
1860                 {"type",         required_argument, 0, 't'},
1861                 {"mdt-count",    required_argument, 0, 'T'},
1862                 {"uid",          required_argument, 0, 'u'},
1863                 {"user",         required_argument, 0, 'U'},
1864                 {0, 0, 0, 0}
1865         };
1866         int pathstart = -1;
1867         int pathend = -1;
1868         int neg_opt = 0;
1869         time_t *xtime;
1870         int *xsign;
1871         int isoption;
1872         char *endptr;
1873
1874         time(&t);
1875
1876         /* when getopt_long_only() hits '!' it returns 1, puts "!" in optarg */
1877         while ((c = getopt_long_only(argc, argv,
1878                         "-A:c:C:D:E:g:G:H:i:L:m:M:n:O:Ppqrs:S:t:T:u:U:v",
1879                         long_opts, NULL)) >= 0) {
1880                 xtime = NULL;
1881                 xsign = NULL;
1882                 if (neg_opt)
1883                         --neg_opt;
1884                 /* '!' is part of option */
1885                 /* when getopt_long_only() finds a string which is not
1886                  * an option nor a known option argument it returns 1
1887                  * in that case if we already have found pathstart and pathend
1888                  * (i.e. we have the list of pathnames),
1889                  * the only supported value is "!"
1890                  */
1891                 isoption = (c != 1) || (strcmp(optarg, "!") == 0);
1892                 if (!isoption && pathend != -1) {
1893                         fprintf(stderr, "err: %s: filename|dirname must either "
1894                                         "precede options or follow options\n",
1895                                         argv[0]);
1896                         ret = CMD_HELP;
1897                         goto err;
1898                 }
1899                 if (!isoption && pathstart == -1)
1900                         pathstart = optind - 1;
1901                 if (isoption && pathstart != -1 && pathend == -1)
1902                         pathend = optind - 2;
1903                 switch (c) {
1904                 case 0:
1905                         /* Long options. */
1906                         break;
1907                 case 1:
1908                         /* unknown; opt is "!" or path component,
1909                          * checking done above.
1910                          */
1911                         if (strcmp(optarg, "!") == 0)
1912                                 neg_opt = 2;
1913                         break;
1914                 case 'A':
1915                         xtime = &param.fp_atime;
1916                         xsign = &param.fp_asign;
1917                         param.fp_exclude_atime = !!neg_opt;
1918                         /* no break, this falls through to 'C' for ctime */
1919                 case 'C':
1920                         if (c == 'C') {
1921                                 xtime = &param.fp_ctime;
1922                                 xsign = &param.fp_csign;
1923                                 param.fp_exclude_ctime = !!neg_opt;
1924                         }
1925                         /* no break, this falls through to 'M' for mtime */
1926                 case 'M':
1927                         if (c == 'M') {
1928                                 xtime = &param.fp_mtime;
1929                                 xsign = &param.fp_msign;
1930                                 param.fp_exclude_mtime = !!neg_opt;
1931                         }
1932                         rc = set_time(&t, xtime, optarg);
1933                         if (rc == INT_MAX) {
1934                                 ret = -1;
1935                                 goto err;
1936                         }
1937                         if (rc)
1938                                 *xsign = rc;
1939                         break;
1940                 case LFS_COMP_COUNT_OPT:
1941                         if (optarg[0] == '+') {
1942                                 param.fp_comp_count_sign = -1;
1943                                 optarg++;
1944                         } else if (optarg[0] == '-') {
1945                                 param.fp_comp_count_sign =  1;
1946                                 optarg++;
1947                         }
1948
1949                         param.fp_comp_count = strtoul(optarg, &endptr, 0);
1950                         if (*endptr != '\0') {
1951                                 fprintf(stderr, "error: bad component count "
1952                                         "'%s'\n", optarg);
1953                                 goto err;
1954                         }
1955                         param.fp_check_comp_count = 1;
1956                         param.fp_exclude_comp_count = !!neg_opt;
1957                         break;
1958                 case LFS_COMP_FLAGS_OPT:
1959                         rc = comp_name2flags(&param.fp_comp_flags, optarg);
1960                         if (rc) {
1961                                 fprintf(stderr, "error: bad component flags "
1962                                         "'%s'\n", optarg);
1963                                 goto err;
1964                         }
1965                         param.fp_check_comp_flags = 1;
1966                         param.fp_exclude_comp_flags = !!neg_opt;
1967                         break;
1968                 case LFS_COMP_START_OPT:
1969                         if (optarg[0] == '+') {
1970                                 param.fp_comp_start_sign = -1;
1971                                 optarg++;
1972                         } else if (optarg[0] == '-') {
1973                                 param.fp_comp_start_sign =  1;
1974                                 optarg++;
1975                         }
1976
1977                         rc = llapi_parse_size(optarg, &param.fp_comp_start,
1978                                               &param.fp_comp_start_units, 0);
1979                         if (rc) {
1980                                 fprintf(stderr, "error: bad component start "
1981                                         "'%s'\n", optarg);
1982                                 goto err;
1983                         }
1984                         param.fp_check_comp_start = 1;
1985                         param.fp_exclude_comp_start = !!neg_opt;
1986                         break;
1987                 case 'c':
1988                         if (optarg[0] == '+') {
1989                                 param.fp_stripe_count_sign = -1;
1990                                 optarg++;
1991                         } else if (optarg[0] == '-') {
1992                                 param.fp_stripe_count_sign =  1;
1993                                 optarg++;
1994                         }
1995
1996                         param.fp_stripe_count = strtoul(optarg, &endptr, 0);
1997                         if (*endptr != '\0') {
1998                                 fprintf(stderr,"error: bad stripe_count '%s'\n",
1999                                         optarg);
2000                                 ret = -1;
2001                                 goto err;
2002                         }
2003                         param.fp_check_stripe_count = 1;
2004                         param.fp_exclude_stripe_count = !!neg_opt;
2005                         break;
2006                 case 'D':
2007                         param.fp_max_depth = strtol(optarg, 0, 0);
2008                         break;
2009                 case 'E':
2010                         if (optarg[0] == '+') {
2011                                 param.fp_comp_end_sign = -1;
2012                                 optarg++;
2013                         } else if (optarg[0] == '-') {
2014                                 param.fp_comp_end_sign =  1;
2015                                 optarg++;
2016                         }
2017
2018                         rc = llapi_parse_size(optarg, &param.fp_comp_end,
2019                                               &param.fp_comp_end_units, 0);
2020                         if (rc) {
2021                                 fprintf(stderr, "error: bad component end "
2022                                         "'%s'\n", optarg);
2023                                 goto err;
2024                         }
2025                         param.fp_check_comp_end = 1;
2026                         param.fp_exclude_comp_end = !!neg_opt;
2027                         break;
2028                 case 'g':
2029                 case 'G':
2030                         rc = name2gid(&param.fp_gid, optarg);
2031                         if (rc) {
2032                                 param.fp_gid = strtoul(optarg, &endptr, 10);
2033                                 if (*endptr != '\0') {
2034                                         fprintf(stderr, "Group/GID: %s cannot "
2035                                                 "be found.\n", optarg);
2036                                         ret = -1;
2037                                         goto err;
2038                                 }
2039                         }
2040                         param.fp_exclude_gid = !!neg_opt;
2041                         param.fp_check_gid = 1;
2042                         break;
2043                 case 'H':
2044                         param.fp_hash_type = check_hashtype(optarg);
2045                         if (param.fp_hash_type == 0) {
2046                                 fprintf(stderr, "error: bad hash_type '%s'\n",
2047                                         optarg);
2048                                 ret = -1;
2049                                 goto err;
2050                         }
2051                         param.fp_check_hash_type = 1;
2052                         param.fp_exclude_hash_type = !!neg_opt;
2053                         break;
2054                 case 'L':
2055                         ret = name2layout(&param.fp_layout, optarg);
2056                         if (ret)
2057                                 goto err;
2058                         param.fp_exclude_layout = !!neg_opt;
2059                         param.fp_check_layout = 1;
2060                         break;
2061                 case 'u':
2062                 case 'U':
2063                         rc = name2uid(&param.fp_uid, optarg);
2064                         if (rc) {
2065                                 param.fp_uid = strtoul(optarg, &endptr, 10);
2066                                 if (*endptr != '\0') {
2067                                         fprintf(stderr, "User/UID: %s cannot "
2068                                                 "be found.\n", optarg);
2069                                         ret = -1;
2070                                         goto err;
2071                                 }
2072                         }
2073                         param.fp_exclude_uid = !!neg_opt;
2074                         param.fp_check_uid = 1;
2075                         break;
2076                 case LFS_POOL_OPT:
2077                         if (strlen(optarg) > LOV_MAXPOOLNAME) {
2078                                 fprintf(stderr,
2079                                         "Pool name %s is too long"
2080                                         " (max is %d)\n", optarg,
2081                                         LOV_MAXPOOLNAME);
2082                                 ret = -1;
2083                                 goto err;
2084                         }
2085                         /* we do check for empty pool because empty pool
2086                          * is used to find V1 lov attributes */
2087                         strncpy(param.fp_poolname, optarg, LOV_MAXPOOLNAME);
2088                         param.fp_poolname[LOV_MAXPOOLNAME] = '\0';
2089                         param.fp_exclude_pool = !!neg_opt;
2090                         param.fp_check_pool = 1;
2091                         break;
2092                 case 'n':
2093                         param.fp_pattern = (char *)optarg;
2094                         param.fp_exclude_pattern = !!neg_opt;
2095                         break;
2096                 case 'm':
2097                 case 'i':
2098                 case 'O': {
2099                         char *buf, *token, *next, *p;
2100                         int len = 1;
2101                         void *tmp;
2102
2103                         buf = strdup(optarg);
2104                         if (buf == NULL) {
2105                                 ret = -ENOMEM;
2106                                 goto err;
2107                         }
2108
2109                         param.fp_exclude_obd = !!neg_opt;
2110
2111                         token = buf;
2112                         while (token && *token) {
2113                                 token = strchr(token, ',');
2114                                 if (token) {
2115                                         len++;
2116                                         token++;
2117                                 }
2118                         }
2119                         if (c == 'm') {
2120                                 param.fp_exclude_mdt = !!neg_opt;
2121                                 param.fp_num_alloc_mdts += len;
2122                                 tmp = realloc(param.fp_mdt_uuid,
2123                                               param.fp_num_alloc_mdts *
2124                                               sizeof(*param.fp_mdt_uuid));
2125                                 if (tmp == NULL) {
2126                                         ret = -ENOMEM;
2127                                         goto err_free;
2128                                 }
2129
2130                                 param.fp_mdt_uuid = tmp;
2131                         } else {
2132                                 param.fp_exclude_obd = !!neg_opt;
2133                                 param.fp_num_alloc_obds += len;
2134                                 tmp = realloc(param.fp_obd_uuid,
2135                                               param.fp_num_alloc_obds *
2136                                               sizeof(*param.fp_obd_uuid));
2137                                 if (tmp == NULL) {
2138                                         ret = -ENOMEM;
2139                                         goto err_free;
2140                                 }
2141
2142                                 param.fp_obd_uuid = tmp;
2143                         }
2144                         for (token = buf; token && *token; token = next) {
2145                                 struct obd_uuid *puuid;
2146                                 if (c == 'm') {
2147                                         puuid =
2148                                         &param.fp_mdt_uuid[param.fp_num_mdts++];
2149                                 } else {
2150                                         puuid =
2151                                         &param.fp_obd_uuid[param.fp_num_obds++];
2152                                 }
2153                                 p = strchr(token, ',');
2154                                 next = 0;
2155                                 if (p) {
2156                                         *p = 0;
2157                                         next = p+1;
2158                                 }
2159
2160                                 if (strlen(token) > sizeof(puuid->uuid) - 1) {
2161                                         ret = -E2BIG;
2162                                         goto err_free;
2163                                 }
2164
2165                                 strncpy(puuid->uuid, token,
2166                                         sizeof(puuid->uuid));
2167                         }
2168 err_free:
2169                         if (buf)
2170                                 free(buf);
2171                         break;
2172                 }
2173                 case 'p':
2174                         param.fp_zero_end = 1;
2175                         break;
2176                 case 'P':
2177                         break;
2178                 case LFS_PROJID_OPT:
2179                         rc = name2projid(&param.fp_projid, optarg);
2180                         if (rc) {
2181                                 param.fp_projid = strtoul(optarg, &endptr, 10);
2182                                 if (*endptr != '\0') {
2183                                         fprintf(stderr,
2184                                                 "Invalid project ID: %s",
2185                                                 optarg);
2186                                         ret = -1;
2187                                         goto err;
2188                                 }
2189                         }
2190                         param.fp_exclude_projid = !!neg_opt;
2191                         param.fp_check_projid = 1;
2192                         break;
2193                 case 's':
2194                         if (optarg[0] == '+') {
2195                                 param.fp_size_sign = -1;
2196                                 optarg++;
2197                         } else if (optarg[0] == '-') {
2198                                 param.fp_size_sign =  1;
2199                                 optarg++;
2200                         }
2201
2202                         ret = llapi_parse_size(optarg, &param.fp_size,
2203                                                &param.fp_size_units, 0);
2204                         if (ret) {
2205                                 fprintf(stderr, "error: bad file size '%s'\n",
2206                                         optarg);
2207                                 goto err;
2208                         }
2209                         param.fp_check_size = 1;
2210                         param.fp_exclude_size = !!neg_opt;
2211                         break;
2212                 case 'S':
2213                         if (optarg[0] == '+') {
2214                                 param.fp_stripe_size_sign = -1;
2215                                 optarg++;
2216                         } else if (optarg[0] == '-') {
2217                                 param.fp_stripe_size_sign =  1;
2218                                 optarg++;
2219                         }
2220
2221                         ret = llapi_parse_size(optarg, &param.fp_stripe_size,
2222                                                &param.fp_stripe_size_units, 0);
2223                         if (ret) {
2224                                 fprintf(stderr, "error: bad stripe_size '%s'\n",
2225                                         optarg);
2226                                 goto err;
2227                         }
2228                         param.fp_check_stripe_size = 1;
2229                         param.fp_exclude_stripe_size = !!neg_opt;
2230                         break;
2231                 case 't':
2232                         param.fp_exclude_type = !!neg_opt;
2233                         switch (optarg[0]) {
2234                         case 'b':
2235                                 param.fp_type = S_IFBLK;
2236                                 break;
2237                         case 'c':
2238                                 param.fp_type = S_IFCHR;
2239                                 break;
2240                         case 'd':
2241                                 param.fp_type = S_IFDIR;
2242                                 break;
2243                         case 'f':
2244                                 param.fp_type = S_IFREG;
2245                                 break;
2246                         case 'l':
2247                                 param.fp_type = S_IFLNK;
2248                                 break;
2249                         case 'p':
2250                                 param.fp_type = S_IFIFO;
2251                                 break;
2252                         case 's':
2253                                 param.fp_type = S_IFSOCK;
2254                                 break;
2255                         default:
2256                                 fprintf(stderr, "error: %s: bad type '%s'\n",
2257                                         argv[0], optarg);
2258                                 ret = CMD_HELP;
2259                                 goto err;
2260                         };
2261                         break;
2262                 case 'T':
2263                         if (optarg[0] == '+') {
2264                                 param.fp_mdt_count_sign = -1;
2265                                 optarg++;
2266                         } else if (optarg[0] == '-') {
2267                                 param.fp_mdt_count_sign =  1;
2268                                 optarg++;
2269                         }
2270
2271                         param.fp_mdt_count = strtoul(optarg, &endptr, 0);
2272                         if (*endptr != '\0') {
2273                                 fprintf(stderr, "error: bad mdt_count '%s'\n",
2274                                         optarg);
2275                                 ret = -1;
2276                                 goto err;
2277                         }
2278                         param.fp_check_mdt_count = 1;
2279                         param.fp_exclude_mdt_count = !!neg_opt;
2280                         break;
2281                 default:
2282                         ret = CMD_HELP;
2283                         goto err;
2284                 };
2285         }
2286
2287         if (pathstart == -1) {
2288                 fprintf(stderr, "error: %s: no filename|pathname\n",
2289                         argv[0]);
2290                 ret = CMD_HELP;
2291                 goto err;
2292         } else if (pathend == -1) {
2293                 /* no options */
2294                 pathend = argc;
2295         }
2296
2297         do {
2298                 rc = llapi_find(argv[pathstart], &param);
2299                 if (rc != 0 && ret == 0)
2300                         ret = rc;
2301         } while (++pathstart < pathend);
2302
2303         if (ret)
2304                 fprintf(stderr, "error: %s failed for %s.\n",
2305                         argv[0], argv[optind - 1]);
2306 err:
2307         if (param.fp_obd_uuid && param.fp_num_alloc_obds)
2308                 free(param.fp_obd_uuid);
2309
2310         if (param.fp_mdt_uuid && param.fp_num_alloc_mdts)
2311                 free(param.fp_mdt_uuid);
2312
2313         return ret;
2314 }
2315
2316 static int lfs_getstripe_internal(int argc, char **argv,
2317                                   struct find_param *param)
2318 {
2319         struct option long_opts[] = {
2320                 {"comp-count",          no_argument, 0, LFS_COMP_COUNT_OPT},
2321                 {"component-count",     no_argument, 0, LFS_COMP_COUNT_OPT},
2322                 {"comp-flags",      required_argument, 0, LFS_COMP_FLAGS_OPT},
2323                 {"component-flags", required_argument, 0, LFS_COMP_FLAGS_OPT},
2324                 {"comp-start",      required_argument, 0, LFS_COMP_START_OPT},
2325                 {"component-start", required_argument, 0, LFS_COMP_START_OPT},
2326 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2327                 /* This formerly implied "stripe-count", but was explicitly
2328                  * made "stripe-count" for consistency with other options,
2329                  * and to separate it from "mdt-count" when DNE arrives. */
2330                 {"count",               no_argument,            0, 'c'},
2331 #endif
2332                 {"stripe-count",        no_argument,            0, 'c'},
2333                 {"stripe_count",        no_argument,            0, 'c'},
2334                 {"directory",           no_argument,            0, 'd'},
2335                 {"default",             no_argument,            0, 'D'},
2336                 {"comp-end",            required_argument,      0, 'E'},
2337                 {"component-end",       required_argument,      0, 'E'},
2338                 {"fid",                 no_argument,            0, 'F'},
2339                 {"generation",          no_argument,            0, 'g'},
2340                 /* dirstripe {"mdt-hash",     required_argument, 0, 'H'}, */
2341 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2342                 /* This formerly implied "stripe-index", but was explicitly
2343                  * made "stripe-index" for consistency with other options,
2344                  * and to separate it from "mdt-index" when DNE arrives. */
2345                 {"index",               no_argument,            0, 'i'},
2346 #endif
2347                 {"stripe-index",        no_argument,            0, 'i'},
2348                 {"stripe_index",        no_argument,            0, 'i'},
2349                 {"comp-id",             required_argument,      0, 'I'},
2350                 {"component-id",        required_argument,      0, 'I'},
2351                 {"layout",              no_argument,            0, 'L'},
2352                 {"mdt",                 no_argument,            0, 'm'},
2353                 {"mdt-index",           no_argument,            0, 'm'},
2354                 {"mdt_index",           no_argument,            0, 'm'},
2355 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2356                 {"mdt-index",           no_argument,            0, 'M'},
2357                 {"mdt_index",           no_argument,            0, 'M'},
2358 #endif
2359 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2360                 /* This formerly implied "stripe-index", but was confusing
2361                  * with "file offset" (which will eventually be needed for
2362                  * with different layouts by offset), so deprecate it. */
2363                 {"offset",              no_argument,            0, 'o'},
2364 #endif
2365                 {"obd",                 required_argument,      0, 'O'},
2366                 {"ost",                 required_argument,      0, 'O'},
2367                 {"pool",                no_argument,            0, 'p'},
2368                 {"quiet",               no_argument,            0, 'q'},
2369                 {"recursive",           no_argument,            0, 'r'},
2370                 {"raw",                 no_argument,            0, 'R'},
2371 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2372                 /* This formerly implied "--stripe-size", but was confusing
2373                  * with "lfs find --size|-s", which means "file size", so use
2374                  * the consistent "--stripe-size|-S" for all commands. */
2375                 {"size",                no_argument,            0, 's'},
2376 #endif
2377                 {"stripe-size",         no_argument,            0, 'S'},
2378                 {"stripe_size",         no_argument,            0, 'S'},
2379                 /* dirstripe {"mdt-count",    required_argument, 0, 'T'}, */
2380                 {"verbose",             no_argument,            0, 'v'},
2381                 {0, 0, 0, 0}
2382         };
2383         int c, rc;
2384         char *end, *tmp;
2385
2386         while ((c = getopt_long(argc, argv, "cdDE:FghiI:LmMoO:pqrRsSv",
2387                                 long_opts, NULL)) != -1) {
2388                 switch (c) {
2389                 case 'c':
2390                         if (strcmp(argv[optind - 1], "--count") == 0)
2391                                 fprintf(stderr, "warning: '--count' deprecated,"
2392                                         " use '--stripe-count' instead\n");
2393                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2394                                 param->fp_verbose |= VERBOSE_COUNT;
2395                                 param->fp_max_depth = 0;
2396                         }
2397                         break;
2398                 case LFS_COMP_COUNT_OPT:
2399                         param->fp_verbose |= VERBOSE_COMP_COUNT;
2400                         param->fp_max_depth = 0;
2401                         break;
2402                 case LFS_COMP_FLAGS_OPT:
2403                         if (optarg != NULL) {
2404                                 rc = comp_name2flags(&param->fp_comp_flags,
2405                                                      optarg);
2406                                 if (rc != 0) {
2407                                         param->fp_verbose |=
2408                                                 VERBOSE_COMP_FLAGS;
2409                                         param->fp_max_depth = 0;
2410                                         optind--;
2411                                 } else {
2412                                         param->fp_check_comp_flags = 1;
2413                                 }
2414                         } else {
2415                                 param->fp_verbose |= VERBOSE_COMP_FLAGS;
2416                                 param->fp_max_depth = 0;
2417                         }
2418                         break;
2419                 case LFS_COMP_START_OPT:
2420                         if (optarg != NULL) {
2421                                 tmp = optarg;
2422                                 if (tmp[0] == '+') {
2423                                         param->fp_comp_start_sign = 1;
2424                                         tmp++;
2425                                 } else if (tmp[0] == '-') {
2426                                         param->fp_comp_start_sign = -1;
2427                                         tmp++;
2428                                 }
2429                                 rc = llapi_parse_size(tmp,
2430                                                 &param->fp_comp_start,
2431                                                 &param->fp_comp_start_units, 0);
2432                                 if (rc != 0) {
2433                                         param->fp_verbose |= VERBOSE_COMP_START;
2434                                         param->fp_max_depth = 0;
2435                                         optind--;
2436                                 } else {
2437                                         param->fp_check_comp_start = 1;
2438                                 }
2439                         } else {
2440                                 param->fp_verbose |= VERBOSE_COMP_START;
2441                                 param->fp_max_depth = 0;
2442                         }
2443                         break;
2444                 case 'd':
2445                         param->fp_max_depth = 0;
2446                         break;
2447                 case 'D':
2448                         param->fp_get_default_lmv = 1;
2449                         break;
2450                 case 'E':
2451                         if (optarg != NULL) {
2452                                 tmp = optarg;
2453                                 if (tmp[0] == '+') {
2454                                         param->fp_comp_end_sign = 1;
2455                                         tmp++;
2456                                 } else if (tmp[0] == '-') {
2457                                         param->fp_comp_end_sign = -1;
2458                                         tmp++;
2459                                 }
2460                                 rc = llapi_parse_size(tmp,
2461                                                 &param->fp_comp_end,
2462                                                 &param->fp_comp_end_units, 0);
2463                                 if (rc != 0) {
2464                                         param->fp_verbose |= VERBOSE_COMP_END;
2465                                         param->fp_max_depth = 0;
2466                                         optind--;
2467                                 } else {
2468                                         param->fp_check_comp_end = 1;
2469                                 }
2470                         } else {
2471                                 param->fp_verbose |= VERBOSE_COMP_END;
2472                                 param->fp_max_depth = 0;
2473                         }
2474                         break;
2475                 case 'F':
2476                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2477                                 param->fp_verbose |= VERBOSE_DFID;
2478                                 param->fp_max_depth = 0;
2479                         }
2480                         break;
2481                 case 'g':
2482                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2483                                 param->fp_verbose |= VERBOSE_GENERATION;
2484                                 param->fp_max_depth = 0;
2485                         }
2486                         break;
2487 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2488                 case 'o':
2489                         fprintf(stderr, "warning: '--offset|-o' deprecated, "
2490                                 "use '--stripe-index|-i' instead\n");
2491 #endif
2492                 case 'i':
2493 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
2494                         if (strcmp(argv[optind - 1], "--index") == 0)
2495                                 fprintf(stderr, "warning: '--index' deprecated"
2496                                         ", use '--stripe-index' instead\n");
2497 #endif
2498                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2499                                 param->fp_verbose |= VERBOSE_OFFSET;
2500                                 param->fp_max_depth = 0;
2501                         }
2502                         break;
2503                 case 'I':
2504                         if (optarg != NULL) {
2505                                 param->fp_comp_id = strtoul(optarg, &end, 0);
2506                                 if (*end != '\0') {
2507                                         param->fp_verbose |= VERBOSE_COMP_ID;
2508                                         param->fp_max_depth = 0;
2509                                         optind--;
2510                                 } else {
2511                                         param->fp_check_comp_id = 1;
2512                                 }
2513                         } else {
2514                                 param->fp_max_depth = 0;
2515                                 param->fp_verbose |= VERBOSE_COMP_ID;
2516                         }
2517                         break;
2518                 case 'L':
2519                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2520                                 param->fp_verbose |= VERBOSE_LAYOUT;
2521                                 param->fp_max_depth = 0;
2522                         }
2523                         break;
2524 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2525                 case 'M':
2526 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2527                         fprintf(stderr, "warning: '-M' deprecated"
2528                                 ", use '-m' instead\n");
2529 #endif
2530 #endif
2531                 case 'm':
2532                         if (!(param->fp_verbose & VERBOSE_DETAIL))
2533                                 param->fp_max_depth = 0;
2534                         param->fp_verbose |= VERBOSE_MDTINDEX;
2535                         break;
2536                 case 'O':
2537                         if (param->fp_obd_uuid) {
2538                                 fprintf(stderr,
2539                                         "error: %s: only one obduuid allowed",
2540                                         argv[0]);
2541                                 return CMD_HELP;
2542                         }
2543                         param->fp_obd_uuid = (struct obd_uuid *)optarg;
2544                         break;
2545                 case 'p':
2546                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2547                                 param->fp_verbose |= VERBOSE_POOL;
2548                                 param->fp_max_depth = 0;
2549                         }
2550                         break;
2551                 case 'q':
2552                         param->fp_quiet++;
2553                         break;
2554                 case 'r':
2555                         param->fp_recursive = 1;
2556                         break;
2557                 case 'R':
2558                         param->fp_raw = 1;
2559                         break;
2560 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2561                 case 's':
2562                         fprintf(stderr, "warning: '--size|-s' deprecated, "
2563                                 "use '--stripe-size|-S' instead\n");
2564 #endif /* LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0) */
2565                 case 'S':
2566                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2567                                 param->fp_verbose |= VERBOSE_SIZE;
2568                                 param->fp_max_depth = 0;
2569                         }
2570                         break;
2571                 case 'v':
2572                         param->fp_verbose = VERBOSE_DEFAULT | VERBOSE_DETAIL;
2573                         break;
2574                 default:
2575                         return CMD_HELP;
2576                 }
2577         }
2578
2579         if (optind >= argc)
2580                 return CMD_HELP;
2581
2582         if (param->fp_recursive)
2583                 param->fp_max_depth = -1;
2584         else if (param->fp_verbose & VERBOSE_DETAIL)
2585                 param->fp_max_depth = 1;
2586
2587         if (!param->fp_verbose)
2588                 param->fp_verbose = VERBOSE_DEFAULT;
2589         if (param->fp_quiet)
2590                 param->fp_verbose = VERBOSE_OBJID;
2591
2592         do {
2593                 rc = llapi_getstripe(argv[optind], param);
2594         } while (++optind < argc && !rc);
2595
2596         if (rc)
2597                 fprintf(stderr, "error: %s failed for %s.\n",
2598                         argv[0], argv[optind - 1]);
2599         return rc;
2600 }
2601
2602 static int lfs_tgts(int argc, char **argv)
2603 {
2604         char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
2605         struct find_param param;
2606         int index = 0, rc=0;
2607
2608         if (argc > 2)
2609                 return CMD_HELP;
2610
2611         if (argc == 2 && !realpath(argv[1], path)) {
2612                 rc = -errno;
2613                 fprintf(stderr, "error: invalid path '%s': %s\n",
2614                         argv[1], strerror(-rc));
2615                 return rc;
2616         }
2617
2618         while (!llapi_search_mounts(path, index++, mntdir, NULL)) {
2619                 /* Check if we have a mount point */
2620                 if (mntdir[0] == '\0')
2621                         continue;
2622
2623                 memset(&param, 0, sizeof(param));
2624                 if (!strcmp(argv[0], "mdts"))
2625                         param.fp_get_lmv = 1;
2626
2627                 rc = llapi_ostlist(mntdir, &param);
2628                 if (rc) {
2629                         fprintf(stderr, "error: %s: failed on %s\n",
2630                                 argv[0], mntdir);
2631                 }
2632                 if (path[0] != '\0')
2633                         break;
2634                 memset(mntdir, 0, PATH_MAX);
2635         }
2636
2637         return rc;
2638 }
2639
2640 static int lfs_getstripe(int argc, char **argv)
2641 {
2642         struct find_param param = { 0 };
2643
2644         param.fp_max_depth = 1;
2645         return lfs_getstripe_internal(argc, argv, &param);
2646 }
2647
2648 /* functions */
2649 static int lfs_getdirstripe(int argc, char **argv)
2650 {
2651         struct find_param param = { 0 };
2652         struct option long_opts[] = {
2653 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2654                 {"mdt-count",   no_argument,            0, 'c'},
2655 #endif
2656                 {"mdt-hash",    no_argument,            0, 'H'},
2657                 {"mdt-index",   no_argument,            0, 'i'},
2658                 {"recursive",   no_argument,            0, 'r'},
2659 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2660                 {"mdt-hash",    no_argument,            0, 't'},
2661 #endif
2662                 {"default",     no_argument,            0, 'D'},
2663                 {"obd",         required_argument,      0, 'O'},
2664                 {"mdt-count",   no_argument,            0, 'T'},
2665                 {0, 0, 0, 0}
2666         };
2667         int c, rc;
2668
2669         param.fp_get_lmv = 1;
2670
2671         while ((c = getopt_long(argc, argv,
2672                                 "cDHiO:rtT", long_opts, NULL)) != -1)
2673         {
2674                 switch (c) {
2675                 case 'O':
2676                         if (param.fp_obd_uuid) {
2677                                 fprintf(stderr,
2678                                         "error: %s: only one obduuid allowed",
2679                                         argv[0]);
2680                                 return CMD_HELP;
2681                         }
2682                         param.fp_obd_uuid = (struct obd_uuid *)optarg;
2683                         break;
2684 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2685                 case 'c':
2686 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 10, 50, 0)
2687                         fprintf(stderr, "warning: '-c' deprecated"
2688                                 ", use '-T' instead\n");
2689 #endif
2690 #endif
2691                 case 'T':
2692                         param.fp_verbose |= VERBOSE_COUNT;
2693                         break;
2694                 case 'i':
2695                         param.fp_verbose |= VERBOSE_OFFSET;
2696                         break;
2697 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2698                 case 't':
2699 #endif
2700                 case 'H':
2701                         param.fp_verbose |= VERBOSE_HASH_TYPE;
2702                         break;
2703                 case 'D':
2704                         param.fp_get_default_lmv = 1;
2705                         break;
2706                 case 'r':
2707                         param.fp_recursive = 1;
2708                         break;
2709                 default:
2710                         return CMD_HELP;
2711                 }
2712         }
2713
2714         if (optind >= argc)
2715                 return CMD_HELP;
2716
2717         if (param.fp_recursive)
2718                 param.fp_max_depth = -1;
2719
2720         if (!param.fp_verbose)
2721                 param.fp_verbose = VERBOSE_DEFAULT;
2722
2723         do {
2724                 rc = llapi_getstripe(argv[optind], &param);
2725         } while (++optind < argc && !rc);
2726
2727         if (rc)
2728                 fprintf(stderr, "error: %s failed for %s.\n",
2729                         argv[0], argv[optind - 1]);
2730         return rc;
2731 }
2732
2733 /* functions */
2734 static int lfs_setdirstripe(int argc, char **argv)
2735 {
2736         char                    *dname;
2737         int                     result;
2738         unsigned int            stripe_offset = -1;
2739         unsigned int            stripe_count = 1;
2740         enum lmv_hash_type      hash_type;
2741         char                    *end;
2742         int                     c;
2743         char                    *stripe_offset_opt = NULL;
2744         char                    *stripe_count_opt = NULL;
2745         char                    *stripe_hash_opt = NULL;
2746         char                    *mode_opt = NULL;
2747         bool                    default_stripe = false;
2748         mode_t                  mode = S_IRWXU | S_IRWXG | S_IRWXO;
2749         mode_t                  previous_mode = 0;
2750         bool                    delete = false;
2751
2752         struct option long_opts[] = {
2753 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2754                 {"count",       required_argument, 0, 'c'},
2755 #endif
2756                 {"mdt-count",   required_argument, 0, 'c'},
2757                 {"delete",      no_argument, 0, 'd'},
2758 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2759                 {"index",       required_argument, 0, 'i'},
2760 #endif
2761                 {"mdt-index",   required_argument, 0, 'i'},
2762                 {"mode",        required_argument, 0, 'm'},
2763 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2764                 {"hash-type",   required_argument, 0, 't'},
2765                 {"mdt-hash",    required_argument, 0, 't'},
2766 #endif
2767                 {"mdt-hash",    required_argument, 0, 'H'},
2768 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2769                 {"default_stripe", no_argument, 0, 'D'},
2770 #endif
2771                 {"default",     no_argument, 0, 'D'},
2772                 {0, 0, 0, 0}
2773         };
2774
2775         while ((c = getopt_long(argc, argv, "c:dDi:H:m:t:", long_opts,
2776                                 NULL)) >= 0) {
2777                 switch (c) {
2778                 case 0:
2779                         /* Long options. */
2780                         break;
2781                 case 'c':
2782 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2783                         if (strcmp(argv[optind - 1], "--count") == 0)
2784                                 fprintf(stderr, "warning: '--count' deprecated"
2785                                         ", use '--mdt-count' instead\n");
2786 #endif
2787                         stripe_count_opt = optarg;
2788                         break;
2789                 case 'd':
2790                         delete = true;
2791                         default_stripe = true;
2792                         break;
2793                 case 'D':
2794                         default_stripe = true;
2795                         break;
2796                 case 'i':
2797 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2798                         if (strcmp(argv[optind - 1], "--index") == 0)
2799                                 fprintf(stderr, "warning: '--index' deprecated"
2800                                         ", use '--mdt-index' instead\n");
2801 #endif
2802                         stripe_offset_opt = optarg;
2803                         break;
2804                 case 'm':
2805                         mode_opt = optarg;
2806                         break;
2807 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2808                 case 't':
2809 #endif
2810                 case 'H':
2811 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2812                         if (strcmp(argv[optind - 1], "--hash-type") == 0)
2813                                 fprintf(stderr, "warning: '--hash-type' "
2814                                         "deprecated, use '--mdt-hash' "
2815                                         "instead\n");
2816 #endif
2817                         stripe_hash_opt = optarg;
2818                         break;
2819                 default:
2820                         fprintf(stderr, "error: %s: option '%s' "
2821                                         "unrecognized\n",
2822                                         argv[0], argv[optind - 1]);
2823                         return CMD_HELP;
2824                 }
2825         }
2826
2827         if (optind == argc) {
2828                 fprintf(stderr, "error: %s: missing dirname\n",
2829                         argv[0]);
2830                 return CMD_HELP;
2831         }
2832
2833         if (!delete && stripe_offset_opt == NULL && stripe_count_opt == NULL) {
2834                 fprintf(stderr, "error: %s: missing stripe offset and count.\n",
2835                         argv[0]);
2836                 return CMD_HELP;
2837         }
2838
2839         if (stripe_offset_opt != NULL) {
2840                 /* get the stripe offset */
2841                 stripe_offset = strtoul(stripe_offset_opt, &end, 0);
2842                 if (*end != '\0') {
2843                         fprintf(stderr, "error: %s: bad stripe offset '%s'\n",
2844                                 argv[0], stripe_offset_opt);
2845                         return CMD_HELP;
2846                 }
2847         }
2848
2849         if (delete) {
2850                 if (stripe_offset_opt != NULL || stripe_count_opt != NULL) {
2851                         fprintf(stderr, "error: %s: cannot specify -d with -s,"
2852                                 " or -i options.\n", argv[0]);
2853                         return CMD_HELP;
2854                 } else {
2855                         stripe_count = 0;
2856                 }
2857         }
2858
2859
2860         if (mode_opt != NULL) {
2861                 mode = strtoul(mode_opt, &end, 8);
2862                 if (*end != '\0') {
2863                         fprintf(stderr, "error: %s: bad mode '%s'\n",
2864                                 argv[0], mode_opt);
2865                         return CMD_HELP;
2866                 }
2867                 previous_mode = umask(0);
2868         }
2869
2870         if (stripe_hash_opt == NULL) {
2871                 hash_type = LMV_HASH_TYPE_FNV_1A_64;
2872         } else {
2873                 hash_type = check_hashtype(stripe_hash_opt);
2874                 if (hash_type == 0) {
2875                         fprintf(stderr,
2876                                 "error: %s: bad stripe hash type '%s'\n",
2877                                 argv[0], stripe_hash_opt);
2878                         return CMD_HELP;
2879                 }
2880         }
2881
2882         /* get the stripe count */
2883         if (stripe_count_opt != NULL) {
2884                 stripe_count = strtoul(stripe_count_opt, &end, 0);
2885                 if (*end != '\0') {
2886                         fprintf(stderr, "error: %s: bad stripe count '%s'\n",
2887                                 argv[0], stripe_count_opt);
2888                         return CMD_HELP;
2889                 }
2890         }
2891
2892         dname = argv[optind];
2893         do {
2894                 if (default_stripe) {
2895                         result = llapi_dir_set_default_lmv_stripe(dname,
2896                                                     stripe_offset, stripe_count,
2897                                                     hash_type, NULL);
2898                 } else {
2899                         result = llapi_dir_create_pool(dname, mode,
2900                                                        stripe_offset,
2901                                                        stripe_count, hash_type,
2902                                                        NULL);
2903                 }
2904
2905                 if (result) {
2906                         fprintf(stderr, "error: %s: create stripe dir '%s' "
2907                                 "failed\n", argv[0], dname);
2908                         break;
2909                 }
2910                 dname = argv[++optind];
2911         } while (dname != NULL);
2912
2913         if (mode_opt != NULL)
2914                 umask(previous_mode);
2915
2916         return result;
2917 }
2918
2919 /* functions */
2920 static int lfs_rmentry(int argc, char **argv)
2921 {
2922         char *dname;
2923         int   index;
2924         int   result = 0;
2925
2926         if (argc <= 1) {
2927                 fprintf(stderr, "error: %s: missing dirname\n",
2928                         argv[0]);
2929                 return CMD_HELP;
2930         }
2931
2932         index = 1;
2933         dname = argv[index];
2934         while (dname != NULL) {
2935                 result = llapi_direntry_remove(dname);
2936                 if (result) {
2937                         fprintf(stderr, "error: %s: remove dir entry '%s' "
2938                                 "failed\n", argv[0], dname);
2939                         break;
2940                 }
2941                 dname = argv[++index];
2942         }
2943         return result;
2944 }
2945
2946 static int lfs_mv(int argc, char **argv)
2947 {
2948         struct  find_param param = {
2949                 .fp_max_depth = -1,
2950                 .fp_mdt_index = -1,
2951         };
2952         char   *end;
2953         int     c;
2954         int     rc = 0;
2955         struct option long_opts[] = {
2956                 {"mdt-index", required_argument, 0, 'M'},
2957                 {"verbose",     no_argument,       0, 'v'},
2958                 {0, 0, 0, 0}
2959         };
2960
2961         while ((c = getopt_long(argc, argv, "M:v", long_opts, NULL)) != -1) {
2962                 switch (c) {
2963                 case 'M': {
2964                         param.fp_mdt_index = strtoul(optarg, &end, 0);
2965                         if (*end != '\0') {
2966                                 fprintf(stderr, "%s: invalid MDT index'%s'\n",
2967                                         argv[0], optarg);
2968                                 return CMD_HELP;
2969                         }
2970                         break;
2971                 }
2972                 case 'v': {
2973                         param.fp_verbose = VERBOSE_DETAIL;
2974                         break;
2975                 }
2976                 default:
2977                         fprintf(stderr, "error: %s: unrecognized option '%s'\n",
2978                                 argv[0], argv[optind - 1]);
2979                         return CMD_HELP;
2980                 }
2981         }
2982
2983         if (param.fp_mdt_index == -1) {
2984                 fprintf(stderr, "%s: MDT index must be specified\n", argv[0]);
2985                 return CMD_HELP;
2986         }
2987
2988         if (optind >= argc) {
2989                 fprintf(stderr, "%s: missing operand path\n", argv[0]);
2990                 return CMD_HELP;
2991         }
2992
2993         param.fp_migrate = 1;
2994         rc = llapi_migrate_mdt(argv[optind], &param);
2995         if (rc != 0)
2996                 fprintf(stderr, "%s: cannot migrate '%s' to MDT%04x: %s\n",
2997                         argv[0], argv[optind], param.fp_mdt_index,
2998                         strerror(-rc));
2999         return rc;
3000 }
3001
3002 static int lfs_osts(int argc, char **argv)
3003 {
3004         return lfs_tgts(argc, argv);
3005 }
3006
3007 static int lfs_mdts(int argc, char **argv)
3008 {
3009         return lfs_tgts(argc, argv);
3010 }
3011
3012 #define COOK(value)                                                     \
3013 ({                                                                      \
3014         int radix = 0;                                                  \
3015         while (value > 1024) {                                          \
3016                 value /= 1024;                                          \
3017                 radix++;                                                \
3018         }                                                               \
3019         radix;                                                          \
3020 })
3021 #define UUF     "%-20s"
3022 #define CSF     "%11s"
3023 #define CDF     "%11llu"
3024 #define HDF     "%8.1f%c"
3025 #define RSF     "%4s"
3026 #define RDF     "%3d%%"
3027
3028 enum mntdf_flags {
3029         MNTDF_INODES    = 0x0001,
3030         MNTDF_COOKED    = 0x0002,
3031         MNTDF_LAZY      = 0x0004,
3032         MNTDF_VERBOSE   = 0x0008,
3033 };
3034
3035 static int showdf(char *mntdir, struct obd_statfs *stat,
3036                   char *uuid, enum mntdf_flags flags,
3037                   char *type, int index, int rc)
3038 {
3039         long long avail, used, total;
3040         double ratio = 0;
3041         char *suffix = "KMGTPEZY";
3042         /* Note if we have >2^64 bytes/fs these buffers will need to be grown */
3043         char tbuf[3 * sizeof(__u64)];
3044         char ubuf[3 * sizeof(__u64)];
3045         char abuf[3 * sizeof(__u64)];
3046         char rbuf[3 * sizeof(__u64)];
3047
3048         if (!uuid || !stat)
3049                 return -EINVAL;
3050
3051         switch (rc) {
3052         case 0:
3053                 if (flags & MNTDF_INODES) {
3054                         avail = stat->os_ffree;
3055                         used = stat->os_files - stat->os_ffree;
3056                         total = stat->os_files;
3057                 } else {
3058                         int shift = flags & MNTDF_COOKED ? 0 : 10;
3059
3060                         avail = (stat->os_bavail * stat->os_bsize) >> shift;
3061                         used  = ((stat->os_blocks - stat->os_bfree) *
3062                                  stat->os_bsize) >> shift;
3063                         total = (stat->os_blocks * stat->os_bsize) >> shift;
3064                 }
3065
3066                 if ((used + avail) > 0)
3067                         ratio = (double)used / (double)(used + avail);
3068
3069                 if (flags & MNTDF_COOKED) {
3070                         int i;
3071                         double cook_val;
3072
3073                         cook_val = (double)total;
3074                         i = COOK(cook_val);
3075                         if (i > 0)
3076                                 snprintf(tbuf, sizeof(tbuf), HDF, cook_val,
3077                                          suffix[i - 1]);
3078                         else
3079                                 snprintf(tbuf, sizeof(tbuf), CDF, total);
3080
3081                         cook_val = (double)used;
3082                         i = COOK(cook_val);
3083                         if (i > 0)
3084                                 snprintf(ubuf, sizeof(ubuf), HDF, cook_val,
3085                                          suffix[i - 1]);
3086                         else
3087                                 snprintf(ubuf, sizeof(ubuf), CDF, used);
3088
3089                         cook_val = (double)avail;
3090                         i = COOK(cook_val);
3091                         if (i > 0)
3092                                 snprintf(abuf, sizeof(abuf), HDF, cook_val,
3093                                          suffix[i - 1]);
3094                         else
3095                                 snprintf(abuf, sizeof(abuf), CDF, avail);
3096                 } else {
3097                         snprintf(tbuf, sizeof(tbuf), CDF, total);
3098                         snprintf(ubuf, sizeof(tbuf), CDF, used);
3099                         snprintf(abuf, sizeof(tbuf), CDF, avail);
3100                 }
3101
3102                 sprintf(rbuf, RDF, (int)(ratio * 100 + 0.5));
3103                 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s",
3104                        uuid, tbuf, ubuf, abuf, rbuf, mntdir);
3105                 if (type)
3106                         printf("[%s:%d]", type, index);
3107
3108                 if (stat->os_state) {
3109                         /*
3110                          * Each character represents the matching
3111                          * OS_STATE_* bit.
3112                          */
3113                         const char state_names[] = "DRSI";
3114                         __u32      state;
3115                         __u32      i;
3116
3117                         printf(" ");
3118                         for (i = 0, state = stat->os_state;
3119                              state && i < sizeof(state_names); i++) {
3120                                 if (!(state & (1 << i)))
3121                                         continue;
3122                                 printf("%c", state_names[i]);
3123                                 state ^= 1 << i;
3124                         }
3125                 }
3126
3127                 printf("\n");
3128                 break;
3129         case -ENODATA:
3130                 printf(UUF": inactive device\n", uuid);
3131                 break;
3132         default:
3133                 printf(UUF": %s\n", uuid, strerror(-rc));
3134                 break;
3135         }
3136
3137         return 0;
3138 }
3139
3140 struct ll_stat_type {
3141         int   st_op;
3142         char *st_name;
3143 };
3144
3145 static int mntdf(char *mntdir, char *fsname, char *pool, enum mntdf_flags flags)
3146 {
3147         struct obd_statfs stat_buf, sum = { .os_bsize = 1 };
3148         struct obd_uuid uuid_buf;
3149         char *poolname = NULL;
3150         struct ll_stat_type types[] = { { LL_STATFS_LMV, "MDT" },
3151                                         { LL_STATFS_LOV, "OST" },
3152                                         { 0, NULL } };
3153         struct ll_stat_type *tp;
3154         __u64 ost_ffree = 0;
3155         __u32 index;
3156         __u32 type;
3157         int fd;
3158         int rc = 0;
3159         int rc2;
3160
3161         if (pool) {
3162                 poolname = strchr(pool, '.');
3163                 if (poolname != NULL) {
3164                         if (strncmp(fsname, pool, strlen(fsname))) {
3165                                 fprintf(stderr, "filesystem name incorrect\n");
3166                                 return -ENODEV;
3167                         }
3168                         poolname++;
3169                 } else
3170                         poolname = pool;
3171         }
3172
3173         fd = open(mntdir, O_RDONLY);
3174         if (fd < 0) {
3175                 rc = -errno;
3176                 fprintf(stderr, "%s: cannot open '%s': %s\n", progname, mntdir,
3177                         strerror(errno));
3178                 return rc;
3179         }
3180
3181         if (flags & MNTDF_INODES)
3182                 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
3183                        "UUID", "Inodes", "IUsed", "IFree",
3184                        "IUse%", "Mounted on");
3185         else
3186                 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
3187                        "UUID", flags & MNTDF_COOKED ? "bytes" : "1K-blocks",
3188                        "Used", "Available", "Use%", "Mounted on");
3189
3190         for (tp = types; tp->st_name != NULL; tp++) {
3191                 for (index = 0; ; index++) {
3192                         memset(&stat_buf, 0, sizeof(struct obd_statfs));
3193                         memset(&uuid_buf, 0, sizeof(struct obd_uuid));
3194                         type = flags & MNTDF_LAZY ?
3195                                 tp->st_op | LL_STATFS_NODELAY : tp->st_op;
3196                         rc2 = llapi_obd_fstatfs(fd, type, index,
3197                                                &stat_buf, &uuid_buf);
3198                         if (rc2 == -ENODEV)
3199                                 break;
3200                         if (rc2 == -EAGAIN)
3201                                 continue;
3202                         if (rc2 == -ENODATA) { /* Inactive device, OK. */
3203                                 if (!(flags & MNTDF_VERBOSE))
3204                                         continue;
3205                         } else if (rc2 < 0 && rc == 0) {
3206                                 rc = rc2;
3207                         }
3208
3209                         if (poolname && tp->st_op == LL_STATFS_LOV &&
3210                             llapi_search_ost(fsname, poolname,
3211                                              obd_uuid2str(&uuid_buf)) != 1)
3212                                 continue;
3213
3214                         /* the llapi_obd_statfs() call may have returned with
3215                          * an error, but if it filled in uuid_buf we will at
3216                          * lease use that to print out a message for that OBD.
3217                          * If we didn't get anything in the uuid_buf, then fill
3218                          * it in so that we can print an error message. */
3219                         if (uuid_buf.uuid[0] == '\0')
3220                                 snprintf(uuid_buf.uuid, sizeof(uuid_buf.uuid),
3221                                          "%s%04x", tp->st_name, index);
3222                         showdf(mntdir, &stat_buf, obd_uuid2str(&uuid_buf),
3223                                flags, tp->st_name, index, rc2);
3224
3225                         if (rc2 == 0) {
3226                                 if (tp->st_op == LL_STATFS_LMV) {
3227                                         sum.os_ffree += stat_buf.os_ffree;
3228                                         sum.os_files += stat_buf.os_files;
3229                                 } else /* if (tp->st_op == LL_STATFS_LOV) */ {
3230                                         sum.os_blocks += stat_buf.os_blocks *
3231                                                 stat_buf.os_bsize;
3232                                         sum.os_bfree  += stat_buf.os_bfree *
3233                                                 stat_buf.os_bsize;
3234                                         sum.os_bavail += stat_buf.os_bavail *
3235                                                 stat_buf.os_bsize;
3236                                         ost_ffree += stat_buf.os_ffree;
3237                                 }
3238                         }
3239                 }
3240         }
3241
3242         close(fd);
3243
3244         /* If we don't have as many objects free on the OST as inodes
3245          * on the MDS, we reduce the total number of inodes to
3246          * compensate, so that the "inodes in use" number is correct.
3247          * Matches ll_statfs_internal() so the results are consistent. */
3248         if (ost_ffree < sum.os_ffree) {
3249                 sum.os_files = (sum.os_files - sum.os_ffree) + ost_ffree;
3250                 sum.os_ffree = ost_ffree;
3251         }
3252         printf("\n");
3253         showdf(mntdir, &sum, "filesystem_summary:", flags, NULL, 0, 0);
3254         printf("\n");
3255
3256         return rc;
3257 }
3258
3259 static int lfs_df(int argc, char **argv)
3260 {
3261         char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
3262         enum mntdf_flags flags = 0;
3263         int c, rc = 0, index = 0;
3264         char fsname[PATH_MAX] = "", *pool_name = NULL;
3265         struct option long_opts[] = {
3266                 {"human-readable", 0, 0, 'h'},
3267                 {"inodes", 0, 0, 'i'},
3268                 {"lazy", 0, 0, 'l'},
3269                 {"pool", required_argument, 0, 'p'},
3270                 {"verbose", 0, 0, 'v'},
3271                 {0, 0, 0, 0}
3272         };
3273
3274         while ((c = getopt_long(argc, argv, "hilp:v", long_opts, NULL)) != -1) {
3275                 switch (c) {
3276                 case 'h':
3277                         flags |= MNTDF_COOKED;
3278                         break;
3279                 case 'i':
3280                         flags |= MNTDF_INODES;
3281                         break;
3282                 case 'l':
3283                         flags |= MNTDF_LAZY;
3284                         break;
3285                 case 'p':
3286                         pool_name = optarg;
3287                         break;
3288                 case 'v':
3289                         flags |= MNTDF_VERBOSE;
3290                         break;
3291                 default:
3292                         return CMD_HELP;
3293                 }
3294         }
3295         if (optind < argc && !realpath(argv[optind], path)) {
3296                 rc = -errno;
3297                 fprintf(stderr, "error: invalid path '%s': %s\n",
3298                         argv[optind], strerror(-rc));
3299                 return rc;
3300         }
3301
3302         while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
3303                 /* Check if we have a mount point */
3304                 if (mntdir[0] == '\0')
3305                         continue;
3306
3307                 rc = mntdf(mntdir, fsname, pool_name, flags);
3308                 if (rc || path[0] != '\0')
3309                         break;
3310                 fsname[0] = '\0'; /* avoid matching in next loop */
3311                 mntdir[0] = '\0'; /* avoid matching in next loop */
3312         }
3313
3314         return rc;
3315 }
3316
3317 static int lfs_getname(int argc, char **argv)
3318 {
3319         char mntdir[PATH_MAX] = "", path[PATH_MAX] = "", fsname[PATH_MAX] = "";
3320         int rc = 0, index = 0, c;
3321         char buf[sizeof(struct obd_uuid)];
3322
3323         while ((c = getopt(argc, argv, "h")) != -1)
3324                 return CMD_HELP;
3325
3326         if (optind == argc) { /* no paths specified, get all paths. */
3327                 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
3328                         rc = llapi_getname(mntdir, buf, sizeof(buf));
3329                         if (rc < 0) {
3330                                 fprintf(stderr,
3331                                         "cannot get name for `%s': %s\n",
3332                                         mntdir, strerror(-rc));
3333                                 break;
3334                         }
3335
3336                         printf("%s %s\n", buf, mntdir);
3337
3338                         path[0] = fsname[0] = mntdir[0] = 0;
3339                 }
3340         } else { /* paths specified, only attempt to search these. */
3341                 for (; optind < argc; optind++) {
3342                         rc = llapi_getname(argv[optind], buf, sizeof(buf));
3343                         if (rc < 0) {
3344                                 fprintf(stderr,
3345                                         "cannot get name for `%s': %s\n",
3346                                         argv[optind], strerror(-rc));
3347                                 break;
3348                         }
3349
3350                         printf("%s %s\n", buf, argv[optind]);
3351                 }
3352         }
3353         return rc;
3354 }
3355
3356 static int lfs_check(int argc, char **argv)
3357 {
3358         int rc;
3359         char mntdir[PATH_MAX] = {'\0'};
3360         int num_types = 1;
3361         char *obd_types[2];
3362         char obd_type1[4];
3363         char obd_type2[4];
3364
3365         if (argc != 2)
3366                 return CMD_HELP;
3367
3368         obd_types[0] = obd_type1;
3369         obd_types[1] = obd_type2;
3370
3371         if (strcmp(argv[1], "osts") == 0) {
3372                 strcpy(obd_types[0], "osc");
3373         } else if (strcmp(argv[1], "mds") == 0) {
3374                 strcpy(obd_types[0], "mdc");
3375         } else if (strcmp(argv[1], "servers") == 0) {
3376                 num_types = 2;
3377                 strcpy(obd_types[0], "osc");
3378                 strcpy(obd_types[1], "mdc");
3379         } else {
3380                 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
3381                                 argv[0], argv[1]);
3382                         return CMD_HELP;
3383         }
3384
3385         rc = llapi_search_mounts(NULL, 0, mntdir, NULL);
3386         if (rc < 0 || mntdir[0] == '\0') {
3387                 fprintf(stderr, "No suitable Lustre mount found\n");
3388                 return rc;
3389         }
3390
3391         rc = llapi_target_check(num_types, obd_types, mntdir);
3392         if (rc)
3393                 fprintf(stderr, "error: %s: %s status failed\n",
3394                                 argv[0],argv[1]);
3395
3396         return rc;
3397
3398 }
3399
3400 #ifdef HAVE_SYS_QUOTA_H
3401 #define ARG2INT(nr, str, msg)                                           \
3402 do {                                                                    \
3403         char *endp;                                                     \
3404         nr = strtol(str, &endp, 0);                                     \
3405         if (*endp) {                                                    \
3406                 fprintf(stderr, "error: bad %s: %s\n", msg, str);       \
3407                 return CMD_HELP;                                        \
3408         }                                                               \
3409 } while (0)
3410
3411 #define ADD_OVERFLOW(a,b) ((a + b) < a) ? (a = ULONG_MAX) : (a = a + b)
3412
3413 /* Convert format time string "XXwXXdXXhXXmXXs" into seconds value
3414  * returns the value or ULONG_MAX on integer overflow or incorrect format
3415  * Notes:
3416  *        1. the order of specifiers is arbitrary (may be: 5w3s or 3s5w)
3417  *        2. specifiers may be encountered multiple times (2s3s is 5 seconds)
3418  *        3. empty integer value is interpreted as 0
3419  */
3420 static unsigned long str2sec(const char* timestr)
3421 {
3422         const char spec[] = "smhdw";
3423         const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
3424         unsigned long val = 0;
3425         char *tail;
3426
3427         if (strpbrk(timestr, spec) == NULL) {
3428                 /* no specifiers inside the time string,
3429                    should treat it as an integer value */
3430                 val = strtoul(timestr, &tail, 10);
3431                 return *tail ? ULONG_MAX : val;
3432         }
3433
3434         /* format string is XXwXXdXXhXXmXXs */
3435         while (*timestr) {
3436                 unsigned long v;
3437                 int ind;
3438                 char* ptr;
3439
3440                 v = strtoul(timestr, &tail, 10);
3441                 if (v == ULONG_MAX || *tail == '\0')
3442                         /* value too large (ULONG_MAX or more)
3443                            or missing specifier */
3444                         goto error;
3445
3446                 ptr = strchr(spec, *tail);
3447                 if (ptr == NULL)
3448                         /* unknown specifier */
3449                         goto error;
3450
3451                 ind = ptr - spec;
3452
3453                 /* check if product will overflow the type */
3454                 if (!(v < ULONG_MAX / mult[ind]))
3455                         goto error;
3456
3457                 ADD_OVERFLOW(val, mult[ind] * v);
3458                 if (val == ULONG_MAX)
3459                         goto error;
3460
3461                 timestr = tail + 1;
3462         }
3463
3464         return val;
3465
3466 error:
3467         return ULONG_MAX;
3468 }
3469
3470 #define ARG2ULL(nr, str, def_units)                                     \
3471 do {                                                                    \
3472         unsigned long long limit, units = def_units;                    \
3473         int rc;                                                         \
3474                                                                         \
3475         rc = llapi_parse_size(str, &limit, &units, 1);                  \
3476         if (rc < 0) {                                                   \
3477                 fprintf(stderr, "error: bad limit value %s\n", str);    \
3478                 return CMD_HELP;                                        \
3479         }                                                               \
3480         nr = limit;                                                     \
3481 } while (0)
3482
3483 static inline int has_times_option(int argc, char **argv)
3484 {
3485         int i;
3486
3487         for (i = 1; i < argc; i++)
3488                 if (!strcmp(argv[i], "-t"))
3489                         return 1;
3490
3491         return 0;
3492 }
3493
3494 int lfs_setquota_times(int argc, char **argv)
3495 {
3496         int c, rc;
3497         struct if_quotactl qctl;
3498         char *mnt, *obd_type = (char *)qctl.obd_type;
3499         struct obd_dqblk *dqb = &qctl.qc_dqblk;
3500         struct obd_dqinfo *dqi = &qctl.qc_dqinfo;
3501         struct option long_opts[] = {
3502                 {"block-grace",     required_argument, 0, 'b'},
3503                 {"group",           no_argument,       0, 'g'},
3504                 {"inode-grace",     required_argument, 0, 'i'},
3505                 {"project",         no_argument,       0, 'p'},
3506                 {"times",           no_argument,       0, 't'},
3507                 {"user",            no_argument,       0, 'u'},
3508                 {0, 0, 0, 0}
3509         };
3510         int qtype;
3511
3512         memset(&qctl, 0, sizeof(qctl));
3513         qctl.qc_cmd  = LUSTRE_Q_SETINFO;
3514         qctl.qc_type = ALLQUOTA;
3515
3516         while ((c = getopt_long(argc, argv, "b:gi:ptu",
3517                                 long_opts, NULL)) != -1) {
3518                 switch (c) {
3519                 case 'u':
3520                         qtype = USRQUOTA;
3521                         goto quota_type;
3522                 case 'g':
3523                         qtype = GRPQUOTA;
3524                         goto quota_type;
3525                 case 'p':
3526                         qtype = PRJQUOTA;
3527 quota_type:
3528                         if (qctl.qc_type != ALLQUOTA) {
3529                                 fprintf(stderr, "error: -u/g/p can't be used "
3530                                                 "more than once\n");
3531                                 return CMD_HELP;
3532                         }
3533                         qctl.qc_type = qtype;
3534                         break;
3535                 case 'b':
3536                         if ((dqi->dqi_bgrace = str2sec(optarg)) == ULONG_MAX) {
3537                                 fprintf(stderr, "error: bad block-grace: %s\n",
3538                                         optarg);
3539                                 return CMD_HELP;
3540                         }
3541                         dqb->dqb_valid |= QIF_BTIME;
3542                         break;
3543                 case 'i':
3544                         if ((dqi->dqi_igrace = str2sec(optarg)) == ULONG_MAX) {
3545                                 fprintf(stderr, "error: bad inode-grace: %s\n",
3546                                         optarg);
3547                                 return CMD_HELP;
3548                         }
3549                         dqb->dqb_valid |= QIF_ITIME;
3550                         break;
3551                 case 't': /* Yes, of course! */
3552                         break;
3553                 default: /* getopt prints error message for us when opterr != 0 */
3554                         return CMD_HELP;
3555                 }
3556         }
3557
3558         if (qctl.qc_type == ALLQUOTA) {
3559                 fprintf(stderr, "error: neither -u, -g nor -p specified\n");
3560                 return CMD_HELP;
3561         }
3562
3563         if (optind != argc - 1) {
3564                 fprintf(stderr, "error: unexpected parameters encountered\n");
3565                 return CMD_HELP;
3566         }
3567
3568         mnt = argv[optind];
3569         rc = llapi_quotactl(mnt, &qctl);
3570         if (rc) {
3571                 if (*obd_type)
3572                         fprintf(stderr, "%s %s ", obd_type,
3573                                 obd_uuid2str(&qctl.obd_uuid));
3574                 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
3575                 return rc;
3576         }
3577
3578         return 0;
3579 }
3580
3581 #define BSLIMIT (1 << 0)
3582 #define BHLIMIT (1 << 1)
3583 #define ISLIMIT (1 << 2)
3584 #define IHLIMIT (1 << 3)
3585
3586 int lfs_setquota(int argc, char **argv)
3587 {
3588         int c, rc;
3589         struct if_quotactl qctl;
3590         char *mnt, *obd_type = (char *)qctl.obd_type;
3591         struct obd_dqblk *dqb = &qctl.qc_dqblk;
3592         struct option long_opts[] = {
3593                 {"block-softlimit", required_argument, 0, 'b'},
3594                 {"block-hardlimit", required_argument, 0, 'B'},
3595                 {"group",           required_argument, 0, 'g'},
3596                 {"inode-softlimit", required_argument, 0, 'i'},
3597                 {"inode-hardlimit", required_argument, 0, 'I'},
3598                 {"user",            required_argument, 0, 'u'},
3599                 {"project",         required_argument, 0, 'p'},
3600                 {0, 0, 0, 0}
3601         };
3602         unsigned limit_mask = 0;
3603         char *endptr;
3604         int qtype;
3605
3606         if (has_times_option(argc, argv))
3607                 return lfs_setquota_times(argc, argv);
3608
3609         memset(&qctl, 0, sizeof(qctl));
3610         qctl.qc_cmd  = LUSTRE_Q_SETQUOTA;
3611         qctl.qc_type = ALLQUOTA; /* ALLQUOTA makes no sense for setquota,
3612                                  * so it can be used as a marker that qc_type
3613                                  * isn't reinitialized from command line */
3614
3615         while ((c = getopt_long(argc, argv, "b:B:g:i:I:p:u:",
3616                 long_opts, NULL)) != -1) {
3617                 switch (c) {
3618                 case 'u':
3619                         qtype = USRQUOTA;
3620                         rc = name2uid(&qctl.qc_id, optarg);
3621                         goto quota_type;
3622                 case 'g':
3623                         qtype = GRPQUOTA;
3624                         rc = name2gid(&qctl.qc_id, optarg);
3625                         goto quota_type;
3626                 case 'p':
3627                         qtype = PRJQUOTA;
3628                         rc = name2projid(&qctl.qc_id, optarg);
3629 quota_type:
3630                         if (qctl.qc_type != ALLQUOTA) {
3631                                 fprintf(stderr, "error: -u and -g can't be used"
3632                                                 " more than once\n");
3633                                 return CMD_HELP;
3634                         }
3635                         qctl.qc_type = qtype;
3636                         if (rc) {
3637                                 qctl.qc_id = strtoul(optarg, &endptr, 10);
3638                                 if (*endptr != '\0') {
3639                                         fprintf(stderr, "error: can't find id "
3640                                                 "for name %s\n", optarg);
3641                                         return CMD_HELP;
3642                                 }
3643                         }
3644                         break;
3645                 case 'b':
3646                         ARG2ULL(dqb->dqb_bsoftlimit, optarg, 1024);
3647                         dqb->dqb_bsoftlimit >>= 10;
3648                         limit_mask |= BSLIMIT;
3649                         if (dqb->dqb_bsoftlimit &&
3650                             dqb->dqb_bsoftlimit <= 1024) /* <= 1M? */
3651                                 fprintf(stderr, "warning: block softlimit is "
3652                                         "smaller than the miminal qunit size, "
3653                                         "please see the help of setquota or "
3654                                         "Lustre manual for details.\n");
3655                         break;
3656                 case 'B':
3657                         ARG2ULL(dqb->dqb_bhardlimit, optarg, 1024);
3658                         dqb->dqb_bhardlimit >>= 10;
3659                         limit_mask |= BHLIMIT;
3660                         if (dqb->dqb_bhardlimit &&
3661                             dqb->dqb_bhardlimit <= 1024) /* <= 1M? */
3662                                 fprintf(stderr, "warning: block hardlimit is "
3663                                         "smaller than the miminal qunit size, "
3664                                         "please see the help of setquota or "
3665                                         "Lustre manual for details.\n");
3666                         break;
3667                 case 'i':
3668                         ARG2ULL(dqb->dqb_isoftlimit, optarg, 1);
3669                         limit_mask |= ISLIMIT;
3670                         if (dqb->dqb_isoftlimit &&
3671                             dqb->dqb_isoftlimit <= 1024) /* <= 1K inodes? */
3672                                 fprintf(stderr, "warning: inode softlimit is "
3673                                         "smaller than the miminal qunit size, "
3674                                         "please see the help of setquota or "
3675                                         "Lustre manual for details.\n");
3676                         break;
3677                 case 'I':
3678                         ARG2ULL(dqb->dqb_ihardlimit, optarg, 1);
3679                         limit_mask |= IHLIMIT;
3680                         if (dqb->dqb_ihardlimit &&
3681                             dqb->dqb_ihardlimit <= 1024) /* <= 1K inodes? */
3682                                 fprintf(stderr, "warning: inode hardlimit is "
3683                                         "smaller than the miminal qunit size, "
3684                                         "please see the help of setquota or "
3685                                         "Lustre manual for details.\n");
3686                         break;
3687                 default: /* getopt prints error message for us when opterr != 0 */
3688                         return CMD_HELP;
3689                 }
3690         }
3691
3692         if (qctl.qc_type == ALLQUOTA) {
3693                 fprintf(stderr, "error: neither -u, -g nor -p was specified\n");
3694                 return CMD_HELP;
3695         }
3696
3697         if (limit_mask == 0) {
3698                 fprintf(stderr, "error: at least one limit must be specified\n");
3699                 return CMD_HELP;
3700         }
3701
3702         if (optind != argc - 1) {
3703                 fprintf(stderr, "error: unexpected parameters encountered\n");
3704                 return CMD_HELP;
3705         }
3706
3707         mnt = argv[optind];
3708
3709         if ((!(limit_mask & BHLIMIT) ^ !(limit_mask & BSLIMIT)) ||
3710             (!(limit_mask & IHLIMIT) ^ !(limit_mask & ISLIMIT))) {
3711                 /* sigh, we can't just set blimits/ilimits */
3712                 struct if_quotactl tmp_qctl = {.qc_cmd  = LUSTRE_Q_GETQUOTA,
3713                                                .qc_type = qctl.qc_type,
3714                                                .qc_id   = qctl.qc_id};
3715
3716                 rc = llapi_quotactl(mnt, &tmp_qctl);
3717                 if (rc < 0) {
3718                         fprintf(stderr, "error: setquota failed while retrieving"
3719                                         " current quota settings (%s)\n",
3720                                         strerror(-rc));
3721                         return rc;
3722                 }
3723
3724                 if (!(limit_mask & BHLIMIT))
3725                         dqb->dqb_bhardlimit = tmp_qctl.qc_dqblk.dqb_bhardlimit;
3726                 if (!(limit_mask & BSLIMIT))
3727                         dqb->dqb_bsoftlimit = tmp_qctl.qc_dqblk.dqb_bsoftlimit;
3728                 if (!(limit_mask & IHLIMIT))
3729                         dqb->dqb_ihardlimit = tmp_qctl.qc_dqblk.dqb_ihardlimit;
3730                 if (!(limit_mask & ISLIMIT))
3731                         dqb->dqb_isoftlimit = tmp_qctl.qc_dqblk.dqb_isoftlimit;
3732
3733                 /* Keep grace times if we have got no softlimit arguments */
3734                 if ((limit_mask & BHLIMIT) && !(limit_mask & BSLIMIT)) {
3735                         dqb->dqb_valid |= QIF_BTIME;
3736                         dqb->dqb_btime = tmp_qctl.qc_dqblk.dqb_btime;
3737                 }
3738
3739                 if ((limit_mask & IHLIMIT) && !(limit_mask & ISLIMIT)) {
3740                         dqb->dqb_valid |= QIF_ITIME;
3741                         dqb->dqb_itime = tmp_qctl.qc_dqblk.dqb_itime;
3742                 }
3743         }
3744
3745         dqb->dqb_valid |= (limit_mask & (BHLIMIT | BSLIMIT)) ? QIF_BLIMITS : 0;
3746         dqb->dqb_valid |= (limit_mask & (IHLIMIT | ISLIMIT)) ? QIF_ILIMITS : 0;
3747
3748         rc = llapi_quotactl(mnt, &qctl);
3749         if (rc) {
3750                 if (*obd_type)
3751                         fprintf(stderr, "%s %s ", obd_type,
3752                                 obd_uuid2str(&qctl.obd_uuid));
3753                 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
3754                 return rc;
3755         }
3756
3757         return 0;
3758 }
3759
3760 /* Converts seconds value into format string
3761  * result is returned in buf
3762  * Notes:
3763  *        1. result is in descenting order: 1w2d3h4m5s
3764  *        2. zero fields are not filled (except for p. 3): 5d1s
3765  *        3. zero seconds value is presented as "0s"
3766  */
3767 static char * __sec2str(time_t seconds, char *buf)
3768 {
3769         const char spec[] = "smhdw";
3770         const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
3771         unsigned long c;
3772         char *tail = buf;
3773         int i;
3774
3775         for (i = sizeof(mult) / sizeof(mult[0]) - 1 ; i >= 0; i--) {
3776                 c = seconds / mult[i];
3777
3778                 if (c > 0 || (i == 0 && buf == tail))
3779                         tail += snprintf(tail, 40-(tail-buf), "%lu%c", c, spec[i]);
3780
3781                 seconds %= mult[i];
3782         }
3783
3784         return tail;
3785 }
3786
3787 static void sec2str(time_t seconds, char *buf, int rc)
3788 {
3789         char *tail = buf;
3790
3791         if (rc)
3792                 *tail++ = '[';
3793
3794         tail = __sec2str(seconds, tail);
3795
3796         if (rc && tail - buf < 39) {
3797                 *tail++ = ']';
3798                 *tail++ = 0;
3799         }
3800 }
3801
3802 static void diff2str(time_t seconds, char *buf, time_t now)
3803 {
3804
3805         buf[0] = 0;
3806         if (!seconds)
3807                 return;
3808         if (seconds <= now) {
3809                 strcpy(buf, "none");
3810                 return;
3811         }
3812         __sec2str(seconds - now, buf);
3813 }
3814
3815 static void print_quota_title(char *name, struct if_quotactl *qctl,
3816                               bool human_readable)
3817 {
3818         printf("Disk quotas for %s %s (%cid %u):\n",
3819                qtype_name(qctl->qc_type), name,
3820                *qtype_name(qctl->qc_type), qctl->qc_id);
3821         printf("%15s%8s %7s%8s%8s%8s %7s%8s%8s\n",
3822                "Filesystem", human_readable ? "used" : "kbytes",
3823                "quota", "limit", "grace",
3824                "files", "quota", "limit", "grace");
3825 }
3826
3827 static void kbytes2str(__u64 num, char *buf, int buflen, bool h)
3828 {
3829         if (!h) {
3830                 snprintf(buf, buflen, "%ju", (uintmax_t)num);
3831         } else {
3832                 if (num >> 40)
3833                         snprintf(buf, buflen, "%5.4gP",
3834                                  (double)num / ((__u64)1 << 40));
3835                 else if (num >> 30)
3836                         snprintf(buf, buflen, "%5.4gT",
3837                                  (double)num / (1 << 30));
3838                 else if (num >> 20)
3839                         snprintf(buf, buflen, "%5.4gG",
3840                                  (double)num / (1 << 20));
3841                 else if (num >> 10)
3842                         snprintf(buf, buflen, "%5.4gM",
3843                                  (double)num / (1 << 10));
3844                 else
3845                         snprintf(buf, buflen, "%ju%s", (uintmax_t)num, "k");
3846         }
3847 }
3848
3849 #define STRBUF_LEN      32
3850 static void print_quota(char *mnt, struct if_quotactl *qctl, int type,
3851                         int rc, bool h)
3852 {
3853         time_t now;
3854
3855         time(&now);
3856
3857         if (qctl->qc_cmd == LUSTRE_Q_GETQUOTA || qctl->qc_cmd == Q_GETOQUOTA) {
3858                 int bover = 0, iover = 0;
3859                 struct obd_dqblk *dqb = &qctl->qc_dqblk;
3860                 char numbuf[3][STRBUF_LEN];
3861                 char timebuf[40];
3862                 char strbuf[STRBUF_LEN];
3863
3864                 if (dqb->dqb_bhardlimit &&
3865                     lustre_stoqb(dqb->dqb_curspace) >= dqb->dqb_bhardlimit) {
3866                         bover = 1;
3867                 } else if (dqb->dqb_bsoftlimit && dqb->dqb_btime) {
3868                         if (dqb->dqb_btime > now) {
3869                                 bover = 2;
3870                         } else {
3871                                 bover = 3;
3872                         }
3873                 }
3874
3875                 if (dqb->dqb_ihardlimit &&
3876                     dqb->dqb_curinodes >= dqb->dqb_ihardlimit) {
3877                         iover = 1;
3878                 } else if (dqb->dqb_isoftlimit && dqb->dqb_itime) {
3879                         if (dqb->dqb_itime > now) {
3880                                 iover = 2;
3881                         } else {
3882                                 iover = 3;
3883                         }
3884                 }
3885
3886
3887                 if (strlen(mnt) > 15)
3888                         printf("%s\n%15s", mnt, "");
3889                 else
3890                         printf("%15s", mnt);
3891
3892                 if (bover)
3893                         diff2str(dqb->dqb_btime, timebuf, now);
3894
3895                 kbytes2str(lustre_stoqb(dqb->dqb_curspace),
3896                            strbuf, sizeof(strbuf), h);
3897                 if (rc == -EREMOTEIO)
3898                         sprintf(numbuf[0], "%s*", strbuf);
3899                 else
3900                         sprintf(numbuf[0], (dqb->dqb_valid & QIF_SPACE) ?
3901                                 "%s" : "[%s]", strbuf);
3902
3903                 kbytes2str(dqb->dqb_bsoftlimit, strbuf, sizeof(strbuf), h);
3904                 if (type == QC_GENERAL)
3905                         sprintf(numbuf[1], (dqb->dqb_valid & QIF_BLIMITS) ?
3906                                 "%s" : "[%s]", strbuf);
3907                 else
3908                         sprintf(numbuf[1], "%s", "-");
3909
3910                 kbytes2str(dqb->dqb_bhardlimit, strbuf, sizeof(strbuf), h);
3911                 sprintf(numbuf[2], (dqb->dqb_valid & QIF_BLIMITS) ?
3912                         "%s" : "[%s]", strbuf);
3913
3914                 printf(" %7s%c %6s %7s %7s",
3915                        numbuf[0], bover ? '*' : ' ', numbuf[1],
3916                        numbuf[2], bover > 1 ? timebuf : "-");
3917
3918                 if (iover)
3919                         diff2str(dqb->dqb_itime, timebuf, now);
3920
3921                 sprintf(numbuf[0], (dqb->dqb_valid & QIF_INODES) ?
3922                         "%ju" : "[%ju]", (uintmax_t)dqb->dqb_curinodes);
3923
3924                 if (type == QC_GENERAL)
3925                         sprintf(numbuf[1], (dqb->dqb_valid & QIF_ILIMITS) ?
3926                                 "%ju" : "[%ju]",
3927                                 (uintmax_t)dqb->dqb_isoftlimit);
3928                 else
3929                         sprintf(numbuf[1], "%s", "-");
3930
3931                 sprintf(numbuf[2], (dqb->dqb_valid & QIF_ILIMITS) ?
3932                         "%ju" : "[%ju]", (uintmax_t)dqb->dqb_ihardlimit);
3933
3934                 if (type != QC_OSTIDX)
3935                         printf(" %7s%c %6s %7s %7s",
3936                                numbuf[0], iover ? '*' : ' ', numbuf[1],
3937                                numbuf[2], iover > 1 ? timebuf : "-");
3938                 else
3939                         printf(" %7s %7s %7s %7s", "-", "-", "-", "-");
3940                 printf("\n");
3941
3942         } else if (qctl->qc_cmd == LUSTRE_Q_GETINFO ||
3943                    qctl->qc_cmd == Q_GETOINFO) {
3944                 char bgtimebuf[40];
3945                 char igtimebuf[40];
3946
3947                 sec2str(qctl->qc_dqinfo.dqi_bgrace, bgtimebuf, rc);
3948                 sec2str(qctl->qc_dqinfo.dqi_igrace, igtimebuf, rc);
3949                 printf("Block grace time: %s; Inode grace time: %s\n",
3950                        bgtimebuf, igtimebuf);
3951         }
3952 }
3953
3954 static int print_obd_quota(char *mnt, struct if_quotactl *qctl, int is_mdt,
3955                            bool h, __u64 *total)
3956 {
3957         int rc = 0, rc1 = 0, count = 0;
3958         __u32 valid = qctl->qc_valid;
3959
3960         rc = llapi_get_obd_count(mnt, &count, is_mdt);
3961         if (rc) {
3962                 fprintf(stderr, "can not get %s count: %s\n",
3963                         is_mdt ? "mdt": "ost", strerror(-rc));
3964                 return rc;
3965         }
3966
3967         for (qctl->qc_idx = 0; qctl->qc_idx < count; qctl->qc_idx++) {
3968                 qctl->qc_valid = is_mdt ? QC_MDTIDX : QC_OSTIDX;
3969                 rc = llapi_quotactl(mnt, qctl);
3970                 if (rc) {
3971                         /* It is remote client case. */
3972                         if (rc == -EOPNOTSUPP) {
3973                                 rc = 0;
3974                                 goto out;
3975                         }
3976
3977                         if (!rc1)
3978                                 rc1 = rc;
3979                         fprintf(stderr, "quotactl %s%d failed.\n",
3980                                 is_mdt ? "mdt": "ost", qctl->qc_idx);
3981                         continue;
3982                 }
3983
3984                 print_quota(obd_uuid2str(&qctl->obd_uuid), qctl,
3985                             qctl->qc_valid, 0, h);
3986                 *total += is_mdt ? qctl->qc_dqblk.dqb_ihardlimit :
3987                                    qctl->qc_dqblk.dqb_bhardlimit;
3988         }
3989 out:
3990         qctl->qc_valid = valid;
3991         return rc ? : rc1;
3992 }
3993
3994 static int lfs_quota(int argc, char **argv)
3995 {
3996         int c;
3997         char *mnt, *name = NULL;
3998         struct if_quotactl qctl = { .qc_cmd = LUSTRE_Q_GETQUOTA,
3999                                     .qc_type = ALLQUOTA };
4000         char *obd_type = (char *)qctl.obd_type;
4001         char *obd_uuid = (char *)qctl.obd_uuid.uuid;
4002         int rc = 0, rc1 = 0, rc2 = 0, rc3 = 0,
4003             verbose = 0, pass = 0, quiet = 0, inacc;
4004         char *endptr;
4005         __u32 valid = QC_GENERAL, idx = 0;
4006         __u64 total_ialloc = 0, total_balloc = 0;
4007         bool human_readable = false;
4008         int qtype;
4009
4010         while ((c = getopt(argc, argv, "gi:I:o:pqtuvh")) != -1) {
4011                 switch (c) {
4012                 case 'u':
4013                         qtype = USRQUOTA;
4014                         goto quota_type;
4015                 case 'g':
4016                         qtype = GRPQUOTA;
4017                         goto quota_type;
4018                 case 'p':
4019                         qtype = PRJQUOTA;
4020 quota_type:
4021                         if (qctl.qc_type != ALLQUOTA) {
4022                                 fprintf(stderr, "error: use either -u or -g\n");
4023                                 return CMD_HELP;
4024                         }
4025                         qctl.qc_type = qtype;
4026                         break;
4027                 case 't':
4028                         qctl.qc_cmd = LUSTRE_Q_GETINFO;
4029                         break;
4030                 case 'o':
4031                         valid = qctl.qc_valid = QC_UUID;
4032                         strlcpy(obd_uuid, optarg, sizeof(qctl.obd_uuid));
4033                         break;
4034                 case 'i':
4035                         valid = qctl.qc_valid = QC_MDTIDX;
4036                         idx = qctl.qc_idx = atoi(optarg);
4037                         break;
4038                 case 'I':
4039                         valid = qctl.qc_valid = QC_OSTIDX;
4040                         idx = qctl.qc_idx = atoi(optarg);
4041                         break;
4042                 case 'v':
4043                         verbose = 1;
4044                         break;
4045                 case 'q':
4046                         quiet = 1;
4047                         break;
4048                 case 'h':
4049                         human_readable = true;
4050                         break;
4051                 default:
4052                         fprintf(stderr, "error: %s: option '-%c' "
4053                                         "unrecognized\n", argv[0], c);
4054                         return CMD_HELP;
4055                 }
4056         }
4057
4058         /* current uid/gid info for "lfs quota /path/to/lustre/mount" */
4059         if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA && qctl.qc_type == ALLQUOTA &&
4060             optind == argc - 1) {
4061 all_output:
4062                 memset(&qctl, 0, sizeof(qctl)); /* spoiled by print_*_quota */
4063                 qctl.qc_cmd = LUSTRE_Q_GETQUOTA;
4064                 qctl.qc_valid = valid;
4065                 qctl.qc_idx = idx;
4066                 qctl.qc_type = pass;
4067                 switch (qctl.qc_type) {
4068                 case USRQUOTA:
4069                         qctl.qc_id = geteuid();
4070                         rc = uid2name(&name, qctl.qc_id);
4071                         break;
4072                 case GRPQUOTA:
4073                         qctl.qc_id = getegid();
4074                         rc = gid2name(&name, qctl.qc_id);
4075                         break;
4076                 default:
4077                         rc = -ENOTSUP;
4078                         break;
4079                 }
4080                 if (rc)
4081                         name = "<unknown>";
4082                 pass++;
4083         /* lfs quota -u username /path/to/lustre/mount */
4084         } else if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA) {
4085                 /* options should be followed by u/g-name and mntpoint */
4086                 if (optind + 2 != argc || qctl.qc_type == ALLQUOTA) {
4087                         fprintf(stderr, "error: missing quota argument(s)\n");
4088                         return CMD_HELP;
4089                 }
4090
4091                 name = argv[optind++];
4092                 switch (qctl.qc_type) {
4093                 case USRQUOTA:
4094                         rc = name2uid(&qctl.qc_id, name);
4095                         break;
4096                 case GRPQUOTA:
4097                         rc = name2gid(&qctl.qc_id, name);
4098                         break;
4099                 case PRJQUOTA:
4100                         rc = name2projid(&qctl.qc_id, name);
4101                         break;
4102                 default:
4103                         rc = -ENOTSUP;
4104                         break;
4105                 }
4106                 if (rc) {
4107                         qctl.qc_id = strtoul(name, &endptr, 10);
4108                         if (*endptr != '\0') {
4109                                 fprintf(stderr, "error: can't find id for name "
4110                                         "%s\n", name);
4111                                 return CMD_HELP;
4112                         }
4113                 }
4114         } else if (optind + 1 != argc || qctl.qc_type == ALLQUOTA) {
4115                 fprintf(stderr, "error: missing quota info argument(s)\n");
4116                 return CMD_HELP;
4117         }
4118
4119         mnt = argv[optind];
4120
4121         rc1 = llapi_quotactl(mnt, &qctl);
4122         if (rc1 < 0) {
4123                 switch (rc1) {
4124                 case -ESRCH:
4125                         fprintf(stderr, "%s quotas are not enabled.\n",
4126                                 qtype_name(qctl.qc_type));
4127                         goto out;
4128                 case -EPERM:
4129                         fprintf(stderr, "Permission denied.\n");
4130                 case -ENODEV:
4131                 case -ENOENT:
4132                         /* We already got error message. */
4133                         goto out;
4134                 default:
4135                         fprintf(stderr, "Unexpected quotactl error: %s\n",
4136                                 strerror(-rc1));
4137                 }
4138         }
4139
4140         if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA && !quiet)
4141                 print_quota_title(name, &qctl, human_readable);
4142
4143         if (rc1 && *obd_type)
4144                 fprintf(stderr, "%s %s ", obd_type, obd_uuid);
4145
4146         if (qctl.qc_valid != QC_GENERAL)
4147                 mnt = "";
4148
4149         inacc = (qctl.qc_cmd == LUSTRE_Q_GETQUOTA) &&
4150                 ((qctl.qc_dqblk.dqb_valid & (QIF_LIMITS|QIF_USAGE)) !=
4151                  (QIF_LIMITS|QIF_USAGE));
4152
4153         print_quota(mnt, &qctl, QC_GENERAL, rc1, human_readable);
4154
4155         if (qctl.qc_valid == QC_GENERAL && qctl.qc_cmd != LUSTRE_Q_GETINFO &&
4156             verbose) {
4157                 char strbuf[STRBUF_LEN];
4158
4159                 rc2 = print_obd_quota(mnt, &qctl, 1, human_readable,
4160                                       &total_ialloc);
4161                 rc3 = print_obd_quota(mnt, &qctl, 0, human_readable,
4162                                       &total_balloc);
4163                 kbytes2str(total_balloc, strbuf, sizeof(strbuf),
4164                            human_readable);
4165                 printf("Total allocated inode limit: %ju, total "
4166                        "allocated block limit: %s\n", (uintmax_t)total_ialloc,
4167                        strbuf);
4168         }
4169
4170         if (rc1 || rc2 || rc3 || inacc)
4171                 printf("Some errors happened when getting quota info. "
4172                        "Some devices may be not working or deactivated. "
4173                        "The data in \"[]\" is inaccurate.\n");
4174
4175 out:
4176         if (pass > 0 && pass < LL_MAXQUOTAS)
4177                 goto all_output;
4178
4179         return rc1;
4180 }
4181 #endif /* HAVE_SYS_QUOTA_H! */
4182
4183 static int flushctx_ioctl(char *mp)
4184 {
4185         int fd, rc;
4186
4187         fd = open(mp, O_RDONLY);
4188         if (fd == -1) {
4189                 fprintf(stderr, "flushctx: error open %s: %s\n",
4190                         mp, strerror(errno));
4191                 return -1;
4192         }
4193
4194         rc = ioctl(fd, LL_IOC_FLUSHCTX);
4195         if (rc == -1)
4196                 fprintf(stderr, "flushctx: error ioctl %s: %s\n",
4197                         mp, strerror(errno));
4198
4199         close(fd);
4200         return rc;
4201 }
4202
4203 static int lfs_flushctx(int argc, char **argv)
4204 {
4205         int     kdestroy = 0, c;
4206         char    mntdir[PATH_MAX] = {'\0'};
4207         int     index = 0;
4208         int     rc = 0;
4209
4210         while ((c = getopt(argc, argv, "k")) != -1) {
4211                 switch (c) {
4212                 case 'k':
4213                         kdestroy = 1;
4214                         break;
4215                 default:
4216                         fprintf(stderr, "error: %s: option '-%c' "
4217                                         "unrecognized\n", argv[0], c);
4218                         return CMD_HELP;
4219                 }
4220         }
4221
4222         if (kdestroy) {
4223             if ((rc = system("kdestroy > /dev/null")) != 0) {
4224                 rc = WEXITSTATUS(rc);
4225                 fprintf(stderr, "error destroying tickets: %d, continuing\n", rc);
4226             }
4227         }
4228
4229         if (optind >= argc) {
4230                 /* flush for all mounted lustre fs. */
4231                 while (!llapi_search_mounts(NULL, index++, mntdir, NULL)) {
4232                         /* Check if we have a mount point */
4233                         if (mntdir[0] == '\0')
4234                                 continue;
4235
4236                         if (flushctx_ioctl(mntdir))
4237                                 rc = -1;
4238
4239                         mntdir[0] = '\0'; /* avoid matching in next loop */
4240                 }
4241         } else {
4242                 /* flush fs as specified */
4243                 while (optind < argc) {
4244                         if (flushctx_ioctl(argv[optind++]))
4245                                 rc = -1;
4246                 }
4247         }
4248         return rc;
4249 }
4250
4251 static int lfs_cp(int argc, char **argv)
4252 {
4253         fprintf(stderr, "remote client copy file(s).\n"
4254                 "obsolete, does not support it anymore.\n");
4255         return 0;
4256 }
4257
4258 static int lfs_ls(int argc, char **argv)
4259 {
4260         fprintf(stderr, "remote client lists directory contents.\n"
4261                 "obsolete, does not support it anymore.\n");
4262         return 0;
4263 }
4264
4265 static int lfs_changelog(int argc, char **argv)
4266 {
4267         void *changelog_priv;
4268         struct changelog_rec *rec;
4269         long long startrec = 0, endrec = 0;
4270         char *mdd;
4271         struct option long_opts[] = {
4272                 {"follow", no_argument, 0, 'f'},
4273                 {0, 0, 0, 0}
4274         };
4275         char short_opts[] = "f";
4276         int rc, follow = 0;
4277
4278         while ((rc = getopt_long(argc, argv, short_opts,
4279                                 long_opts, NULL)) != -1) {
4280                 switch (rc) {
4281                 case 'f':
4282                         follow++;
4283                         break;
4284                 case '?':
4285                         return CMD_HELP;
4286                 default:
4287                         fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4288                                 argv[0], argv[optind - 1]);
4289                         return CMD_HELP;
4290                 }
4291         }
4292         if (optind >= argc)
4293                 return CMD_HELP;
4294
4295         mdd = argv[optind++];
4296         if (argc > optind)
4297                 startrec = strtoll(argv[optind++], NULL, 10);
4298         if (argc > optind)
4299                 endrec = strtoll(argv[optind++], NULL, 10);
4300
4301         rc = llapi_changelog_start(&changelog_priv,
4302                                    CHANGELOG_FLAG_BLOCK |
4303                                    CHANGELOG_FLAG_JOBID |
4304                                    (follow ? CHANGELOG_FLAG_FOLLOW : 0),
4305                                    mdd, startrec);
4306         if (rc < 0) {
4307                 fprintf(stderr, "Can't start changelog: %s\n",
4308                         strerror(errno = -rc));
4309                 return rc;
4310         }
4311
4312         while ((rc = llapi_changelog_recv(changelog_priv, &rec)) == 0) {
4313                 time_t secs;
4314                 struct tm ts;
4315
4316                 if (endrec && rec->cr_index > endrec) {
4317                         llapi_changelog_free(&rec);
4318                         break;
4319                 }
4320                 if (rec->cr_index < startrec) {
4321                         llapi_changelog_free(&rec);
4322                         continue;
4323                 }
4324
4325                 secs = rec->cr_time >> 30;
4326                 gmtime_r(&secs, &ts);
4327                 printf("%ju %02d%-5s %02d:%02d:%02d.%06d %04d.%02d.%02d "
4328                        "0x%x t="DFID, (uintmax_t) rec->cr_index, rec->cr_type,
4329                        changelog_type2str(rec->cr_type),
4330                        ts.tm_hour, ts.tm_min, ts.tm_sec,
4331                        (int)(rec->cr_time & ((1<<30) - 1)),
4332                        ts.tm_year + 1900, ts.tm_mon + 1, ts.tm_mday,
4333                        rec->cr_flags & CLF_FLAGMASK, PFID(&rec->cr_tfid));
4334
4335                 if (rec->cr_flags & CLF_JOBID) {
4336                         struct changelog_ext_jobid *jid =
4337                                 changelog_rec_jobid(rec);
4338
4339                         if (jid->cr_jobid[0] != '\0')
4340                                 printf(" j=%s", jid->cr_jobid);
4341                 }
4342
4343                 if (rec->cr_namelen)
4344                         printf(" p="DFID" %.*s", PFID(&rec->cr_pfid),
4345                                rec->cr_namelen, changelog_rec_name(rec));
4346
4347                 if (rec->cr_flags & CLF_RENAME) {
4348                         struct changelog_ext_rename *rnm =
4349                                 changelog_rec_rename(rec);
4350
4351                         if (!fid_is_zero(&rnm->cr_sfid))
4352                                 printf(" s="DFID" sp="DFID" %.*s",
4353                                        PFID(&rnm->cr_sfid),
4354                                        PFID(&rnm->cr_spfid),
4355                                        (int)changelog_rec_snamelen(rec),
4356                                        changelog_rec_sname(rec));
4357                 }
4358                 printf("\n");
4359
4360                 llapi_changelog_free(&rec);
4361         }
4362
4363         llapi_changelog_fini(&changelog_priv);
4364
4365         if (rc < 0)
4366                 fprintf(stderr, "Changelog: %s\n", strerror(errno = -rc));
4367
4368         return (rc == 1 ? 0 : rc);
4369 }
4370
4371 static int lfs_changelog_clear(int argc, char **argv)
4372 {
4373         long long endrec;
4374         int rc;
4375
4376         if (argc != 4)
4377                 return CMD_HELP;
4378
4379         endrec = strtoll(argv[3], NULL, 10);
4380
4381         rc = llapi_changelog_clear(argv[1], argv[2], endrec);
4382
4383         if (rc == -EINVAL)
4384                 fprintf(stderr, "%s: record out of range: %llu\n",
4385                         argv[0], endrec);
4386         else if (rc == -ENOENT)
4387                 fprintf(stderr, "%s: no changelog user: %s\n",
4388                         argv[0], argv[2]);
4389         else if (rc)
4390                 fprintf(stderr, "%s error: %s\n", argv[0],
4391                         strerror(-rc));
4392
4393         if (rc)
4394                 errno = -rc;
4395
4396         return rc;
4397 }
4398
4399 static int lfs_fid2path(int argc, char **argv)
4400 {
4401         struct option long_opts[] = {
4402                 {"cur", no_argument, 0, 'c'},
4403                 {"link", required_argument, 0, 'l'},
4404                 {"rec", required_argument, 0, 'r'},
4405                 {0, 0, 0, 0}
4406         };
4407         char  short_opts[] = "cl:r:";
4408         char *device, *fid, *path;
4409         long long recno = -1;
4410         int linkno = -1;
4411         int lnktmp;
4412         int printcur = 0;
4413         int rc = 0;
4414
4415         while ((rc = getopt_long(argc, argv, short_opts,
4416                                 long_opts, NULL)) != -1) {
4417                 switch (rc) {
4418                 case 'c':
4419                         printcur++;
4420                         break;
4421                 case 'l':
4422                         linkno = strtol(optarg, NULL, 10);
4423                         break;
4424                 case 'r':
4425                         recno = strtoll(optarg, NULL, 10);
4426                         break;
4427                 case '?':
4428                         return CMD_HELP;
4429                 default:
4430                         fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4431                                 argv[0], argv[optind - 1]);
4432                         return CMD_HELP;
4433                 }
4434         }
4435
4436         if (argc < 3)
4437                 return CMD_HELP;
4438
4439         device = argv[optind++];
4440         path = calloc(1, PATH_MAX);
4441         if (path == NULL) {
4442                 fprintf(stderr, "error: Not enough memory\n");
4443                 return -errno;
4444         }
4445
4446         rc = 0;
4447         while (optind < argc) {
4448                 fid = argv[optind++];
4449
4450                 lnktmp = (linkno >= 0) ? linkno : 0;
4451                 while (1) {
4452                         int oldtmp = lnktmp;
4453                         long long rectmp = recno;
4454                         int rc2;
4455                         rc2 = llapi_fid2path(device, fid, path, PATH_MAX,
4456                                              &rectmp, &lnktmp);
4457                         if (rc2 < 0) {
4458                                 fprintf(stderr, "%s: error on FID %s: %s\n",
4459                                         argv[0], fid, strerror(errno = -rc2));
4460                                 if (rc == 0)
4461                                         rc = rc2;
4462                                 break;
4463                         }
4464
4465                         if (printcur)
4466                                 fprintf(stdout, "%lld ", rectmp);
4467                         if (device[0] == '/') {
4468                                 fprintf(stdout, "%s", device);
4469                                 if (device[strlen(device) - 1] != '/')
4470                                         fprintf(stdout, "/");
4471                         } else if (path[0] == '\0') {
4472                                 fprintf(stdout, "/");
4473                         }
4474                         fprintf(stdout, "%s\n", path);
4475
4476                         if (linkno >= 0)
4477                                 /* specified linkno */
4478                                 break;
4479                         if (oldtmp == lnktmp)
4480                                 /* no more links */
4481                                 break;
4482                 }
4483         }
4484
4485         free(path);
4486         return rc;
4487 }
4488
4489 static int lfs_path2fid(int argc, char **argv)
4490 {
4491         struct option     long_opts[] = {
4492                 {"parents", no_argument, 0, 'p'},
4493                 {0, 0, 0, 0}
4494         };
4495         char            **path;
4496         const char        short_opts[] = "p";
4497         const char       *sep = "";
4498         lustre_fid        fid;
4499         int               rc = 0;
4500         bool              show_parents = false;
4501
4502         while ((rc = getopt_long(argc, argv, short_opts,
4503                                  long_opts, NULL)) != -1) {
4504                 switch (rc) {
4505                 case 'p':
4506                         show_parents = true;
4507                         break;
4508                 default:
4509                         fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4510                                 argv[0], argv[optind - 1]);
4511                         return CMD_HELP;
4512                 }
4513         }
4514
4515         if (optind > argc - 1)
4516                 return CMD_HELP;
4517         else if (optind < argc - 1)
4518                 sep = ": ";
4519
4520         rc = 0;
4521         for (path = argv + optind; *path != NULL; path++) {
4522                 int err = 0;
4523                 if (!show_parents) {
4524                         err = llapi_path2fid(*path, &fid);
4525                         if (!err)
4526                                 printf("%s%s"DFID"\n",
4527                                        *sep != '\0' ? *path : "", sep,
4528                                        PFID(&fid));
4529                 } else {
4530                         char            name[NAME_MAX + 1];
4531                         unsigned int    linkno = 0;
4532
4533                         while ((err = llapi_path2parent(*path, linkno, &fid,
4534                                                 name, sizeof(name))) == 0) {
4535                                 if (*sep != '\0' && linkno == 0)
4536                                         printf("%s%s", *path, sep);
4537
4538                                 printf("%s"DFID"/%s", linkno != 0 ? "\t" : "",
4539                                        PFID(&fid), name);
4540                                 linkno++;
4541                         }
4542
4543                         /* err == -ENODATA is end-of-loop */
4544                         if (linkno > 0 && err == -ENODATA) {
4545                                 printf("\n");
4546                                 err = 0;
4547                         }
4548                 }
4549
4550                 if (err) {
4551                         fprintf(stderr, "%s: can't get %sfid for %s: %s\n",
4552                                 argv[0], show_parents ? "parent " : "", *path,
4553                                 strerror(-err));
4554                         if (rc == 0) {
4555                                 rc = err;
4556                                 errno = -err;
4557                         }
4558                 }
4559         }
4560
4561         return rc;
4562 }
4563
4564 static int lfs_data_version(int argc, char **argv)
4565 {
4566         char *path;
4567         __u64 data_version;
4568         int fd;
4569         int rc;
4570         int c;
4571         int data_version_flags = LL_DV_RD_FLUSH; /* Read by default */
4572
4573         if (argc < 2)
4574                 return CMD_HELP;
4575
4576         while ((c = getopt(argc, argv, "nrw")) != -1) {
4577                 switch (c) {
4578                 case 'n':
4579                         data_version_flags = 0;
4580                         break;
4581                 case 'r':
4582                         data_version_flags |= LL_DV_RD_FLUSH;
4583                         break;
4584                 case 'w':
4585                         data_version_flags |= LL_DV_WR_FLUSH;
4586                         break;
4587                 default:
4588                         return CMD_HELP;
4589                 }
4590         }
4591         if (optind == argc)
4592                 return CMD_HELP;
4593
4594         path = argv[optind];
4595         fd = open(path, O_RDONLY);
4596         if (fd < 0)
4597                 err(errno, "cannot open file %s", path);
4598
4599         rc = llapi_get_data_version(fd, &data_version, data_version_flags);
4600         if (rc < 0)
4601                 err(errno, "cannot get version for %s", path);
4602         else
4603                 printf("%ju" "\n", (uintmax_t)data_version);
4604
4605         close(fd);
4606         return rc;
4607 }
4608
4609 static int lfs_hsm_state(int argc, char **argv)
4610 {
4611         int rc;
4612         int i = 1;
4613         char *path;
4614         struct hsm_user_state hus;
4615
4616         if (argc < 2)
4617                 return CMD_HELP;
4618
4619         do {
4620                 path = argv[i];
4621
4622                 rc = llapi_hsm_state_get(path, &hus);
4623                 if (rc) {
4624                         fprintf(stderr, "can't get hsm state for %s: %s\n",
4625                                 path, strerror(errno = -rc));
4626                         return rc;
4627                 }
4628
4629                 /* Display path name and status flags */
4630                 printf("%s: (0x%08x)", path, hus.hus_states);
4631
4632                 if (hus.hus_states & HS_RELEASED)
4633                         printf(" released");
4634                 if (hus.hus_states & HS_EXISTS)
4635                         printf(" exists");
4636                 if (hus.hus_states & HS_DIRTY)
4637                         printf(" dirty");
4638                 if (hus.hus_states & HS_ARCHIVED)
4639                         printf(" archived");
4640                 /* Display user-settable flags */
4641                 if (hus.hus_states & HS_NORELEASE)
4642                         printf(" never_release");
4643                 if (hus.hus_states & HS_NOARCHIVE)
4644                         printf(" never_archive");
4645                 if (hus.hus_states & HS_LOST)
4646                         printf(" lost_from_hsm");
4647
4648                 if (hus.hus_archive_id != 0)
4649                         printf(", archive_id:%d", hus.hus_archive_id);
4650                 printf("\n");
4651
4652         } while (++i < argc);
4653
4654         return 0;
4655 }
4656
4657 #define LFS_HSM_SET   0
4658 #define LFS_HSM_CLEAR 1
4659
4660 /**
4661  * Generic function to set or clear HSM flags.
4662  * Used by hsm_set and hsm_clear.
4663  *
4664  * @mode  if LFS_HSM_SET, set the flags, if LFS_HSM_CLEAR, clear the flags.
4665  */
4666 static int lfs_hsm_change_flags(int argc, char **argv, int mode)
4667 {
4668         struct option long_opts[] = {
4669                 {"lost", 0, 0, 'l'},
4670                 {"norelease", 0, 0, 'r'},
4671                 {"noarchive", 0, 0, 'a'},
4672                 {"archived", 0, 0, 'A'},
4673                 {"dirty", 0, 0, 'd'},
4674                 {"exists", 0, 0, 'e'},
4675                 {0, 0, 0, 0}
4676         };
4677         char short_opts[] = "lraAde";
4678         __u64 mask = 0;
4679         int c, rc;
4680         char *path;
4681
4682         if (argc < 3)
4683                 return CMD_HELP;
4684
4685         while ((c = getopt_long(argc, argv, short_opts,
4686                                 long_opts, NULL)) != -1) {
4687                 switch (c) {
4688                 case 'l':
4689                         mask |= HS_LOST;
4690                         break;
4691                 case 'a':
4692                         mask |= HS_NOARCHIVE;
4693                         break;
4694                 case 'A':
4695                         mask |= HS_ARCHIVED;
4696                         break;
4697                 case 'r':
4698                         mask |= HS_NORELEASE;
4699                         break;
4700                 case 'd':
4701                         mask |= HS_DIRTY;
4702                         break;
4703                 case 'e':
4704                         mask |= HS_EXISTS;
4705                         break;
4706                 case '?':
4707                         return CMD_HELP;
4708                 default:
4709                         fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4710                                 argv[0], argv[optind - 1]);
4711                         return CMD_HELP;
4712                 }
4713         }
4714
4715         /* User should have specified a flag */
4716         if (mask == 0)
4717                 return CMD_HELP;
4718
4719         while (optind < argc) {
4720
4721                 path = argv[optind];
4722
4723                 /* If mode == 0, this means we apply the mask. */
4724                 if (mode == LFS_HSM_SET)
4725                         rc = llapi_hsm_state_set(path, mask, 0, 0);
4726                 else
4727                         rc = llapi_hsm_state_set(path, 0, mask, 0);
4728
4729                 if (rc != 0) {
4730                         fprintf(stderr, "Can't change hsm flags for %s: %s\n",
4731                                 path, strerror(errno = -rc));
4732                         return rc;
4733                 }
4734                 optind++;
4735         }
4736
4737         return 0;
4738 }
4739
4740 static int lfs_hsm_action(int argc, char **argv)
4741 {
4742         int                              rc;
4743         int                              i = 1;
4744         char                            *path;
4745         struct hsm_current_action        hca;
4746         struct hsm_extent                he;
4747         enum hsm_user_action             hua;
4748         enum hsm_progress_states         hps;
4749
4750         if (argc < 2)
4751                 return CMD_HELP;
4752
4753         do {
4754                 path = argv[i];
4755
4756                 rc = llapi_hsm_current_action(path, &hca);
4757                 if (rc) {
4758                         fprintf(stderr, "can't get hsm action for %s: %s\n",
4759                                 path, strerror(errno = -rc));
4760                         return rc;
4761                 }
4762                 he = hca.hca_location;
4763                 hua = hca.hca_action;
4764                 hps = hca.hca_state;
4765
4766                 printf("%s: %s", path, hsm_user_action2name(hua));
4767
4768                 /* Skip file without action */
4769                 if (hca.hca_action == HUA_NONE) {
4770                         printf("\n");
4771                         continue;
4772                 }
4773
4774                 printf(" %s ", hsm_progress_state2name(hps));
4775
4776                 if ((hps == HPS_RUNNING) &&
4777                     (hua == HUA_ARCHIVE || hua == HUA_RESTORE))
4778                         printf("(%llu bytes moved)\n",
4779                                (unsigned long long)he.length);
4780                 else if ((he.offset + he.length) == LUSTRE_EOF)
4781                         printf("(from %llu to EOF)\n",
4782                                (unsigned long long)he.offset);
4783                 else
4784                         printf("(from %llu to %llu)\n",
4785                                (unsigned long long)he.offset,
4786                                (unsigned long long)(he.offset + he.length));
4787
4788         } while (++i < argc);
4789
4790         return 0;
4791 }
4792
4793 static int lfs_hsm_set(int argc, char **argv)
4794 {
4795         return lfs_hsm_change_flags(argc, argv, LFS_HSM_SET);
4796 }
4797
4798 static int lfs_hsm_clear(int argc, char **argv)
4799 {
4800         return lfs_hsm_change_flags(argc, argv, LFS_HSM_CLEAR);
4801 }
4802
4803 /**
4804  * Check file state and return its fid, to be used by lfs_hsm_request().
4805  *
4806  * \param[in]     file      Path to file to check
4807  * \param[in,out] fid       Pointer to allocated lu_fid struct.
4808  * \param[in,out] last_dev  Pointer to last device id used.
4809  *
4810  * \return 0 on success.
4811  */
4812 static int lfs_hsm_prepare_file(const char *file, struct lu_fid *fid,
4813                                 dev_t *last_dev)
4814 {
4815         struct stat     st;
4816         int             rc;
4817
4818         rc = lstat(file, &st);
4819         if (rc) {
4820                 fprintf(stderr, "Cannot stat %s: %s\n", file, strerror(errno));
4821                 return -errno;
4822         }
4823         /* Checking for regular file as archiving as posix copytool
4824          * rejects archiving files other than regular files
4825          */
4826         if (!S_ISREG(st.st_mode)) {
4827                 fprintf(stderr, "error: \"%s\" is not a regular file\n", file);
4828                 return CMD_HELP;
4829         }
4830         /* A request should be ... */
4831         if (*last_dev != st.st_dev && *last_dev != 0) {
4832                 fprintf(stderr, "All files should be "
4833                         "on the same filesystem: %s\n", file);
4834                 return -EINVAL;
4835         }
4836         *last_dev = st.st_dev;
4837
4838         rc = llapi_path2fid(file, fid);
4839         if (rc) {
4840                 fprintf(stderr, "Cannot read FID of %s: %s\n",
4841                         file, strerror(-rc));
4842                 return rc;
4843         }
4844         return 0;
4845 }
4846
4847 /* Fill an HSM HUR item with a given file name.
4848  *
4849  * If mntpath is set, then the filename is actually a FID, and no
4850  * lookup on the filesystem will be performed.
4851  *
4852  * \param[in]  hur         the user request to fill
4853  * \param[in]  idx         index of the item inside the HUR to fill
4854  * \param[in]  mntpath     mountpoint of Lustre
4855  * \param[in]  fname       filename (if mtnpath is NULL)
4856  *                         or FID (if mntpath is set)
4857  * \param[in]  last_dev    pointer to last device id used
4858  *
4859  * \retval 0 on success
4860  * \retval CMD_HELP or a negative errno on error
4861  */
4862 static int fill_hur_item(struct hsm_user_request *hur, unsigned int idx,
4863                          const char *mntpath, const char *fname,
4864                          dev_t *last_dev)
4865 {
4866         struct hsm_user_item *hui = &hur->hur_user_item[idx];
4867         int rc;
4868
4869         hui->hui_extent.length = -1;
4870
4871         if (mntpath != NULL) {
4872                 if (*fname == '[')
4873                         fname++;
4874                 rc = sscanf(fname, SFID, RFID(&hui->hui_fid));
4875                 if (rc == 3) {
4876                         rc = 0;
4877                 } else {
4878                         fprintf(stderr, "hsm: '%s' is not a valid FID\n",
4879                                 fname);
4880                         rc = -EINVAL;
4881                 }
4882         } else {
4883                 rc = lfs_hsm_prepare_file(fname, &hui->hui_fid, last_dev);
4884         }
4885
4886         if (rc == 0)
4887                 hur->hur_request.hr_itemcount++;
4888
4889         return rc;
4890 }
4891
4892 static int lfs_hsm_request(int argc, char **argv, int action)
4893 {
4894         struct option            long_opts[] = {
4895                 {"filelist", 1, 0, 'l'},
4896                 {"data", 1, 0, 'D'},
4897                 {"archive", 1, 0, 'a'},
4898                 {"mntpath", 1, 0, 'm'},
4899                 {0, 0, 0, 0}
4900         };
4901         dev_t                    last_dev = 0;
4902         char                     short_opts[] = "l:D:a:m:";
4903         struct hsm_user_request *hur, *oldhur;
4904         int                      c, i;
4905         size_t                   len;
4906         int                      nbfile;
4907         char                    *line = NULL;
4908         char                    *filelist = NULL;
4909         char                     fullpath[PATH_MAX];
4910         char                    *opaque = NULL;
4911         int                      opaque_len = 0;
4912         int                      archive_id = 0;
4913         FILE                    *fp;
4914         int                      nbfile_alloc = 0;
4915         char                    *some_file = NULL;
4916         char                    *mntpath = NULL;
4917         int                      rc;
4918
4919         if (argc < 2)
4920                 return CMD_HELP;
4921
4922         while ((c = getopt_long(argc, argv, short_opts,
4923                                 long_opts, NULL)) != -1) {
4924                 switch (c) {
4925                 case 'l':
4926                         filelist = optarg;
4927                         break;
4928                 case 'D':
4929                         opaque = optarg;
4930                         break;
4931                 case 'a':
4932                         if (action != HUA_ARCHIVE &&
4933                             action != HUA_REMOVE) {
4934                                 fprintf(stderr,
4935                                         "error: -a is supported only "
4936                                         "when archiving or removing\n");
4937                                 return CMD_HELP;
4938                         }
4939                         archive_id = atoi(optarg);
4940                         break;
4941                 case 'm':
4942                         if (some_file == NULL) {
4943                                 mntpath = optarg;
4944                                 some_file = strdup(optarg);
4945                         }
4946                         break;
4947                 case '?':
4948                         return CMD_HELP;
4949                 default:
4950                         fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4951                                 argv[0], argv[optind - 1]);
4952                         return CMD_HELP;
4953                 }
4954         }
4955
4956         /* All remaining args are files, so we have at least nbfile */
4957         nbfile = argc - optind;
4958
4959         if ((nbfile == 0) && (filelist == NULL))
4960                 return CMD_HELP;
4961
4962         if (opaque != NULL)
4963                 opaque_len = strlen(opaque);
4964
4965         /* Alloc the request structure with enough place to store all files
4966          * from command line. */
4967         hur = llapi_hsm_user_request_alloc(nbfile, opaque_len);
4968         if (hur == NULL) {
4969                 fprintf(stderr, "Cannot create the request: %s\n",
4970                         strerror(errno));
4971                 return errno;
4972         }
4973         nbfile_alloc = nbfile;
4974
4975         hur->hur_request.hr_action = action;
4976         hur->hur_request.hr_archive_id = archive_id;
4977         hur->hur_request.hr_flags = 0;
4978
4979         /* All remaining args are files, add them */
4980         if (nbfile != 0 && some_file == NULL)
4981                 some_file = strdup(argv[optind]);
4982
4983         for (i = 0; i < nbfile; i++) {
4984                 rc = fill_hur_item(hur, i, mntpath, argv[optind + i],
4985                                    &last_dev);
4986                 if (rc)
4987                         goto out_free;
4988         }
4989
4990         /* from here stop using nb_file, use hur->hur_request.hr_itemcount */
4991
4992         /* If a filelist was specified, read the filelist from it. */
4993         if (filelist != NULL) {
4994                 fp = fopen(filelist, "r");
4995                 if (fp == NULL) {
4996                         fprintf(stderr, "Cannot read the file list %s: %s\n",
4997                                 filelist, strerror(errno));
4998                         rc = -errno;
4999                         goto out_free;
5000                 }
5001
5002                 while ((rc = getline(&line, &len, fp)) != -1) {
5003                         /* If allocated buffer was too small, get something
5004                          * larger */
5005                         if (nbfile_alloc <= hur->hur_request.hr_itemcount) {
5006                                 ssize_t size;
5007
5008                                 nbfile_alloc = nbfile_alloc * 2 + 1;
5009                                 oldhur = hur;
5010                                 hur = llapi_hsm_user_request_alloc(nbfile_alloc,
5011                                                                    opaque_len);
5012                                 if (hur == NULL) {
5013                                         fprintf(stderr, "hsm: cannot allocate "
5014                                                 "the request: %s\n",
5015                                                 strerror(errno));
5016                                         hur = oldhur;
5017                                         rc = -errno;
5018                                         fclose(fp);
5019                                         goto out_free;
5020                                 }
5021                                 size = hur_len(oldhur);
5022                                 if (size < 0) {
5023                                         fprintf(stderr, "hsm: cannot allocate "
5024                                                 "%u files + %u bytes data\n",
5025                                             oldhur->hur_request.hr_itemcount,
5026                                             oldhur->hur_request.hr_data_len);
5027                                         free(hur);
5028                                         hur = oldhur;
5029                                         rc = -E2BIG;
5030                                         fclose(fp);
5031                                         goto out_free;
5032                                 }
5033                                 memcpy(hur, oldhur, size);
5034                                 free(oldhur);
5035                         }
5036
5037                         /* Chop CR */
5038                         if (line[strlen(line) - 1] == '\n')
5039                                 line[strlen(line) - 1] = '\0';
5040
5041                         rc = fill_hur_item(hur, hur->hur_request.hr_itemcount,
5042                                            mntpath, line, &last_dev);
5043                         if (rc) {
5044                                 fclose(fp);
5045                                 goto out_free;
5046                         }
5047
5048                         if (some_file == NULL) {
5049                                 some_file = line;
5050                                 line = NULL;
5051                         }
5052                 }
5053
5054                 rc = fclose(fp);
5055                 free(line);
5056         }
5057
5058         /* If a --data was used, add it to the request */
5059         hur->hur_request.hr_data_len = opaque_len;
5060         if (opaque != NULL)
5061                 memcpy(hur_data(hur), opaque, opaque_len);
5062
5063         /* Send the HSM request */
5064         if (realpath(some_file, fullpath) == NULL) {
5065                 fprintf(stderr, "Could not find path '%s': %s\n",
5066                         some_file, strerror(errno));
5067         }
5068         rc = llapi_hsm_request(fullpath, hur);
5069         if (rc) {
5070                 fprintf(stderr, "Cannot send HSM request (use of %s): %s\n",
5071                         some_file, strerror(-rc));
5072                 goto out_free;
5073         }
5074
5075 out_free:
5076         free(some_file);
5077         free(hur);
5078         return rc;
5079 }
5080
5081 static int lfs_hsm_archive(int argc, char **argv)
5082 {
5083         return lfs_hsm_request(argc, argv, HUA_ARCHIVE);
5084 }
5085
5086 static int lfs_hsm_restore(int argc, char **argv)
5087 {
5088         return lfs_hsm_request(argc, argv, HUA_RESTORE);
5089 }
5090
5091 static int lfs_hsm_release(int argc, char **argv)
5092 {
5093         return lfs_hsm_request(argc, argv, HUA_RELEASE);
5094 }
5095
5096 static int lfs_hsm_remove(int argc, char **argv)
5097 {
5098         return lfs_hsm_request(argc, argv, HUA_REMOVE);
5099 }
5100
5101 static int lfs_hsm_cancel(int argc, char **argv)
5102 {
5103         return lfs_hsm_request(argc, argv, HUA_CANCEL);
5104 }
5105
5106 static int lfs_swap_layouts(int argc, char **argv)
5107 {
5108         if (argc != 3)
5109                 return CMD_HELP;
5110
5111         return llapi_swap_layouts(argv[1], argv[2], 0, 0,
5112                                   SWAP_LAYOUTS_KEEP_MTIME |
5113                                   SWAP_LAYOUTS_KEEP_ATIME);
5114 }
5115
5116 static const char *const ladvise_names[] = LU_LADVISE_NAMES;
5117
5118 static enum lu_ladvise_type lfs_get_ladvice(const char *string)
5119 {
5120         enum lu_ladvise_type advice;
5121
5122         for (advice = 0;
5123              advice < ARRAY_SIZE(ladvise_names); advice++) {
5124                 if (ladvise_names[advice] == NULL)
5125                         continue;
5126                 if (strcmp(string, ladvise_names[advice]) == 0)
5127                         return advice;
5128         }
5129
5130         return LU_LADVISE_INVALID;
5131 }
5132
5133 static int lfs_ladvise(int argc, char **argv)
5134 {
5135         struct option            long_opts[] = {
5136                 {"advice",      required_argument,      0, 'a'},
5137                 {"background",  no_argument,            0, 'b'},
5138                 {"end",         required_argument,      0, 'e'},
5139                 {"start",       required_argument,      0, 's'},
5140                 {"length",      required_argument,      0, 'l'},
5141                 {0, 0, 0, 0}
5142         };
5143         char                     short_opts[] = "a:be:l:s:";
5144         int                      c;
5145         int                      rc = 0;
5146         const char              *path;
5147         int                      fd;
5148         struct llapi_lu_ladvise  advice;
5149         enum lu_ladvise_type     advice_type = LU_LADVISE_INVALID;
5150         unsigned long long       start = 0;
5151         unsigned long long       end = LUSTRE_EOF;
5152         unsigned long long       length = 0;
5153         unsigned long long       size_units;
5154         unsigned long long       flags = 0;
5155
5156         optind = 0;
5157         while ((c = getopt_long(argc, argv, short_opts,
5158                                 long_opts, NULL)) != -1) {
5159                 switch (c) {
5160                 case 'a':
5161                         advice_type = lfs_get_ladvice(optarg);
5162                         if (advice_type == LU_LADVISE_INVALID) {
5163                                 fprintf(stderr, "%s: invalid advice type "
5164                                         "'%s'\n", argv[0], optarg);
5165                                 fprintf(stderr, "Valid types:");
5166
5167                                 for (advice_type = 0;
5168                                      advice_type < ARRAY_SIZE(ladvise_names);
5169                                      advice_type++) {
5170                                         if (ladvise_names[advice_type] == NULL)
5171                                                 continue;
5172                                         fprintf(stderr, " %s",
5173                                                 ladvise_names[advice_type]);
5174                                 }
5175                                 fprintf(stderr, "\n");
5176
5177                                 return CMD_HELP;
5178                         }
5179                         break;
5180                 case 'b':
5181                         flags |= LF_ASYNC;
5182                         break;
5183                 case 'e':
5184                         size_units = 1;
5185                         rc = llapi_parse_size(optarg, &end,
5186                                               &size_units, 0);
5187                         if (rc) {
5188                                 fprintf(stderr, "%s: bad end offset '%s'\n",
5189                                         argv[0], optarg);
5190                                 return CMD_HELP;
5191                         }
5192                         break;
5193                 case 's':
5194                         size_units = 1;
5195                         rc = llapi_parse_size(optarg, &start,
5196                                               &size_units, 0);
5197                         if (rc) {
5198                                 fprintf(stderr, "%s: bad start offset "
5199                                         "'%s'\n", argv[0], optarg);
5200                                 return CMD_HELP;
5201                         }
5202                         break;
5203                 case 'l':
5204                         size_units = 1;
5205                         rc = llapi_parse_size(optarg, &length,
5206                                               &size_units, 0);
5207                         if (rc) {
5208                                 fprintf(stderr, "%s: bad length '%s'\n",
5209                                         argv[0], optarg);
5210                                 return CMD_HELP;
5211                         }
5212                         break;
5213                 case '?':
5214                         return CMD_HELP;
5215                 default:
5216                         fprintf(stderr, "%s: option '%s' unrecognized\n",
5217                                 argv[0], argv[optind - 1]);
5218                         return CMD_HELP;
5219                 }
5220         }
5221
5222         if (advice_type == LU_LADVISE_INVALID) {
5223                 fprintf(stderr, "%s: please give an advice type\n", argv[0]);
5224                 fprintf(stderr, "Valid types:");
5225                 for (advice_type = 0; advice_type < ARRAY_SIZE(ladvise_names);
5226                      advice_type++) {
5227                         if (ladvise_names[advice_type] == NULL)
5228                                 continue;
5229                         fprintf(stderr, " %s", ladvise_names[advice_type]);
5230                 }
5231                 fprintf(stderr, "\n");
5232                 return CMD_HELP;
5233         }
5234
5235         if (argc <= optind) {
5236                 fprintf(stderr, "%s: please give one or more file names\n",
5237                         argv[0]);
5238                 return CMD_HELP;
5239         }
5240
5241         if (end != LUSTRE_EOF && length != 0 && end != start + length) {
5242                 fprintf(stderr, "%s: conflicting arguments of -l and -e\n",
5243                         argv[0]);
5244                 return CMD_HELP;
5245         }
5246
5247         if (end == LUSTRE_EOF && length != 0)
5248                 end = start + length;
5249
5250         if (end <= start) {
5251                 fprintf(stderr, "%s: range [%llu, %llu] is invalid\n",
5252                         argv[0], start, end);
5253                 return CMD_HELP;
5254         }
5255
5256         while (optind < argc) {
5257                 int rc2;
5258
5259                 path = argv[optind++];
5260
5261                 fd = open(path, O_RDONLY);
5262                 if (fd < 0) {
5263                         fprintf(stderr, "%s: cannot open file '%s': %s\n",
5264                                 argv[0], path, strerror(errno));
5265                         rc2 = -errno;
5266                         goto next;
5267                 }
5268
5269                 advice.lla_start = start;
5270                 advice.lla_end = end;
5271                 advice.lla_advice = advice_type;
5272                 advice.lla_value1 = 0;
5273                 advice.lla_value2 = 0;
5274                 advice.lla_value3 = 0;
5275                 advice.lla_value4 = 0;
5276                 rc2 = llapi_ladvise(fd, flags, 1, &advice);
5277                 close(fd);
5278                 if (rc2 < 0) {
5279                         fprintf(stderr, "%s: cannot give advice '%s' to file "
5280                                 "'%s': %s\n", argv[0],
5281                                 ladvise_names[advice_type],
5282                                 path, strerror(errno));
5283                 }
5284 next:
5285                 if (rc == 0 && rc2 < 0)
5286                         rc = rc2;
5287         }
5288         return rc;
5289 }
5290
5291 static int lfs_list_commands(int argc, char **argv)
5292 {
5293         char buffer[81] = ""; /* 80 printable chars + terminating NUL */
5294
5295         Parser_list_commands(cmdlist, buffer, sizeof(buffer), NULL, 0, 4);
5296
5297         return 0;
5298 }
5299
5300 int main(int argc, char **argv)
5301 {
5302         int rc;
5303
5304         /* Ensure that liblustreapi constructor has run */
5305         if (!liblustreapi_initialized)
5306                 fprintf(stderr, "liblustreapi was not properly initialized\n");
5307
5308         setlinebuf(stdout);
5309
5310         Parser_init("lfs > ", cmdlist);
5311
5312         progname = argv[0]; /* Used in error messages */
5313         if (argc > 1) {
5314                 rc = Parser_execarg(argc - 1, argv + 1, cmdlist);
5315         } else {
5316                 rc = Parser_commands();
5317         }
5318
5319         return rc < 0 ? -rc : rc;
5320 }
5321
5322 #ifdef _LUSTRE_IDL_H_
5323 /* Everything we need here should be included by lustreapi.h. */
5324 # error "lfs should not depend on lustre_idl.h"
5325 #endif /* _LUSTRE_IDL_H_ */