Whamcloud - gitweb
LU-8998 tools: parse optional argument properly
[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 'AT MOST' requested value\n"
261          "\t +: used before a value indicates 'AT LEAST' 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         head = llapi_layout_get_by_path(fname, 0);
1164         if (head == NULL) {
1165                 fprintf(stderr, "Read layout from %s failed. %s\n",
1166                         fname, strerror(errno));
1167                 return -EINVAL;
1168         }
1169
1170         /* Current component of 'head' should be tail of component list by
1171          * default, but we do an extra move cursor operation here to test
1172          * if the layout is non-composite. */
1173         rc = llapi_layout_comp_use(head, LLAPI_LAYOUT_COMP_USE_LAST);
1174         if (rc < 0) {
1175                 fprintf(stderr, "'%s' isn't a composite file?\n", fname);
1176                 llapi_layout_free(head);
1177                 return rc;
1178         }
1179
1180         rc = llapi_layout_comp_extent_get(head, &start, &prev_end);
1181         if (rc) {
1182                 fprintf(stderr, "Get prev extent failed. %s\n",
1183                         strerror(errno));
1184                 llapi_layout_free(head);
1185                 return rc;
1186         }
1187
1188         llapi_layout_free(head);
1189
1190         /* Make sure we use the first component of the layout to be added. */
1191         rc = llapi_layout_comp_use(layout, LLAPI_LAYOUT_COMP_USE_FIRST);
1192         if (rc < 0) {
1193                 fprintf(stderr, "Move component cursor failed. %s\n",
1194                         strerror(errno));
1195                 return rc;
1196         }
1197
1198         rc = llapi_layout_comp_extent_get(layout, &start, &end);
1199         if (rc) {
1200                 fprintf(stderr, "Get extent failed. %s\n", strerror(errno));
1201                 return rc;
1202         }
1203
1204         if (start > prev_end || end <= prev_end) {
1205                 fprintf(stderr, "First extent to be set [%lu, %lu) isn't "
1206                         "adjacent with the existing file extent end: %lu\n",
1207                         start, end, prev_end);
1208                 return -EINVAL;
1209         }
1210
1211         rc = llapi_layout_stripe_size_get(layout, &stripe_size);
1212         if (rc) {
1213                 fprintf(stderr, "Get stripe size failed. %s\n",
1214                         strerror(errno));
1215                 return rc;
1216         }
1217
1218         if (stripe_size != LLAPI_LAYOUT_DEFAULT &&
1219             (prev_end & (stripe_size - 1))) {
1220                 fprintf(stderr, "Stripe size %lu not aligned with %lu\n",
1221                         stripe_size, prev_end);
1222                 return -EINVAL;
1223         }
1224
1225         rc = llapi_layout_comp_extent_set(layout, prev_end, end);
1226         if (rc) {
1227                 fprintf(stderr, "Set component extent [%lu, %lu) failed. %s\n",
1228                         prev_end, end, strerror(errno));
1229                 return rc;
1230         }
1231
1232         return 0;
1233 }
1234
1235 static inline bool comp_flags_is_neg(__u32 flags)
1236 {
1237         return flags & LCME_FL_NEG;
1238 }
1239
1240 static inline void comp_flags_set_neg(__u32 *flags)
1241 {
1242         *flags |= LCME_FL_NEG;
1243 }
1244
1245 static inline void comp_flags_clear_neg(__u32 *flags)
1246 {
1247         *flags &= ~LCME_FL_NEG;
1248 }
1249
1250 static int comp_name2flags(__u32 *flags, char *name)
1251 {
1252         char *ptr;
1253         __u32 neg_flags = 0;
1254
1255         if (name == NULL)
1256                 return -EINVAL;
1257
1258         *flags = 0;
1259         for (ptr = name; ; ptr = NULL) {
1260                 char *flg = strtok(ptr, ",");
1261                 if (flg == NULL)
1262                         break;
1263                 if (strcmp(flg, "init") == 0)
1264                         *flags |= LCME_FL_INIT;
1265                 else if (strcmp(flg, "^init") == 0)
1266                         neg_flags |= LCME_FL_INIT;
1267                 else
1268                         return -EINVAL;
1269         }
1270
1271         if (*flags == 0 && neg_flags == 0)
1272                 return -EINVAL;
1273         /* don't support mixed flags for now */
1274         if (*flags && neg_flags)
1275                 return -EINVAL;
1276
1277         if (neg_flags) {
1278                 *flags = neg_flags;
1279                 comp_flags_set_neg(flags);
1280         }
1281
1282         return 0;
1283 }
1284
1285 static inline bool arg_is_eof(char *arg)
1286 {
1287         return !strncmp(arg, "-1", strlen("-1")) ||
1288                !strncmp(arg, "EOF", strlen("EOF")) ||
1289                !strncmp(arg, "eof", strlen("eof"));
1290 }
1291
1292 enum {
1293         LFS_POOL_OPT = 3,
1294         LFS_COMP_COUNT_OPT,
1295         LFS_COMP_START_OPT,
1296         LFS_COMP_FLAGS_OPT,
1297         LFS_COMP_DEL_OPT,
1298         LFS_COMP_SET_OPT,
1299         LFS_COMP_ADD_OPT,
1300         LFS_PROJID_OPT,
1301 };
1302
1303 /* functions */
1304 static int lfs_setstripe(int argc, char **argv)
1305 {
1306         struct lfs_setstripe_args        lsa;
1307         struct llapi_stripe_param       *param = NULL;
1308         struct find_param                migrate_mdt_param = {
1309                 .fp_max_depth = -1,
1310                 .fp_mdt_index = -1,
1311         };
1312         char                            *fname;
1313         int                              result;
1314         int                              result2 = 0;
1315         char                            *end;
1316         int                              c;
1317         int                              delete = 0;
1318         char                            *mdt_idx_arg = NULL;
1319         unsigned long long               size_units = 1;
1320         bool                             migrate_mode = false;
1321         bool                             migration_block = false;
1322         __u64                            migration_flags = 0;
1323         __u32                            osts[LOV_MAX_STRIPE_COUNT] = { 0 };
1324         int                              comp_del = 0, comp_set = 0;
1325         int                              comp_add = 0;
1326         __u32                            comp_id = 0;
1327         struct llapi_layout             *layout = NULL;
1328
1329         struct option            long_opts[] = {
1330                 /* --block is only valid in migrate mode */
1331                 {"block",        no_argument,       0, 'b'},
1332                 {"comp-add",     no_argument,       0, LFS_COMP_ADD_OPT},
1333                 {"component-add", no_argument,      0, LFS_COMP_ADD_OPT},
1334                 {"comp-del",     no_argument,       0, LFS_COMP_DEL_OPT},
1335                 {"component-del", no_argument,      0, LFS_COMP_DEL_OPT},
1336                 {"comp-flags",   required_argument, 0, LFS_COMP_FLAGS_OPT},
1337                 {"component-flags", required_argument, 0, LFS_COMP_FLAGS_OPT},
1338                 {"comp-set",     no_argument,       0, LFS_COMP_SET_OPT},
1339                 {"component-set", no_argument,      0, LFS_COMP_SET_OPT},
1340 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
1341                 /* This formerly implied "stripe-count", but was explicitly
1342                  * made "stripe-count" for consistency with other options,
1343                  * and to separate it from "mdt-count" when DNE arrives. */
1344                 {"count",        required_argument, 0, 'c'},
1345 #endif
1346                 {"stripe-count", required_argument, 0, 'c'},
1347                 {"stripe_count", required_argument, 0, 'c'},
1348                 {"delete",       no_argument,       0, 'd'},
1349                 {"comp-end",     required_argument, 0, 'E'},
1350                 {"component-end", required_argument, 0, 'E'},
1351                 /* dirstripe {"mdt-hash",     required_argument, 0, 'H'}, */
1352 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
1353                 /* This formerly implied "stripe-index", but was explicitly
1354                  * made "stripe-index" for consistency with other options,
1355                  * and to separate it from "mdt-index" when DNE arrives. */
1356                 {"index",        required_argument, 0, 'i'},
1357 #endif
1358                 {"stripe-index", required_argument, 0, 'i'},
1359                 {"stripe_index", required_argument, 0, 'i'},
1360                 {"comp-id",      required_argument, 0, 'I'},
1361                 {"component-id", required_argument, 0, 'I'},
1362                 {"mdt",          required_argument, 0, 'm'},
1363                 {"mdt-index",    required_argument, 0, 'm'},
1364                 {"mdt_index",    required_argument, 0, 'm'},
1365                 /* --non-block is only valid in migrate mode */
1366                 {"non-block",    no_argument,       0, 'n'},
1367                 {"ost",          required_argument, 0, 'o'},
1368 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
1369                 {"ost-list",     required_argument, 0, 'o'},
1370                 {"ost_list",     required_argument, 0, 'o'},
1371 #endif
1372                 {"pool",         required_argument, 0, 'p'},
1373 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
1374                 /* This formerly implied "--stripe-size", but was confusing
1375                  * with "lfs find --size|-s", which means "file size", so use
1376                  * the consistent "--stripe-size|-S" for all commands. */
1377                 {"size",         required_argument, 0, 's'},
1378 #endif
1379                 {"stripe-size",  required_argument, 0, 'S'},
1380                 {"stripe_size",  required_argument, 0, 'S'},
1381                 /* dirstripe {"mdt-count",    required_argument, 0, 'T'}, */
1382                 /* --verbose is only valid in migrate mode */
1383                 {"verbose",      no_argument,       0, 'v'},
1384                 {0, 0, 0, 0}
1385         };
1386
1387         setstripe_args_init(&lsa);
1388
1389         if (strcmp(argv[0], "migrate") == 0)
1390                 migrate_mode = true;
1391
1392         while ((c = getopt_long(argc, argv, "bc:dE:i:I:m:no:p:s:S:v",
1393                                 long_opts, NULL)) >= 0) {
1394                 switch (c) {
1395                 case 0:
1396                         /* Long options. */
1397                         break;
1398                 case LFS_COMP_ADD_OPT:
1399                         comp_add = 1;
1400                         break;
1401                 case LFS_COMP_DEL_OPT:
1402                         comp_del = 1;
1403                         break;
1404                 case LFS_COMP_FLAGS_OPT:
1405                         result = comp_name2flags(&lsa.lsa_comp_flags, optarg);
1406                         if (result != 0) {
1407                                 fprintf(stderr, "error: %s: bad comp flags "
1408                                         "'%s'\n", argv[0], optarg);
1409                                 goto error;
1410                         }
1411                         break;
1412                 case LFS_COMP_SET_OPT:
1413                         comp_set = 1;
1414                         break;
1415                 case 'b':
1416                         if (!migrate_mode) {
1417                                 fprintf(stderr, "--block is valid only for"
1418                                                 " migrate mode\n");
1419                                 goto error;
1420                         }
1421                         migration_block = true;
1422                         break;
1423                 case 'c':
1424 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1425                         if (strcmp(argv[optind - 1], "--count") == 0)
1426                                 fprintf(stderr, "warning: '--count' deprecated"
1427                                         ", use '--stripe-count' instead\n");
1428 #endif
1429                         lsa.lsa_stripe_count = strtoul(optarg, &end, 0);
1430                         if (*end != '\0') {
1431                                 fprintf(stderr, "error: %s: bad stripe count "
1432                                         "'%s'\n", argv[0], optarg);
1433                                 goto error;
1434                         }
1435                         break;
1436                 case 'd':
1437                         /* delete the default striping pattern */
1438                         delete = 1;
1439                         break;
1440                 case 'E':
1441                         if (lsa.lsa_comp_end != 0) {
1442                                 result = comp_args_to_layout(&layout, &lsa);
1443                                 if (result)
1444                                         goto error;
1445
1446                                 setstripe_args_init(&lsa);
1447                         }
1448
1449                         if (arg_is_eof(optarg)) {
1450                                 lsa.lsa_comp_end = LUSTRE_EOF;
1451                         } else {
1452                                 result = llapi_parse_size(optarg,
1453                                                         &lsa.lsa_comp_end,
1454                                                         &size_units, 0);
1455                                 if (result) {
1456                                         fprintf(stderr, "error: %s: "
1457                                                 "bad component end '%s'\n",
1458                                                 argv[0], optarg);
1459                                         goto error;
1460                                 }
1461                         }
1462                         break;
1463                 case 'i':
1464                         if (strcmp(argv[optind - 1], "--index") == 0)
1465                                 fprintf(stderr, "warning: '--index' deprecated"
1466                                         ", use '--stripe-index' instead\n");
1467                         lsa.lsa_stripe_off = strtol(optarg, &end, 0);
1468                         if (*end != '\0') {
1469                                 fprintf(stderr, "error: %s: bad stripe offset "
1470                                         "'%s'\n", argv[0], optarg);
1471                                 goto error;
1472                         }
1473                         break;
1474                 case 'I':
1475                         comp_id = strtoul(optarg, &end, 0);
1476                         if (*end != '\0' || comp_id == 0 ||
1477                             comp_id > LCME_ID_MAX) {
1478                                 fprintf(stderr, "error: %s: bad comp ID "
1479                                         "'%s'\n", argv[0], optarg);
1480                                 goto error;
1481                         }
1482                         break;
1483                 case 'm':
1484                         if (!migrate_mode) {
1485                                 fprintf(stderr, "--mdt-index is valid only for"
1486                                                 " migrate mode\n");
1487                                 goto error;
1488                         }
1489                         mdt_idx_arg = optarg;
1490                         break;
1491                 case 'n':
1492                         if (!migrate_mode) {
1493                                 fprintf(stderr, "--non-block is valid only for"
1494                                                 " migrate mode\n");
1495                                 goto error;
1496                         }
1497                         migration_flags |= MIGRATION_NONBLOCK;
1498                         break;
1499                 case 'o':
1500                         lsa.lsa_nr_osts = parse_targets(osts,
1501                                                 sizeof(osts) / sizeof(__u32),
1502                                                 lsa.lsa_nr_osts, optarg);
1503                         if (lsa.lsa_nr_osts < 0) {
1504                                 fprintf(stderr,
1505                                         "error: %s: bad OST indices '%s'\n",
1506                                         argv[0], optarg);
1507                                 goto error;
1508                         }
1509
1510                         lsa.lsa_osts = osts;
1511                         if (lsa.lsa_stripe_off == -1)
1512                                 lsa.lsa_stripe_off = osts[0];
1513                         break;
1514                 case 'p':
1515                         result = verify_pool_name(argv[0], optarg);
1516                         if (result)
1517                                 goto error;
1518                         lsa.lsa_pool_name = optarg;
1519                         break;
1520 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
1521                 case 's':
1522 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1523                         fprintf(stderr, "warning: '--size|-s' deprecated, "
1524                                 "use '--stripe-size|-S' instead\n");
1525 #endif
1526 #endif /* LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0) */
1527                 case 'S':
1528                         result = llapi_parse_size(optarg, &lsa.lsa_stripe_size,
1529                                                   &size_units, 0);
1530                         if (result) {
1531                                 fprintf(stderr, "error: %s: bad stripe size "
1532                                         "'%s'\n", argv[0], optarg);
1533                                 goto error;
1534                         }
1535                         break;
1536                 case 'v':
1537                         if (!migrate_mode) {
1538                                 fprintf(stderr, "--verbose is valid only for"
1539                                                 " migrate mode\n");
1540                                 goto error;
1541                         }
1542                         migrate_mdt_param.fp_verbose = VERBOSE_DETAIL;
1543                         break;
1544                 default:
1545                         goto error;
1546                 }
1547         }
1548
1549         fname = argv[optind];
1550
1551         if (lsa.lsa_comp_end != 0) {
1552                 result = comp_args_to_layout(&layout, &lsa);
1553                 if (result)
1554                         goto error;
1555         }
1556
1557         if (optind == argc) {
1558                 fprintf(stderr, "error: %s: missing filename|dirname\n",
1559                         argv[0]);
1560                 goto error;
1561         }
1562
1563         /* Only LCME_FL_INIT flags is used in PFL, and it shouldn't be
1564          * altered by user space tool, so we don't need to support the
1565          * --component-set for this moment. */
1566         if (comp_set != 0) {
1567                 fprintf(stderr, "error: %s: --component-set isn't supported.\n",
1568                         argv[0]);
1569                 goto error;
1570         }
1571
1572         if ((delete + comp_set + comp_del + comp_add) > 1) {
1573                 fprintf(stderr, "error: %s: can't specify --component-set, "
1574                         "--component-del, --component-add or -d together\n",
1575                         argv[0]);
1576                 goto error;
1577         }
1578
1579         if (delete && (setstripe_args_specified(&lsa) || comp_id != 0 ||
1580                        lsa.lsa_comp_flags != 0 || layout != NULL)) {
1581                 fprintf(stderr, "error: %s: can't specify -d with "
1582                         "-s, -c, -o, -p, -I, -F or -E options\n",
1583                         argv[0]);
1584                 goto error;
1585         }
1586
1587         if ((comp_set || comp_del) &&
1588             (setstripe_args_specified(&lsa) || layout != NULL)) {
1589                 fprintf(stderr, "error: %s: can't specify --component-del or "
1590                         "--component-set with -s, -c, -o, -p or -E options.\n",
1591                         argv[0]);
1592                 goto error;
1593         }
1594
1595         if (comp_del && comp_id != 0 && lsa.lsa_comp_flags != 0) {
1596                 fprintf(stderr, "error: %s: can't specify both -I and -F for "
1597                         "--component-del option.\n", argv[0]);
1598                 goto error;
1599         }
1600
1601         if (comp_add) {
1602                 if (layout == NULL) {
1603                         fprintf(stderr, "error: %s: -E option must be present"
1604                                 "in --component-add mode.\n", argv[0]);
1605                         goto error;
1606                 }
1607                 result = adjust_first_extent(fname, layout);
1608                 if (result != 0)
1609                         goto error;
1610         }
1611
1612         if (mdt_idx_arg != NULL && optind > 3) {
1613                 fprintf(stderr, "error: %s: cannot specify -m with other "
1614                         "options\n", argv[0]);
1615                 goto error;
1616         }
1617
1618         if ((migration_flags & MIGRATION_NONBLOCK) && migration_block) {
1619                 fprintf(stderr,
1620                         "error: %s: cannot specify --non-block and --block\n",
1621                         argv[0]);
1622                 goto error;
1623         }
1624
1625         if (!comp_del && !comp_set && comp_id != 0) {
1626                 fprintf(stderr, "error: %s: -I can only be used with "
1627                         "--component-del.\n", argv[0]);
1628                 goto error;
1629         }
1630
1631         if (mdt_idx_arg != NULL) {
1632                 /* initialize migrate mdt parameters */
1633                 migrate_mdt_param.fp_mdt_index = strtoul(mdt_idx_arg, &end, 0);
1634                 if (*end != '\0') {
1635                         fprintf(stderr, "error: %s: bad MDT index '%s'\n",
1636                                 argv[0], mdt_idx_arg);
1637                         goto error;
1638                 }
1639                 migrate_mdt_param.fp_migrate = 1;
1640         } else if (layout == NULL) {
1641                 /* initialize stripe parameters */
1642                 param = calloc(1, offsetof(typeof(*param),
1643                                lsp_osts[lsa.lsa_nr_osts]));
1644                 if (param == NULL) {
1645                         fprintf(stderr, "error: %s: %s\n", argv[0],
1646                                 strerror(ENOMEM));
1647                         goto error;
1648                 }
1649
1650                 param->lsp_stripe_size = lsa.lsa_stripe_size;
1651                 param->lsp_stripe_offset = lsa.lsa_stripe_off;
1652                 param->lsp_stripe_count = lsa.lsa_stripe_count;
1653                 param->lsp_stripe_pattern = 0;
1654                 param->lsp_pool = lsa.lsa_pool_name;
1655                 param->lsp_is_specific = false;
1656                 if (lsa.lsa_nr_osts > 0) {
1657                         if (lsa.lsa_stripe_count > 0 &&
1658                             lsa.lsa_nr_osts != lsa.lsa_stripe_count) {
1659                                 fprintf(stderr, "error: %s: stripe count '%d' "
1660                                         "doesn't match the number of OSTs: %d\n"
1661                                         , argv[0], lsa.lsa_stripe_count,
1662                                         lsa.lsa_nr_osts);
1663                                 free(param);
1664                                 goto error;
1665                         }
1666
1667                         param->lsp_is_specific = true;
1668                         param->lsp_stripe_count = lsa.lsa_nr_osts;
1669                         memcpy(param->lsp_osts, osts,
1670                                sizeof(*osts) * lsa.lsa_nr_osts);
1671                 }
1672         }
1673
1674         for (fname = argv[optind]; fname != NULL; fname = argv[++optind]) {
1675                 char *op;
1676                 if (mdt_idx_arg != NULL) {
1677                         result = llapi_migrate_mdt(fname, &migrate_mdt_param);
1678                         op = "migrate mdt objects of";
1679                 } else if (migrate_mode) {
1680                         result = lfs_migrate(fname, migration_flags, param,
1681                                              layout);
1682                         op = "migrate ost objects of";
1683                 } else if (comp_set != 0) {
1684                         result = lfs_component_set(fname, comp_id,
1685                                                    lsa.lsa_comp_flags);
1686                         op = "modify component flags of";
1687                 } else if (comp_del != 0) {
1688                         result = lfs_component_del(fname, comp_id,
1689                                                    lsa.lsa_comp_flags);
1690                         op = "delete component of";
1691                 } else if (comp_add != 0) {
1692                         result = lfs_component_add(fname, layout);
1693                         op = "add component to";
1694                 } else if (layout != NULL) {
1695                         result = lfs_component_create(fname, O_CREAT | O_WRONLY,
1696                                                       0644, layout);
1697                         if (result >= 0) {
1698                                 close(result);
1699                                 result = 0;
1700                         }
1701                         op = "create composite";
1702                 } else {
1703                         result = llapi_file_open_param(fname,
1704                                                        O_CREAT | O_WRONLY,
1705                                                        0644, param);
1706                         if (result >= 0) {
1707                                 close(result);
1708                                 result = 0;
1709                         }
1710                         op = "create striped";
1711                 }
1712                 if (result) {
1713                         /* Save the first error encountered. */
1714                         if (result2 == 0)
1715                                 result2 = result;
1716                         fprintf(stderr, "error: %s: %s file '%s' failed: %s\n",
1717                                 argv[0], op, fname,
1718                                 lsa.lsa_pool_name != NULL && result == EINVAL ?
1719                                 "OST not in pool?" : strerror(errno));
1720                         continue;
1721                 }
1722         }
1723
1724         free(param);
1725         llapi_layout_free(layout);
1726         return result2;
1727 error:
1728         llapi_layout_free(layout);
1729         return CMD_HELP;
1730 }
1731
1732 static int lfs_poollist(int argc, char **argv)
1733 {
1734         if (argc != 2)
1735                 return CMD_HELP;
1736
1737         return llapi_poollist(argv[1]);
1738 }
1739
1740 static int set_time(time_t *time, time_t *set, char *str)
1741 {
1742         time_t t;
1743         int res = 0;
1744
1745         if (str[0] == '+')
1746                 res = 1;
1747         else if (str[0] == '-')
1748                 res = -1;
1749
1750         if (res)
1751                 str++;
1752
1753         t = strtol(str, NULL, 0);
1754         if (*time < t * 24 * 60 * 60) {
1755                 if (res)
1756                         str--;
1757                 fprintf(stderr, "Wrong time '%s' is specified.\n", str);
1758                 return INT_MAX;
1759         }
1760
1761         *set = *time - t * 24 * 60 * 60;
1762         return res;
1763 }
1764 static int name2uid(unsigned int *id, const char *name)
1765 {
1766         struct passwd *passwd;
1767
1768         passwd = getpwnam(name);
1769         if (passwd == NULL)
1770                 return -ENOENT;
1771         *id = passwd->pw_uid;
1772
1773         return 0;
1774 }
1775
1776 static int name2gid(unsigned int *id, const char *name)
1777 {
1778         struct group *group;
1779
1780         group = getgrnam(name);
1781         if (group == NULL)
1782                 return -ENOENT;
1783         *id = group->gr_gid;
1784
1785         return 0;
1786 }
1787
1788 static inline int name2projid(unsigned int *id, const char *name)
1789 {
1790         return -ENOTSUP;
1791 }
1792
1793 static int uid2name(char **name, unsigned int id)
1794 {
1795         struct passwd *passwd;
1796
1797         passwd = getpwuid(id);
1798         if (passwd == NULL)
1799                 return -ENOENT;
1800         *name = passwd->pw_name;
1801
1802         return 0;
1803 }
1804
1805 static inline int gid2name(char **name, unsigned int id)
1806 {
1807         struct group *group;
1808
1809         group = getgrgid(id);
1810         if (group == NULL)
1811                 return -ENOENT;
1812         *name = group->gr_name;
1813
1814         return 0;
1815 }
1816
1817 static int name2layout(__u32 *layout, char *name)
1818 {
1819         char *ptr, *lyt;
1820
1821         *layout = 0;
1822         for (ptr = name; ; ptr = NULL) {
1823                 lyt = strtok(ptr, ",");
1824                 if (lyt == NULL)
1825                         break;
1826                 if (strcmp(lyt, "released") == 0)
1827                         *layout |= LOV_PATTERN_F_RELEASED;
1828                 else if (strcmp(lyt, "raid0") == 0)
1829                         *layout |= LOV_PATTERN_RAID0;
1830                 else
1831                         return -1;
1832         }
1833         return 0;
1834 }
1835
1836 static int lfs_find(int argc, char **argv)
1837 {
1838         int c, rc;
1839         int ret = 0;
1840         time_t t;
1841         struct find_param param = {
1842                 .fp_max_depth = -1,
1843                 .fp_quiet = 1,
1844         };
1845         struct option long_opts[] = {
1846                 {"atime",        required_argument, 0, 'A'},
1847                 {"comp-count",   required_argument, 0, LFS_COMP_COUNT_OPT},
1848                 {"component-count", required_argument, 0, LFS_COMP_COUNT_OPT},
1849                 {"comp-flags",   required_argument, 0, LFS_COMP_FLAGS_OPT},
1850                 {"component-flags", required_argument, 0, LFS_COMP_FLAGS_OPT},
1851                 {"comp-start",   required_argument, 0, LFS_COMP_START_OPT},
1852                 {"component-start", required_argument, 0, LFS_COMP_START_OPT},
1853                 {"stripe-count", required_argument, 0, 'c'},
1854                 {"stripe_count", required_argument, 0, 'c'},
1855                 {"ctime",        required_argument, 0, 'C'},
1856                 {"maxdepth",     required_argument, 0, 'D'},
1857                 {"comp-end",     required_argument, 0, 'E'},
1858                 {"component-end", required_argument, 0, 'E'},
1859                 {"gid",          required_argument, 0, 'g'},
1860                 {"group",        required_argument, 0, 'G'},
1861                 {"mdt-hash",     required_argument, 0, 'H'},
1862                 {"stripe-index", required_argument, 0, 'i'},
1863                 {"stripe_index", required_argument, 0, 'i'},
1864                 /*{"component-id", required_argument, 0, 'I'},*/
1865                 {"layout",       required_argument, 0, 'L'},
1866                 {"mdt",          required_argument, 0, 'm'},
1867                 {"mdt-index",    required_argument, 0, 'm'},
1868                 {"mdt_index",    required_argument, 0, 'm'},
1869                 {"mtime",        required_argument, 0, 'M'},
1870                 {"name",         required_argument, 0, 'n'},
1871      /* reserve {"or",           no_argument,     , 0, 'o'}, to match find(1) */
1872                 {"obd",          required_argument, 0, 'O'},
1873                 {"ost",          required_argument, 0, 'O'},
1874                 /* no short option for pool, p/P already used */
1875                 {"pool",         required_argument, 0, LFS_POOL_OPT},
1876                 {"print0",       no_argument,       0, 'p'},
1877                 {"print",        no_argument,       0, 'P'},
1878                 {"projid",       required_argument, 0, LFS_PROJID_OPT},
1879                 {"size",         required_argument, 0, 's'},
1880                 {"stripe-size",  required_argument, 0, 'S'},
1881                 {"stripe_size",  required_argument, 0, 'S'},
1882                 {"type",         required_argument, 0, 't'},
1883                 {"mdt-count",    required_argument, 0, 'T'},
1884                 {"uid",          required_argument, 0, 'u'},
1885                 {"user",         required_argument, 0, 'U'},
1886                 {0, 0, 0, 0}
1887         };
1888         int pathstart = -1;
1889         int pathend = -1;
1890         int neg_opt = 0;
1891         time_t *xtime;
1892         int *xsign;
1893         int isoption;
1894         char *endptr;
1895
1896         time(&t);
1897
1898         /* when getopt_long_only() hits '!' it returns 1, puts "!" in optarg */
1899         while ((c = getopt_long_only(argc, argv,
1900                         "-A:c:C:D:E:g:G:H:i:L:m:M:n:O:Ppqrs:S:t:T:u:U:v",
1901                         long_opts, NULL)) >= 0) {
1902                 xtime = NULL;
1903                 xsign = NULL;
1904                 if (neg_opt)
1905                         --neg_opt;
1906                 /* '!' is part of option */
1907                 /* when getopt_long_only() finds a string which is not
1908                  * an option nor a known option argument it returns 1
1909                  * in that case if we already have found pathstart and pathend
1910                  * (i.e. we have the list of pathnames),
1911                  * the only supported value is "!"
1912                  */
1913                 isoption = (c != 1) || (strcmp(optarg, "!") == 0);
1914                 if (!isoption && pathend != -1) {
1915                         fprintf(stderr, "err: %s: filename|dirname must either "
1916                                         "precede options or follow options\n",
1917                                         argv[0]);
1918                         ret = CMD_HELP;
1919                         goto err;
1920                 }
1921                 if (!isoption && pathstart == -1)
1922                         pathstart = optind - 1;
1923                 if (isoption && pathstart != -1 && pathend == -1)
1924                         pathend = optind - 2;
1925                 switch (c) {
1926                 case 0:
1927                         /* Long options. */
1928                         break;
1929                 case 1:
1930                         /* unknown; opt is "!" or path component,
1931                          * checking done above.
1932                          */
1933                         if (strcmp(optarg, "!") == 0)
1934                                 neg_opt = 2;
1935                         break;
1936                 case 'A':
1937                         xtime = &param.fp_atime;
1938                         xsign = &param.fp_asign;
1939                         param.fp_exclude_atime = !!neg_opt;
1940                         /* no break, this falls through to 'C' for ctime */
1941                 case 'C':
1942                         if (c == 'C') {
1943                                 xtime = &param.fp_ctime;
1944                                 xsign = &param.fp_csign;
1945                                 param.fp_exclude_ctime = !!neg_opt;
1946                         }
1947                         /* no break, this falls through to 'M' for mtime */
1948                 case 'M':
1949                         if (c == 'M') {
1950                                 xtime = &param.fp_mtime;
1951                                 xsign = &param.fp_msign;
1952                                 param.fp_exclude_mtime = !!neg_opt;
1953                         }
1954                         rc = set_time(&t, xtime, optarg);
1955                         if (rc == INT_MAX) {
1956                                 ret = -1;
1957                                 goto err;
1958                         }
1959                         if (rc)
1960                                 *xsign = rc;
1961                         break;
1962                 case LFS_COMP_COUNT_OPT:
1963                         if (optarg[0] == '+') {
1964                                 param.fp_comp_count_sign = -1;
1965                                 optarg++;
1966                         } else if (optarg[0] == '-') {
1967                                 param.fp_comp_count_sign =  1;
1968                                 optarg++;
1969                         }
1970
1971                         param.fp_comp_count = strtoul(optarg, &endptr, 0);
1972                         if (*endptr != '\0') {
1973                                 fprintf(stderr, "error: bad component count "
1974                                         "'%s'\n", optarg);
1975                                 goto err;
1976                         }
1977                         param.fp_check_comp_count = 1;
1978                         param.fp_exclude_comp_count = !!neg_opt;
1979                         break;
1980                 case LFS_COMP_FLAGS_OPT:
1981                         rc = comp_name2flags(&param.fp_comp_flags, optarg);
1982                         if (rc || comp_flags_is_neg(param.fp_comp_flags)) {
1983                                 fprintf(stderr, "error: bad component flags "
1984                                         "'%s'\n", optarg);
1985                                 goto err;
1986                         }
1987                         param.fp_check_comp_flags = 1;
1988                         param.fp_exclude_comp_flags = !!neg_opt;
1989                         break;
1990                 case LFS_COMP_START_OPT:
1991                         if (optarg[0] == '+') {
1992                                 param.fp_comp_start_sign = -1;
1993                                 optarg++;
1994                         } else if (optarg[0] == '-') {
1995                                 param.fp_comp_start_sign =  1;
1996                                 optarg++;
1997                         }
1998
1999                         rc = llapi_parse_size(optarg, &param.fp_comp_start,
2000                                               &param.fp_comp_start_units, 0);
2001                         if (rc) {
2002                                 fprintf(stderr, "error: bad component start "
2003                                         "'%s'\n", optarg);
2004                                 goto err;
2005                         }
2006                         param.fp_check_comp_start = 1;
2007                         param.fp_exclude_comp_start = !!neg_opt;
2008                         break;
2009                 case 'c':
2010                         if (optarg[0] == '+') {
2011                                 param.fp_stripe_count_sign = -1;
2012                                 optarg++;
2013                         } else if (optarg[0] == '-') {
2014                                 param.fp_stripe_count_sign =  1;
2015                                 optarg++;
2016                         }
2017
2018                         param.fp_stripe_count = strtoul(optarg, &endptr, 0);
2019                         if (*endptr != '\0') {
2020                                 fprintf(stderr,"error: bad stripe_count '%s'\n",
2021                                         optarg);
2022                                 ret = -1;
2023                                 goto err;
2024                         }
2025                         param.fp_check_stripe_count = 1;
2026                         param.fp_exclude_stripe_count = !!neg_opt;
2027                         break;
2028                 case 'D':
2029                         param.fp_max_depth = strtol(optarg, 0, 0);
2030                         break;
2031                 case 'E':
2032                         if (optarg[0] == '+') {
2033                                 param.fp_comp_end_sign = -1;
2034                                 optarg++;
2035                         } else if (optarg[0] == '-') {
2036                                 param.fp_comp_end_sign =  1;
2037                                 optarg++;
2038                         }
2039
2040                         if (arg_is_eof(optarg)) {
2041                                 param.fp_comp_end = LUSTRE_EOF;
2042                                 param.fp_comp_end_units = 1;
2043                                 rc = 0;
2044                         } else {
2045                                 rc = llapi_parse_size(optarg,
2046                                                 &param.fp_comp_end,
2047                                                 &param.fp_comp_end_units, 0);
2048                         }
2049                         if (rc) {
2050                                 fprintf(stderr, "error: bad component end "
2051                                         "'%s'\n", optarg);
2052                                 goto err;
2053                         }
2054                         param.fp_check_comp_end = 1;
2055                         param.fp_exclude_comp_end = !!neg_opt;
2056                         break;
2057                 case 'g':
2058                 case 'G':
2059                         rc = name2gid(&param.fp_gid, optarg);
2060                         if (rc) {
2061                                 param.fp_gid = strtoul(optarg, &endptr, 10);
2062                                 if (*endptr != '\0') {
2063                                         fprintf(stderr, "Group/GID: %s cannot "
2064                                                 "be found.\n", optarg);
2065                                         ret = -1;
2066                                         goto err;
2067                                 }
2068                         }
2069                         param.fp_exclude_gid = !!neg_opt;
2070                         param.fp_check_gid = 1;
2071                         break;
2072                 case 'H':
2073                         param.fp_hash_type = check_hashtype(optarg);
2074                         if (param.fp_hash_type == 0) {
2075                                 fprintf(stderr, "error: bad hash_type '%s'\n",
2076                                         optarg);
2077                                 ret = -1;
2078                                 goto err;
2079                         }
2080                         param.fp_check_hash_type = 1;
2081                         param.fp_exclude_hash_type = !!neg_opt;
2082                         break;
2083                 case 'L':
2084                         ret = name2layout(&param.fp_layout, optarg);
2085                         if (ret)
2086                                 goto err;
2087                         param.fp_exclude_layout = !!neg_opt;
2088                         param.fp_check_layout = 1;
2089                         break;
2090                 case 'u':
2091                 case 'U':
2092                         rc = name2uid(&param.fp_uid, optarg);
2093                         if (rc) {
2094                                 param.fp_uid = strtoul(optarg, &endptr, 10);
2095                                 if (*endptr != '\0') {
2096                                         fprintf(stderr, "User/UID: %s cannot "
2097                                                 "be found.\n", optarg);
2098                                         ret = -1;
2099                                         goto err;
2100                                 }
2101                         }
2102                         param.fp_exclude_uid = !!neg_opt;
2103                         param.fp_check_uid = 1;
2104                         break;
2105                 case LFS_POOL_OPT:
2106                         if (strlen(optarg) > LOV_MAXPOOLNAME) {
2107                                 fprintf(stderr,
2108                                         "Pool name %s is too long"
2109                                         " (max is %d)\n", optarg,
2110                                         LOV_MAXPOOLNAME);
2111                                 ret = -1;
2112                                 goto err;
2113                         }
2114                         /* we do check for empty pool because empty pool
2115                          * is used to find V1 lov attributes */
2116                         strncpy(param.fp_poolname, optarg, LOV_MAXPOOLNAME);
2117                         param.fp_poolname[LOV_MAXPOOLNAME] = '\0';
2118                         param.fp_exclude_pool = !!neg_opt;
2119                         param.fp_check_pool = 1;
2120                         break;
2121                 case 'n':
2122                         param.fp_pattern = (char *)optarg;
2123                         param.fp_exclude_pattern = !!neg_opt;
2124                         break;
2125                 case 'm':
2126                 case 'i':
2127                 case 'O': {
2128                         char *buf, *token, *next, *p;
2129                         int len = 1;
2130                         void *tmp;
2131
2132                         buf = strdup(optarg);
2133                         if (buf == NULL) {
2134                                 ret = -ENOMEM;
2135                                 goto err;
2136                         }
2137
2138                         param.fp_exclude_obd = !!neg_opt;
2139
2140                         token = buf;
2141                         while (token && *token) {
2142                                 token = strchr(token, ',');
2143                                 if (token) {
2144                                         len++;
2145                                         token++;
2146                                 }
2147                         }
2148                         if (c == 'm') {
2149                                 param.fp_exclude_mdt = !!neg_opt;
2150                                 param.fp_num_alloc_mdts += len;
2151                                 tmp = realloc(param.fp_mdt_uuid,
2152                                               param.fp_num_alloc_mdts *
2153                                               sizeof(*param.fp_mdt_uuid));
2154                                 if (tmp == NULL) {
2155                                         ret = -ENOMEM;
2156                                         goto err_free;
2157                                 }
2158
2159                                 param.fp_mdt_uuid = tmp;
2160                         } else {
2161                                 param.fp_exclude_obd = !!neg_opt;
2162                                 param.fp_num_alloc_obds += len;
2163                                 tmp = realloc(param.fp_obd_uuid,
2164                                               param.fp_num_alloc_obds *
2165                                               sizeof(*param.fp_obd_uuid));
2166                                 if (tmp == NULL) {
2167                                         ret = -ENOMEM;
2168                                         goto err_free;
2169                                 }
2170
2171                                 param.fp_obd_uuid = tmp;
2172                         }
2173                         for (token = buf; token && *token; token = next) {
2174                                 struct obd_uuid *puuid;
2175                                 if (c == 'm') {
2176                                         puuid =
2177                                         &param.fp_mdt_uuid[param.fp_num_mdts++];
2178                                 } else {
2179                                         puuid =
2180                                         &param.fp_obd_uuid[param.fp_num_obds++];
2181                                 }
2182                                 p = strchr(token, ',');
2183                                 next = 0;
2184                                 if (p) {
2185                                         *p = 0;
2186                                         next = p+1;
2187                                 }
2188
2189                                 if (strlen(token) > sizeof(puuid->uuid) - 1) {
2190                                         ret = -E2BIG;
2191                                         goto err_free;
2192                                 }
2193
2194                                 strncpy(puuid->uuid, token,
2195                                         sizeof(puuid->uuid));
2196                         }
2197 err_free:
2198                         if (buf)
2199                                 free(buf);
2200                         break;
2201                 }
2202                 case 'p':
2203                         param.fp_zero_end = 1;
2204                         break;
2205                 case 'P':
2206                         break;
2207                 case LFS_PROJID_OPT:
2208                         rc = name2projid(&param.fp_projid, optarg);
2209                         if (rc) {
2210                                 param.fp_projid = strtoul(optarg, &endptr, 10);
2211                                 if (*endptr != '\0') {
2212                                         fprintf(stderr,
2213                                                 "Invalid project ID: %s",
2214                                                 optarg);
2215                                         ret = -1;
2216                                         goto err;
2217                                 }
2218                         }
2219                         param.fp_exclude_projid = !!neg_opt;
2220                         param.fp_check_projid = 1;
2221                         break;
2222                 case 's':
2223                         if (optarg[0] == '+') {
2224                                 param.fp_size_sign = -1;
2225                                 optarg++;
2226                         } else if (optarg[0] == '-') {
2227                                 param.fp_size_sign =  1;
2228                                 optarg++;
2229                         }
2230
2231                         ret = llapi_parse_size(optarg, &param.fp_size,
2232                                                &param.fp_size_units, 0);
2233                         if (ret) {
2234                                 fprintf(stderr, "error: bad file size '%s'\n",
2235                                         optarg);
2236                                 goto err;
2237                         }
2238                         param.fp_check_size = 1;
2239                         param.fp_exclude_size = !!neg_opt;
2240                         break;
2241                 case 'S':
2242                         if (optarg[0] == '+') {
2243                                 param.fp_stripe_size_sign = -1;
2244                                 optarg++;
2245                         } else if (optarg[0] == '-') {
2246                                 param.fp_stripe_size_sign =  1;
2247                                 optarg++;
2248                         }
2249
2250                         ret = llapi_parse_size(optarg, &param.fp_stripe_size,
2251                                                &param.fp_stripe_size_units, 0);
2252                         if (ret) {
2253                                 fprintf(stderr, "error: bad stripe_size '%s'\n",
2254                                         optarg);
2255                                 goto err;
2256                         }
2257                         param.fp_check_stripe_size = 1;
2258                         param.fp_exclude_stripe_size = !!neg_opt;
2259                         break;
2260                 case 't':
2261                         param.fp_exclude_type = !!neg_opt;
2262                         switch (optarg[0]) {
2263                         case 'b':
2264                                 param.fp_type = S_IFBLK;
2265                                 break;
2266                         case 'c':
2267                                 param.fp_type = S_IFCHR;
2268                                 break;
2269                         case 'd':
2270                                 param.fp_type = S_IFDIR;
2271                                 break;
2272                         case 'f':
2273                                 param.fp_type = S_IFREG;
2274                                 break;
2275                         case 'l':
2276                                 param.fp_type = S_IFLNK;
2277                                 break;
2278                         case 'p':
2279                                 param.fp_type = S_IFIFO;
2280                                 break;
2281                         case 's':
2282                                 param.fp_type = S_IFSOCK;
2283                                 break;
2284                         default:
2285                                 fprintf(stderr, "error: %s: bad type '%s'\n",
2286                                         argv[0], optarg);
2287                                 ret = CMD_HELP;
2288                                 goto err;
2289                         };
2290                         break;
2291                 case 'T':
2292                         if (optarg[0] == '+') {
2293                                 param.fp_mdt_count_sign = -1;
2294                                 optarg++;
2295                         } else if (optarg[0] == '-') {
2296                                 param.fp_mdt_count_sign =  1;
2297                                 optarg++;
2298                         }
2299
2300                         param.fp_mdt_count = strtoul(optarg, &endptr, 0);
2301                         if (*endptr != '\0') {
2302                                 fprintf(stderr, "error: bad mdt_count '%s'\n",
2303                                         optarg);
2304                                 ret = -1;
2305                                 goto err;
2306                         }
2307                         param.fp_check_mdt_count = 1;
2308                         param.fp_exclude_mdt_count = !!neg_opt;
2309                         break;
2310                 default:
2311                         ret = CMD_HELP;
2312                         goto err;
2313                 };
2314         }
2315
2316         if (pathstart == -1) {
2317                 fprintf(stderr, "error: %s: no filename|pathname\n",
2318                         argv[0]);
2319                 ret = CMD_HELP;
2320                 goto err;
2321         } else if (pathend == -1) {
2322                 /* no options */
2323                 pathend = argc;
2324         }
2325
2326         do {
2327                 rc = llapi_find(argv[pathstart], &param);
2328                 if (rc != 0 && ret == 0)
2329                         ret = rc;
2330         } while (++pathstart < pathend);
2331
2332         if (ret)
2333                 fprintf(stderr, "error: %s failed for %s.\n",
2334                         argv[0], argv[optind - 1]);
2335 err:
2336         if (param.fp_obd_uuid && param.fp_num_alloc_obds)
2337                 free(param.fp_obd_uuid);
2338
2339         if (param.fp_mdt_uuid && param.fp_num_alloc_mdts)
2340                 free(param.fp_mdt_uuid);
2341
2342         return ret;
2343 }
2344
2345 static int lfs_getstripe_internal(int argc, char **argv,
2346                                   struct find_param *param)
2347 {
2348         struct option long_opts[] = {
2349                 {"comp-count",          no_argument, 0, LFS_COMP_COUNT_OPT},
2350                 {"component-count",     no_argument, 0, LFS_COMP_COUNT_OPT},
2351                 {"comp-flags",      optional_argument, 0, LFS_COMP_FLAGS_OPT},
2352                 {"component-flags", optional_argument, 0, LFS_COMP_FLAGS_OPT},
2353                 {"comp-start",      optional_argument, 0, LFS_COMP_START_OPT},
2354                 {"component-start", optional_argument, 0, LFS_COMP_START_OPT},
2355 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2356                 /* This formerly implied "stripe-count", but was explicitly
2357                  * made "stripe-count" for consistency with other options,
2358                  * and to separate it from "mdt-count" when DNE arrives. */
2359                 {"count",               no_argument,            0, 'c'},
2360 #endif
2361                 {"stripe-count",        no_argument,            0, 'c'},
2362                 {"stripe_count",        no_argument,            0, 'c'},
2363                 {"directory",           no_argument,            0, 'd'},
2364                 {"default",             no_argument,            0, 'D'},
2365                 {"comp-end",            optional_argument,      0, 'E'},
2366                 {"component-end",       optional_argument,      0, 'E'},
2367                 {"fid",                 no_argument,            0, 'F'},
2368                 {"generation",          no_argument,            0, 'g'},
2369                 /* dirstripe {"mdt-hash",     required_argument, 0, 'H'}, */
2370 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2371                 /* This formerly implied "stripe-index", but was explicitly
2372                  * made "stripe-index" for consistency with other options,
2373                  * and to separate it from "mdt-index" when DNE arrives. */
2374                 {"index",               no_argument,            0, 'i'},
2375 #endif
2376                 {"stripe-index",        no_argument,            0, 'i'},
2377                 {"stripe_index",        no_argument,            0, 'i'},
2378                 {"comp-id",             optional_argument,      0, 'I'},
2379                 {"component-id",        optional_argument,      0, 'I'},
2380                 {"layout",              no_argument,            0, 'L'},
2381                 {"mdt",                 no_argument,            0, 'm'},
2382                 {"mdt-index",           no_argument,            0, 'm'},
2383                 {"mdt_index",           no_argument,            0, 'm'},
2384 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2385                 {"mdt-index",           no_argument,            0, 'M'},
2386                 {"mdt_index",           no_argument,            0, 'M'},
2387 #endif
2388 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2389                 /* This formerly implied "stripe-index", but was confusing
2390                  * with "file offset" (which will eventually be needed for
2391                  * with different layouts by offset), so deprecate it. */
2392                 {"offset",              no_argument,            0, 'o'},
2393 #endif
2394                 {"obd",                 required_argument,      0, 'O'},
2395                 {"ost",                 required_argument,      0, 'O'},
2396                 {"pool",                no_argument,            0, 'p'},
2397                 {"quiet",               no_argument,            0, 'q'},
2398                 {"recursive",           no_argument,            0, 'r'},
2399                 {"raw",                 no_argument,            0, 'R'},
2400 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2401                 /* This formerly implied "--stripe-size", but was confusing
2402                  * with "lfs find --size|-s", which means "file size", so use
2403                  * the consistent "--stripe-size|-S" for all commands. */
2404                 {"size",                no_argument,            0, 's'},
2405 #endif
2406                 {"stripe-size",         no_argument,            0, 'S'},
2407                 {"stripe_size",         no_argument,            0, 'S'},
2408                 /* dirstripe {"mdt-count",    required_argument, 0, 'T'}, */
2409                 {"verbose",             no_argument,            0, 'v'},
2410                 {"yaml",                no_argument,            0, 'y'},
2411                 {0, 0, 0, 0}
2412         };
2413         int c, rc;
2414         char *end, *tmp;
2415
2416         while ((c = getopt_long(argc, argv, "cdDE::FghiI::LmMoO:pqrRsSvy",
2417                                 long_opts, NULL)) != -1) {
2418                 switch (c) {
2419                 case 'c':
2420                         if (strcmp(argv[optind - 1], "--count") == 0)
2421                                 fprintf(stderr, "warning: '--count' deprecated,"
2422                                         " use '--stripe-count' instead\n");
2423                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2424                                 param->fp_verbose |= VERBOSE_COUNT;
2425                                 param->fp_max_depth = 0;
2426                         }
2427                         break;
2428                 case LFS_COMP_COUNT_OPT:
2429                         param->fp_verbose |= VERBOSE_COMP_COUNT;
2430                         param->fp_max_depth = 0;
2431                         break;
2432                 case LFS_COMP_FLAGS_OPT:
2433                         if (optarg != NULL) {
2434                                 __u32 *flags = &param->fp_comp_flags;
2435                                 rc = comp_name2flags(flags, optarg);
2436                                 if (rc != 0) {
2437                                         fprintf(stderr, "error: %s bad "
2438                                                 "component flags '%s'.\n",
2439                                                 argv[0], optarg);
2440                                         return CMD_HELP;
2441                                 } else {
2442                                         param->fp_check_comp_flags = 1;
2443                                         param->fp_exclude_comp_flags =
2444                                                 comp_flags_is_neg(*flags);
2445                                         comp_flags_clear_neg(flags);
2446                                 }
2447                         } else {
2448                                 param->fp_verbose |= VERBOSE_COMP_FLAGS;
2449                                 param->fp_max_depth = 0;
2450                         }
2451                         break;
2452                 case LFS_COMP_START_OPT:
2453                         if (optarg != NULL) {
2454                                 tmp = optarg;
2455                                 if (tmp[0] == '+') {
2456                                         param->fp_comp_start_sign = -1;
2457                                         tmp++;
2458                                 } else if (tmp[0] == '-') {
2459                                         param->fp_comp_start_sign = 1;
2460                                         tmp++;
2461                                 }
2462                                 rc = llapi_parse_size(tmp,
2463                                                 &param->fp_comp_start,
2464                                                 &param->fp_comp_start_units, 0);
2465                                 if (rc != 0) {
2466                                         fprintf(stderr, "error: %s bad "
2467                                                 "component start '%s'.\n",
2468                                                 argv[0], tmp);
2469                                         return CMD_HELP;
2470                                 } else {
2471                                         param->fp_check_comp_start = 1;
2472                                 }
2473                         } else {
2474                                 param->fp_verbose |= VERBOSE_COMP_START;
2475                                 param->fp_max_depth = 0;
2476                         }
2477                         break;
2478                 case 'd':
2479                         param->fp_max_depth = 0;
2480                         break;
2481                 case 'D':
2482                         param->fp_get_default_lmv = 1;
2483                         break;
2484                 case 'E':
2485                         if (optarg != NULL) {
2486                                 tmp = optarg;
2487                                 if (tmp[0] == '+') {
2488                                         param->fp_comp_end_sign = -1;
2489                                         tmp++;
2490                                 } else if (tmp[0] == '-') {
2491                                         param->fp_comp_end_sign = 1;
2492                                         tmp++;
2493                                 }
2494
2495                                 if (arg_is_eof(tmp)) {
2496                                         param->fp_comp_end = LUSTRE_EOF;
2497                                         param->fp_comp_end_units = 1;
2498                                         rc = 0;
2499                                 } else {
2500                                         rc = llapi_parse_size(tmp,
2501                                                 &param->fp_comp_end,
2502                                                 &param->fp_comp_end_units, 0);
2503                                 }
2504                                 if (rc != 0) {
2505                                         fprintf(stderr, "error: %s bad "
2506                                                 "component end '%s'.\n",
2507                                                 argv[0], tmp);
2508                                         return CMD_HELP;
2509                                 }
2510                                 param->fp_check_comp_end = 1;
2511                         } else {
2512                                 param->fp_verbose |= VERBOSE_COMP_END;
2513                                 param->fp_max_depth = 0;
2514                         }
2515                         break;
2516                 case 'F':
2517                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2518                                 param->fp_verbose |= VERBOSE_DFID;
2519                                 param->fp_max_depth = 0;
2520                         }
2521                         break;
2522                 case 'g':
2523                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2524                                 param->fp_verbose |= VERBOSE_GENERATION;
2525                                 param->fp_max_depth = 0;
2526                         }
2527                         break;
2528 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2529                 case 'o':
2530                         fprintf(stderr, "warning: '--offset|-o' deprecated, "
2531                                 "use '--stripe-index|-i' instead\n");
2532 #endif
2533                 case 'i':
2534 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
2535                         if (strcmp(argv[optind - 1], "--index") == 0)
2536                                 fprintf(stderr, "warning: '--index' deprecated"
2537                                         ", use '--stripe-index' instead\n");
2538 #endif
2539                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2540                                 param->fp_verbose |= VERBOSE_OFFSET;
2541                                 param->fp_max_depth = 0;
2542                         }
2543                         break;
2544                 case 'I':
2545                         if (optarg != NULL) {
2546                                 param->fp_comp_id = strtoul(optarg, &end, 0);
2547                                 if (*end != '\0' || param->fp_comp_id == 0 ||
2548                                     param->fp_comp_id > LCME_ID_MAX) {
2549                                         fprintf(stderr, "error: %s bad "
2550                                                 "component id '%s'\n",
2551                                                 argv[0], optarg);
2552                                         return CMD_HELP;
2553                                 } else {
2554                                         param->fp_check_comp_id = 1;
2555                                 }
2556                         } else {
2557                                 param->fp_max_depth = 0;
2558                                 param->fp_verbose |= VERBOSE_COMP_ID;
2559                         }
2560                         break;
2561                 case 'L':
2562                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2563                                 param->fp_verbose |= VERBOSE_LAYOUT;
2564                                 param->fp_max_depth = 0;
2565                         }
2566                         break;
2567 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2568                 case 'M':
2569 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2570                         fprintf(stderr, "warning: '-M' deprecated"
2571                                 ", use '-m' instead\n");
2572 #endif
2573 #endif
2574                 case 'm':
2575                         if (!(param->fp_verbose & VERBOSE_DETAIL))
2576                                 param->fp_max_depth = 0;
2577                         param->fp_verbose |= VERBOSE_MDTINDEX;
2578                         break;
2579                 case 'O':
2580                         if (param->fp_obd_uuid) {
2581                                 fprintf(stderr,
2582                                         "error: %s: only one obduuid allowed",
2583                                         argv[0]);
2584                                 return CMD_HELP;
2585                         }
2586                         param->fp_obd_uuid = (struct obd_uuid *)optarg;
2587                         break;
2588                 case 'p':
2589                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2590                                 param->fp_verbose |= VERBOSE_POOL;
2591                                 param->fp_max_depth = 0;
2592                         }
2593                         break;
2594                 case 'q':
2595                         param->fp_quiet++;
2596                         break;
2597                 case 'r':
2598                         param->fp_recursive = 1;
2599                         break;
2600                 case 'R':
2601                         param->fp_raw = 1;
2602                         break;
2603 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2604                 case 's':
2605                         fprintf(stderr, "warning: '--size|-s' deprecated, "
2606                                 "use '--stripe-size|-S' instead\n");
2607 #endif /* LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0) */
2608                 case 'S':
2609                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2610                                 param->fp_verbose |= VERBOSE_SIZE;
2611                                 param->fp_max_depth = 0;
2612                         }
2613                         break;
2614                 case 'v':
2615                         param->fp_verbose = VERBOSE_DEFAULT | VERBOSE_DETAIL;
2616                         break;
2617                 case 'y':
2618                         param->fp_yaml = 1;
2619                         break;
2620                 default:
2621                         return CMD_HELP;
2622                 }
2623         }
2624
2625         if (optind >= argc)
2626                 return CMD_HELP;
2627
2628         if (param->fp_recursive)
2629                 param->fp_max_depth = -1;
2630         else if (param->fp_verbose & VERBOSE_DETAIL)
2631                 param->fp_max_depth = 1;
2632
2633         if (!param->fp_verbose)
2634                 param->fp_verbose = VERBOSE_DEFAULT;
2635         if (param->fp_quiet)
2636                 param->fp_verbose = VERBOSE_OBJID;
2637
2638         do {
2639                 rc = llapi_getstripe(argv[optind], param);
2640         } while (++optind < argc && !rc);
2641
2642         if (rc)
2643                 fprintf(stderr, "error: %s failed for %s.\n",
2644                         argv[0], argv[optind - 1]);
2645         return rc;
2646 }
2647
2648 static int lfs_tgts(int argc, char **argv)
2649 {
2650         char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
2651         struct find_param param;
2652         int index = 0, rc=0;
2653
2654         if (argc > 2)
2655                 return CMD_HELP;
2656
2657         if (argc == 2 && !realpath(argv[1], path)) {
2658                 rc = -errno;
2659                 fprintf(stderr, "error: invalid path '%s': %s\n",
2660                         argv[1], strerror(-rc));
2661                 return rc;
2662         }
2663
2664         while (!llapi_search_mounts(path, index++, mntdir, NULL)) {
2665                 /* Check if we have a mount point */
2666                 if (mntdir[0] == '\0')
2667                         continue;
2668
2669                 memset(&param, 0, sizeof(param));
2670                 if (!strcmp(argv[0], "mdts"))
2671                         param.fp_get_lmv = 1;
2672
2673                 rc = llapi_ostlist(mntdir, &param);
2674                 if (rc) {
2675                         fprintf(stderr, "error: %s: failed on %s\n",
2676                                 argv[0], mntdir);
2677                 }
2678                 if (path[0] != '\0')
2679                         break;
2680                 memset(mntdir, 0, PATH_MAX);
2681         }
2682
2683         return rc;
2684 }
2685
2686 static int lfs_getstripe(int argc, char **argv)
2687 {
2688         struct find_param param = { 0 };
2689
2690         param.fp_max_depth = 1;
2691         return lfs_getstripe_internal(argc, argv, &param);
2692 }
2693
2694 /* functions */
2695 static int lfs_getdirstripe(int argc, char **argv)
2696 {
2697         struct find_param param = { 0 };
2698         struct option long_opts[] = {
2699 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2700                 {"mdt-count",   no_argument,            0, 'c'},
2701 #endif
2702                 {"mdt-hash",    no_argument,            0, 'H'},
2703                 {"mdt-index",   no_argument,            0, 'i'},
2704                 {"recursive",   no_argument,            0, 'r'},
2705 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2706                 {"mdt-hash",    no_argument,            0, 't'},
2707 #endif
2708                 {"default",     no_argument,            0, 'D'},
2709                 {"obd",         required_argument,      0, 'O'},
2710                 {"mdt-count",   no_argument,            0, 'T'},
2711                 {"yaml",        no_argument,            0, 'y'},
2712                 {0, 0, 0, 0}
2713         };
2714         int c, rc;
2715
2716         param.fp_get_lmv = 1;
2717
2718         while ((c = getopt_long(argc, argv,
2719                                 "cDHiO:rtTy", long_opts, NULL)) != -1)
2720         {
2721                 switch (c) {
2722                 case 'O':
2723                         if (param.fp_obd_uuid) {
2724                                 fprintf(stderr,
2725                                         "error: %s: only one obduuid allowed",
2726                                         argv[0]);
2727                                 return CMD_HELP;
2728                         }
2729                         param.fp_obd_uuid = (struct obd_uuid *)optarg;
2730                         break;
2731 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2732                 case 'c':
2733 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 10, 50, 0)
2734                         fprintf(stderr, "warning: '-c' deprecated"
2735                                 ", use '-T' instead\n");
2736 #endif
2737 #endif
2738                 case 'T':
2739                         param.fp_verbose |= VERBOSE_COUNT;
2740                         break;
2741                 case 'i':
2742                         param.fp_verbose |= VERBOSE_OFFSET;
2743                         break;
2744 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2745                 case 't':
2746 #endif
2747                 case 'H':
2748                         param.fp_verbose |= VERBOSE_HASH_TYPE;
2749                         break;
2750                 case 'D':
2751                         param.fp_get_default_lmv = 1;
2752                         break;
2753                 case 'r':
2754                         param.fp_recursive = 1;
2755                         break;
2756                 case 'y':
2757                         param.fp_yaml = 1;
2758                         break;
2759                 default:
2760                         return CMD_HELP;
2761                 }
2762         }
2763
2764         if (optind >= argc)
2765                 return CMD_HELP;
2766
2767         if (param.fp_recursive)
2768                 param.fp_max_depth = -1;
2769
2770         if (!param.fp_verbose)
2771                 param.fp_verbose = VERBOSE_DEFAULT;
2772
2773         do {
2774                 rc = llapi_getstripe(argv[optind], &param);
2775         } while (++optind < argc && !rc);
2776
2777         if (rc)
2778                 fprintf(stderr, "error: %s failed for %s.\n",
2779                         argv[0], argv[optind - 1]);
2780         return rc;
2781 }
2782
2783 /* functions */
2784 static int lfs_setdirstripe(int argc, char **argv)
2785 {
2786         char                    *dname;
2787         int                     result;
2788         unsigned int            stripe_offset = -1;
2789         unsigned int            stripe_count = 1;
2790         enum lmv_hash_type      hash_type;
2791         char                    *end;
2792         int                     c;
2793         char                    *stripe_offset_opt = NULL;
2794         char                    *stripe_count_opt = NULL;
2795         char                    *stripe_hash_opt = NULL;
2796         char                    *mode_opt = NULL;
2797         bool                    default_stripe = false;
2798         mode_t                  mode = S_IRWXU | S_IRWXG | S_IRWXO;
2799         mode_t                  previous_mode = 0;
2800         bool                    delete = false;
2801
2802         struct option long_opts[] = {
2803 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2804                 {"count",       required_argument, 0, 'c'},
2805 #endif
2806                 {"mdt-count",   required_argument, 0, 'c'},
2807                 {"delete",      no_argument, 0, 'd'},
2808 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2809                 {"index",       required_argument, 0, 'i'},
2810 #endif
2811                 {"mdt-index",   required_argument, 0, 'i'},
2812                 {"mode",        required_argument, 0, 'm'},
2813 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2814                 {"hash-type",   required_argument, 0, 't'},
2815                 {"mdt-hash",    required_argument, 0, 't'},
2816 #endif
2817                 {"mdt-hash",    required_argument, 0, 'H'},
2818 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2819                 {"default_stripe", no_argument, 0, 'D'},
2820 #endif
2821                 {"default",     no_argument, 0, 'D'},
2822                 {0, 0, 0, 0}
2823         };
2824
2825         while ((c = getopt_long(argc, argv, "c:dDi:H:m:t:", long_opts,
2826                                 NULL)) >= 0) {
2827                 switch (c) {
2828                 case 0:
2829                         /* Long options. */
2830                         break;
2831                 case 'c':
2832 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2833                         if (strcmp(argv[optind - 1], "--count") == 0)
2834                                 fprintf(stderr, "warning: '--count' deprecated"
2835                                         ", use '--mdt-count' instead\n");
2836 #endif
2837                         stripe_count_opt = optarg;
2838                         break;
2839                 case 'd':
2840                         delete = true;
2841                         default_stripe = true;
2842                         break;
2843                 case 'D':
2844                         default_stripe = true;
2845                         break;
2846                 case 'i':
2847 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2848                         if (strcmp(argv[optind - 1], "--index") == 0)
2849                                 fprintf(stderr, "warning: '--index' deprecated"
2850                                         ", use '--mdt-index' instead\n");
2851 #endif
2852                         stripe_offset_opt = optarg;
2853                         break;
2854                 case 'm':
2855                         mode_opt = optarg;
2856                         break;
2857 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2858                 case 't':
2859 #endif
2860                 case 'H':
2861 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2862                         if (strcmp(argv[optind - 1], "--hash-type") == 0)
2863                                 fprintf(stderr, "warning: '--hash-type' "
2864                                         "deprecated, use '--mdt-hash' "
2865                                         "instead\n");
2866 #endif
2867                         stripe_hash_opt = optarg;
2868                         break;
2869                 default:
2870                         fprintf(stderr, "error: %s: option '%s' "
2871                                         "unrecognized\n",
2872                                         argv[0], argv[optind - 1]);
2873                         return CMD_HELP;
2874                 }
2875         }
2876
2877         if (optind == argc) {
2878                 fprintf(stderr, "error: %s: missing dirname\n",
2879                         argv[0]);
2880                 return CMD_HELP;
2881         }
2882
2883         if (!delete && stripe_offset_opt == NULL && stripe_count_opt == NULL) {
2884                 fprintf(stderr, "error: %s: missing stripe offset and count.\n",
2885                         argv[0]);
2886                 return CMD_HELP;
2887         }
2888
2889         if (stripe_offset_opt != NULL) {
2890                 /* get the stripe offset */
2891                 stripe_offset = strtoul(stripe_offset_opt, &end, 0);
2892                 if (*end != '\0') {
2893                         fprintf(stderr, "error: %s: bad stripe offset '%s'\n",
2894                                 argv[0], stripe_offset_opt);
2895                         return CMD_HELP;
2896                 }
2897         }
2898
2899         if (delete) {
2900                 if (stripe_offset_opt != NULL || stripe_count_opt != NULL) {
2901                         fprintf(stderr, "error: %s: cannot specify -d with -s,"
2902                                 " or -i options.\n", argv[0]);
2903                         return CMD_HELP;
2904                 } else {
2905                         stripe_count = 0;
2906                 }
2907         }
2908
2909
2910         if (mode_opt != NULL) {
2911                 mode = strtoul(mode_opt, &end, 8);
2912                 if (*end != '\0') {
2913                         fprintf(stderr, "error: %s: bad mode '%s'\n",
2914                                 argv[0], mode_opt);
2915                         return CMD_HELP;
2916                 }
2917                 previous_mode = umask(0);
2918         }
2919
2920         if (stripe_hash_opt == NULL) {
2921                 hash_type = LMV_HASH_TYPE_FNV_1A_64;
2922         } else {
2923                 hash_type = check_hashtype(stripe_hash_opt);
2924                 if (hash_type == 0) {
2925                         fprintf(stderr,
2926                                 "error: %s: bad stripe hash type '%s'\n",
2927                                 argv[0], stripe_hash_opt);
2928                         return CMD_HELP;
2929                 }
2930         }
2931
2932         /* get the stripe count */
2933         if (stripe_count_opt != NULL) {
2934                 stripe_count = strtoul(stripe_count_opt, &end, 0);
2935                 if (*end != '\0') {
2936                         fprintf(stderr, "error: %s: bad stripe count '%s'\n",
2937                                 argv[0], stripe_count_opt);
2938                         return CMD_HELP;
2939                 }
2940         }
2941
2942         dname = argv[optind];
2943         do {
2944                 if (default_stripe) {
2945                         result = llapi_dir_set_default_lmv_stripe(dname,
2946                                                     stripe_offset, stripe_count,
2947                                                     hash_type, NULL);
2948                 } else {
2949                         result = llapi_dir_create_pool(dname, mode,
2950                                                        stripe_offset,
2951                                                        stripe_count, hash_type,
2952                                                        NULL);
2953                 }
2954
2955                 if (result) {
2956                         fprintf(stderr, "error: %s: create stripe dir '%s' "
2957                                 "failed\n", argv[0], dname);
2958                         break;
2959                 }
2960                 dname = argv[++optind];
2961         } while (dname != NULL);
2962
2963         if (mode_opt != NULL)
2964                 umask(previous_mode);
2965
2966         return result;
2967 }
2968
2969 /* functions */
2970 static int lfs_rmentry(int argc, char **argv)
2971 {
2972         char *dname;
2973         int   index;
2974         int   result = 0;
2975
2976         if (argc <= 1) {
2977                 fprintf(stderr, "error: %s: missing dirname\n",
2978                         argv[0]);
2979                 return CMD_HELP;
2980         }
2981
2982         index = 1;
2983         dname = argv[index];
2984         while (dname != NULL) {
2985                 result = llapi_direntry_remove(dname);
2986                 if (result) {
2987                         fprintf(stderr, "error: %s: remove dir entry '%s' "
2988                                 "failed\n", argv[0], dname);
2989                         break;
2990                 }
2991                 dname = argv[++index];
2992         }
2993         return result;
2994 }
2995
2996 static int lfs_mv(int argc, char **argv)
2997 {
2998         struct  find_param param = {
2999                 .fp_max_depth = -1,
3000                 .fp_mdt_index = -1,
3001         };
3002         char   *end;
3003         int     c;
3004         int     rc = 0;
3005         struct option long_opts[] = {
3006                 {"mdt-index", required_argument, 0, 'M'},
3007                 {"verbose",     no_argument,       0, 'v'},
3008                 {0, 0, 0, 0}
3009         };
3010
3011         while ((c = getopt_long(argc, argv, "M:v", long_opts, NULL)) != -1) {
3012                 switch (c) {
3013                 case 'M': {
3014                         param.fp_mdt_index = strtoul(optarg, &end, 0);
3015                         if (*end != '\0') {
3016                                 fprintf(stderr, "%s: invalid MDT index'%s'\n",
3017                                         argv[0], optarg);
3018                                 return CMD_HELP;
3019                         }
3020                         break;
3021                 }
3022                 case 'v': {
3023                         param.fp_verbose = VERBOSE_DETAIL;
3024                         break;
3025                 }
3026                 default:
3027                         fprintf(stderr, "error: %s: unrecognized option '%s'\n",
3028                                 argv[0], argv[optind - 1]);
3029                         return CMD_HELP;
3030                 }
3031         }
3032
3033         if (param.fp_mdt_index == -1) {
3034                 fprintf(stderr, "%s: MDT index must be specified\n", argv[0]);
3035                 return CMD_HELP;
3036         }
3037
3038         if (optind >= argc) {
3039                 fprintf(stderr, "%s: missing operand path\n", argv[0]);
3040                 return CMD_HELP;
3041         }
3042
3043         param.fp_migrate = 1;
3044         rc = llapi_migrate_mdt(argv[optind], &param);
3045         if (rc != 0)
3046                 fprintf(stderr, "%s: cannot migrate '%s' to MDT%04x: %s\n",
3047                         argv[0], argv[optind], param.fp_mdt_index,
3048                         strerror(-rc));
3049         return rc;
3050 }
3051
3052 static int lfs_osts(int argc, char **argv)
3053 {
3054         return lfs_tgts(argc, argv);
3055 }
3056
3057 static int lfs_mdts(int argc, char **argv)
3058 {
3059         return lfs_tgts(argc, argv);
3060 }
3061
3062 #define COOK(value)                                                     \
3063 ({                                                                      \
3064         int radix = 0;                                                  \
3065         while (value > 1024) {                                          \
3066                 value /= 1024;                                          \
3067                 radix++;                                                \
3068         }                                                               \
3069         radix;                                                          \
3070 })
3071 #define UUF     "%-20s"
3072 #define CSF     "%11s"
3073 #define CDF     "%11llu"
3074 #define HDF     "%8.1f%c"
3075 #define RSF     "%4s"
3076 #define RDF     "%3d%%"
3077
3078 enum mntdf_flags {
3079         MNTDF_INODES    = 0x0001,
3080         MNTDF_COOKED    = 0x0002,
3081         MNTDF_LAZY      = 0x0004,
3082         MNTDF_VERBOSE   = 0x0008,
3083 };
3084
3085 static int showdf(char *mntdir, struct obd_statfs *stat,
3086                   char *uuid, enum mntdf_flags flags,
3087                   char *type, int index, int rc)
3088 {
3089         long long avail, used, total;
3090         double ratio = 0;
3091         char *suffix = "KMGTPEZY";
3092         /* Note if we have >2^64 bytes/fs these buffers will need to be grown */
3093         char tbuf[3 * sizeof(__u64)];
3094         char ubuf[3 * sizeof(__u64)];
3095         char abuf[3 * sizeof(__u64)];
3096         char rbuf[3 * sizeof(__u64)];
3097
3098         if (!uuid || !stat)
3099                 return -EINVAL;
3100
3101         switch (rc) {
3102         case 0:
3103                 if (flags & MNTDF_INODES) {
3104                         avail = stat->os_ffree;
3105                         used = stat->os_files - stat->os_ffree;
3106                         total = stat->os_files;
3107                 } else {
3108                         int shift = flags & MNTDF_COOKED ? 0 : 10;
3109
3110                         avail = (stat->os_bavail * stat->os_bsize) >> shift;
3111                         used  = ((stat->os_blocks - stat->os_bfree) *
3112                                  stat->os_bsize) >> shift;
3113                         total = (stat->os_blocks * stat->os_bsize) >> shift;
3114                 }
3115
3116                 if ((used + avail) > 0)
3117                         ratio = (double)used / (double)(used + avail);
3118
3119                 if (flags & MNTDF_COOKED) {
3120                         int i;
3121                         double cook_val;
3122
3123                         cook_val = (double)total;
3124                         i = COOK(cook_val);
3125                         if (i > 0)
3126                                 snprintf(tbuf, sizeof(tbuf), HDF, cook_val,
3127                                          suffix[i - 1]);
3128                         else
3129                                 snprintf(tbuf, sizeof(tbuf), CDF, total);
3130
3131                         cook_val = (double)used;
3132                         i = COOK(cook_val);
3133                         if (i > 0)
3134                                 snprintf(ubuf, sizeof(ubuf), HDF, cook_val,
3135                                          suffix[i - 1]);
3136                         else
3137                                 snprintf(ubuf, sizeof(ubuf), CDF, used);
3138
3139                         cook_val = (double)avail;
3140                         i = COOK(cook_val);
3141                         if (i > 0)
3142                                 snprintf(abuf, sizeof(abuf), HDF, cook_val,
3143                                          suffix[i - 1]);
3144                         else
3145                                 snprintf(abuf, sizeof(abuf), CDF, avail);
3146                 } else {
3147                         snprintf(tbuf, sizeof(tbuf), CDF, total);
3148                         snprintf(ubuf, sizeof(tbuf), CDF, used);
3149                         snprintf(abuf, sizeof(tbuf), CDF, avail);
3150                 }
3151
3152                 sprintf(rbuf, RDF, (int)(ratio * 100 + 0.5));
3153                 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s",
3154                        uuid, tbuf, ubuf, abuf, rbuf, mntdir);
3155                 if (type)
3156                         printf("[%s:%d]", type, index);
3157
3158                 if (stat->os_state) {
3159                         /*
3160                          * Each character represents the matching
3161                          * OS_STATE_* bit.
3162                          */
3163                         const char state_names[] = "DRSI";
3164                         __u32      state;
3165                         __u32      i;
3166
3167                         printf(" ");
3168                         for (i = 0, state = stat->os_state;
3169                              state && i < sizeof(state_names); i++) {
3170                                 if (!(state & (1 << i)))
3171                                         continue;
3172                                 printf("%c", state_names[i]);
3173                                 state ^= 1 << i;
3174                         }
3175                 }
3176
3177                 printf("\n");
3178                 break;
3179         case -ENODATA:
3180                 printf(UUF": inactive device\n", uuid);
3181                 break;
3182         default:
3183                 printf(UUF": %s\n", uuid, strerror(-rc));
3184                 break;
3185         }
3186
3187         return 0;
3188 }
3189
3190 struct ll_stat_type {
3191         int   st_op;
3192         char *st_name;
3193 };
3194
3195 static int mntdf(char *mntdir, char *fsname, char *pool, enum mntdf_flags flags)
3196 {
3197         struct obd_statfs stat_buf, sum = { .os_bsize = 1 };
3198         struct obd_uuid uuid_buf;
3199         char *poolname = NULL;
3200         struct ll_stat_type types[] = { { LL_STATFS_LMV, "MDT" },
3201                                         { LL_STATFS_LOV, "OST" },
3202                                         { 0, NULL } };
3203         struct ll_stat_type *tp;
3204         __u64 ost_ffree = 0;
3205         __u32 index;
3206         __u32 type;
3207         int fd;
3208         int rc = 0;
3209         int rc2;
3210
3211         if (pool) {
3212                 poolname = strchr(pool, '.');
3213                 if (poolname != NULL) {
3214                         if (strncmp(fsname, pool, strlen(fsname))) {
3215                                 fprintf(stderr, "filesystem name incorrect\n");
3216                                 return -ENODEV;
3217                         }
3218                         poolname++;
3219                 } else
3220                         poolname = pool;
3221         }
3222
3223         fd = open(mntdir, O_RDONLY);
3224         if (fd < 0) {
3225                 rc = -errno;
3226                 fprintf(stderr, "%s: cannot open '%s': %s\n", progname, mntdir,
3227                         strerror(errno));
3228                 return rc;
3229         }
3230
3231         if (flags & MNTDF_INODES)
3232                 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
3233                        "UUID", "Inodes", "IUsed", "IFree",
3234                        "IUse%", "Mounted on");
3235         else
3236                 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
3237                        "UUID", flags & MNTDF_COOKED ? "bytes" : "1K-blocks",
3238                        "Used", "Available", "Use%", "Mounted on");
3239
3240         for (tp = types; tp->st_name != NULL; tp++) {
3241                 for (index = 0; ; index++) {
3242                         memset(&stat_buf, 0, sizeof(struct obd_statfs));
3243                         memset(&uuid_buf, 0, sizeof(struct obd_uuid));
3244                         type = flags & MNTDF_LAZY ?
3245                                 tp->st_op | LL_STATFS_NODELAY : tp->st_op;
3246                         rc2 = llapi_obd_fstatfs(fd, type, index,
3247                                                &stat_buf, &uuid_buf);
3248                         if (rc2 == -ENODEV)
3249                                 break;
3250                         if (rc2 == -EAGAIN)
3251                                 continue;
3252                         if (rc2 == -ENODATA) { /* Inactive device, OK. */
3253                                 if (!(flags & MNTDF_VERBOSE))
3254                                         continue;
3255                         } else if (rc2 < 0 && rc == 0) {
3256                                 rc = rc2;
3257                         }
3258
3259                         if (poolname && tp->st_op == LL_STATFS_LOV &&
3260                             llapi_search_ost(fsname, poolname,
3261                                              obd_uuid2str(&uuid_buf)) != 1)
3262                                 continue;
3263
3264                         /* the llapi_obd_statfs() call may have returned with
3265                          * an error, but if it filled in uuid_buf we will at
3266                          * lease use that to print out a message for that OBD.
3267                          * If we didn't get anything in the uuid_buf, then fill
3268                          * it in so that we can print an error message. */
3269                         if (uuid_buf.uuid[0] == '\0')
3270                                 snprintf(uuid_buf.uuid, sizeof(uuid_buf.uuid),
3271                                          "%s%04x", tp->st_name, index);
3272                         showdf(mntdir, &stat_buf, obd_uuid2str(&uuid_buf),
3273                                flags, tp->st_name, index, rc2);
3274
3275                         if (rc2 == 0) {
3276                                 if (tp->st_op == LL_STATFS_LMV) {
3277                                         sum.os_ffree += stat_buf.os_ffree;
3278                                         sum.os_files += stat_buf.os_files;
3279                                 } else /* if (tp->st_op == LL_STATFS_LOV) */ {
3280                                         sum.os_blocks += stat_buf.os_blocks *
3281                                                 stat_buf.os_bsize;
3282                                         sum.os_bfree  += stat_buf.os_bfree *
3283                                                 stat_buf.os_bsize;
3284                                         sum.os_bavail += stat_buf.os_bavail *
3285                                                 stat_buf.os_bsize;
3286                                         ost_ffree += stat_buf.os_ffree;
3287                                 }
3288                         }
3289                 }
3290         }
3291
3292         close(fd);
3293
3294         /* If we don't have as many objects free on the OST as inodes
3295          * on the MDS, we reduce the total number of inodes to
3296          * compensate, so that the "inodes in use" number is correct.
3297          * Matches ll_statfs_internal() so the results are consistent. */
3298         if (ost_ffree < sum.os_ffree) {
3299                 sum.os_files = (sum.os_files - sum.os_ffree) + ost_ffree;
3300                 sum.os_ffree = ost_ffree;
3301         }
3302         printf("\n");
3303         showdf(mntdir, &sum, "filesystem_summary:", flags, NULL, 0, 0);
3304         printf("\n");
3305
3306         return rc;
3307 }
3308
3309 static int lfs_df(int argc, char **argv)
3310 {
3311         char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
3312         enum mntdf_flags flags = 0;
3313         int c, rc = 0, index = 0;
3314         char fsname[PATH_MAX] = "", *pool_name = NULL;
3315         struct option long_opts[] = {
3316                 {"human-readable", 0, 0, 'h'},
3317                 {"inodes", 0, 0, 'i'},
3318                 {"lazy", 0, 0, 'l'},
3319                 {"pool", required_argument, 0, 'p'},
3320                 {"verbose", 0, 0, 'v'},
3321                 {0, 0, 0, 0}
3322         };
3323
3324         while ((c = getopt_long(argc, argv, "hilp:v", long_opts, NULL)) != -1) {
3325                 switch (c) {
3326                 case 'h':
3327                         flags |= MNTDF_COOKED;
3328                         break;
3329                 case 'i':
3330                         flags |= MNTDF_INODES;
3331                         break;
3332                 case 'l':
3333                         flags |= MNTDF_LAZY;
3334                         break;
3335                 case 'p':
3336                         pool_name = optarg;
3337                         break;
3338                 case 'v':
3339                         flags |= MNTDF_VERBOSE;
3340                         break;
3341                 default:
3342                         return CMD_HELP;
3343                 }
3344         }
3345         if (optind < argc && !realpath(argv[optind], path)) {
3346                 rc = -errno;
3347                 fprintf(stderr, "error: invalid path '%s': %s\n",
3348                         argv[optind], strerror(-rc));
3349                 return rc;
3350         }
3351
3352         while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
3353                 /* Check if we have a mount point */
3354                 if (mntdir[0] == '\0')
3355                         continue;
3356
3357                 rc = mntdf(mntdir, fsname, pool_name, flags);
3358                 if (rc || path[0] != '\0')
3359                         break;
3360                 fsname[0] = '\0'; /* avoid matching in next loop */
3361                 mntdir[0] = '\0'; /* avoid matching in next loop */
3362         }
3363
3364         return rc;
3365 }
3366
3367 static int lfs_getname(int argc, char **argv)
3368 {
3369         char mntdir[PATH_MAX] = "", path[PATH_MAX] = "", fsname[PATH_MAX] = "";
3370         int rc = 0, index = 0, c;
3371         char buf[sizeof(struct obd_uuid)];
3372
3373         while ((c = getopt(argc, argv, "h")) != -1)
3374                 return CMD_HELP;
3375
3376         if (optind == argc) { /* no paths specified, get all paths. */
3377                 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
3378                         rc = llapi_getname(mntdir, buf, sizeof(buf));
3379                         if (rc < 0) {
3380                                 fprintf(stderr,
3381                                         "cannot get name for `%s': %s\n",
3382                                         mntdir, strerror(-rc));
3383                                 break;
3384                         }
3385
3386                         printf("%s %s\n", buf, mntdir);
3387
3388                         path[0] = fsname[0] = mntdir[0] = 0;
3389                 }
3390         } else { /* paths specified, only attempt to search these. */
3391                 for (; optind < argc; optind++) {
3392                         rc = llapi_getname(argv[optind], buf, sizeof(buf));
3393                         if (rc < 0) {
3394                                 fprintf(stderr,
3395                                         "cannot get name for `%s': %s\n",
3396                                         argv[optind], strerror(-rc));
3397                                 break;
3398                         }
3399
3400                         printf("%s %s\n", buf, argv[optind]);
3401                 }
3402         }
3403         return rc;
3404 }
3405
3406 static int lfs_check(int argc, char **argv)
3407 {
3408         int rc;
3409         char mntdir[PATH_MAX] = {'\0'};
3410         int num_types = 1;
3411         char *obd_types[2];
3412         char obd_type1[4];
3413         char obd_type2[4];
3414
3415         if (argc != 2)
3416                 return CMD_HELP;
3417
3418         obd_types[0] = obd_type1;
3419         obd_types[1] = obd_type2;
3420
3421         if (strcmp(argv[1], "osts") == 0) {
3422                 strcpy(obd_types[0], "osc");
3423         } else if (strcmp(argv[1], "mds") == 0) {
3424                 strcpy(obd_types[0], "mdc");
3425         } else if (strcmp(argv[1], "servers") == 0) {
3426                 num_types = 2;
3427                 strcpy(obd_types[0], "osc");
3428                 strcpy(obd_types[1], "mdc");
3429         } else {
3430                 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
3431                                 argv[0], argv[1]);
3432                         return CMD_HELP;
3433         }
3434
3435         rc = llapi_search_mounts(NULL, 0, mntdir, NULL);
3436         if (rc < 0 || mntdir[0] == '\0') {
3437                 fprintf(stderr, "No suitable Lustre mount found\n");
3438                 return rc;
3439         }
3440
3441         rc = llapi_target_check(num_types, obd_types, mntdir);
3442         if (rc)
3443                 fprintf(stderr, "error: %s: %s status failed\n",
3444                                 argv[0],argv[1]);
3445
3446         return rc;
3447
3448 }
3449
3450 #ifdef HAVE_SYS_QUOTA_H
3451 #define ARG2INT(nr, str, msg)                                           \
3452 do {                                                                    \
3453         char *endp;                                                     \
3454         nr = strtol(str, &endp, 0);                                     \
3455         if (*endp) {                                                    \
3456                 fprintf(stderr, "error: bad %s: %s\n", msg, str);       \
3457                 return CMD_HELP;                                        \
3458         }                                                               \
3459 } while (0)
3460
3461 #define ADD_OVERFLOW(a,b) ((a + b) < a) ? (a = ULONG_MAX) : (a = a + b)
3462
3463 /* Convert format time string "XXwXXdXXhXXmXXs" into seconds value
3464  * returns the value or ULONG_MAX on integer overflow or incorrect format
3465  * Notes:
3466  *        1. the order of specifiers is arbitrary (may be: 5w3s or 3s5w)
3467  *        2. specifiers may be encountered multiple times (2s3s is 5 seconds)
3468  *        3. empty integer value is interpreted as 0
3469  */
3470 static unsigned long str2sec(const char* timestr)
3471 {
3472         const char spec[] = "smhdw";
3473         const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
3474         unsigned long val = 0;
3475         char *tail;
3476
3477         if (strpbrk(timestr, spec) == NULL) {
3478                 /* no specifiers inside the time string,
3479                    should treat it as an integer value */
3480                 val = strtoul(timestr, &tail, 10);
3481                 return *tail ? ULONG_MAX : val;
3482         }
3483
3484         /* format string is XXwXXdXXhXXmXXs */
3485         while (*timestr) {
3486                 unsigned long v;
3487                 int ind;
3488                 char* ptr;
3489
3490                 v = strtoul(timestr, &tail, 10);
3491                 if (v == ULONG_MAX || *tail == '\0')
3492                         /* value too large (ULONG_MAX or more)
3493                            or missing specifier */
3494                         goto error;
3495
3496                 ptr = strchr(spec, *tail);
3497                 if (ptr == NULL)
3498                         /* unknown specifier */
3499                         goto error;
3500
3501                 ind = ptr - spec;
3502
3503                 /* check if product will overflow the type */
3504                 if (!(v < ULONG_MAX / mult[ind]))
3505                         goto error;
3506
3507                 ADD_OVERFLOW(val, mult[ind] * v);
3508                 if (val == ULONG_MAX)
3509                         goto error;
3510
3511                 timestr = tail + 1;
3512         }
3513
3514         return val;
3515
3516 error:
3517         return ULONG_MAX;
3518 }
3519
3520 #define ARG2ULL(nr, str, def_units)                                     \
3521 do {                                                                    \
3522         unsigned long long limit, units = def_units;                    \
3523         int rc;                                                         \
3524                                                                         \
3525         rc = llapi_parse_size(str, &limit, &units, 1);                  \
3526         if (rc < 0) {                                                   \
3527                 fprintf(stderr, "error: bad limit value %s\n", str);    \
3528                 return CMD_HELP;                                        \
3529         }                                                               \
3530         nr = limit;                                                     \
3531 } while (0)
3532
3533 static inline int has_times_option(int argc, char **argv)
3534 {
3535         int i;
3536
3537         for (i = 1; i < argc; i++)
3538                 if (!strcmp(argv[i], "-t"))
3539                         return 1;
3540
3541         return 0;
3542 }
3543
3544 int lfs_setquota_times(int argc, char **argv)
3545 {
3546         int c, rc;
3547         struct if_quotactl qctl;
3548         char *mnt, *obd_type = (char *)qctl.obd_type;
3549         struct obd_dqblk *dqb = &qctl.qc_dqblk;
3550         struct obd_dqinfo *dqi = &qctl.qc_dqinfo;
3551         struct option long_opts[] = {
3552                 {"block-grace",     required_argument, 0, 'b'},
3553                 {"group",           no_argument,       0, 'g'},
3554                 {"inode-grace",     required_argument, 0, 'i'},
3555                 {"projid",          no_argument,       0, 'p'},
3556                 {"times",           no_argument,       0, 't'},
3557                 {"user",            no_argument,       0, 'u'},
3558                 {0, 0, 0, 0}
3559         };
3560         int qtype;
3561
3562         memset(&qctl, 0, sizeof(qctl));
3563         qctl.qc_cmd  = LUSTRE_Q_SETINFO;
3564         qctl.qc_type = ALLQUOTA;
3565
3566         while ((c = getopt_long(argc, argv, "b:gi:ptu",
3567                                 long_opts, NULL)) != -1) {
3568                 switch (c) {
3569                 case 'u':
3570                         qtype = USRQUOTA;
3571                         goto quota_type;
3572                 case 'g':
3573                         qtype = GRPQUOTA;
3574                         goto quota_type;
3575                 case 'p':
3576                         qtype = PRJQUOTA;
3577 quota_type:
3578                         if (qctl.qc_type != ALLQUOTA) {
3579                                 fprintf(stderr, "error: -u/g/p can't be used "
3580                                                 "more than once\n");
3581                                 return CMD_HELP;
3582                         }
3583                         qctl.qc_type = qtype;
3584                         break;
3585                 case 'b':
3586                         if ((dqi->dqi_bgrace = str2sec(optarg)) == ULONG_MAX) {
3587                                 fprintf(stderr, "error: bad block-grace: %s\n",
3588                                         optarg);
3589                                 return CMD_HELP;
3590                         }
3591                         dqb->dqb_valid |= QIF_BTIME;
3592                         break;
3593                 case 'i':
3594                         if ((dqi->dqi_igrace = str2sec(optarg)) == ULONG_MAX) {
3595                                 fprintf(stderr, "error: bad inode-grace: %s\n",
3596                                         optarg);
3597                                 return CMD_HELP;
3598                         }
3599                         dqb->dqb_valid |= QIF_ITIME;
3600                         break;
3601                 case 't': /* Yes, of course! */
3602                         break;
3603                 default: /* getopt prints error message for us when opterr != 0 */
3604                         return CMD_HELP;
3605                 }
3606         }
3607
3608         if (qctl.qc_type == ALLQUOTA) {
3609                 fprintf(stderr, "error: neither -u, -g nor -p specified\n");
3610                 return CMD_HELP;
3611         }
3612
3613         if (optind != argc - 1) {
3614                 fprintf(stderr, "error: unexpected parameters encountered\n");
3615                 return CMD_HELP;
3616         }
3617
3618         mnt = argv[optind];
3619         rc = llapi_quotactl(mnt, &qctl);
3620         if (rc) {
3621                 if (*obd_type)
3622                         fprintf(stderr, "%s %s ", obd_type,
3623                                 obd_uuid2str(&qctl.obd_uuid));
3624                 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
3625                 return rc;
3626         }
3627
3628         return 0;
3629 }
3630
3631 #define BSLIMIT (1 << 0)
3632 #define BHLIMIT (1 << 1)
3633 #define ISLIMIT (1 << 2)
3634 #define IHLIMIT (1 << 3)
3635
3636 int lfs_setquota(int argc, char **argv)
3637 {
3638         int c, rc;
3639         struct if_quotactl qctl;
3640         char *mnt, *obd_type = (char *)qctl.obd_type;
3641         struct obd_dqblk *dqb = &qctl.qc_dqblk;
3642         struct option long_opts[] = {
3643                 {"block-softlimit", required_argument, 0, 'b'},
3644                 {"block-hardlimit", required_argument, 0, 'B'},
3645                 {"group",           required_argument, 0, 'g'},
3646                 {"inode-softlimit", required_argument, 0, 'i'},
3647                 {"inode-hardlimit", required_argument, 0, 'I'},
3648                 {"user",            required_argument, 0, 'u'},
3649                 {"projid",         required_argument, 0, 'p'},
3650                 {0, 0, 0, 0}
3651         };
3652         unsigned limit_mask = 0;
3653         char *endptr;
3654         int qtype;
3655
3656         if (has_times_option(argc, argv))
3657                 return lfs_setquota_times(argc, argv);
3658
3659         memset(&qctl, 0, sizeof(qctl));
3660         qctl.qc_cmd  = LUSTRE_Q_SETQUOTA;
3661         qctl.qc_type = ALLQUOTA; /* ALLQUOTA makes no sense for setquota,
3662                                   * so it can be used as a marker that qc_type
3663                                   * isn't reinitialized from command line */
3664
3665         while ((c = getopt_long(argc, argv, "b:B:g:i:I:p:u:",
3666                 long_opts, NULL)) != -1) {
3667                 switch (c) {
3668                 case 'u':
3669                         qtype = USRQUOTA;
3670                         rc = name2uid(&qctl.qc_id, optarg);
3671                         goto quota_type;
3672                 case 'g':
3673                         qtype = GRPQUOTA;
3674                         rc = name2gid(&qctl.qc_id, optarg);
3675                         goto quota_type;
3676                 case 'p':
3677                         qtype = PRJQUOTA;
3678                         rc = name2projid(&qctl.qc_id, optarg);
3679 quota_type:
3680                         if (qctl.qc_type != ALLQUOTA) {
3681                                 fprintf(stderr, "error: -u and -g can't be used"
3682                                                 " more than once\n");
3683                                 return CMD_HELP;
3684                         }
3685                         qctl.qc_type = qtype;
3686                         if (rc) {
3687                                 qctl.qc_id = strtoul(optarg, &endptr, 10);
3688                                 if (*endptr != '\0') {
3689                                         fprintf(stderr, "error: can't find id "
3690                                                 "for name %s\n", optarg);
3691                                         return CMD_HELP;
3692                                 }
3693                         }
3694                         break;
3695                 case 'b':
3696                         ARG2ULL(dqb->dqb_bsoftlimit, optarg, 1024);
3697                         dqb->dqb_bsoftlimit >>= 10;
3698                         limit_mask |= BSLIMIT;
3699                         if (dqb->dqb_bsoftlimit &&
3700                             dqb->dqb_bsoftlimit <= 1024) /* <= 1M? */
3701                                 fprintf(stderr, "warning: block softlimit is "
3702                                         "smaller than the miminal qunit size, "
3703                                         "please see the help of setquota or "
3704                                         "Lustre manual for details.\n");
3705                         break;
3706                 case 'B':
3707                         ARG2ULL(dqb->dqb_bhardlimit, optarg, 1024);
3708                         dqb->dqb_bhardlimit >>= 10;
3709                         limit_mask |= BHLIMIT;
3710                         if (dqb->dqb_bhardlimit &&
3711                             dqb->dqb_bhardlimit <= 1024) /* <= 1M? */
3712                                 fprintf(stderr, "warning: block hardlimit is "
3713                                         "smaller than the miminal qunit size, "
3714                                         "please see the help of setquota or "
3715                                         "Lustre manual for details.\n");
3716                         break;
3717                 case 'i':
3718                         ARG2ULL(dqb->dqb_isoftlimit, optarg, 1);
3719                         limit_mask |= ISLIMIT;
3720                         if (dqb->dqb_isoftlimit &&
3721                             dqb->dqb_isoftlimit <= 1024) /* <= 1K inodes? */
3722                                 fprintf(stderr, "warning: inode softlimit is "
3723                                         "smaller than the miminal qunit size, "
3724                                         "please see the help of setquota or "
3725                                         "Lustre manual for details.\n");
3726                         break;
3727                 case 'I':
3728                         ARG2ULL(dqb->dqb_ihardlimit, optarg, 1);
3729                         limit_mask |= IHLIMIT;
3730                         if (dqb->dqb_ihardlimit &&
3731                             dqb->dqb_ihardlimit <= 1024) /* <= 1K inodes? */
3732                                 fprintf(stderr, "warning: inode hardlimit is "
3733                                         "smaller than the miminal qunit size, "
3734                                         "please see the help of setquota or "
3735                                         "Lustre manual for details.\n");
3736                         break;
3737                 default: /* getopt prints error message for us when opterr != 0 */
3738                         return CMD_HELP;
3739                 }
3740         }
3741
3742         if (qctl.qc_type == ALLQUOTA) {
3743                 fprintf(stderr, "error: neither -u, -g nor -p was specified\n");
3744                 return CMD_HELP;
3745         }
3746
3747         if (limit_mask == 0) {
3748                 fprintf(stderr, "error: at least one limit must be specified\n");
3749                 return CMD_HELP;
3750         }
3751
3752         if (optind != argc - 1) {
3753                 fprintf(stderr, "error: unexpected parameters encountered\n");
3754                 return CMD_HELP;
3755         }
3756
3757         mnt = argv[optind];
3758
3759         if ((!(limit_mask & BHLIMIT) ^ !(limit_mask & BSLIMIT)) ||
3760             (!(limit_mask & IHLIMIT) ^ !(limit_mask & ISLIMIT))) {
3761                 /* sigh, we can't just set blimits/ilimits */
3762                 struct if_quotactl tmp_qctl = {.qc_cmd  = LUSTRE_Q_GETQUOTA,
3763                                                .qc_type = qctl.qc_type,
3764                                                .qc_id   = qctl.qc_id};
3765
3766                 rc = llapi_quotactl(mnt, &tmp_qctl);
3767                 if (rc < 0) {
3768                         fprintf(stderr, "error: setquota failed while retrieving"
3769                                         " current quota settings (%s)\n",
3770                                         strerror(-rc));
3771                         return rc;
3772                 }
3773
3774                 if (!(limit_mask & BHLIMIT))
3775                         dqb->dqb_bhardlimit = tmp_qctl.qc_dqblk.dqb_bhardlimit;
3776                 if (!(limit_mask & BSLIMIT))
3777                         dqb->dqb_bsoftlimit = tmp_qctl.qc_dqblk.dqb_bsoftlimit;
3778                 if (!(limit_mask & IHLIMIT))
3779                         dqb->dqb_ihardlimit = tmp_qctl.qc_dqblk.dqb_ihardlimit;
3780                 if (!(limit_mask & ISLIMIT))
3781                         dqb->dqb_isoftlimit = tmp_qctl.qc_dqblk.dqb_isoftlimit;
3782
3783                 /* Keep grace times if we have got no softlimit arguments */
3784                 if ((limit_mask & BHLIMIT) && !(limit_mask & BSLIMIT)) {
3785                         dqb->dqb_valid |= QIF_BTIME;
3786                         dqb->dqb_btime = tmp_qctl.qc_dqblk.dqb_btime;
3787                 }
3788
3789                 if ((limit_mask & IHLIMIT) && !(limit_mask & ISLIMIT)) {
3790                         dqb->dqb_valid |= QIF_ITIME;
3791                         dqb->dqb_itime = tmp_qctl.qc_dqblk.dqb_itime;
3792                 }
3793         }
3794
3795         dqb->dqb_valid |= (limit_mask & (BHLIMIT | BSLIMIT)) ? QIF_BLIMITS : 0;
3796         dqb->dqb_valid |= (limit_mask & (IHLIMIT | ISLIMIT)) ? QIF_ILIMITS : 0;
3797
3798         rc = llapi_quotactl(mnt, &qctl);
3799         if (rc) {
3800                 if (*obd_type)
3801                         fprintf(stderr, "%s %s ", obd_type,
3802                                 obd_uuid2str(&qctl.obd_uuid));
3803                 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
3804                 return rc;
3805         }
3806
3807         return 0;
3808 }
3809
3810 /* Converts seconds value into format string
3811  * result is returned in buf
3812  * Notes:
3813  *        1. result is in descenting order: 1w2d3h4m5s
3814  *        2. zero fields are not filled (except for p. 3): 5d1s
3815  *        3. zero seconds value is presented as "0s"
3816  */
3817 static char * __sec2str(time_t seconds, char *buf)
3818 {
3819         const char spec[] = "smhdw";
3820         const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
3821         unsigned long c;
3822         char *tail = buf;
3823         int i;
3824
3825         for (i = sizeof(mult) / sizeof(mult[0]) - 1 ; i >= 0; i--) {
3826                 c = seconds / mult[i];
3827
3828                 if (c > 0 || (i == 0 && buf == tail))
3829                         tail += snprintf(tail, 40-(tail-buf), "%lu%c", c, spec[i]);
3830
3831                 seconds %= mult[i];
3832         }
3833
3834         return tail;
3835 }
3836
3837 static void sec2str(time_t seconds, char *buf, int rc)
3838 {
3839         char *tail = buf;
3840
3841         if (rc)
3842                 *tail++ = '[';
3843
3844         tail = __sec2str(seconds, tail);
3845
3846         if (rc && tail - buf < 39) {
3847                 *tail++ = ']';
3848                 *tail++ = 0;
3849         }
3850 }
3851
3852 static void diff2str(time_t seconds, char *buf, time_t now)
3853 {
3854
3855         buf[0] = 0;
3856         if (!seconds)
3857                 return;
3858         if (seconds <= now) {
3859                 strcpy(buf, "none");
3860                 return;
3861         }
3862         __sec2str(seconds - now, buf);
3863 }
3864
3865 static void print_quota_title(char *name, struct if_quotactl *qctl,
3866                               bool human_readable)
3867 {
3868         printf("Disk quotas for %s %s (%cid %u):\n",
3869                qtype_name(qctl->qc_type), name,
3870                *qtype_name(qctl->qc_type), qctl->qc_id);
3871         printf("%15s%8s %7s%8s%8s%8s %7s%8s%8s\n",
3872                "Filesystem", human_readable ? "used" : "kbytes",
3873                "quota", "limit", "grace",
3874                "files", "quota", "limit", "grace");
3875 }
3876
3877 static void kbytes2str(__u64 num, char *buf, int buflen, bool h)
3878 {
3879         if (!h) {
3880                 snprintf(buf, buflen, "%ju", (uintmax_t)num);
3881         } else {
3882                 if (num >> 40)
3883                         snprintf(buf, buflen, "%5.4gP",
3884                                  (double)num / ((__u64)1 << 40));
3885                 else if (num >> 30)
3886                         snprintf(buf, buflen, "%5.4gT",
3887                                  (double)num / (1 << 30));
3888                 else if (num >> 20)
3889                         snprintf(buf, buflen, "%5.4gG",
3890                                  (double)num / (1 << 20));
3891                 else if (num >> 10)
3892                         snprintf(buf, buflen, "%5.4gM",
3893                                  (double)num / (1 << 10));
3894                 else
3895                         snprintf(buf, buflen, "%ju%s", (uintmax_t)num, "k");
3896         }
3897 }
3898
3899 #define STRBUF_LEN      32
3900 static void print_quota(char *mnt, struct if_quotactl *qctl, int type,
3901                         int rc, bool h)
3902 {
3903         time_t now;
3904
3905         time(&now);
3906
3907         if (qctl->qc_cmd == LUSTRE_Q_GETQUOTA || qctl->qc_cmd == Q_GETOQUOTA) {
3908                 int bover = 0, iover = 0;
3909                 struct obd_dqblk *dqb = &qctl->qc_dqblk;
3910                 char numbuf[3][STRBUF_LEN];
3911                 char timebuf[40];
3912                 char strbuf[STRBUF_LEN];
3913
3914                 if (dqb->dqb_bhardlimit &&
3915                     lustre_stoqb(dqb->dqb_curspace) >= dqb->dqb_bhardlimit) {
3916                         bover = 1;
3917                 } else if (dqb->dqb_bsoftlimit && dqb->dqb_btime) {
3918                         if (dqb->dqb_btime > now) {
3919                                 bover = 2;
3920                         } else {
3921                                 bover = 3;
3922                         }
3923                 }
3924
3925                 if (dqb->dqb_ihardlimit &&
3926                     dqb->dqb_curinodes >= dqb->dqb_ihardlimit) {
3927                         iover = 1;
3928                 } else if (dqb->dqb_isoftlimit && dqb->dqb_itime) {
3929                         if (dqb->dqb_itime > now) {
3930                                 iover = 2;
3931                         } else {
3932                                 iover = 3;
3933                         }
3934                 }
3935
3936
3937                 if (strlen(mnt) > 15)
3938                         printf("%s\n%15s", mnt, "");
3939                 else
3940                         printf("%15s", mnt);
3941
3942                 if (bover)
3943                         diff2str(dqb->dqb_btime, timebuf, now);
3944
3945                 kbytes2str(lustre_stoqb(dqb->dqb_curspace),
3946                            strbuf, sizeof(strbuf), h);
3947                 if (rc == -EREMOTEIO)
3948                         sprintf(numbuf[0], "%s*", strbuf);
3949                 else
3950                         sprintf(numbuf[0], (dqb->dqb_valid & QIF_SPACE) ?
3951                                 "%s" : "[%s]", strbuf);
3952
3953                 kbytes2str(dqb->dqb_bsoftlimit, strbuf, sizeof(strbuf), h);
3954                 if (type == QC_GENERAL)
3955                         sprintf(numbuf[1], (dqb->dqb_valid & QIF_BLIMITS) ?
3956                                 "%s" : "[%s]", strbuf);
3957                 else
3958                         sprintf(numbuf[1], "%s", "-");
3959
3960                 kbytes2str(dqb->dqb_bhardlimit, strbuf, sizeof(strbuf), h);
3961                 sprintf(numbuf[2], (dqb->dqb_valid & QIF_BLIMITS) ?
3962                         "%s" : "[%s]", strbuf);
3963
3964                 printf(" %7s%c %6s %7s %7s",
3965                        numbuf[0], bover ? '*' : ' ', numbuf[1],
3966                        numbuf[2], bover > 1 ? timebuf : "-");
3967
3968                 if (iover)
3969                         diff2str(dqb->dqb_itime, timebuf, now);
3970
3971                 sprintf(numbuf[0], (dqb->dqb_valid & QIF_INODES) ?
3972                         "%ju" : "[%ju]", (uintmax_t)dqb->dqb_curinodes);
3973
3974                 if (type == QC_GENERAL)
3975                         sprintf(numbuf[1], (dqb->dqb_valid & QIF_ILIMITS) ?
3976                                 "%ju" : "[%ju]",
3977                                 (uintmax_t)dqb->dqb_isoftlimit);
3978                 else
3979                         sprintf(numbuf[1], "%s", "-");
3980
3981                 sprintf(numbuf[2], (dqb->dqb_valid & QIF_ILIMITS) ?
3982                         "%ju" : "[%ju]", (uintmax_t)dqb->dqb_ihardlimit);
3983
3984                 if (type != QC_OSTIDX)
3985                         printf(" %7s%c %6s %7s %7s",
3986                                numbuf[0], iover ? '*' : ' ', numbuf[1],
3987                                numbuf[2], iover > 1 ? timebuf : "-");
3988                 else
3989                         printf(" %7s %7s %7s %7s", "-", "-", "-", "-");
3990                 printf("\n");
3991
3992         } else if (qctl->qc_cmd == LUSTRE_Q_GETINFO ||
3993                    qctl->qc_cmd == Q_GETOINFO) {
3994                 char bgtimebuf[40];
3995                 char igtimebuf[40];
3996
3997                 sec2str(qctl->qc_dqinfo.dqi_bgrace, bgtimebuf, rc);
3998                 sec2str(qctl->qc_dqinfo.dqi_igrace, igtimebuf, rc);
3999                 printf("Block grace time: %s; Inode grace time: %s\n",
4000                        bgtimebuf, igtimebuf);
4001         }
4002 }
4003
4004 static int print_obd_quota(char *mnt, struct if_quotactl *qctl, int is_mdt,
4005                            bool h, __u64 *total)
4006 {
4007         int rc = 0, rc1 = 0, count = 0;
4008         __u32 valid = qctl->qc_valid;
4009
4010         rc = llapi_get_obd_count(mnt, &count, is_mdt);
4011         if (rc) {
4012                 fprintf(stderr, "can not get %s count: %s\n",
4013                         is_mdt ? "mdt": "ost", strerror(-rc));
4014                 return rc;
4015         }
4016
4017         for (qctl->qc_idx = 0; qctl->qc_idx < count; qctl->qc_idx++) {
4018                 qctl->qc_valid = is_mdt ? QC_MDTIDX : QC_OSTIDX;
4019                 rc = llapi_quotactl(mnt, qctl);
4020                 if (rc) {
4021                         /* It is remote client case. */
4022                         if (rc == -EOPNOTSUPP) {
4023                                 rc = 0;
4024                                 goto out;
4025                         }
4026
4027                         if (!rc1)
4028                                 rc1 = rc;
4029                         fprintf(stderr, "quotactl %s%d failed.\n",
4030                                 is_mdt ? "mdt": "ost", qctl->qc_idx);
4031                         continue;
4032                 }
4033
4034                 print_quota(obd_uuid2str(&qctl->obd_uuid), qctl,
4035                             qctl->qc_valid, 0, h);
4036                 *total += is_mdt ? qctl->qc_dqblk.dqb_ihardlimit :
4037                                    qctl->qc_dqblk.dqb_bhardlimit;
4038         }
4039 out:
4040         qctl->qc_valid = valid;
4041         return rc ? : rc1;
4042 }
4043
4044 static int lfs_quota(int argc, char **argv)
4045 {
4046         int c;
4047         char *mnt, *name = NULL;
4048         struct if_quotactl qctl = { .qc_cmd = LUSTRE_Q_GETQUOTA,
4049                                     .qc_type = ALLQUOTA };
4050         char *obd_type = (char *)qctl.obd_type;
4051         char *obd_uuid = (char *)qctl.obd_uuid.uuid;
4052         int rc = 0, rc1 = 0, rc2 = 0, rc3 = 0,
4053             verbose = 0, pass = 0, quiet = 0, inacc;
4054         char *endptr;
4055         __u32 valid = QC_GENERAL, idx = 0;
4056         __u64 total_ialloc = 0, total_balloc = 0;
4057         bool human_readable = false;
4058         int qtype;
4059
4060         while ((c = getopt(argc, argv, "gi:I:o:pqtuvh")) != -1) {
4061                 switch (c) {
4062                 case 'u':
4063                         qtype = USRQUOTA;
4064                         goto quota_type;
4065                 case 'g':
4066                         qtype = GRPQUOTA;
4067                         goto quota_type;
4068                 case 'p':
4069                         qtype = PRJQUOTA;
4070 quota_type:
4071                         if (qctl.qc_type != ALLQUOTA) {
4072                                 fprintf(stderr, "error: use either -u or -g\n");
4073                                 return CMD_HELP;
4074                         }
4075                         qctl.qc_type = qtype;
4076                         break;
4077                 case 't':
4078                         qctl.qc_cmd = LUSTRE_Q_GETINFO;
4079                         break;
4080                 case 'o':
4081                         valid = qctl.qc_valid = QC_UUID;
4082                         strlcpy(obd_uuid, optarg, sizeof(qctl.obd_uuid));
4083                         break;
4084                 case 'i':
4085                         valid = qctl.qc_valid = QC_MDTIDX;
4086                         idx = qctl.qc_idx = atoi(optarg);
4087                         break;
4088                 case 'I':
4089                         valid = qctl.qc_valid = QC_OSTIDX;
4090                         idx = qctl.qc_idx = atoi(optarg);
4091                         break;
4092                 case 'v':
4093                         verbose = 1;
4094                         break;
4095                 case 'q':
4096                         quiet = 1;
4097                         break;
4098                 case 'h':
4099                         human_readable = true;
4100                         break;
4101                 default:
4102                         fprintf(stderr, "error: %s: option '-%c' "
4103                                         "unrecognized\n", argv[0], c);
4104                         return CMD_HELP;
4105                 }
4106         }
4107
4108         /* current uid/gid info for "lfs quota /path/to/lustre/mount" */
4109         if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA && qctl.qc_type == ALLQUOTA &&
4110             optind == argc - 1) {
4111 all_output:
4112                 memset(&qctl, 0, sizeof(qctl)); /* spoiled by print_*_quota */
4113                 qctl.qc_cmd = LUSTRE_Q_GETQUOTA;
4114                 qctl.qc_valid = valid;
4115                 qctl.qc_idx = idx;
4116                 qctl.qc_type = pass;
4117                 switch (qctl.qc_type) {
4118                 case USRQUOTA:
4119                         qctl.qc_id = geteuid();
4120                         rc = uid2name(&name, qctl.qc_id);
4121                         break;
4122                 case GRPQUOTA:
4123                         qctl.qc_id = getegid();
4124                         rc = gid2name(&name, qctl.qc_id);
4125                         break;
4126                 default:
4127                         rc = -ENOTSUP;
4128                         break;
4129                 }
4130                 if (rc)
4131                         name = "<unknown>";
4132                 pass++;
4133         /* lfs quota -u username /path/to/lustre/mount */
4134         } else if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA) {
4135                 /* options should be followed by u/g-name and mntpoint */
4136                 if (optind + 2 != argc || qctl.qc_type == ALLQUOTA) {
4137                         fprintf(stderr, "error: missing quota argument(s)\n");
4138                         return CMD_HELP;
4139                 }
4140
4141                 name = argv[optind++];
4142                 switch (qctl.qc_type) {
4143                 case USRQUOTA:
4144                         rc = name2uid(&qctl.qc_id, name);
4145                         break;
4146                 case GRPQUOTA:
4147                         rc = name2gid(&qctl.qc_id, name);
4148                         break;
4149                 case PRJQUOTA:
4150                         rc = name2projid(&qctl.qc_id, name);
4151                         break;
4152                 default:
4153                         rc = -ENOTSUP;
4154                         break;
4155                 }
4156                 if (rc) {
4157                         qctl.qc_id = strtoul(name, &endptr, 10);
4158                         if (*endptr != '\0') {
4159                                 fprintf(stderr, "error: can't find id for name: %s\n",
4160                                                 name);
4161                                 return CMD_HELP;
4162                         }
4163                 }
4164         } else if (optind + 1 != argc || qctl.qc_type == ALLQUOTA) {
4165                 fprintf(stderr, "error: missing quota info argument(s)\n");
4166                 return CMD_HELP;
4167         }
4168
4169         mnt = argv[optind];
4170         rc1 = llapi_quotactl(mnt, &qctl);
4171         if (rc1 < 0) {
4172                 switch (rc1) {
4173                 case -ESRCH:
4174                         fprintf(stderr, "%s quotas are not enabled.\n",
4175                                 qtype_name(qctl.qc_type));
4176                         goto out;
4177                 case -EPERM:
4178                         fprintf(stderr, "Permission denied.\n");
4179                 case -ENODEV:
4180                 case -ENOENT:
4181                         /* We already got error message. */
4182                         goto out;
4183                 default:
4184                         fprintf(stderr, "Unexpected quotactl error: %s\n",
4185                                 strerror(-rc1));
4186                 }
4187         }
4188
4189         if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA && !quiet)
4190                 print_quota_title(name, &qctl, human_readable);
4191
4192         if (rc1 && *obd_type)
4193                 fprintf(stderr, "%s %s ", obd_type, obd_uuid);
4194
4195         if (qctl.qc_valid != QC_GENERAL)
4196                 mnt = "";
4197
4198         inacc = (qctl.qc_cmd == LUSTRE_Q_GETQUOTA) &&
4199                 ((qctl.qc_dqblk.dqb_valid & (QIF_LIMITS|QIF_USAGE)) !=
4200                  (QIF_LIMITS|QIF_USAGE));
4201
4202         print_quota(mnt, &qctl, QC_GENERAL, rc1, human_readable);
4203
4204         if (qctl.qc_valid == QC_GENERAL && qctl.qc_cmd != LUSTRE_Q_GETINFO &&
4205             verbose) {
4206                 char strbuf[STRBUF_LEN];
4207
4208                 rc2 = print_obd_quota(mnt, &qctl, 1, human_readable,
4209                                       &total_ialloc);
4210                 rc3 = print_obd_quota(mnt, &qctl, 0, human_readable,
4211                                       &total_balloc);
4212                 kbytes2str(total_balloc, strbuf, sizeof(strbuf),
4213                            human_readable);
4214                 printf("Total allocated inode limit: %ju, total "
4215                        "allocated block limit: %s\n", (uintmax_t)total_ialloc,
4216                        strbuf);
4217         }
4218
4219         if (rc1 || rc2 || rc3 || inacc)
4220                 printf("Some errors happened when getting quota info. "
4221                        "Some devices may be not working or deactivated. "
4222                        "The data in \"[]\" is inaccurate.\n");
4223
4224 out:
4225         if (pass > 0 && pass < LL_MAXQUOTAS)
4226                 goto all_output;
4227
4228         return rc1;
4229 }
4230 #endif /* HAVE_SYS_QUOTA_H! */
4231
4232 static int flushctx_ioctl(char *mp)
4233 {
4234         int fd, rc;
4235
4236         fd = open(mp, O_RDONLY);
4237         if (fd == -1) {
4238                 fprintf(stderr, "flushctx: error open %s: %s\n",
4239                         mp, strerror(errno));
4240                 return -1;
4241         }
4242
4243         rc = ioctl(fd, LL_IOC_FLUSHCTX);
4244         if (rc == -1)
4245                 fprintf(stderr, "flushctx: error ioctl %s: %s\n",
4246                         mp, strerror(errno));
4247
4248         close(fd);
4249         return rc;
4250 }
4251
4252 static int lfs_flushctx(int argc, char **argv)
4253 {
4254         int     kdestroy = 0, c;
4255         char    mntdir[PATH_MAX] = {'\0'};
4256         int     index = 0;
4257         int     rc = 0;
4258
4259         while ((c = getopt(argc, argv, "k")) != -1) {
4260                 switch (c) {
4261                 case 'k':
4262                         kdestroy = 1;
4263                         break;
4264                 default:
4265                         fprintf(stderr, "error: %s: option '-%c' "
4266                                         "unrecognized\n", argv[0], c);
4267                         return CMD_HELP;
4268                 }
4269         }
4270
4271         if (kdestroy) {
4272             if ((rc = system("kdestroy > /dev/null")) != 0) {
4273                 rc = WEXITSTATUS(rc);
4274                 fprintf(stderr, "error destroying tickets: %d, continuing\n", rc);
4275             }
4276         }
4277
4278         if (optind >= argc) {
4279                 /* flush for all mounted lustre fs. */
4280                 while (!llapi_search_mounts(NULL, index++, mntdir, NULL)) {
4281                         /* Check if we have a mount point */
4282                         if (mntdir[0] == '\0')
4283                                 continue;
4284
4285                         if (flushctx_ioctl(mntdir))
4286                                 rc = -1;
4287
4288                         mntdir[0] = '\0'; /* avoid matching in next loop */
4289                 }
4290         } else {
4291                 /* flush fs as specified */
4292                 while (optind < argc) {
4293                         if (flushctx_ioctl(argv[optind++]))
4294                                 rc = -1;
4295                 }
4296         }
4297         return rc;
4298 }
4299
4300 static int lfs_cp(int argc, char **argv)
4301 {
4302         fprintf(stderr, "remote client copy file(s).\n"
4303                 "obsolete, does not support it anymore.\n");
4304         return 0;
4305 }
4306
4307 static int lfs_ls(int argc, char **argv)
4308 {
4309         fprintf(stderr, "remote client lists directory contents.\n"
4310                 "obsolete, does not support it anymore.\n");
4311         return 0;
4312 }
4313
4314 static int lfs_changelog(int argc, char **argv)
4315 {
4316         void *changelog_priv;
4317         struct changelog_rec *rec;
4318         long long startrec = 0, endrec = 0;
4319         char *mdd;
4320         struct option long_opts[] = {
4321                 {"follow", no_argument, 0, 'f'},
4322                 {0, 0, 0, 0}
4323         };
4324         char short_opts[] = "f";
4325         int rc, follow = 0;
4326
4327         while ((rc = getopt_long(argc, argv, short_opts,
4328                                 long_opts, NULL)) != -1) {
4329                 switch (rc) {
4330                 case 'f':
4331                         follow++;
4332                         break;
4333                 case '?':
4334                         return CMD_HELP;
4335                 default:
4336                         fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4337                                 argv[0], argv[optind - 1]);
4338                         return CMD_HELP;
4339                 }
4340         }
4341         if (optind >= argc)
4342                 return CMD_HELP;
4343
4344         mdd = argv[optind++];
4345         if (argc > optind)
4346                 startrec = strtoll(argv[optind++], NULL, 10);
4347         if (argc > optind)
4348                 endrec = strtoll(argv[optind++], NULL, 10);
4349
4350         rc = llapi_changelog_start(&changelog_priv,
4351                                    CHANGELOG_FLAG_BLOCK |
4352                                    CHANGELOG_FLAG_JOBID |
4353                                    (follow ? CHANGELOG_FLAG_FOLLOW : 0),
4354                                    mdd, startrec);
4355         if (rc < 0) {
4356                 fprintf(stderr, "Can't start changelog: %s\n",
4357                         strerror(errno = -rc));
4358                 return rc;
4359         }
4360
4361         while ((rc = llapi_changelog_recv(changelog_priv, &rec)) == 0) {
4362                 time_t secs;
4363                 struct tm ts;
4364
4365                 if (endrec && rec->cr_index > endrec) {
4366                         llapi_changelog_free(&rec);
4367                         break;
4368                 }
4369                 if (rec->cr_index < startrec) {
4370                         llapi_changelog_free(&rec);
4371                         continue;
4372                 }
4373
4374                 secs = rec->cr_time >> 30;
4375                 gmtime_r(&secs, &ts);
4376                 printf("%ju %02d%-5s %02d:%02d:%02d.%09d %04d.%02d.%02d "
4377                        "0x%x t="DFID, (uintmax_t)rec->cr_index, rec->cr_type,
4378                        changelog_type2str(rec->cr_type),
4379                        ts.tm_hour, ts.tm_min, ts.tm_sec,
4380                        (int)(rec->cr_time & ((1 << 30) - 1)),
4381                        ts.tm_year + 1900, ts.tm_mon + 1, ts.tm_mday,
4382                        rec->cr_flags & CLF_FLAGMASK, PFID(&rec->cr_tfid));
4383
4384                 if (rec->cr_flags & CLF_JOBID) {
4385                         struct changelog_ext_jobid *jid =
4386                                 changelog_rec_jobid(rec);
4387
4388                         if (jid->cr_jobid[0] != '\0')
4389                                 printf(" j=%s", jid->cr_jobid);
4390                 }
4391
4392                 if (rec->cr_namelen)
4393                         printf(" p="DFID" %.*s", PFID(&rec->cr_pfid),
4394                                rec->cr_namelen, changelog_rec_name(rec));
4395
4396                 if (rec->cr_flags & CLF_RENAME) {
4397                         struct changelog_ext_rename *rnm =
4398                                 changelog_rec_rename(rec);
4399
4400                         if (!fid_is_zero(&rnm->cr_sfid))
4401                                 printf(" s="DFID" sp="DFID" %.*s",
4402                                        PFID(&rnm->cr_sfid),
4403                                        PFID(&rnm->cr_spfid),
4404                                        (int)changelog_rec_snamelen(rec),
4405                                        changelog_rec_sname(rec));
4406                 }
4407                 printf("\n");
4408
4409                 llapi_changelog_free(&rec);
4410         }
4411
4412         llapi_changelog_fini(&changelog_priv);
4413
4414         if (rc < 0)
4415                 fprintf(stderr, "Changelog: %s\n", strerror(errno = -rc));
4416
4417         return (rc == 1 ? 0 : rc);
4418 }
4419
4420 static int lfs_changelog_clear(int argc, char **argv)
4421 {
4422         long long endrec;
4423         int rc;
4424
4425         if (argc != 4)
4426                 return CMD_HELP;
4427
4428         endrec = strtoll(argv[3], NULL, 10);
4429
4430         rc = llapi_changelog_clear(argv[1], argv[2], endrec);
4431
4432         if (rc == -EINVAL)
4433                 fprintf(stderr, "%s: record out of range: %llu\n",
4434                         argv[0], endrec);
4435         else if (rc == -ENOENT)
4436                 fprintf(stderr, "%s: no changelog user: %s\n",
4437                         argv[0], argv[2]);
4438         else if (rc)
4439                 fprintf(stderr, "%s error: %s\n", argv[0],
4440                         strerror(-rc));
4441
4442         if (rc)
4443                 errno = -rc;
4444
4445         return rc;
4446 }
4447
4448 static int lfs_fid2path(int argc, char **argv)
4449 {
4450         struct option long_opts[] = {
4451                 {"cur", no_argument, 0, 'c'},
4452                 {"link", required_argument, 0, 'l'},
4453                 {"rec", required_argument, 0, 'r'},
4454                 {0, 0, 0, 0}
4455         };
4456         char  short_opts[] = "cl:r:";
4457         char *device, *fid, *path;
4458         long long recno = -1;
4459         int linkno = -1;
4460         int lnktmp;
4461         int printcur = 0;
4462         int rc = 0;
4463
4464         while ((rc = getopt_long(argc, argv, short_opts,
4465                                 long_opts, NULL)) != -1) {
4466                 switch (rc) {
4467                 case 'c':
4468                         printcur++;
4469                         break;
4470                 case 'l':
4471                         linkno = strtol(optarg, NULL, 10);
4472                         break;
4473                 case 'r':
4474                         recno = strtoll(optarg, NULL, 10);
4475                         break;
4476                 case '?':
4477                         return CMD_HELP;
4478                 default:
4479                         fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4480                                 argv[0], argv[optind - 1]);
4481                         return CMD_HELP;
4482                 }
4483         }
4484
4485         if (argc < 3)
4486                 return CMD_HELP;
4487
4488         device = argv[optind++];
4489         path = calloc(1, PATH_MAX);
4490         if (path == NULL) {
4491                 fprintf(stderr, "error: Not enough memory\n");
4492                 return -errno;
4493         }
4494
4495         rc = 0;
4496         while (optind < argc) {
4497                 fid = argv[optind++];
4498
4499                 lnktmp = (linkno >= 0) ? linkno : 0;
4500                 while (1) {
4501                         int oldtmp = lnktmp;
4502                         long long rectmp = recno;
4503                         int rc2;
4504                         rc2 = llapi_fid2path(device, fid, path, PATH_MAX,
4505                                              &rectmp, &lnktmp);
4506                         if (rc2 < 0) {
4507                                 fprintf(stderr, "%s: error on FID %s: %s\n",
4508                                         argv[0], fid, strerror(errno = -rc2));
4509                                 if (rc == 0)
4510                                         rc = rc2;
4511                                 break;
4512                         }
4513
4514                         if (printcur)
4515                                 fprintf(stdout, "%lld ", rectmp);
4516                         if (device[0] == '/') {
4517                                 fprintf(stdout, "%s", device);
4518                                 if (device[strlen(device) - 1] != '/')
4519                                         fprintf(stdout, "/");
4520                         } else if (path[0] == '\0') {
4521                                 fprintf(stdout, "/");
4522                         }
4523                         fprintf(stdout, "%s\n", path);
4524
4525                         if (linkno >= 0)
4526                                 /* specified linkno */
4527                                 break;
4528                         if (oldtmp == lnktmp)
4529                                 /* no more links */
4530                                 break;
4531                 }
4532         }
4533
4534         free(path);
4535         return rc;
4536 }
4537
4538 static int lfs_path2fid(int argc, char **argv)
4539 {
4540         struct option     long_opts[] = {
4541                 {"parents", no_argument, 0, 'p'},
4542                 {0, 0, 0, 0}
4543         };
4544         char            **path;
4545         const char        short_opts[] = "p";
4546         const char       *sep = "";
4547         lustre_fid        fid;
4548         int               rc = 0;
4549         bool              show_parents = false;
4550
4551         while ((rc = getopt_long(argc, argv, short_opts,
4552                                  long_opts, NULL)) != -1) {
4553                 switch (rc) {
4554                 case 'p':
4555                         show_parents = true;
4556                         break;
4557                 default:
4558                         fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4559                                 argv[0], argv[optind - 1]);
4560                         return CMD_HELP;
4561                 }
4562         }
4563
4564         if (optind > argc - 1)
4565                 return CMD_HELP;
4566         else if (optind < argc - 1)
4567                 sep = ": ";
4568
4569         rc = 0;
4570         for (path = argv + optind; *path != NULL; path++) {
4571                 int err = 0;
4572                 if (!show_parents) {
4573                         err = llapi_path2fid(*path, &fid);
4574                         if (!err)
4575                                 printf("%s%s"DFID"\n",
4576                                        *sep != '\0' ? *path : "", sep,
4577                                        PFID(&fid));
4578                 } else {
4579                         char            name[NAME_MAX + 1];
4580                         unsigned int    linkno = 0;
4581
4582                         while ((err = llapi_path2parent(*path, linkno, &fid,
4583                                                 name, sizeof(name))) == 0) {
4584                                 if (*sep != '\0' && linkno == 0)
4585                                         printf("%s%s", *path, sep);
4586
4587                                 printf("%s"DFID"/%s", linkno != 0 ? "\t" : "",
4588                                        PFID(&fid), name);
4589                                 linkno++;
4590                         }
4591
4592                         /* err == -ENODATA is end-of-loop */
4593                         if (linkno > 0 && err == -ENODATA) {
4594                                 printf("\n");
4595                                 err = 0;
4596                         }
4597                 }
4598
4599                 if (err) {
4600                         fprintf(stderr, "%s: can't get %sfid for %s: %s\n",
4601                                 argv[0], show_parents ? "parent " : "", *path,
4602                                 strerror(-err));
4603                         if (rc == 0) {
4604                                 rc = err;
4605                                 errno = -err;
4606                         }
4607                 }
4608         }
4609
4610         return rc;
4611 }
4612
4613 static int lfs_data_version(int argc, char **argv)
4614 {
4615         char *path;
4616         __u64 data_version;
4617         int fd;
4618         int rc;
4619         int c;
4620         int data_version_flags = LL_DV_RD_FLUSH; /* Read by default */
4621
4622         if (argc < 2)
4623                 return CMD_HELP;
4624
4625         while ((c = getopt(argc, argv, "nrw")) != -1) {
4626                 switch (c) {
4627                 case 'n':
4628                         data_version_flags = 0;
4629                         break;
4630                 case 'r':
4631                         data_version_flags |= LL_DV_RD_FLUSH;
4632                         break;
4633                 case 'w':
4634                         data_version_flags |= LL_DV_WR_FLUSH;
4635                         break;
4636                 default:
4637                         return CMD_HELP;
4638                 }
4639         }
4640         if (optind == argc)
4641                 return CMD_HELP;
4642
4643         path = argv[optind];
4644         fd = open(path, O_RDONLY);
4645         if (fd < 0)
4646                 err(errno, "cannot open file %s", path);
4647
4648         rc = llapi_get_data_version(fd, &data_version, data_version_flags);
4649         if (rc < 0)
4650                 err(errno, "cannot get version for %s", path);
4651         else
4652                 printf("%ju" "\n", (uintmax_t)data_version);
4653
4654         close(fd);
4655         return rc;
4656 }
4657
4658 static int lfs_hsm_state(int argc, char **argv)
4659 {
4660         int rc;
4661         int i = 1;
4662         char *path;
4663         struct hsm_user_state hus;
4664
4665         if (argc < 2)
4666                 return CMD_HELP;
4667
4668         do {
4669                 path = argv[i];
4670
4671                 rc = llapi_hsm_state_get(path, &hus);
4672                 if (rc) {
4673                         fprintf(stderr, "can't get hsm state for %s: %s\n",
4674                                 path, strerror(errno = -rc));
4675                         return rc;
4676                 }
4677
4678                 /* Display path name and status flags */
4679                 printf("%s: (0x%08x)", path, hus.hus_states);
4680
4681                 if (hus.hus_states & HS_RELEASED)
4682                         printf(" released");
4683                 if (hus.hus_states & HS_EXISTS)
4684                         printf(" exists");
4685                 if (hus.hus_states & HS_DIRTY)
4686                         printf(" dirty");
4687                 if (hus.hus_states & HS_ARCHIVED)
4688                         printf(" archived");
4689                 /* Display user-settable flags */
4690                 if (hus.hus_states & HS_NORELEASE)
4691                         printf(" never_release");
4692                 if (hus.hus_states & HS_NOARCHIVE)
4693                         printf(" never_archive");
4694                 if (hus.hus_states & HS_LOST)
4695                         printf(" lost_from_hsm");
4696
4697                 if (hus.hus_archive_id != 0)
4698                         printf(", archive_id:%d", hus.hus_archive_id);
4699                 printf("\n");
4700
4701         } while (++i < argc);
4702
4703         return 0;
4704 }
4705
4706 #define LFS_HSM_SET   0
4707 #define LFS_HSM_CLEAR 1
4708
4709 /**
4710  * Generic function to set or clear HSM flags.
4711  * Used by hsm_set and hsm_clear.
4712  *
4713  * @mode  if LFS_HSM_SET, set the flags, if LFS_HSM_CLEAR, clear the flags.
4714  */
4715 static int lfs_hsm_change_flags(int argc, char **argv, int mode)
4716 {
4717         struct option long_opts[] = {
4718                 {"lost", 0, 0, 'l'},
4719                 {"norelease", 0, 0, 'r'},
4720                 {"noarchive", 0, 0, 'a'},
4721                 {"archived", 0, 0, 'A'},
4722                 {"dirty", 0, 0, 'd'},
4723                 {"exists", 0, 0, 'e'},
4724                 {0, 0, 0, 0}
4725         };
4726         char short_opts[] = "lraAde";
4727         __u64 mask = 0;
4728         int c, rc;
4729         char *path;
4730
4731         if (argc < 3)
4732                 return CMD_HELP;
4733
4734         while ((c = getopt_long(argc, argv, short_opts,
4735                                 long_opts, NULL)) != -1) {
4736                 switch (c) {
4737                 case 'l':
4738                         mask |= HS_LOST;
4739                         break;
4740                 case 'a':
4741                         mask |= HS_NOARCHIVE;
4742                         break;
4743                 case 'A':
4744                         mask |= HS_ARCHIVED;
4745                         break;
4746                 case 'r':
4747                         mask |= HS_NORELEASE;
4748                         break;
4749                 case 'd':
4750                         mask |= HS_DIRTY;
4751                         break;
4752                 case 'e':
4753                         mask |= HS_EXISTS;
4754                         break;
4755                 case '?':
4756                         return CMD_HELP;
4757                 default:
4758                         fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4759                                 argv[0], argv[optind - 1]);
4760                         return CMD_HELP;
4761                 }
4762         }
4763
4764         /* User should have specified a flag */
4765         if (mask == 0)
4766                 return CMD_HELP;
4767
4768         while (optind < argc) {
4769
4770                 path = argv[optind];
4771
4772                 /* If mode == 0, this means we apply the mask. */
4773                 if (mode == LFS_HSM_SET)
4774                         rc = llapi_hsm_state_set(path, mask, 0, 0);
4775                 else
4776                         rc = llapi_hsm_state_set(path, 0, mask, 0);
4777
4778                 if (rc != 0) {
4779                         fprintf(stderr, "Can't change hsm flags for %s: %s\n",
4780                                 path, strerror(errno = -rc));
4781                         return rc;
4782                 }
4783                 optind++;
4784         }
4785
4786         return 0;
4787 }
4788
4789 static int lfs_hsm_action(int argc, char **argv)
4790 {
4791         int                              rc;
4792         int                              i = 1;
4793         char                            *path;
4794         struct hsm_current_action        hca;
4795         struct hsm_extent                he;
4796         enum hsm_user_action             hua;
4797         enum hsm_progress_states         hps;
4798
4799         if (argc < 2)
4800                 return CMD_HELP;
4801
4802         do {
4803                 path = argv[i];
4804
4805                 rc = llapi_hsm_current_action(path, &hca);
4806                 if (rc) {
4807                         fprintf(stderr, "can't get hsm action for %s: %s\n",
4808                                 path, strerror(errno = -rc));
4809                         return rc;
4810                 }
4811                 he = hca.hca_location;
4812                 hua = hca.hca_action;
4813                 hps = hca.hca_state;
4814
4815                 printf("%s: %s", path, hsm_user_action2name(hua));
4816
4817                 /* Skip file without action */
4818                 if (hca.hca_action == HUA_NONE) {
4819                         printf("\n");
4820                         continue;
4821                 }
4822
4823                 printf(" %s ", hsm_progress_state2name(hps));
4824
4825                 if ((hps == HPS_RUNNING) &&
4826                     (hua == HUA_ARCHIVE || hua == HUA_RESTORE))
4827                         printf("(%llu bytes moved)\n",
4828                                (unsigned long long)he.length);
4829                 else if ((he.offset + he.length) == LUSTRE_EOF)
4830                         printf("(from %llu to EOF)\n",
4831                                (unsigned long long)he.offset);
4832                 else
4833                         printf("(from %llu to %llu)\n",
4834                                (unsigned long long)he.offset,
4835                                (unsigned long long)(he.offset + he.length));
4836
4837         } while (++i < argc);
4838
4839         return 0;
4840 }
4841
4842 static int lfs_hsm_set(int argc, char **argv)
4843 {
4844         return lfs_hsm_change_flags(argc, argv, LFS_HSM_SET);
4845 }
4846
4847 static int lfs_hsm_clear(int argc, char **argv)
4848 {
4849         return lfs_hsm_change_flags(argc, argv, LFS_HSM_CLEAR);
4850 }
4851
4852 /**
4853  * Check file state and return its fid, to be used by lfs_hsm_request().
4854  *
4855  * \param[in]     file      Path to file to check
4856  * \param[in,out] fid       Pointer to allocated lu_fid struct.
4857  * \param[in,out] last_dev  Pointer to last device id used.
4858  *
4859  * \return 0 on success.
4860  */
4861 static int lfs_hsm_prepare_file(const char *file, struct lu_fid *fid,
4862                                 dev_t *last_dev)
4863 {
4864         struct stat     st;
4865         int             rc;
4866
4867         rc = lstat(file, &st);
4868         if (rc) {
4869                 fprintf(stderr, "Cannot stat %s: %s\n", file, strerror(errno));
4870                 return -errno;
4871         }
4872         /* Checking for regular file as archiving as posix copytool
4873          * rejects archiving files other than regular files
4874          */
4875         if (!S_ISREG(st.st_mode)) {
4876                 fprintf(stderr, "error: \"%s\" is not a regular file\n", file);
4877                 return CMD_HELP;
4878         }
4879         /* A request should be ... */
4880         if (*last_dev != st.st_dev && *last_dev != 0) {
4881                 fprintf(stderr, "All files should be "
4882                         "on the same filesystem: %s\n", file);
4883                 return -EINVAL;
4884         }
4885         *last_dev = st.st_dev;
4886
4887         rc = llapi_path2fid(file, fid);
4888         if (rc) {
4889                 fprintf(stderr, "Cannot read FID of %s: %s\n",
4890                         file, strerror(-rc));
4891                 return rc;
4892         }
4893         return 0;
4894 }
4895
4896 /* Fill an HSM HUR item with a given file name.
4897  *
4898  * If mntpath is set, then the filename is actually a FID, and no
4899  * lookup on the filesystem will be performed.
4900  *
4901  * \param[in]  hur         the user request to fill
4902  * \param[in]  idx         index of the item inside the HUR to fill
4903  * \param[in]  mntpath     mountpoint of Lustre
4904  * \param[in]  fname       filename (if mtnpath is NULL)
4905  *                         or FID (if mntpath is set)
4906  * \param[in]  last_dev    pointer to last device id used
4907  *
4908  * \retval 0 on success
4909  * \retval CMD_HELP or a negative errno on error
4910  */
4911 static int fill_hur_item(struct hsm_user_request *hur, unsigned int idx,
4912                          const char *mntpath, const char *fname,
4913                          dev_t *last_dev)
4914 {
4915         struct hsm_user_item *hui = &hur->hur_user_item[idx];
4916         int rc;
4917
4918         hui->hui_extent.length = -1;
4919
4920         if (mntpath != NULL) {
4921                 if (*fname == '[')
4922                         fname++;
4923                 rc = sscanf(fname, SFID, RFID(&hui->hui_fid));
4924                 if (rc == 3) {
4925                         rc = 0;
4926                 } else {
4927                         fprintf(stderr, "hsm: '%s' is not a valid FID\n",
4928                                 fname);
4929                         rc = -EINVAL;
4930                 }
4931         } else {
4932                 rc = lfs_hsm_prepare_file(fname, &hui->hui_fid, last_dev);
4933         }
4934
4935         if (rc == 0)
4936                 hur->hur_request.hr_itemcount++;
4937
4938         return rc;
4939 }
4940
4941 static int lfs_hsm_request(int argc, char **argv, int action)
4942 {
4943         struct option            long_opts[] = {
4944                 {"filelist", 1, 0, 'l'},
4945                 {"data", 1, 0, 'D'},
4946                 {"archive", 1, 0, 'a'},
4947                 {"mntpath", 1, 0, 'm'},
4948                 {0, 0, 0, 0}
4949         };
4950         dev_t                    last_dev = 0;
4951         char                     short_opts[] = "l:D:a:m:";
4952         struct hsm_user_request *hur, *oldhur;
4953         int                      c, i;
4954         size_t                   len;
4955         int                      nbfile;
4956         char                    *line = NULL;
4957         char                    *filelist = NULL;
4958         char                     fullpath[PATH_MAX];
4959         char                    *opaque = NULL;
4960         int                      opaque_len = 0;
4961         int                      archive_id = 0;
4962         FILE                    *fp;
4963         int                      nbfile_alloc = 0;
4964         char                    *some_file = NULL;
4965         char                    *mntpath = NULL;
4966         int                      rc;
4967
4968         if (argc < 2)
4969                 return CMD_HELP;
4970
4971         while ((c = getopt_long(argc, argv, short_opts,
4972                                 long_opts, NULL)) != -1) {
4973                 switch (c) {
4974                 case 'l':
4975                         filelist = optarg;
4976                         break;
4977                 case 'D':
4978                         opaque = optarg;
4979                         break;
4980                 case 'a':
4981                         if (action != HUA_ARCHIVE &&
4982                             action != HUA_REMOVE) {
4983                                 fprintf(stderr,
4984                                         "error: -a is supported only "
4985                                         "when archiving or removing\n");
4986                                 return CMD_HELP;
4987                         }
4988                         archive_id = atoi(optarg);
4989                         break;
4990                 case 'm':
4991                         if (some_file == NULL) {
4992                                 mntpath = optarg;
4993                                 some_file = strdup(optarg);
4994                         }
4995                         break;
4996                 case '?':
4997                         return CMD_HELP;
4998                 default:
4999                         fprintf(stderr, "error: %s: option '%s' unrecognized\n",
5000                                 argv[0], argv[optind - 1]);
5001                         return CMD_HELP;
5002                 }
5003         }
5004
5005         /* All remaining args are files, so we have at least nbfile */
5006         nbfile = argc - optind;
5007
5008         if ((nbfile == 0) && (filelist == NULL))
5009                 return CMD_HELP;
5010
5011         if (opaque != NULL)
5012                 opaque_len = strlen(opaque);
5013
5014         /* Alloc the request structure with enough place to store all files
5015          * from command line. */
5016         hur = llapi_hsm_user_request_alloc(nbfile, opaque_len);
5017         if (hur == NULL) {
5018                 fprintf(stderr, "Cannot create the request: %s\n",
5019                         strerror(errno));
5020                 return errno;
5021         }
5022         nbfile_alloc = nbfile;
5023
5024         hur->hur_request.hr_action = action;
5025         hur->hur_request.hr_archive_id = archive_id;
5026         hur->hur_request.hr_flags = 0;
5027
5028         /* All remaining args are files, add them */
5029         if (nbfile != 0 && some_file == NULL)
5030                 some_file = strdup(argv[optind]);
5031
5032         for (i = 0; i < nbfile; i++) {
5033                 rc = fill_hur_item(hur, i, mntpath, argv[optind + i],
5034                                    &last_dev);
5035                 if (rc)
5036                         goto out_free;
5037         }
5038
5039         /* from here stop using nb_file, use hur->hur_request.hr_itemcount */
5040
5041         /* If a filelist was specified, read the filelist from it. */
5042         if (filelist != NULL) {
5043                 fp = fopen(filelist, "r");
5044                 if (fp == NULL) {
5045                         fprintf(stderr, "Cannot read the file list %s: %s\n",
5046                                 filelist, strerror(errno));
5047                         rc = -errno;
5048                         goto out_free;
5049                 }
5050
5051                 while ((rc = getline(&line, &len, fp)) != -1) {
5052                         /* If allocated buffer was too small, get something
5053                          * larger */
5054                         if (nbfile_alloc <= hur->hur_request.hr_itemcount) {
5055                                 ssize_t size;
5056
5057                                 nbfile_alloc = nbfile_alloc * 2 + 1;
5058                                 oldhur = hur;
5059                                 hur = llapi_hsm_user_request_alloc(nbfile_alloc,
5060                                                                    opaque_len);
5061                                 if (hur == NULL) {
5062                                         fprintf(stderr, "hsm: cannot allocate "
5063                                                 "the request: %s\n",
5064                                                 strerror(errno));
5065                                         hur = oldhur;
5066                                         rc = -errno;
5067                                         fclose(fp);
5068                                         goto out_free;
5069                                 }
5070                                 size = hur_len(oldhur);
5071                                 if (size < 0) {
5072                                         fprintf(stderr, "hsm: cannot allocate "
5073                                                 "%u files + %u bytes data\n",
5074                                             oldhur->hur_request.hr_itemcount,
5075                                             oldhur->hur_request.hr_data_len);
5076                                         free(hur);
5077                                         hur = oldhur;
5078                                         rc = -E2BIG;
5079                                         fclose(fp);
5080                                         goto out_free;
5081                                 }
5082                                 memcpy(hur, oldhur, size);
5083                                 free(oldhur);
5084                         }
5085
5086                         /* Chop CR */
5087                         if (line[strlen(line) - 1] == '\n')
5088                                 line[strlen(line) - 1] = '\0';
5089
5090                         rc = fill_hur_item(hur, hur->hur_request.hr_itemcount,
5091                                            mntpath, line, &last_dev);
5092                         if (rc) {
5093                                 fclose(fp);
5094                                 goto out_free;
5095                         }
5096
5097                         if (some_file == NULL) {
5098                                 some_file = line;
5099                                 line = NULL;
5100                         }
5101                 }
5102
5103                 rc = fclose(fp);
5104                 free(line);
5105         }
5106
5107         /* If a --data was used, add it to the request */
5108         hur->hur_request.hr_data_len = opaque_len;
5109         if (opaque != NULL)
5110                 memcpy(hur_data(hur), opaque, opaque_len);
5111
5112         /* Send the HSM request */
5113         if (realpath(some_file, fullpath) == NULL) {
5114                 fprintf(stderr, "Could not find path '%s': %s\n",
5115                         some_file, strerror(errno));
5116         }
5117         rc = llapi_hsm_request(fullpath, hur);
5118         if (rc) {
5119                 fprintf(stderr, "Cannot send HSM request (use of %s): %s\n",
5120                         some_file, strerror(-rc));
5121                 goto out_free;
5122         }
5123
5124 out_free:
5125         free(some_file);
5126         free(hur);
5127         return rc;
5128 }
5129
5130 static int lfs_hsm_archive(int argc, char **argv)
5131 {
5132         return lfs_hsm_request(argc, argv, HUA_ARCHIVE);
5133 }
5134
5135 static int lfs_hsm_restore(int argc, char **argv)
5136 {
5137         return lfs_hsm_request(argc, argv, HUA_RESTORE);
5138 }
5139
5140 static int lfs_hsm_release(int argc, char **argv)
5141 {
5142         return lfs_hsm_request(argc, argv, HUA_RELEASE);
5143 }
5144
5145 static int lfs_hsm_remove(int argc, char **argv)
5146 {
5147         return lfs_hsm_request(argc, argv, HUA_REMOVE);
5148 }
5149
5150 static int lfs_hsm_cancel(int argc, char **argv)
5151 {
5152         return lfs_hsm_request(argc, argv, HUA_CANCEL);
5153 }
5154
5155 static int lfs_swap_layouts(int argc, char **argv)
5156 {
5157         if (argc != 3)
5158                 return CMD_HELP;
5159
5160         return llapi_swap_layouts(argv[1], argv[2], 0, 0,
5161                                   SWAP_LAYOUTS_KEEP_MTIME |
5162                                   SWAP_LAYOUTS_KEEP_ATIME);
5163 }
5164
5165 static const char *const ladvise_names[] = LU_LADVISE_NAMES;
5166
5167 static enum lu_ladvise_type lfs_get_ladvice(const char *string)
5168 {
5169         enum lu_ladvise_type advice;
5170
5171         for (advice = 0;
5172              advice < ARRAY_SIZE(ladvise_names); advice++) {
5173                 if (ladvise_names[advice] == NULL)
5174                         continue;
5175                 if (strcmp(string, ladvise_names[advice]) == 0)
5176                         return advice;
5177         }
5178
5179         return LU_LADVISE_INVALID;
5180 }
5181
5182 static int lfs_ladvise(int argc, char **argv)
5183 {
5184         struct option            long_opts[] = {
5185                 {"advice",      required_argument,      0, 'a'},
5186                 {"background",  no_argument,            0, 'b'},
5187                 {"end",         required_argument,      0, 'e'},
5188                 {"start",       required_argument,      0, 's'},
5189                 {"length",      required_argument,      0, 'l'},
5190                 {0, 0, 0, 0}
5191         };
5192         char                     short_opts[] = "a:be:l:s:";
5193         int                      c;
5194         int                      rc = 0;
5195         const char              *path;
5196         int                      fd;
5197         struct llapi_lu_ladvise  advice;
5198         enum lu_ladvise_type     advice_type = LU_LADVISE_INVALID;
5199         unsigned long long       start = 0;
5200         unsigned long long       end = LUSTRE_EOF;
5201         unsigned long long       length = 0;
5202         unsigned long long       size_units;
5203         unsigned long long       flags = 0;
5204
5205         optind = 0;
5206         while ((c = getopt_long(argc, argv, short_opts,
5207                                 long_opts, NULL)) != -1) {
5208                 switch (c) {
5209                 case 'a':
5210                         advice_type = lfs_get_ladvice(optarg);
5211                         if (advice_type == LU_LADVISE_INVALID) {
5212                                 fprintf(stderr, "%s: invalid advice type "
5213                                         "'%s'\n", argv[0], optarg);
5214                                 fprintf(stderr, "Valid types:");
5215
5216                                 for (advice_type = 0;
5217                                      advice_type < ARRAY_SIZE(ladvise_names);
5218                                      advice_type++) {
5219                                         if (ladvise_names[advice_type] == NULL)
5220                                                 continue;
5221                                         fprintf(stderr, " %s",
5222                                                 ladvise_names[advice_type]);
5223                                 }
5224                                 fprintf(stderr, "\n");
5225
5226                                 return CMD_HELP;
5227                         }
5228                         break;
5229                 case 'b':
5230                         flags |= LF_ASYNC;
5231                         break;
5232                 case 'e':
5233                         size_units = 1;
5234                         rc = llapi_parse_size(optarg, &end,
5235                                               &size_units, 0);
5236                         if (rc) {
5237                                 fprintf(stderr, "%s: bad end offset '%s'\n",
5238                                         argv[0], optarg);
5239                                 return CMD_HELP;
5240                         }
5241                         break;
5242                 case 's':
5243                         size_units = 1;
5244                         rc = llapi_parse_size(optarg, &start,
5245                                               &size_units, 0);
5246                         if (rc) {
5247                                 fprintf(stderr, "%s: bad start offset "
5248                                         "'%s'\n", argv[0], optarg);
5249                                 return CMD_HELP;
5250                         }
5251                         break;
5252                 case 'l':
5253                         size_units = 1;
5254                         rc = llapi_parse_size(optarg, &length,
5255                                               &size_units, 0);
5256                         if (rc) {
5257                                 fprintf(stderr, "%s: bad length '%s'\n",
5258                                         argv[0], optarg);
5259                                 return CMD_HELP;
5260                         }
5261                         break;
5262                 case '?':
5263                         return CMD_HELP;
5264                 default:
5265                         fprintf(stderr, "%s: option '%s' unrecognized\n",
5266                                 argv[0], argv[optind - 1]);
5267                         return CMD_HELP;
5268                 }
5269         }
5270
5271         if (advice_type == LU_LADVISE_INVALID) {
5272                 fprintf(stderr, "%s: please give an advice type\n", argv[0]);
5273                 fprintf(stderr, "Valid types:");
5274                 for (advice_type = 0; advice_type < ARRAY_SIZE(ladvise_names);
5275                      advice_type++) {
5276                         if (ladvise_names[advice_type] == NULL)
5277                                 continue;
5278                         fprintf(stderr, " %s", ladvise_names[advice_type]);
5279                 }
5280                 fprintf(stderr, "\n");
5281                 return CMD_HELP;
5282         }
5283
5284         if (argc <= optind) {
5285                 fprintf(stderr, "%s: please give one or more file names\n",
5286                         argv[0]);
5287                 return CMD_HELP;
5288         }
5289
5290         if (end != LUSTRE_EOF && length != 0 && end != start + length) {
5291                 fprintf(stderr, "%s: conflicting arguments of -l and -e\n",
5292                         argv[0]);
5293                 return CMD_HELP;
5294         }
5295
5296         if (end == LUSTRE_EOF && length != 0)
5297                 end = start + length;
5298
5299         if (end <= start) {
5300                 fprintf(stderr, "%s: range [%llu, %llu] is invalid\n",
5301                         argv[0], start, end);
5302                 return CMD_HELP;
5303         }
5304
5305         while (optind < argc) {
5306                 int rc2;
5307
5308                 path = argv[optind++];
5309
5310                 fd = open(path, O_RDONLY);
5311                 if (fd < 0) {
5312                         fprintf(stderr, "%s: cannot open file '%s': %s\n",
5313                                 argv[0], path, strerror(errno));
5314                         rc2 = -errno;
5315                         goto next;
5316                 }
5317
5318                 advice.lla_start = start;
5319                 advice.lla_end = end;
5320                 advice.lla_advice = advice_type;
5321                 advice.lla_value1 = 0;
5322                 advice.lla_value2 = 0;
5323                 advice.lla_value3 = 0;
5324                 advice.lla_value4 = 0;
5325                 rc2 = llapi_ladvise(fd, flags, 1, &advice);
5326                 close(fd);
5327                 if (rc2 < 0) {
5328                         fprintf(stderr, "%s: cannot give advice '%s' to file "
5329                                 "'%s': %s\n", argv[0],
5330                                 ladvise_names[advice_type],
5331                                 path, strerror(errno));
5332                 }
5333 next:
5334                 if (rc == 0 && rc2 < 0)
5335                         rc = rc2;
5336         }
5337         return rc;
5338 }
5339
5340 static int lfs_list_commands(int argc, char **argv)
5341 {
5342         char buffer[81] = ""; /* 80 printable chars + terminating NUL */
5343
5344         Parser_list_commands(cmdlist, buffer, sizeof(buffer), NULL, 0, 4);
5345
5346         return 0;
5347 }
5348
5349 int main(int argc, char **argv)
5350 {
5351         int rc;
5352
5353         /* Ensure that liblustreapi constructor has run */
5354         if (!liblustreapi_initialized)
5355                 fprintf(stderr, "liblustreapi was not properly initialized\n");
5356
5357         setlinebuf(stdout);
5358
5359         Parser_init("lfs > ", cmdlist);
5360
5361         progname = argv[0]; /* Used in error messages */
5362         if (argc > 1) {
5363                 rc = Parser_execarg(argc - 1, argv + 1, cmdlist);
5364         } else {
5365                 rc = Parser_commands();
5366         }
5367
5368         return rc < 0 ? -rc : rc;
5369 }
5370
5371 #ifdef _LUSTRE_IDL_H_
5372 /* Everything we need here should be included by lustreapi.h. */
5373 # error "lfs should not depend on lustre_idl.h"
5374 #endif /* _LUSTRE_IDL_H_ */