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