Whamcloud - gitweb
LU-4017 quota: cleanup to improve quota codes
[fs/lustre-release.git] / lustre / utils / lfs.c
1 /*
2  * GPL HEADER START
3  *
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 only,
8  * as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License version 2 for more details (a copy is included
14  * in the LICENSE file that accompanied this code).
15  *
16  * You should have received a copy of the GNU General Public License
17  * version 2 along with this program; If not, see
18  * http://www.gnu.org/licenses/gpl-2.0.html
19  *
20  * GPL HEADER END
21  */
22 /*
23  * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
24  * Use is subject to license terms.
25  *
26  * Copyright (c) 2011, 2016, Intel Corporation.
27  */
28 /*
29  * This file is part of Lustre, http://www.lustre.org/
30  * Lustre is a trademark of Sun Microsystems, Inc.
31  *
32  * lustre/utils/lfs.c
33  *
34  * Author: Peter J. Braam <braam@clusterfs.com>
35  * Author: Phil Schwan <phil@clusterfs.com>
36  * Author: Robert Read <rread@clusterfs.com>
37  */
38
39 /* for O_DIRECTORY */
40 #ifndef _GNU_SOURCE
41 #define _GNU_SOURCE
42 #endif
43
44 #include <stdlib.h>
45 #include <stdio.h>
46 #include <getopt.h>
47 #include <string.h>
48 #include <mntent.h>
49 #include <unistd.h>
50 #include <errno.h>
51 #include <err.h>
52 #include <pwd.h>
53 #include <grp.h>
54 #include <sys/ioctl.h>
55 #include <sys/quota.h>
56 #include <sys/time.h>
57 #include <sys/types.h>
58 #include <sys/stat.h>
59 #include <fcntl.h>
60 #include <dirent.h>
61 #include <time.h>
62 #include <ctype.h>
63
64 #include <libcfs/util/string.h>
65 #include <libcfs/util/ioctl.h>
66 #include <libcfs/util/parser.h>
67 #include <lustre/lustreapi.h>
68 #include <lustre_ver.h>
69 #include <lustre_param.h>
70
71 #ifndef ARRAY_SIZE
72 # define ARRAY_SIZE(a) ((sizeof(a)) / (sizeof((a)[0])))
73 #endif /* !ARRAY_SIZE */
74
75 /* all functions */
76 static int lfs_setstripe(int argc, char **argv);
77 static int lfs_find(int argc, char **argv);
78 static int lfs_getstripe(int argc, char **argv);
79 static int lfs_getdirstripe(int argc, char **argv);
80 static int lfs_setdirstripe(int argc, char **argv);
81 static int lfs_rmentry(int argc, char **argv);
82 static int lfs_osts(int argc, char **argv);
83 static int lfs_mdts(int argc, char **argv);
84 static int lfs_df(int argc, char **argv);
85 static int lfs_getname(int argc, char **argv);
86 static int lfs_check(int argc, char **argv);
87 #ifdef HAVE_SYS_QUOTA_H
88 static int lfs_setquota(int argc, char **argv);
89 static int lfs_quota(int argc, char **argv);
90 #endif
91 static int lfs_flushctx(int argc, char **argv);
92 static int lfs_cp(int argc, char **argv);
93 static int lfs_ls(int argc, char **argv);
94 static int lfs_poollist(int argc, char **argv);
95 static int lfs_changelog(int argc, char **argv);
96 static int lfs_changelog_clear(int argc, char **argv);
97 static int lfs_fid2path(int argc, char **argv);
98 static int lfs_path2fid(int argc, char **argv);
99 static int lfs_data_version(int argc, char **argv);
100 static int lfs_hsm_state(int argc, char **argv);
101 static int lfs_hsm_set(int argc, char **argv);
102 static int lfs_hsm_clear(int argc, char **argv);
103 static int lfs_hsm_action(int argc, char **argv);
104 static int lfs_hsm_archive(int argc, char **argv);
105 static int lfs_hsm_restore(int argc, char **argv);
106 static int lfs_hsm_release(int argc, char **argv);
107 static int lfs_hsm_remove(int argc, char **argv);
108 static int lfs_hsm_cancel(int argc, char **argv);
109 static int lfs_swap_layouts(int argc, char **argv);
110 static int lfs_mv(int argc, char **argv);
111 static int lfs_ladvise(int argc, char **argv);
112 static int lfs_list_commands(int argc, char **argv);
113
114 /* Setstripe and migrate share mostly the same parameters */
115 #define SSM_CMD_COMMON(cmd) \
116         "usage: "cmd" [--stripe-count|-c <stripe_count>]\n"             \
117         "                 [--stripe-index|-i <start_ost_idx>]\n"        \
118         "                 [--stripe-size|-S <stripe_size>]\n"           \
119         "                 [--pool|-p <pool_name>]\n"                    \
120         "                 [--ost|-o <ost_indices>]\n"                   \
121         "                 [--component-end|-E <comp_end>]\n"
122
123 #define SSM_HELP_COMMON \
124         "\tstripe_size:  Number of bytes on each OST (0 filesystem default)\n" \
125         "\t              Can be specified with k, m or g (in KB, MB and GB\n" \
126         "\t              respectively)\n"                               \
127         "\tstart_ost_idx: OST index of first stripe (-1 default)\n"     \
128         "\tstripe_count: Number of OSTs to stripe over (0 default, -1 all)\n" \
129         "\tpool_name:    Name of OST pool to use (default none)\n"      \
130         "\tost_indices:  List of OST indices, can be repeated multiple times\n"\
131         "\t              Indices be specified in a format of:\n"        \
132         "\t                -o <ost_1>,<ost_i>-<ost_j>,<ost_n>\n"        \
133         "\t              Or:\n"                                         \
134         "\t                -o <ost_1> -o <ost_i>-<ost_j> -o <ost_n>\n"  \
135         "\t              If --pool is set with --ost, then the OSTs\n"  \
136         "\t              must be the members of the pool."              \
137         "\tcomp_end:     Extent end of the component\n"                 \
138         "\t              Can be specified with k, m or g (in KB, MB and GB\n" \
139         "\t              respectively, -1 for EOF), it must be aligned with\n"\
140         "\t              the stripe_size\n"
141
142 #define SETSTRIPE_USAGE                                         \
143         SSM_CMD_COMMON("setstripe")                             \
144         "                 <directory|filename>\n"               \
145         SSM_HELP_COMMON                                         \
146
147 #define MIGRATE_USAGE                                                   \
148         SSM_CMD_COMMON("migrate  ")                                     \
149         "                 [--block|-b]\n"                               \
150         "                 [--non-block|-n]\n"                           \
151         "                 <filename>\n"                                 \
152         SSM_HELP_COMMON                                                 \
153         "\n"                                                            \
154         "\tblock:        Block file access during data migration (default)\n" \
155         "\tnon-block:    Abort migrations if concurrent access is detected\n" \
156
157 #define SETDIRSTRIPE_USAGE                                      \
158         "               [--mdt-count|-c stripe_count>\n"        \
159         "               [--mdt-index|-i mdt_index]\n"           \
160         "               [--mdt-hash|-H mdt_hash]\n"             \
161         "               [--default|-D] [--mode|-m mode] <dir>\n"        \
162         "\tstripe_count: stripe count of the striped directory\n"       \
163         "\tmdt_index: MDT index of first stripe\n"                      \
164         "\tmdt_hash:  hash type of the striped directory. mdt types:\n" \
165         "       fnv_1a_64 FNV-1a hash algorithm (default)\n"            \
166         "       all_char  sum of characters % MDT_COUNT (not recommended)\n" \
167         "\tdefault_stripe: set default dirstripe of the directory\n"    \
168         "\tmode: the mode of the directory\n"
169
170 static const char       *progname;
171 static bool              file_lease_supported = true;
172
173 /* all available commands */
174 command_t cmdlist[] = {
175         {"setstripe", lfs_setstripe, 0,
176          "Create a new file with a specific striping pattern or\n"
177          "set the default striping pattern on an existing directory or\n"
178          "delete the default striping pattern from an existing directory or\n"
179          "add layout component(s) to an existing composite file or\n"
180          "delete specified component(s) from an existing composite file\n\n"
181          "To delete default striping from an existing directory:\n"
182          "usage: setstripe -d <directory>\n"
183          " or\n"
184          "To delete component(s) from an existing composite file:\n"
185          "usage: setstripe --component-del [--component-id|-I <comp_id>]\n"
186          "                               [--component-flags|-F <comp_flags>]\n"
187          "                               <filename>\n"
188          "\tcomp_id:     Unique component ID\n"
189          "\tcomp_flags:  'init' indicating all instantiated components\n"
190          "\t-I and -F can't be specified at the same time\n"
191          " or\n"
192          "To add component(s) to an existing composite file:\n"
193          SSM_CMD_COMMON("setstripe --component-add")
194          " or\n"
195          "To create a file with specified striping/composite layout:\n"
196          SETSTRIPE_USAGE},
197         {"getstripe", lfs_getstripe, 0,
198          "To list the striping info for a given file or files in a\n"
199          "directory or recursively for all files in a directory tree.\n"
200          "usage: getstripe [--ost|-O <uuid>] [--quiet|-q] [--verbose|-v]\n"
201          "                 [--stripe-count|-c] [--stripe-index|-i]\n"
202          "                 [--pool|-p] [--stripe-size|-S] [--directory|-d]\n"
203          "                 [--mdt|-m] [--recursive|-r] [--raw|-R]\n"
204          "                 [--layout|-L] [--fid|-F] [--generation|-g]\n"
205          "                 [--component-id|-I [comp_id]]\n"
206          "                 [--component-flags [comp_flags]]\n"
207          "                 [--component-count [comp_count]]\n"
208          "                 [--component-start [comp_start]]\n"
209          "                 [--component-end|-E [comp_end]]\n"
210          "                 <directory|filename> ..."},
211         {"setdirstripe", lfs_setdirstripe, 0,
212          "To create a striped directory on a specified MDT. This can only\n"
213          "be done on MDT0 with the right of administrator.\n"
214          "usage: setdirstripe [OPTION] <directory>\n"
215          SETDIRSTRIPE_USAGE},
216         {"getdirstripe", lfs_getdirstripe, 0,
217          "To list the striping info for a given directory\n"
218          "or recursively for all directories in a directory tree.\n"
219          "usage: getdirstripe [--obd|-O <uuid>] [--mdt-count|-c]\n"
220          "                    [--mdt-index|-i] [--mdt-hash|-H]\n"
221          "                    [--recursive|-r] [--default|-D] <dir> ..."},
222         {"mkdir", lfs_setdirstripe, 0,
223          "To create a striped directory on a specified MDT. This can only\n"
224          "be done on MDT0 with the right of administrator.\n"
225          "usage: mkdir [OPTION] <directory>\n"
226          SETDIRSTRIPE_USAGE},
227         {"rm_entry", lfs_rmentry, 0,
228          "To remove the name entry of the remote directory. Note: This\n"
229          "command will only delete the name entry, i.e. the remote directory\n"
230          "will become inaccessable after this command. This can only be done\n"
231          "by the administrator\n"
232          "usage: rm_entry <dir>\n"},
233         {"pool_list", lfs_poollist, 0,
234          "List pools or pool OSTs\n"
235          "usage: pool_list <fsname>[.<pool>] | <pathname>\n"},
236         {"find", lfs_find, 0,
237          "find files matching given attributes recursively in directory tree.\n"
238          "usage: find <directory|filename> ...\n"
239          "     [[!] --atime|-A [+-]N] [[!] --ctime|-C [+-]N]\n"
240          "     [[!] --mtime|-M [+-]N] [[!] --mdt|-m <uuid|index,...>]\n"
241          "     [--maxdepth|-D N] [[!] --name|-n <pattern>]\n"
242          "     [[!] --ost|-O <uuid|index,...>] [--print|-p] [--print0|-P]\n"
243          "     [[!] --size|-s [+-]N[bkMGTPE]]\n"
244          "     [[!] --stripe-count|-c [+-]<stripes>]\n"
245          "     [[!] --stripe-index|-i <index,...>]\n"
246          "     [[!] --stripe-size|-S [+-]N[kMGT]] [[!] --type|-t <filetype>]\n"
247          "     [[!] --gid|-g|--group|-G <gid>|<gname>]\n"
248          "     [[!] --uid|-u|--user|-U <uid>|<uname>] [[!] --pool <pool>]\n"
249          "     [[!] --projid <projid>]\n"
250          "     [[!] --layout|-L released,raid0]\n"
251          "     [[!] --component-count [+-]<comp_cnt>]\n"
252          "     [[!] --component-start [+-]N[kMGTPE]]\n"
253          "     [[!] --component-end|-E [+-]N[kMGTPE]]\n"
254          "     [[!] --component-flags <comp_flags>]\n"
255          "     [[!] --mdt-count|-T [+-]<stripes>]\n"
256          "     [[!] --mdt-hash|-H <hashtype>\n"
257          "\t !: used before an option indicates 'NOT' requested attribute\n"
258          "\t -: used before a value indicates 'AT MOST' requested value\n"
259          "\t +: used before a value indicates 'AT LEAST' requested value\n"
260          "\tmdt-hash:   hash type of the striped directory.\n"
261          "\t            fnv_1a_64 FNV-1a hash algorithm\n"
262          "\t            all_char  sum of characters % MDT_COUNT\n"},
263         {"check", lfs_check, 0,
264          "Display the status of MDS or OSTs (as specified in the command)\n"
265          "or all the servers (MDS and OSTs).\n"
266          "usage: check <osts|mds|servers>"},
267         {"osts", lfs_osts, 0, "list OSTs connected to client "
268          "[for specified path only]\n" "usage: osts [path]"},
269         {"mdts", lfs_mdts, 0, "list MDTs connected to client "
270          "[for specified path only]\n" "usage: mdts [path]"},
271         {"df", lfs_df, 0,
272          "report filesystem disk space usage or inodes usage"
273          "of each MDS and all OSDs or a batch belonging to a specific pool .\n"
274          "Usage: df [-i] [-h] [--lazy|-l] [--pool|-p <fsname>[.<pool>] [path]"},
275         {"getname", lfs_getname, 0, "list instances and specified mount points "
276          "[for specified path only]\n"
277          "Usage: getname [-h]|[path ...] "},
278 #ifdef HAVE_SYS_QUOTA_H
279         {"setquota", lfs_setquota, 0, "Set filesystem quotas.\n"
280          "usage: setquota <-u|-g|-p> <uname>|<uid>|<gname>|<gid>|<projid>\n"
281          "                -b <block-softlimit> -B <block-hardlimit>\n"
282          "                -i <inode-softlimit> -I <inode-hardlimit> <filesystem>\n"
283          "       setquota <-u|--user|-g|--group|-p|--projid> <uname>|<uid>|<gname>|<gid>|<projid>\n"
284          "                [--block-softlimit <block-softlimit>]\n"
285          "                [--block-hardlimit <block-hardlimit>]\n"
286          "                [--inode-softlimit <inode-softlimit>]\n"
287          "                [--inode-hardlimit <inode-hardlimit>] <filesystem>\n"
288          "       setquota [-t] <-u|--user|-g|--group|-p|--projid>\n"
289          "                [--block-grace <block-grace>]\n"
290          "                [--inode-grace <inode-grace>] <filesystem>\n"
291          "       -b can be used instead of --block-softlimit/--block-grace\n"
292          "       -B can be used instead of --block-hardlimit\n"
293          "       -i can be used instead of --inode-softlimit/--inode-grace\n"
294          "       -I can be used instead of --inode-hardlimit\n\n"
295          "Note: The total quota space will be split into many qunits and\n"
296          "      balanced over all server targets, the minimal qunit size is\n"
297          "      1M bytes for block space and 1K inodes for inode space.\n\n"
298          "      Quota space rebalancing process will stop when this mininum\n"
299          "      value is reached. As a result, quota exceeded can be returned\n"
300          "      while many targets still have 1MB or 1K inodes of spare\n"
301          "      quota space."},
302         {"quota", lfs_quota, 0, "Display disk usage and limits.\n"
303          "usage: quota [-q] [-v] [-h] [-o <obd_uuid>|-i <mdt_idx>|-I "
304                        "<ost_idx>]\n"
305          "             [<-u|-g|-p> <uname>|<uid>|<gname>|<gid>|<projid>] <filesystem>\n"
306          "       quota [-o <obd_uuid>|-i <mdt_idx>|-I <ost_idx>] -t <-u|-g|-p> <filesystem>"},
307 #endif
308         {"flushctx", lfs_flushctx, 0, "Flush security context for current user.\n"
309          "usage: flushctx [-k] [mountpoint...]"},
310         {"cp", lfs_cp, 0,
311          "Remote user copy files and directories.\n"
312          "usage: cp [OPTION]... [-T] SOURCE DEST\n\tcp [OPTION]... SOURCE... DIRECTORY\n\tcp [OPTION]... -t DIRECTORY SOURCE..."},
313         {"ls", lfs_ls, 0,
314          "Remote user list directory contents.\n"
315          "usage: ls [OPTION]... [FILE]..."},
316         {"changelog", lfs_changelog, 0,
317          "Show the metadata changes on an MDT."
318          "\nusage: changelog <mdtname> [startrec [endrec]]"},
319         {"changelog_clear", lfs_changelog_clear, 0,
320          "Indicate that old changelog records up to <endrec> are no longer of "
321          "interest to consumer <id>, allowing the system to free up space.\n"
322          "An <endrec> of 0 means all records.\n"
323          "usage: changelog_clear <mdtname> <id> <endrec>"},
324         {"fid2path", lfs_fid2path, 0,
325          "Resolve the full path(s) for given FID(s). For a specific hardlink "
326          "specify link number <linkno>.\n"
327         /* "For a historical link name, specify changelog record <recno>.\n" */
328          "usage: fid2path [--link <linkno>] <fsname|rootpath> <fid> ..."
329                 /* [ --rec <recno> ] */ },
330         {"path2fid", lfs_path2fid, 0, "Display the fid(s) for a given path(s).\n"
331          "usage: path2fid [--parents] <path> ..."},
332         {"data_version", lfs_data_version, 0, "Display file data version for "
333          "a given path.\n" "usage: data_version -[n|r|w] <path>"},
334         {"hsm_state", lfs_hsm_state, 0, "Display the HSM information (states, "
335          "undergoing actions) for given files.\n usage: hsm_state <file> ..."},
336         {"hsm_set", lfs_hsm_set, 0, "Set HSM user flag on specified files.\n"
337          "usage: hsm_set [--norelease] [--noarchive] [--dirty] [--exists] "
338          "[--archived] [--lost] <file> ..."},
339         {"hsm_clear", lfs_hsm_clear, 0, "Clear HSM user flag on specified "
340          "files.\n"
341          "usage: hsm_clear [--norelease] [--noarchive] [--dirty] [--exists] "
342          "[--archived] [--lost] <file> ..."},
343         {"hsm_action", lfs_hsm_action, 0, "Display current HSM request for "
344          "given files.\n" "usage: hsm_action <file> ..."},
345         {"hsm_archive", lfs_hsm_archive, 0,
346          "Archive file to external storage.\n"
347          "usage: hsm_archive [--filelist FILELIST] [--data DATA] [--archive NUM] "
348          "<file> ..."},
349         {"hsm_restore", lfs_hsm_restore, 0,
350          "Restore file from external storage.\n"
351          "usage: hsm_restore [--filelist FILELIST] [--data DATA] <file> ..."},
352         {"hsm_release", lfs_hsm_release, 0,
353          "Release files from Lustre.\n"
354          "usage: hsm_release [--filelist FILELIST] [--data DATA] <file> ..."},
355         {"hsm_remove", lfs_hsm_remove, 0,
356          "Remove file copy from external storage.\n"
357          "usage: hsm_remove [--filelist FILELIST] [--data DATA]\n"
358          "                  [--mntpath MOUNTPATH] [--archive NUM] <file|FID> ...\n"
359          "\n"
360          "Note: To remove files from the archive that have been deleted on\n"
361          "Lustre, set mntpath and optionally archive. In that case, all the\n"
362          "positional arguments and entries in the file list must be FIDs."
363         },
364         {"hsm_cancel", lfs_hsm_cancel, 0,
365          "Cancel requests related to specified files.\n"
366          "usage: hsm_cancel [--filelist FILELIST] [--data DATA] <file> ..."},
367         {"swap_layouts", lfs_swap_layouts, 0, "Swap layouts between 2 files.\n"
368          "usage: swap_layouts <path1> <path2>"},
369         {"migrate", lfs_setstripe, 0,
370          "migrate a directory between MDTs.\n"
371          "usage: migrate --mdt-index <mdt_idx> [--verbose|-v] "
372          "<directory>\n"
373          "\tmdt_idx:      index of the destination MDT\n"
374          "\n"
375          "migrate file objects from one OST "
376          "layout\nto another (may be not safe with concurent writes).\n"
377          "usage: migrate  "
378          "[--stripe-count|-c] <stripe_count>\n"
379          "              [--stripe-index|-i] <start_ost_index>\n"
380          "              [--stripe-size|-S] <stripe_size>\n"
381          "              [--pool|-p] <pool_name>\n"
382          "              [--ost-list|-o] <ost_indices>\n"
383          "              [--block|-b]\n"
384          "              [--non-block|-n]\n"
385          "              <file|directory>\n"
386          "\tstripe_count:     number of OSTs to stripe a file over\n"
387          "\tstripe_ost_index: index of the first OST to stripe a file over\n"
388          "\tstripe_size:      number of bytes to store before moving to the next OST\n"
389          "\tpool_name:        name of the predefined pool of OSTs\n"
390          "\tost_indices:      OSTs to stripe over, in order\n"
391          "\tblock:            wait for the operation to return before continuing\n"
392          "\tnon-block:        do not wait for the operation to return.\n"},
393         {"mv", lfs_mv, 0,
394          "To move directories between MDTs. This command is deprecated, "
395          "use \"migrate\" instead.\n"
396          "usage: mv <directory|filename> [--mdt-index|-M] <mdt_index> "
397          "[--verbose|-v]\n"},
398         {"ladvise", lfs_ladvise, 0,
399          "Provide servers with advice about access patterns for a file.\n"
400          "usage: ladvise [--advice|-a ADVICE] [--start|-s START[kMGT]]\n"
401          "               [--background|-b]\n"
402          "               {[--end|-e END[kMGT]] | [--length|-l LENGTH[kMGT]]}\n"
403          "               <file> ...\n"},
404         {"help", Parser_help, 0, "help"},
405         {"exit", Parser_quit, 0, "quit"},
406         {"quit", Parser_quit, 0, "quit"},
407         {"--version", Parser_version, 0,
408          "output build version of the utility and exit"},
409         {"--list-commands", lfs_list_commands, 0,
410          "list commands supported by the utility and exit"},
411         { 0, 0, 0, NULL }
412 };
413
414
415 #define MIGRATION_NONBLOCK      1
416
417 static int check_hashtype(const char *hashtype)
418 {
419         int i;
420
421         for (i = LMV_HASH_TYPE_ALL_CHARS; i < LMV_HASH_TYPE_MAX; i++)
422                 if (strcmp(hashtype, mdt_hash_name[i]) == 0)
423                         return i;
424
425         return 0;
426 }
427
428 /**
429  * Internal helper for migrate_copy_data(). Check lease and report error if
430  * need be.
431  *
432  * \param[in]  fd           File descriptor on which to check the lease.
433  * \param[out] lease_broken Set to true if the lease was broken.
434  * \param[in]  group_locked Whether a group lock was taken or not.
435  * \param[in]  path         Name of the file being processed, for error
436  *                          reporting
437  *
438  * \retval 0       Migration can keep on going.
439  * \retval -errno  Error occurred, abort migration.
440  */
441 static int check_lease(int fd, bool *lease_broken, bool group_locked,
442                        const char *path)
443 {
444         int rc;
445
446         if (!file_lease_supported)
447                 return 0;
448
449         rc = llapi_lease_check(fd);
450         if (rc > 0)
451                 return 0; /* llapi_check_lease returns > 0 on success. */
452
453         if (!group_locked) {
454                 fprintf(stderr, "%s: cannot migrate '%s': file busy\n",
455                         progname, path);
456                 rc = rc ? rc : -EAGAIN;
457         } else {
458                 fprintf(stderr, "%s: external attempt to access file '%s' "
459                         "blocked until migration ends.\n", progname, path);
460                 rc = 0;
461         }
462         *lease_broken = true;
463         return rc;
464 }
465
466 static int migrate_copy_data(int fd_src, int fd_dst, size_t buf_size,
467                              bool group_locked, const char *fname)
468 {
469         void    *buf = NULL;
470         ssize_t  rsize = -1;
471         ssize_t  wsize = 0;
472         size_t   rpos = 0;
473         size_t   wpos = 0;
474         off_t    bufoff = 0;
475         int      rc;
476         bool     lease_broken = false;
477
478         /* Use a page-aligned buffer for direct I/O */
479         rc = posix_memalign(&buf, getpagesize(), buf_size);
480         if (rc != 0)
481                 return -rc;
482
483         while (1) {
484                 /* read new data only if we have written all
485                  * previously read data */
486                 if (wpos == rpos) {
487                         if (!lease_broken) {
488                                 rc = check_lease(fd_src, &lease_broken,
489                                                  group_locked, fname);
490                                 if (rc < 0)
491                                         goto out;
492                         }
493                         rsize = read(fd_src, buf, buf_size);
494                         if (rsize < 0) {
495                                 rc = -errno;
496                                 fprintf(stderr, "%s: %s: read failed: %s\n",
497                                         progname, fname, strerror(-rc));
498                                 goto out;
499                         }
500                         rpos += rsize;
501                         bufoff = 0;
502                 }
503                 /* eof ? */
504                 if (rsize == 0)
505                         break;
506
507                 wsize = write(fd_dst, buf + bufoff, rpos - wpos);
508                 if (wsize < 0) {
509                         rc = -errno;
510                         fprintf(stderr,
511                                 "%s: %s: write failed on volatile: %s\n",
512                                 progname, fname, strerror(-rc));
513                         goto out;
514                 }
515                 wpos += wsize;
516                 bufoff += wsize;
517         }
518
519         rc = fsync(fd_dst);
520         if (rc < 0) {
521                 rc = -errno;
522                 fprintf(stderr, "%s: %s: fsync failed: %s\n",
523                         progname, fname, strerror(-rc));
524         }
525
526 out:
527         free(buf);
528         return rc;
529 }
530
531 static int migrate_copy_timestamps(int fdv, const struct stat *st)
532 {
533         struct timeval  tv[2] = {
534                 {.tv_sec = st->st_atime},
535                 {.tv_sec = st->st_mtime}
536         };
537
538         return futimes(fdv, tv);
539 }
540
541 static int migrate_block(int fd, int fdv, const struct stat *st,
542                          size_t buf_size, const char *name)
543 {
544         __u64   dv1;
545         int     gid;
546         int     rc;
547         int     rc2;
548
549         rc = llapi_get_data_version(fd, &dv1, LL_DV_RD_FLUSH);
550         if (rc < 0) {
551                 fprintf(stderr, "%s: %s: cannot get dataversion: %s\n",
552                         progname, name, strerror(-rc));
553                 return rc;
554         }
555
556         do
557                 gid = random();
558         while (gid == 0);
559
560         /* The grouplock blocks all concurrent accesses to the file.
561          * It has to be taken after llapi_get_data_version as it would
562          * block it too. */
563         rc = llapi_group_lock(fd, gid);
564         if (rc < 0) {
565                 fprintf(stderr, "%s: %s: cannot get group lock: %s\n",
566                         progname, name, strerror(-rc));
567                 return rc;
568         }
569
570         rc = migrate_copy_data(fd, fdv, buf_size, true, name);
571         if (rc < 0) {
572                 fprintf(stderr, "%s: %s: data copy failed\n", progname, name);
573                 goto out_unlock;
574         }
575
576         /* Make sure we keep original atime/mtime values */
577         rc = migrate_copy_timestamps(fdv, st);
578         if (rc < 0) {
579                 fprintf(stderr, "%s: %s: timestamp copy failed\n",
580                         progname, name);
581                 goto out_unlock;
582         }
583
584         /* swap layouts
585          * for a migration we need to check data version on file did
586          * not change.
587          *
588          * Pass in gid=0 since we already own grouplock. */
589         rc = llapi_fswap_layouts_grouplock(fd, fdv, dv1, 0, 0,
590                                            SWAP_LAYOUTS_CHECK_DV1);
591         if (rc == -EAGAIN) {
592                 fprintf(stderr, "%s: %s: dataversion changed during copy, "
593                         "migration aborted\n", progname, name);
594                 goto out_unlock;
595         } else if (rc < 0) {
596                 fprintf(stderr, "%s: %s: cannot swap layouts: %s\n", progname,
597                         name, strerror(-rc));
598                 goto out_unlock;
599         }
600
601 out_unlock:
602         rc2 = llapi_group_unlock(fd, gid);
603         if (rc2 < 0 && rc == 0) {
604                 fprintf(stderr, "%s: %s: putting group lock failed: %s\n",
605                         progname, name, strerror(-rc2));
606                 rc = rc2;
607         }
608
609         return rc;
610 }
611
612 static int migrate_nonblock(int fd, int fdv, const struct stat *st,
613                             size_t buf_size, const char *name)
614 {
615         __u64   dv1;
616         __u64   dv2;
617         int     rc;
618
619         rc = llapi_get_data_version(fd, &dv1, LL_DV_RD_FLUSH);
620         if (rc < 0) {
621                 fprintf(stderr, "%s: %s: cannot get data version: %s\n",
622                         progname, name, strerror(-rc));
623                 return rc;
624         }
625
626         rc = migrate_copy_data(fd, fdv, buf_size, false, name);
627         if (rc < 0) {
628                 fprintf(stderr, "%s: %s: data copy failed\n", progname, name);
629                 return rc;
630         }
631
632         rc = llapi_get_data_version(fd, &dv2, LL_DV_RD_FLUSH);
633         if (rc != 0) {
634                 fprintf(stderr, "%s: %s: cannot get data version: %s\n",
635                         progname, name, strerror(-rc));
636                 return rc;
637         }
638
639         if (dv1 != dv2) {
640                 rc = -EAGAIN;
641                 fprintf(stderr, "%s: %s: data version changed during "
642                                 "migration\n",
643                         progname, name);
644                 return rc;
645         }
646
647         /* Make sure we keep original atime/mtime values */
648         rc = migrate_copy_timestamps(fdv, st);
649         if (rc < 0) {
650                 fprintf(stderr, "%s: %s: timestamp copy failed\n",
651                         progname, name);
652                 return rc;
653         }
654
655         /* Atomically put lease, swap layouts and close.
656          * for a migration we need to check data version on file did
657          * not change. */
658         rc = llapi_fswap_layouts(fd, fdv, 0, 0, SWAP_LAYOUTS_CLOSE);
659         if (rc < 0) {
660                 fprintf(stderr, "%s: %s: cannot swap layouts: %s\n",
661                         progname, name, strerror(-rc));
662                 return rc;
663         }
664
665         return 0;
666 }
667
668 static int lfs_component_set(char *fname, int comp_id, __u32 flags)
669 {
670         return -ENOTSUP;
671 }
672
673 static int lfs_component_del(char *fname, __u32 comp_id, __u32 flags)
674 {
675         int     rc = 0;
676
677         if (flags != 0 && comp_id != 0)
678                 return -EINVAL;
679
680         /* LCME_FL_INIT is the only supported flag in PFL */
681         if (flags != 0) {
682                 if (flags & ~LCME_KNOWN_FLAGS) {
683                         fprintf(stderr, "Invalid component flags %#x\n", flags);
684                         return -EINVAL;
685                 }
686                 comp_id = LCME_ID_NONE | flags;
687         } else if (comp_id > LCME_ID_MAX) {
688                 fprintf(stderr, "Invalid component id %u\n", comp_id);
689                 return -EINVAL;
690         }
691
692         rc = llapi_layout_file_comp_del(fname, comp_id);
693         if (rc)
694                 fprintf(stderr, "Delete component %#x from %s failed. %s\n",
695                         comp_id, fname, strerror(errno));
696         return rc;
697 }
698
699 static int lfs_component_add(char *fname, struct llapi_layout *layout)
700 {
701         int     rc;
702
703         if (layout == NULL)
704                 return -EINVAL;
705
706         rc = llapi_layout_file_comp_add(fname, layout);
707         if (rc)
708                 fprintf(stderr, "Add layout component(s) to %s failed. %s\n",
709                         fname, strerror(errno));
710         return rc;
711 }
712
713 static int lfs_component_create(char *fname, int open_flags, mode_t open_mode,
714                                 struct llapi_layout *layout)
715 {
716         struct stat     st;
717         int     fd;
718
719         if (layout == NULL)
720                 return -EINVAL;
721
722         fd = lstat(fname, &st);
723         if (fd == 0 && S_ISDIR(st.st_mode))
724                 open_flags = O_DIRECTORY | O_RDONLY;
725
726         fd = llapi_layout_file_open(fname, open_flags, open_mode, layout);
727         if (fd < 0)
728                 fprintf(stderr, "%s %s failed. %s\n",
729                         S_ISDIR(st.st_mode) ?
730                                 "Set default composite layout to " :
731                                 "Create composite file",
732                         fname, strerror(errno));
733         return fd;
734 }
735
736 static int lfs_migrate(char *name, __u64 migration_flags,
737                        struct llapi_stripe_param *param,
738                        struct llapi_layout *layout)
739 {
740         int                      fd = -1;
741         int                      fdv = -1;
742         char                     parent[PATH_MAX];
743         int                      mdt_index;
744         int                      random_value;
745         char                     volatile_file[sizeof(parent) +
746                                                LUSTRE_VOLATILE_HDR_LEN +
747                                                2 * sizeof(mdt_index) +
748                                                2 * sizeof(random_value) + 4];
749         char                    *ptr;
750         int                      rc;
751         struct lov_user_md      *lum = NULL;
752         int                      lum_size;
753         int                      buf_size = 1024 * 1024 * 4;
754         bool                     have_lease_rdlck = false;
755         struct stat              st;
756         struct stat              stv;
757
758         /* find the right size for the IO and allocate the buffer */
759         lum_size = lov_user_md_size(LOV_MAX_STRIPE_COUNT, LOV_USER_MAGIC_V3);
760         lum = malloc(lum_size);
761         if (lum == NULL) {
762                 rc = -ENOMEM;
763                 goto free;
764         }
765
766         rc = llapi_file_get_stripe(name, lum);
767         /* failure can happen for many reasons and some may be not real errors
768          * (eg: no stripe)
769          * in case of a real error, a later call will fail with better
770          * error management */
771         if (rc == 0) {
772                 if ((lum->lmm_magic == LOV_USER_MAGIC_V1 ||
773                      lum->lmm_magic == LOV_USER_MAGIC_V3) &&
774                     lum->lmm_stripe_size != 0)
775                         buf_size = lum->lmm_stripe_size;
776         }
777
778         /* open file, direct io */
779         /* even if the file is only read, WR mode is nedeed to allow
780          * layout swap on fd */
781         fd = open(name, O_RDWR | O_DIRECT);
782         if (fd == -1) {
783                 rc = -errno;
784                 fprintf(stderr, "%s: %s: cannot open: %s\n", progname, name,
785                         strerror(-rc));
786                 goto free;
787         }
788
789         if (file_lease_supported) {
790                 rc = llapi_lease_get(fd, LL_LEASE_RDLCK);
791                 if (rc == -EOPNOTSUPP) {
792                         /* Older servers do not support file lease.
793                          * Disable related checks. This opens race conditions
794                          * as explained in LU-4840 */
795                         file_lease_supported = false;
796                 } else if (rc < 0) {
797                         fprintf(stderr, "%s: %s: cannot get open lease: %s\n",
798                                 progname, name, strerror(-rc));
799                         goto error;
800                 } else {
801                         have_lease_rdlck = true;
802                 }
803         }
804
805         /* search for file directory pathname */
806         if (strlen(name) > sizeof(parent)-1) {
807                 rc = -E2BIG;
808                 goto error;
809         }
810         strncpy(parent, name, sizeof(parent));
811         ptr = strrchr(parent, '/');
812         if (ptr == NULL) {
813                 if (getcwd(parent, sizeof(parent)) == NULL) {
814                         rc = -errno;
815                         goto error;
816                 }
817         } else {
818                 if (ptr == parent)
819                         strcpy(parent, "/");
820                 else
821                         *ptr = '\0';
822         }
823
824         rc = llapi_file_fget_mdtidx(fd, &mdt_index);
825         if (rc < 0) {
826                 fprintf(stderr, "%s: %s: cannot get MDT index: %s\n",
827                         progname, name, strerror(-rc));
828                 goto error;
829         }
830
831         do {
832                 int open_flags = O_WRONLY | O_CREAT | O_EXCL | O_NOFOLLOW;
833                 mode_t open_mode = S_IRUSR | S_IWUSR;
834
835                 random_value = random();
836                 rc = snprintf(volatile_file, sizeof(volatile_file),
837                               "%s/%s:%.4X:%.4X", parent, LUSTRE_VOLATILE_HDR,
838                               mdt_index, random_value);
839                 if (rc >= sizeof(volatile_file)) {
840                         rc = -E2BIG;
841                         goto error;
842                 }
843
844                 /* create, open a volatile file, use caching (ie no directio) */
845                 if (param != NULL)
846                         fdv = llapi_file_open_param(volatile_file, open_flags,
847                                                     open_mode, param);
848                 else if (layout != NULL)
849                         fdv = lfs_component_create(volatile_file, open_flags,
850                                                    open_mode, layout);
851                 else
852                         fdv = -EINVAL;
853         } while (fdv == -EEXIST);
854
855         if (fdv < 0) {
856                 rc = fdv;
857                 fprintf(stderr, "%s: %s: cannot create volatile file in"
858                                 " directory: %s\n",
859                         progname, parent, strerror(-rc));
860                 goto error;
861         }
862
863         /* In case the MDT does not support creation of volatile files
864          * we should try to unlink it. */
865         (void)unlink(volatile_file);
866
867         /* Not-owner (root?) special case.
868          * Need to set owner/group of volatile file like original.
869          * This will allow to pass related check during layout_swap.
870          */
871         rc = fstat(fd, &st);
872         if (rc != 0) {
873                 rc = -errno;
874                 fprintf(stderr, "%s: %s: cannot stat: %s\n", progname, name,
875                         strerror(errno));
876                 goto error;
877         }
878         rc = fstat(fdv, &stv);
879         if (rc != 0) {
880                 rc = -errno;
881                 fprintf(stderr, "%s: %s: cannot stat: %s\n", progname,
882                         volatile_file, strerror(errno));
883                 goto error;
884         }
885         if (st.st_uid != stv.st_uid || st.st_gid != stv.st_gid) {
886                 rc = fchown(fdv, st.st_uid, st.st_gid);
887                 if (rc != 0) {
888                         rc = -errno;
889                         fprintf(stderr, "%s: %s: cannot chown: %s\n", progname,
890                                 name, strerror(errno));
891                         goto error;
892                 }
893         }
894
895         if (migration_flags & MIGRATION_NONBLOCK && file_lease_supported) {
896                 rc = migrate_nonblock(fd, fdv, &st, buf_size, name);
897                 if (rc == 0) {
898                         have_lease_rdlck = false;
899                         fdv = -1; /* The volatile file is closed as we put the
900                                    * lease in non-blocking mode. */
901                 }
902         } else {
903                 /* Blocking mode (forced if servers do not support file lease).
904                  * It is also the default mode, since we cannot distinguish
905                  * between a broken lease and a server that does not support
906                  * atomic swap/close (LU-6785) */
907                 rc = migrate_block(fd, fdv, &st, buf_size, name);
908         }
909
910 error:
911         if (have_lease_rdlck)
912                 llapi_lease_put(fd);
913
914         if (fd >= 0)
915                 close(fd);
916
917         if (fdv >= 0)
918                 close(fdv);
919
920 free:
921         if (lum)
922                 free(lum);
923
924         return rc;
925 }
926
927 /**
928  * Parse a string containing an OST index list into an array of integers.
929  *
930  * The input string contains a comma delimited list of individual
931  * indices and ranges, for example "1,2-4,7". Add the indices into the
932  * \a osts array and remove duplicates.
933  *
934  * \param[out] osts    array to store indices in
935  * \param[in] size     size of \a osts array
936  * \param[in] offset   starting index in \a osts
937  * \param[in] arg      string containing OST index list
938  *
939  * \retval positive    number of indices in \a osts
940  * \retval -EINVAL     unable to parse \a arg
941  */
942 static int parse_targets(__u32 *osts, int size, int offset, char *arg)
943 {
944         int rc;
945         int nr = offset;
946         int slots = size - offset;
947         char *ptr = NULL;
948         bool end_of_loop;
949
950         if (arg == NULL)
951                 return -EINVAL;
952
953         end_of_loop = false;
954         while (!end_of_loop) {
955                 int start_index;
956                 int end_index;
957                 int i;
958                 char *endptr = NULL;
959
960                 rc = -EINVAL;
961
962                 ptr = strchrnul(arg, ',');
963
964                 end_of_loop = *ptr == '\0';
965                 *ptr = '\0';
966
967                 start_index = strtol(arg, &endptr, 0);
968                 if (endptr == arg) /* no data at all */
969                         break;
970                 if (*endptr != '-' && *endptr != '\0') /* has invalid data */
971                         break;
972                 if (start_index < 0)
973                         break;
974
975                 end_index = start_index;
976                 if (*endptr == '-') {
977                         end_index = strtol(endptr + 1, &endptr, 0);
978                         if (*endptr != '\0')
979                                 break;
980                         if (end_index < start_index)
981                                 break;
982                 }
983
984                 for (i = start_index; i <= end_index && slots > 0; i++) {
985                         int j;
986
987                         /* remove duplicate */
988                         for (j = 0; j < offset; j++) {
989                                 if (osts[j] == i)
990                                         break;
991                         }
992                         if (j == offset) { /* no duplicate */
993                                 osts[nr++] = i;
994                                 --slots;
995                         }
996                 }
997                 if (slots == 0 && i < end_index)
998                         break;
999
1000                 *ptr = ',';
1001                 arg = ++ptr;
1002                 offset = nr;
1003                 rc = 0;
1004         }
1005         if (!end_of_loop && ptr != NULL)
1006                 *ptr = ',';
1007
1008         return rc < 0 ? rc : nr;
1009 }
1010
1011 static int verify_pool_name(char *prog_name, char *pool_name)
1012 {
1013         char    *ptr;
1014         int      rc;
1015
1016         if (pool_name == NULL)
1017                 return 0;
1018
1019         ptr = strchr(pool_name, '.');
1020         if (ptr == NULL) {
1021                 ptr = pool_name;
1022         } else {
1023                 if (ptr == pool_name) {
1024                         fprintf(stderr, "error: %s: fsname is empty "
1025                                 "in pool name '%s'\n",
1026                                 prog_name, pool_name);
1027                         return -EINVAL;
1028                 }
1029                 ++ptr;
1030         }
1031
1032         rc = lustre_is_poolname_valid(ptr, 1, LOV_MAXPOOLNAME);
1033         if (rc == -1) {
1034                 fprintf(stderr, "error: %s: poolname '%s' is empty\n",
1035                         prog_name, pool_name);
1036                 return -EINVAL;
1037         } else if (rc == -2) {
1038                 fprintf(stderr, "error: %s: pool name '%s' is too long "
1039                         "(max is %d characters)\n",
1040                         prog_name, pool_name, LOV_MAXPOOLNAME);
1041                 return -EINVAL;
1042         } else if (rc > 0) {
1043                 fprintf(stderr, "error: %s: char '%c' not allowed in "
1044                         "pool name '%s'\n",
1045                         prog_name, rc, pool_name);
1046                 return -EINVAL;
1047         }
1048         return rc;
1049 }
1050
1051 struct lfs_setstripe_args {
1052         unsigned long long       lsa_comp_end;
1053         unsigned long long       lsa_stripe_size;
1054         int                      lsa_stripe_count;
1055         int                      lsa_stripe_off;
1056         __u32                    lsa_comp_flags;
1057         int                      lsa_nr_osts;
1058         __u32                   *lsa_osts;
1059         char                    *lsa_pool_name;
1060 };
1061
1062 static inline void setstripe_args_init(struct lfs_setstripe_args *lsa)
1063 {
1064         memset(lsa, 0, sizeof(*lsa));
1065         lsa->lsa_stripe_off = -1;
1066 }
1067
1068 static inline bool setstripe_args_specified(struct lfs_setstripe_args *lsa)
1069 {
1070         return (lsa->lsa_stripe_size != 0 || lsa->lsa_stripe_count != 0 ||
1071                 lsa->lsa_stripe_off != -1 || lsa->lsa_pool_name != NULL ||
1072                 lsa->lsa_comp_end != 0);
1073 }
1074
1075 static int comp_args_to_layout(struct llapi_layout **composite,
1076                                struct lfs_setstripe_args *lsa)
1077 {
1078         struct llapi_layout *layout = *composite;
1079         uint64_t prev_end = 0;
1080         int i = 0, rc;
1081
1082         if (layout == NULL) {
1083                 layout = llapi_layout_alloc();
1084                 if (layout == NULL) {
1085                         fprintf(stderr, "Alloc llapi_layout failed. %s\n",
1086                                 strerror(errno));
1087                         return -ENOMEM;
1088                 }
1089                 *composite = layout;
1090         } else {
1091                 uint64_t start;
1092
1093                 /* Get current component extent, current component
1094                  * must be the tail component. */
1095                 rc = llapi_layout_comp_extent_get(layout, &start, &prev_end);
1096                 if (rc) {
1097                         fprintf(stderr, "Get comp extent failed. %s\n",
1098                                 strerror(errno));
1099                         return rc;
1100                 }
1101
1102                 rc = llapi_layout_comp_add(layout);
1103                 if (rc) {
1104                         fprintf(stderr, "Add component failed. %s\n",
1105                                 strerror(errno));
1106                         return rc;
1107                 }
1108         }
1109
1110         rc = llapi_layout_comp_extent_set(layout, prev_end, lsa->lsa_comp_end);
1111         if (rc) {
1112                 fprintf(stderr, "Set extent [%lu, %llu) failed. %s\n",
1113                         prev_end, lsa->lsa_comp_end, strerror(errno));
1114                 return rc;
1115         }
1116
1117         if (lsa->lsa_stripe_size != 0) {
1118                 rc = llapi_layout_stripe_size_set(layout,
1119                                                   lsa->lsa_stripe_size);
1120                 if (rc) {
1121                         fprintf(stderr, "Set stripe size %llu failed. %s\n",
1122                                 lsa->lsa_stripe_size, strerror(errno));
1123                         return rc;
1124                 }
1125         }
1126
1127         if (lsa->lsa_stripe_count != 0) {
1128                 rc = llapi_layout_stripe_count_set(layout,
1129                                                    lsa->lsa_stripe_count == -1 ?
1130                                                    LLAPI_LAYOUT_WIDE :
1131                                                    lsa->lsa_stripe_count);
1132                 if (rc) {
1133                         fprintf(stderr, "Set stripe count %d failed. %s\n",
1134                                 lsa->lsa_stripe_count, strerror(errno));
1135                         return rc;
1136                 }
1137         }
1138
1139         if (lsa->lsa_pool_name != NULL) {
1140                 rc = llapi_layout_pool_name_set(layout, lsa->lsa_pool_name);
1141                 if (rc) {
1142                         fprintf(stderr, "Set pool name: %s failed. %s\n",
1143                                 lsa->lsa_pool_name, strerror(errno));
1144                         return rc;
1145                 }
1146         }
1147
1148         if (lsa->lsa_nr_osts > 0) {
1149                 if (lsa->lsa_stripe_count > 0 &&
1150                     lsa->lsa_nr_osts != lsa->lsa_stripe_count) {
1151                         fprintf(stderr, "stripe_count(%d) != nr_osts(%d)\n",
1152                                 lsa->lsa_stripe_count, lsa->lsa_nr_osts);
1153                         return -EINVAL;
1154                 }
1155                 for (i = 0; i < lsa->lsa_nr_osts; i++) {
1156                         rc = llapi_layout_ost_index_set(layout, i,
1157                                                         lsa->lsa_osts[i]);
1158                         if (rc)
1159                                 break;
1160                 }
1161         } else if (lsa->lsa_stripe_off != -1) {
1162                 rc = llapi_layout_ost_index_set(layout, 0, lsa->lsa_stripe_off);
1163         }
1164         if (rc) {
1165                 fprintf(stderr, "Set ost index %d failed. %s\n",
1166                         i, strerror(errno));
1167                 return rc;
1168         }
1169
1170         return 0;
1171 }
1172
1173 /* In 'lfs setstripe --component-add' mode, we need to fetch the extent
1174  * end of the last component in the existing file, and adjust the
1175  * first extent start of the components to be added accordingly. */
1176 static int adjust_first_extent(char *fname, struct llapi_layout *layout)
1177 {
1178         struct llapi_layout *head;
1179         uint64_t start, end, stripe_size, prev_end = 0;
1180         int rc;
1181
1182         if (layout == NULL)
1183                 return -EINVAL;
1184
1185         head = llapi_layout_get_by_path(fname, 0);
1186         if (head == NULL) {
1187                 fprintf(stderr, "Read layout from %s failed. %s\n",
1188                         fname, strerror(errno));
1189                 return -EINVAL;
1190         }
1191
1192         /* Current component of 'head' should be tail of component list. */
1193         rc = llapi_layout_comp_extent_get(head, &start, &prev_end);
1194         if (rc) {
1195                 fprintf(stderr, "Get prev extent failed. %s\n",
1196                         strerror(errno));
1197                 llapi_layout_free(head);
1198                 return rc;
1199         }
1200
1201         llapi_layout_free(head);
1202
1203         /* Make sure we use the first component of the layout to be added. */
1204         rc = llapi_layout_comp_use(layout, LLAPI_LAYOUT_COMP_USE_FIRST);
1205         if (rc < 0) {
1206                 fprintf(stderr, "Move component cursor failed. %s\n",
1207                         strerror(errno));
1208                 return rc;
1209         }
1210
1211         rc = llapi_layout_comp_extent_get(layout, &start, &end);
1212         if (rc) {
1213                 fprintf(stderr, "Get extent failed. %s\n", strerror(errno));
1214                 return rc;
1215         }
1216
1217         if (start > prev_end || end <= prev_end) {
1218                 fprintf(stderr, "First extent to be set [%lu, %lu) isn't "
1219                         "adjacent with the existing file extent end: %lu\n",
1220                         start, end, prev_end);
1221                 return -EINVAL;
1222         }
1223
1224         rc = llapi_layout_stripe_size_get(layout, &stripe_size);
1225         if (rc) {
1226                 fprintf(stderr, "Get stripe size failed. %s\n",
1227                         strerror(errno));
1228                 return rc;
1229         }
1230
1231         if (stripe_size != LLAPI_LAYOUT_DEFAULT &&
1232             (prev_end & (stripe_size - 1))) {
1233                 fprintf(stderr, "Stripe size %lu not aligned with %lu\n",
1234                         stripe_size, prev_end);
1235                 return -EINVAL;
1236         }
1237
1238         rc = llapi_layout_comp_extent_set(layout, prev_end, end);
1239         if (rc) {
1240                 fprintf(stderr, "Set component extent [%lu, %lu) failed. %s\n",
1241                         prev_end, end, strerror(errno));
1242                 return rc;
1243         }
1244
1245         return 0;
1246 }
1247
1248 static int comp_name2flags(__u32 *flags, char *name)
1249 {
1250         char *ptr;
1251
1252         if (name == NULL)
1253                 return -EINVAL;
1254
1255         *flags = 0;
1256         for (ptr = name; ; ptr = NULL) {
1257                 char *flg = strtok(ptr, ",");
1258                 if (flg == NULL)
1259                         break;
1260                 if (strcmp(flg, "init") == 0)
1261                         *flags |= LCME_FL_INIT;
1262                 else
1263                         return -EINVAL;
1264         }
1265         return (*flags == 0) ? -EINVAL : 0;
1266 }
1267
1268 enum {
1269         LFS_POOL_OPT = 3,
1270         LFS_COMP_COUNT_OPT,
1271         LFS_COMP_START_OPT,
1272         LFS_COMP_FLAGS_OPT,
1273         LFS_COMP_DEL_OPT,
1274         LFS_COMP_SET_OPT,
1275         LFS_COMP_ADD_OPT,
1276         LFS_PROJID_OPT,
1277 };
1278
1279 /* functions */
1280 static int lfs_setstripe(int argc, char **argv)
1281 {
1282         struct lfs_setstripe_args        lsa;
1283         struct llapi_stripe_param       *param = NULL;
1284         struct find_param                migrate_mdt_param = {
1285                 .fp_max_depth = -1,
1286                 .fp_mdt_index = -1,
1287         };
1288         char                            *fname;
1289         int                              result;
1290         int                              result2 = 0;
1291         char                            *end;
1292         int                              c;
1293         int                              delete = 0;
1294         char                            *mdt_idx_arg = NULL;
1295         unsigned long long               size_units = 1;
1296         bool                             migrate_mode = false;
1297         bool                             migration_block = false;
1298         __u64                            migration_flags = 0;
1299         __u32                            osts[LOV_MAX_STRIPE_COUNT] = { 0 };
1300         int                              comp_del = 0, comp_set = 0;
1301         int                              comp_add = 0;
1302         __u32                            comp_id = 0;
1303         struct llapi_layout             *layout = NULL;
1304
1305         struct option            long_opts[] = {
1306                 /* --block is only valid in migrate mode */
1307                 {"block",        no_argument,       0, 'b'},
1308                 {"comp-add",     no_argument,       0, LFS_COMP_ADD_OPT},
1309                 {"component-add", no_argument,      0, LFS_COMP_ADD_OPT},
1310                 {"comp-del",     no_argument,       0, LFS_COMP_DEL_OPT},
1311                 {"component-del", no_argument,      0, LFS_COMP_DEL_OPT},
1312                 {"comp-flags",   required_argument, 0, LFS_COMP_FLAGS_OPT},
1313                 {"component-flags", required_argument, 0, LFS_COMP_FLAGS_OPT},
1314                 {"comp-set",     no_argument,       0, LFS_COMP_SET_OPT},
1315                 {"component-set", no_argument,      0, LFS_COMP_SET_OPT},
1316 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
1317                 /* This formerly implied "stripe-count", but was explicitly
1318                  * made "stripe-count" for consistency with other options,
1319                  * and to separate it from "mdt-count" when DNE arrives. */
1320                 {"count",        required_argument, 0, 'c'},
1321 #endif
1322                 {"stripe-count", required_argument, 0, 'c'},
1323                 {"stripe_count", required_argument, 0, 'c'},
1324                 {"delete",       no_argument,       0, 'd'},
1325                 {"comp-end",     required_argument, 0, 'E'},
1326                 {"component-end", required_argument, 0, 'E'},
1327                 /* dirstripe {"mdt-hash",     required_argument, 0, 'H'}, */
1328 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
1329                 /* This formerly implied "stripe-index", but was explicitly
1330                  * made "stripe-index" for consistency with other options,
1331                  * and to separate it from "mdt-index" when DNE arrives. */
1332                 {"index",        required_argument, 0, 'i'},
1333 #endif
1334                 {"stripe-index", required_argument, 0, 'i'},
1335                 {"stripe_index", required_argument, 0, 'i'},
1336                 {"comp-id",      required_argument, 0, 'I'},
1337                 {"component-id", required_argument, 0, 'I'},
1338                 {"mdt",          required_argument, 0, 'm'},
1339                 {"mdt-index",    required_argument, 0, 'm'},
1340                 {"mdt_index",    required_argument, 0, 'm'},
1341                 /* --non-block is only valid in migrate mode */
1342                 {"non-block",    no_argument,       0, 'n'},
1343                 {"ost",          required_argument, 0, 'o'},
1344 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
1345                 {"ost-list",     required_argument, 0, 'o'},
1346                 {"ost_list",     required_argument, 0, 'o'},
1347 #endif
1348                 {"pool",         required_argument, 0, 'p'},
1349 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
1350                 /* This formerly implied "--stripe-size", but was confusing
1351                  * with "lfs find --size|-s", which means "file size", so use
1352                  * the consistent "--stripe-size|-S" for all commands. */
1353                 {"size",         required_argument, 0, 's'},
1354 #endif
1355                 {"stripe-size",  required_argument, 0, 'S'},
1356                 {"stripe_size",  required_argument, 0, 'S'},
1357                 /* dirstripe {"mdt-count",    required_argument, 0, 'T'}, */
1358                 /* --verbose is only valid in migrate mode */
1359                 {"verbose",      no_argument,       0, 'v'},
1360                 {0, 0, 0, 0}
1361         };
1362
1363         setstripe_args_init(&lsa);
1364
1365         if (strcmp(argv[0], "migrate") == 0)
1366                 migrate_mode = true;
1367
1368         while ((c = getopt_long(argc, argv, "bc:dE:i:I:m:no:p:s:S:v",
1369                                 long_opts, NULL)) >= 0) {
1370                 switch (c) {
1371                 case 0:
1372                         /* Long options. */
1373                         break;
1374                 case LFS_COMP_ADD_OPT:
1375                         comp_add = 1;
1376                         break;
1377                 case LFS_COMP_DEL_OPT:
1378                         comp_del = 1;
1379                         break;
1380                 case LFS_COMP_FLAGS_OPT:
1381                         result = comp_name2flags(&lsa.lsa_comp_flags, optarg);
1382                         if (result != 0) {
1383                                 fprintf(stderr, "error: %s: bad comp flags "
1384                                         "'%s'\n", argv[0], optarg);
1385                                 goto error;
1386                         }
1387                         break;
1388                 case LFS_COMP_SET_OPT:
1389                         comp_set = 1;
1390                         break;
1391                 case 'b':
1392                         if (!migrate_mode) {
1393                                 fprintf(stderr, "--block is valid only for"
1394                                                 " migrate mode\n");
1395                                 goto error;
1396                         }
1397                         migration_block = true;
1398                         break;
1399                 case 'c':
1400 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1401                         if (strcmp(argv[optind - 1], "--count") == 0)
1402                                 fprintf(stderr, "warning: '--count' deprecated"
1403                                         ", use '--stripe-count' instead\n");
1404 #endif
1405                         lsa.lsa_stripe_count = strtoul(optarg, &end, 0);
1406                         if (*end != '\0') {
1407                                 fprintf(stderr, "error: %s: bad stripe count "
1408                                         "'%s'\n", argv[0], optarg);
1409                                 goto error;
1410                         }
1411                         break;
1412                 case 'd':
1413                         /* delete the default striping pattern */
1414                         delete = 1;
1415                         break;
1416                 case 'E':
1417                         if (lsa.lsa_comp_end != 0) {
1418                                 result = comp_args_to_layout(&layout, &lsa);
1419                                 if (result)
1420                                         goto error;
1421
1422                                 setstripe_args_init(&lsa);
1423                         }
1424
1425                         if (!strncmp(optarg, "-1", strlen("-1")) ||
1426                             !strncmp(optarg, "EOF", strlen("EOF")) ||
1427                             !strncmp(optarg, "eof", strlen("eof"))) {
1428                                 lsa.lsa_comp_end = LUSTRE_EOF;
1429                         } else {
1430                                 result = llapi_parse_size(optarg,
1431                                                         &lsa.lsa_comp_end,
1432                                                         &size_units, 0);
1433                                 if (result) {
1434                                         fprintf(stderr, "error: %s: "
1435                                                 "bad component end '%s'\n",
1436                                                 argv[0], optarg);
1437                                         goto error;
1438                                 }
1439                         }
1440                         break;
1441                 case 'i':
1442                         if (strcmp(argv[optind - 1], "--index") == 0)
1443                                 fprintf(stderr, "warning: '--index' deprecated"
1444                                         ", use '--stripe-index' instead\n");
1445                         lsa.lsa_stripe_off = strtol(optarg, &end, 0);
1446                         if (*end != '\0') {
1447                                 fprintf(stderr, "error: %s: bad stripe offset "
1448                                         "'%s'\n", argv[0], optarg);
1449                                 goto error;
1450                         }
1451                         break;
1452                 case 'I':
1453                         comp_id = strtoul(optarg, &end, 0);
1454                         if (*end != '\0' || comp_id == 0) {
1455                                 fprintf(stderr, "error: %s: bad comp ID "
1456                                         "'%s'\n", argv[0], optarg);
1457                                 goto error;
1458                         }
1459                         break;
1460                 case 'm':
1461                         if (!migrate_mode) {
1462                                 fprintf(stderr, "--mdt-index is valid only for"
1463                                                 " migrate mode\n");
1464                                 goto error;
1465                         }
1466                         mdt_idx_arg = optarg;
1467                         break;
1468                 case 'n':
1469                         if (!migrate_mode) {
1470                                 fprintf(stderr, "--non-block is valid only for"
1471                                                 " migrate mode\n");
1472                                 goto error;
1473                         }
1474                         migration_flags |= MIGRATION_NONBLOCK;
1475                         break;
1476                 case 'o':
1477                         lsa.lsa_nr_osts = parse_targets(osts,
1478                                                 sizeof(osts) / sizeof(__u32),
1479                                                 lsa.lsa_nr_osts, optarg);
1480                         if (lsa.lsa_nr_osts < 0) {
1481                                 fprintf(stderr,
1482                                         "error: %s: bad OST indices '%s'\n",
1483                                         argv[0], optarg);
1484                                 goto error;
1485                         }
1486
1487                         lsa.lsa_osts = osts;
1488                         if (lsa.lsa_stripe_off == -1)
1489                                 lsa.lsa_stripe_off = osts[0];
1490                         break;
1491                 case 'p':
1492                         result = verify_pool_name(argv[0], optarg);
1493                         if (result)
1494                                 goto error;
1495                         lsa.lsa_pool_name = optarg;
1496                         break;
1497 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
1498                 case 's':
1499 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1500                         fprintf(stderr, "warning: '--size|-s' deprecated, "
1501                                 "use '--stripe-size|-S' instead\n");
1502 #endif
1503 #endif /* LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0) */
1504                 case 'S':
1505                         result = llapi_parse_size(optarg, &lsa.lsa_stripe_size,
1506                                                   &size_units, 0);
1507                         if (result) {
1508                                 fprintf(stderr, "error: %s: bad stripe size "
1509                                         "'%s'\n", argv[0], optarg);
1510                                 goto error;
1511                         }
1512                         break;
1513                 case 'v':
1514                         if (!migrate_mode) {
1515                                 fprintf(stderr, "--verbose is valid only for"
1516                                                 " migrate mode\n");
1517                                 goto error;
1518                         }
1519                         migrate_mdt_param.fp_verbose = VERBOSE_DETAIL;
1520                         break;
1521                 default:
1522                         goto error;
1523                 }
1524         }
1525
1526         fname = argv[optind];
1527
1528         if (lsa.lsa_comp_end != 0) {
1529                 result = comp_args_to_layout(&layout, &lsa);
1530                 if (result)
1531                         goto error;
1532         }
1533
1534         if (optind == argc) {
1535                 fprintf(stderr, "error: %s: missing filename|dirname\n",
1536                         argv[0]);
1537                 goto error;
1538         }
1539
1540         /* Only LCME_FL_INIT flags is used in PFL, and it shouldn't be
1541          * altered by user space tool, so we don't need to support the
1542          * --component-set for this moment. */
1543         if (comp_set != 0) {
1544                 fprintf(stderr, "error: %s: --component-set isn't supported.\n",
1545                         argv[0]);
1546                 goto error;
1547         }
1548
1549         if ((delete + comp_set + comp_del + comp_add) > 1) {
1550                 fprintf(stderr, "error: %s: can't specify --component-set, "
1551                         "--component-del, --component-add or -d together\n",
1552                         argv[0]);
1553                 goto error;
1554         }
1555
1556         if (delete && (setstripe_args_specified(&lsa) || comp_id != 0 ||
1557                        lsa.lsa_comp_flags != 0 || layout != NULL)) {
1558                 fprintf(stderr, "error: %s: can't specify -d with "
1559                         "-s, -c, -o, -p, -I, -F or -E options\n",
1560                         argv[0]);
1561                 goto error;
1562         }
1563
1564         if ((comp_set || comp_del) &&
1565             (setstripe_args_specified(&lsa) || layout != NULL)) {
1566                 fprintf(stderr, "error: %s: can't specify --component-del or "
1567                         "--component-set with -s, -c, -o, -p or -E options.\n",
1568                         argv[0]);
1569                 goto error;
1570         }
1571
1572         if (comp_del && comp_id != 0 && lsa.lsa_comp_flags != 0) {
1573                 fprintf(stderr, "error: %s: can't specify both -I and -F for "
1574                         "--component-del option.\n", argv[0]);
1575                 goto error;
1576         }
1577
1578         if (comp_add) {
1579                 if (layout == NULL) {
1580                         fprintf(stderr, "error: %s: -E option must be present"
1581                                 "in --component-add mode.\n", argv[0]);
1582                         goto error;
1583                 }
1584                 result = adjust_first_extent(fname, layout);
1585                 if (result != 0)
1586                         goto error;
1587         }
1588
1589         if (mdt_idx_arg != NULL && optind > 3) {
1590                 fprintf(stderr, "error: %s: cannot specify -m with other "
1591                         "options\n", argv[0]);
1592                 goto error;
1593         }
1594
1595         if ((migration_flags & MIGRATION_NONBLOCK) && migration_block) {
1596                 fprintf(stderr,
1597                         "error: %s: cannot specify --non-block and --block\n",
1598                         argv[0]);
1599                 goto error;
1600         }
1601
1602         /* support --component-id option for migrate later. */
1603         if (migrate_mode && comp_id != 0) {
1604                 fprintf(stderr, "error: %s: -I isn't supported yet.\n",
1605                         argv[0]);
1606                 goto error;
1607         }
1608
1609         if (mdt_idx_arg != NULL) {
1610                 /* initialize migrate mdt parameters */
1611                 migrate_mdt_param.fp_mdt_index = strtoul(mdt_idx_arg, &end, 0);
1612                 if (*end != '\0') {
1613                         fprintf(stderr, "error: %s: bad MDT index '%s'\n",
1614                                 argv[0], mdt_idx_arg);
1615                         goto error;
1616                 }
1617                 migrate_mdt_param.fp_migrate = 1;
1618         } else if (layout == NULL) {
1619                 /* initialize stripe parameters */
1620                 param = calloc(1, offsetof(typeof(*param),
1621                                lsp_osts[lsa.lsa_nr_osts]));
1622                 if (param == NULL) {
1623                         fprintf(stderr, "error: %s: %s\n", argv[0],
1624                                 strerror(ENOMEM));
1625                         goto error;
1626                 }
1627
1628                 param->lsp_stripe_size = lsa.lsa_stripe_size;
1629                 param->lsp_stripe_offset = lsa.lsa_stripe_off;
1630                 param->lsp_stripe_count = lsa.lsa_stripe_count;
1631                 param->lsp_stripe_pattern = 0;
1632                 param->lsp_pool = lsa.lsa_pool_name;
1633                 param->lsp_is_specific = false;
1634                 if (lsa.lsa_nr_osts > 0) {
1635                         if (lsa.lsa_stripe_count > 0 &&
1636                             lsa.lsa_nr_osts != lsa.lsa_stripe_count) {
1637                                 fprintf(stderr, "error: %s: stripe count '%d' "
1638                                         "doesn't match the number of OSTs: %d\n"
1639                                         , argv[0], lsa.lsa_stripe_count,
1640                                         lsa.lsa_nr_osts);
1641                                 free(param);
1642                                 goto error;
1643                         }
1644
1645                         param->lsp_is_specific = true;
1646                         param->lsp_stripe_count = lsa.lsa_nr_osts;
1647                         memcpy(param->lsp_osts, osts,
1648                                sizeof(*osts) * lsa.lsa_nr_osts);
1649                 }
1650         }
1651
1652         for (fname = argv[optind]; fname != NULL; fname = argv[++optind]) {
1653                 char *op;
1654                 if (mdt_idx_arg != NULL) {
1655                         result = llapi_migrate_mdt(fname, &migrate_mdt_param);
1656                         op = "migrate mdt objects of";
1657                 } else if (migrate_mode) {
1658                         result = lfs_migrate(fname, migration_flags, param,
1659                                              layout);
1660                         op = "migrate ost objects of";
1661                 } else if (comp_set != 0) {
1662                         result = lfs_component_set(fname, comp_id,
1663                                                    lsa.lsa_comp_flags);
1664                         op = "modify component flags of";
1665                 } else if (comp_del != 0) {
1666                         result = lfs_component_del(fname, comp_id,
1667                                                    lsa.lsa_comp_flags);
1668                         op = "delete component of";
1669                 } else if (comp_add != 0) {
1670                         result = lfs_component_add(fname, layout);
1671                         op = "add component to";
1672                 } else if (layout != NULL) {
1673                         result = lfs_component_create(fname, O_CREAT | O_WRONLY,
1674                                                       0644, layout);
1675                         if (result >= 0) {
1676                                 close(result);
1677                                 result = 0;
1678                         }
1679                         op = "create composite";
1680                 } else {
1681                         result = llapi_file_open_param(fname,
1682                                                        O_CREAT | O_WRONLY,
1683                                                        0644, param);
1684                         if (result >= 0) {
1685                                 close(result);
1686                                 result = 0;
1687                         }
1688                         op = "create striped";
1689                 }
1690                 if (result) {
1691                         /* Save the first error encountered. */
1692                         if (result2 == 0)
1693                                 result2 = result;
1694                         fprintf(stderr, "error: %s: %s file '%s' failed: %s\n",
1695                                 argv[0], op, fname,
1696                                 lsa.lsa_pool_name != NULL && result == EINVAL ?
1697                                 "OST not in pool?" : strerror(errno));
1698                         continue;
1699                 }
1700         }
1701
1702         free(param);
1703         llapi_layout_free(layout);
1704         return result2;
1705 error:
1706         llapi_layout_free(layout);
1707         return CMD_HELP;
1708 }
1709
1710 static int lfs_poollist(int argc, char **argv)
1711 {
1712         if (argc != 2)
1713                 return CMD_HELP;
1714
1715         return llapi_poollist(argv[1]);
1716 }
1717
1718 static int set_time(time_t *time, time_t *set, char *str)
1719 {
1720         time_t t;
1721         int res = 0;
1722
1723         if (str[0] == '+')
1724                 res = 1;
1725         else if (str[0] == '-')
1726                 res = -1;
1727
1728         if (res)
1729                 str++;
1730
1731         t = strtol(str, NULL, 0);
1732         if (*time < t * 24 * 60 * 60) {
1733                 if (res)
1734                         str--;
1735                 fprintf(stderr, "Wrong time '%s' is specified.\n", str);
1736                 return INT_MAX;
1737         }
1738
1739         *set = *time - t * 24 * 60 * 60;
1740         return res;
1741 }
1742 static int name2uid(unsigned int *id, const char *name)
1743 {
1744         struct passwd *passwd;
1745
1746         passwd = getpwnam(name);
1747         if (passwd == NULL)
1748                 return -ENOENT;
1749         *id = passwd->pw_uid;
1750
1751         return 0;
1752 }
1753
1754 static int name2gid(unsigned int *id, const char *name)
1755 {
1756         struct group *group;
1757
1758         group = getgrnam(name);
1759         if (group == NULL)
1760                 return -ENOENT;
1761         *id = group->gr_gid;
1762
1763         return 0;
1764 }
1765
1766 static inline int name2projid(unsigned int *id, const char *name)
1767 {
1768         return -ENOTSUP;
1769 }
1770
1771 static int uid2name(char **name, unsigned int id)
1772 {
1773         struct passwd *passwd;
1774
1775         passwd = getpwuid(id);
1776         if (passwd == NULL)
1777                 return -ENOENT;
1778         *name = passwd->pw_name;
1779
1780         return 0;
1781 }
1782
1783 static inline int gid2name(char **name, unsigned int id)
1784 {
1785         struct group *group;
1786
1787         group = getgrgid(id);
1788         if (group == NULL)
1789                 return -ENOENT;
1790         *name = group->gr_name;
1791
1792         return 0;
1793 }
1794
1795 static int name2layout(__u32 *layout, char *name)
1796 {
1797         char *ptr, *lyt;
1798
1799         *layout = 0;
1800         for (ptr = name; ; ptr = NULL) {
1801                 lyt = strtok(ptr, ",");
1802                 if (lyt == NULL)
1803                         break;
1804                 if (strcmp(lyt, "released") == 0)
1805                         *layout |= LOV_PATTERN_F_RELEASED;
1806                 else if (strcmp(lyt, "raid0") == 0)
1807                         *layout |= LOV_PATTERN_RAID0;
1808                 else
1809                         return -1;
1810         }
1811         return 0;
1812 }
1813
1814 static int lfs_find(int argc, char **argv)
1815 {
1816         int c, rc;
1817         int ret = 0;
1818         time_t t;
1819         struct find_param param = {
1820                 .fp_max_depth = -1,
1821                 .fp_quiet = 1,
1822         };
1823         struct option long_opts[] = {
1824                 {"atime",        required_argument, 0, 'A'},
1825                 {"comp-count",   required_argument, 0, LFS_COMP_COUNT_OPT},
1826                 {"component-count", required_argument, 0, LFS_COMP_COUNT_OPT},
1827                 {"comp-flags",   required_argument, 0, LFS_COMP_FLAGS_OPT},
1828                 {"component-flags", required_argument, 0, LFS_COMP_FLAGS_OPT},
1829                 {"comp-start",   required_argument, 0, LFS_COMP_START_OPT},
1830                 {"component-start", required_argument, 0, LFS_COMP_START_OPT},
1831                 {"stripe-count", required_argument, 0, 'c'},
1832                 {"stripe_count", required_argument, 0, 'c'},
1833                 {"ctime",        required_argument, 0, 'C'},
1834                 {"maxdepth",     required_argument, 0, 'D'},
1835                 {"comp-end",     required_argument, 0, 'E'},
1836                 {"component-end", required_argument, 0, 'E'},
1837                 {"gid",          required_argument, 0, 'g'},
1838                 {"group",        required_argument, 0, 'G'},
1839                 {"mdt-hash",     required_argument, 0, 'H'},
1840                 {"stripe-index", required_argument, 0, 'i'},
1841                 {"stripe_index", required_argument, 0, 'i'},
1842                 /*{"component-id", required_argument, 0, 'I'},*/
1843                 {"layout",       required_argument, 0, 'L'},
1844                 {"mdt",          required_argument, 0, 'm'},
1845                 {"mdt-index",    required_argument, 0, 'm'},
1846                 {"mdt_index",    required_argument, 0, 'm'},
1847                 {"mtime",        required_argument, 0, 'M'},
1848                 {"name",         required_argument, 0, 'n'},
1849      /* reserve {"or",           no_argument,     , 0, 'o'}, to match find(1) */
1850                 {"obd",          required_argument, 0, 'O'},
1851                 {"ost",          required_argument, 0, 'O'},
1852                 /* no short option for pool, p/P already used */
1853                 {"pool",         required_argument, 0, LFS_POOL_OPT},
1854                 {"print0",       no_argument,       0, 'p'},
1855                 {"print",        no_argument,       0, 'P'},
1856                 {"projid",       required_argument, 0, LFS_PROJID_OPT},
1857                 {"size",         required_argument, 0, 's'},
1858                 {"stripe-size",  required_argument, 0, 'S'},
1859                 {"stripe_size",  required_argument, 0, 'S'},
1860                 {"type",         required_argument, 0, 't'},
1861                 {"mdt-count",    required_argument, 0, 'T'},
1862                 {"uid",          required_argument, 0, 'u'},
1863                 {"user",         required_argument, 0, 'U'},
1864                 {0, 0, 0, 0}
1865         };
1866         int pathstart = -1;
1867         int pathend = -1;
1868         int neg_opt = 0;
1869         time_t *xtime;
1870         int *xsign;
1871         int isoption;
1872         char *endptr;
1873
1874         time(&t);
1875
1876         /* when getopt_long_only() hits '!' it returns 1, puts "!" in optarg */
1877         while ((c = getopt_long_only(argc, argv,
1878                         "-A:c:C:D:E:g:G:H:i:L:m:M:n:O:Ppqrs:S:t:T:u:U:v",
1879                         long_opts, NULL)) >= 0) {
1880                 xtime = NULL;
1881                 xsign = NULL;
1882                 if (neg_opt)
1883                         --neg_opt;
1884                 /* '!' is part of option */
1885                 /* when getopt_long_only() finds a string which is not
1886                  * an option nor a known option argument it returns 1
1887                  * in that case if we already have found pathstart and pathend
1888                  * (i.e. we have the list of pathnames),
1889                  * the only supported value is "!"
1890                  */
1891                 isoption = (c != 1) || (strcmp(optarg, "!") == 0);
1892                 if (!isoption && pathend != -1) {
1893                         fprintf(stderr, "err: %s: filename|dirname must either "
1894                                         "precede options or follow options\n",
1895                                         argv[0]);
1896                         ret = CMD_HELP;
1897                         goto err;
1898                 }
1899                 if (!isoption && pathstart == -1)
1900                         pathstart = optind - 1;
1901                 if (isoption && pathstart != -1 && pathend == -1)
1902                         pathend = optind - 2;
1903                 switch (c) {
1904                 case 0:
1905                         /* Long options. */
1906                         break;
1907                 case 1:
1908                         /* unknown; opt is "!" or path component,
1909                          * checking done above.
1910                          */
1911                         if (strcmp(optarg, "!") == 0)
1912                                 neg_opt = 2;
1913                         break;
1914                 case 'A':
1915                         xtime = &param.fp_atime;
1916                         xsign = &param.fp_asign;
1917                         param.fp_exclude_atime = !!neg_opt;
1918                         /* no break, this falls through to 'C' for ctime */
1919                 case 'C':
1920                         if (c == 'C') {
1921                                 xtime = &param.fp_ctime;
1922                                 xsign = &param.fp_csign;
1923                                 param.fp_exclude_ctime = !!neg_opt;
1924                         }
1925                         /* no break, this falls through to 'M' for mtime */
1926                 case 'M':
1927                         if (c == 'M') {
1928                                 xtime = &param.fp_mtime;
1929                                 xsign = &param.fp_msign;
1930                                 param.fp_exclude_mtime = !!neg_opt;
1931                         }
1932                         rc = set_time(&t, xtime, optarg);
1933                         if (rc == INT_MAX) {
1934                                 ret = -1;
1935                                 goto err;
1936                         }
1937                         if (rc)
1938                                 *xsign = rc;
1939                         break;
1940                 case LFS_COMP_COUNT_OPT:
1941                         if (optarg[0] == '+') {
1942                                 param.fp_comp_count_sign = -1;
1943                                 optarg++;
1944                         } else if (optarg[0] == '-') {
1945                                 param.fp_comp_count_sign =  1;
1946                                 optarg++;
1947                         }
1948
1949                         param.fp_comp_count = strtoul(optarg, &endptr, 0);
1950                         if (*endptr != '\0') {
1951                                 fprintf(stderr, "error: bad component count "
1952                                         "'%s'\n", optarg);
1953                                 goto err;
1954                         }
1955                         param.fp_check_comp_count = 1;
1956                         param.fp_exclude_comp_count = !!neg_opt;
1957                         break;
1958                 case LFS_COMP_FLAGS_OPT:
1959                         rc = comp_name2flags(&param.fp_comp_flags, optarg);
1960                         if (rc) {
1961                                 fprintf(stderr, "error: bad component flags "
1962                                         "'%s'\n", optarg);
1963                                 goto err;
1964                         }
1965                         param.fp_check_comp_flags = 1;
1966                         param.fp_exclude_comp_flags = !!neg_opt;
1967                         break;
1968                 case LFS_COMP_START_OPT:
1969                         if (optarg[0] == '+') {
1970                                 param.fp_comp_start_sign = -1;
1971                                 optarg++;
1972                         } else if (optarg[0] == '-') {
1973                                 param.fp_comp_start_sign =  1;
1974                                 optarg++;
1975                         }
1976
1977                         rc = llapi_parse_size(optarg, &param.fp_comp_start,
1978                                               &param.fp_comp_start_units, 0);
1979                         if (rc) {
1980                                 fprintf(stderr, "error: bad component start "
1981                                         "'%s'\n", optarg);
1982                                 goto err;
1983                         }
1984                         param.fp_check_comp_start = 1;
1985                         param.fp_exclude_comp_start = !!neg_opt;
1986                         break;
1987                 case 'c':
1988                         if (optarg[0] == '+') {
1989                                 param.fp_stripe_count_sign = -1;
1990                                 optarg++;
1991                         } else if (optarg[0] == '-') {
1992                                 param.fp_stripe_count_sign =  1;
1993                                 optarg++;
1994                         }
1995
1996                         param.fp_stripe_count = strtoul(optarg, &endptr, 0);
1997                         if (*endptr != '\0') {
1998                                 fprintf(stderr,"error: bad stripe_count '%s'\n",
1999                                         optarg);
2000                                 ret = -1;
2001                                 goto err;
2002                         }
2003                         param.fp_check_stripe_count = 1;
2004                         param.fp_exclude_stripe_count = !!neg_opt;
2005                         break;
2006                 case 'D':
2007                         param.fp_max_depth = strtol(optarg, 0, 0);
2008                         break;
2009                 case 'E':
2010                         if (optarg[0] == '+') {
2011                                 param.fp_comp_end_sign = -1;
2012                                 optarg++;
2013                         } else if (optarg[0] == '-') {
2014                                 param.fp_comp_end_sign =  1;
2015                                 optarg++;
2016                         }
2017
2018                         rc = llapi_parse_size(optarg, &param.fp_comp_end,
2019                                               &param.fp_comp_end_units, 0);
2020                         if (rc) {
2021                                 fprintf(stderr, "error: bad component end "
2022                                         "'%s'\n", optarg);
2023                                 goto err;
2024                         }
2025                         param.fp_check_comp_end = 1;
2026                         param.fp_exclude_comp_end = !!neg_opt;
2027                         break;
2028                 case 'g':
2029                 case 'G':
2030                         rc = name2gid(&param.fp_gid, optarg);
2031                         if (rc) {
2032                                 param.fp_gid = strtoul(optarg, &endptr, 10);
2033                                 if (*endptr != '\0') {
2034                                         fprintf(stderr, "Group/GID: %s cannot "
2035                                                 "be found.\n", optarg);
2036                                         ret = -1;
2037                                         goto err;
2038                                 }
2039                         }
2040                         param.fp_exclude_gid = !!neg_opt;
2041                         param.fp_check_gid = 1;
2042                         break;
2043                 case 'H':
2044                         param.fp_hash_type = check_hashtype(optarg);
2045                         if (param.fp_hash_type == 0) {
2046                                 fprintf(stderr, "error: bad hash_type '%s'\n",
2047                                         optarg);
2048                                 ret = -1;
2049                                 goto err;
2050                         }
2051                         param.fp_check_hash_type = 1;
2052                         param.fp_exclude_hash_type = !!neg_opt;
2053                         break;
2054                 case 'L':
2055                         ret = name2layout(&param.fp_layout, optarg);
2056                         if (ret)
2057                                 goto err;
2058                         param.fp_exclude_layout = !!neg_opt;
2059                         param.fp_check_layout = 1;
2060                         break;
2061                 case 'u':
2062                 case 'U':
2063                         rc = name2uid(&param.fp_uid, optarg);
2064                         if (rc) {
2065                                 param.fp_uid = strtoul(optarg, &endptr, 10);
2066                                 if (*endptr != '\0') {
2067                                         fprintf(stderr, "User/UID: %s cannot "
2068                                                 "be found.\n", optarg);
2069                                         ret = -1;
2070                                         goto err;
2071                                 }
2072                         }
2073                         param.fp_exclude_uid = !!neg_opt;
2074                         param.fp_check_uid = 1;
2075                         break;
2076                 case LFS_POOL_OPT:
2077                         if (strlen(optarg) > LOV_MAXPOOLNAME) {
2078                                 fprintf(stderr,
2079                                         "Pool name %s is too long"
2080                                         " (max is %d)\n", optarg,
2081                                         LOV_MAXPOOLNAME);
2082                                 ret = -1;
2083                                 goto err;
2084                         }
2085                         /* we do check for empty pool because empty pool
2086                          * is used to find V1 lov attributes */
2087                         strncpy(param.fp_poolname, optarg, LOV_MAXPOOLNAME);
2088                         param.fp_poolname[LOV_MAXPOOLNAME] = '\0';
2089                         param.fp_exclude_pool = !!neg_opt;
2090                         param.fp_check_pool = 1;
2091                         break;
2092                 case 'n':
2093                         param.fp_pattern = (char *)optarg;
2094                         param.fp_exclude_pattern = !!neg_opt;
2095                         break;
2096                 case 'm':
2097                 case 'i':
2098                 case 'O': {
2099                         char *buf, *token, *next, *p;
2100                         int len = 1;
2101                         void *tmp;
2102
2103                         buf = strdup(optarg);
2104                         if (buf == NULL) {
2105                                 ret = -ENOMEM;
2106                                 goto err;
2107                         }
2108
2109                         param.fp_exclude_obd = !!neg_opt;
2110
2111                         token = buf;
2112                         while (token && *token) {
2113                                 token = strchr(token, ',');
2114                                 if (token) {
2115                                         len++;
2116                                         token++;
2117                                 }
2118                         }
2119                         if (c == 'm') {
2120                                 param.fp_exclude_mdt = !!neg_opt;
2121                                 param.fp_num_alloc_mdts += len;
2122                                 tmp = realloc(param.fp_mdt_uuid,
2123                                               param.fp_num_alloc_mdts *
2124                                               sizeof(*param.fp_mdt_uuid));
2125                                 if (tmp == NULL) {
2126                                         ret = -ENOMEM;
2127                                         goto err_free;
2128                                 }
2129
2130                                 param.fp_mdt_uuid = tmp;
2131                         } else {
2132                                 param.fp_exclude_obd = !!neg_opt;
2133                                 param.fp_num_alloc_obds += len;
2134                                 tmp = realloc(param.fp_obd_uuid,
2135                                               param.fp_num_alloc_obds *
2136                                               sizeof(*param.fp_obd_uuid));
2137                                 if (tmp == NULL) {
2138                                         ret = -ENOMEM;
2139                                         goto err_free;
2140                                 }
2141
2142                                 param.fp_obd_uuid = tmp;
2143                         }
2144                         for (token = buf; token && *token; token = next) {
2145                                 struct obd_uuid *puuid;
2146                                 if (c == 'm') {
2147                                         puuid =
2148                                         &param.fp_mdt_uuid[param.fp_num_mdts++];
2149                                 } else {
2150                                         puuid =
2151                                         &param.fp_obd_uuid[param.fp_num_obds++];
2152                                 }
2153                                 p = strchr(token, ',');
2154                                 next = 0;
2155                                 if (p) {
2156                                         *p = 0;
2157                                         next = p+1;
2158                                 }
2159
2160                                 if (strlen(token) > sizeof(puuid->uuid) - 1) {
2161                                         ret = -E2BIG;
2162                                         goto err_free;
2163                                 }
2164
2165                                 strncpy(puuid->uuid, token,
2166                                         sizeof(puuid->uuid));
2167                         }
2168 err_free:
2169                         if (buf)
2170                                 free(buf);
2171                         break;
2172                 }
2173                 case 'p':
2174                         param.fp_zero_end = 1;
2175                         break;
2176                 case 'P':
2177                         break;
2178                 case LFS_PROJID_OPT:
2179                         rc = name2projid(&param.fp_projid, optarg);
2180                         if (rc) {
2181                                 param.fp_projid = strtoul(optarg, &endptr, 10);
2182                                 if (*endptr != '\0') {
2183                                         fprintf(stderr,
2184                                                 "Invalid project ID: %s",
2185                                                 optarg);
2186                                         ret = -1;
2187                                         goto err;
2188                                 }
2189                         }
2190                         param.fp_exclude_projid = !!neg_opt;
2191                         param.fp_check_projid = 1;
2192                         break;
2193                 case 's':
2194                         if (optarg[0] == '+') {
2195                                 param.fp_size_sign = -1;
2196                                 optarg++;
2197                         } else if (optarg[0] == '-') {
2198                                 param.fp_size_sign =  1;
2199                                 optarg++;
2200                         }
2201
2202                         ret = llapi_parse_size(optarg, &param.fp_size,
2203                                                &param.fp_size_units, 0);
2204                         if (ret) {
2205                                 fprintf(stderr, "error: bad file size '%s'\n",
2206                                         optarg);
2207                                 goto err;
2208                         }
2209                         param.fp_check_size = 1;
2210                         param.fp_exclude_size = !!neg_opt;
2211                         break;
2212                 case 'S':
2213                         if (optarg[0] == '+') {
2214                                 param.fp_stripe_size_sign = -1;
2215                                 optarg++;
2216                         } else if (optarg[0] == '-') {
2217                                 param.fp_stripe_size_sign =  1;
2218                                 optarg++;
2219                         }
2220
2221                         ret = llapi_parse_size(optarg, &param.fp_stripe_size,
2222                                                &param.fp_stripe_size_units, 0);
2223                         if (ret) {
2224                                 fprintf(stderr, "error: bad stripe_size '%s'\n",
2225                                         optarg);
2226                                 goto err;
2227                         }
2228                         param.fp_check_stripe_size = 1;
2229                         param.fp_exclude_stripe_size = !!neg_opt;
2230                         break;
2231                 case 't':
2232                         param.fp_exclude_type = !!neg_opt;
2233                         switch (optarg[0]) {
2234                         case 'b':
2235                                 param.fp_type = S_IFBLK;
2236                                 break;
2237                         case 'c':
2238                                 param.fp_type = S_IFCHR;
2239                                 break;
2240                         case 'd':
2241                                 param.fp_type = S_IFDIR;
2242                                 break;
2243                         case 'f':
2244                                 param.fp_type = S_IFREG;
2245                                 break;
2246                         case 'l':
2247                                 param.fp_type = S_IFLNK;
2248                                 break;
2249                         case 'p':
2250                                 param.fp_type = S_IFIFO;
2251                                 break;
2252                         case 's':
2253                                 param.fp_type = S_IFSOCK;
2254                                 break;
2255                         default:
2256                                 fprintf(stderr, "error: %s: bad type '%s'\n",
2257                                         argv[0], optarg);
2258                                 ret = CMD_HELP;
2259                                 goto err;
2260                         };
2261                         break;
2262                 case 'T':
2263                         if (optarg[0] == '+') {
2264                                 param.fp_mdt_count_sign = -1;
2265                                 optarg++;
2266                         } else if (optarg[0] == '-') {
2267                                 param.fp_mdt_count_sign =  1;
2268                                 optarg++;
2269                         }
2270
2271                         param.fp_mdt_count = strtoul(optarg, &endptr, 0);
2272                         if (*endptr != '\0') {
2273                                 fprintf(stderr, "error: bad mdt_count '%s'\n",
2274                                         optarg);
2275                                 ret = -1;
2276                                 goto err;
2277                         }
2278                         param.fp_check_mdt_count = 1;
2279                         param.fp_exclude_mdt_count = !!neg_opt;
2280                         break;
2281                 default:
2282                         ret = CMD_HELP;
2283                         goto err;
2284                 };
2285         }
2286
2287         if (pathstart == -1) {
2288                 fprintf(stderr, "error: %s: no filename|pathname\n",
2289                         argv[0]);
2290                 ret = CMD_HELP;
2291                 goto err;
2292         } else if (pathend == -1) {
2293                 /* no options */
2294                 pathend = argc;
2295         }
2296
2297         do {
2298                 rc = llapi_find(argv[pathstart], &param);
2299                 if (rc != 0 && ret == 0)
2300                         ret = rc;
2301         } while (++pathstart < pathend);
2302
2303         if (ret)
2304                 fprintf(stderr, "error: %s failed for %s.\n",
2305                         argv[0], argv[optind - 1]);
2306 err:
2307         if (param.fp_obd_uuid && param.fp_num_alloc_obds)
2308                 free(param.fp_obd_uuid);
2309
2310         if (param.fp_mdt_uuid && param.fp_num_alloc_mdts)
2311                 free(param.fp_mdt_uuid);
2312
2313         return ret;
2314 }
2315
2316 static int lfs_getstripe_internal(int argc, char **argv,
2317                                   struct find_param *param)
2318 {
2319         struct option long_opts[] = {
2320                 {"comp-count",          no_argument, 0, LFS_COMP_COUNT_OPT},
2321                 {"component-count",     no_argument, 0, LFS_COMP_COUNT_OPT},
2322                 {"comp-flags",      required_argument, 0, LFS_COMP_FLAGS_OPT},
2323                 {"component-flags", required_argument, 0, LFS_COMP_FLAGS_OPT},
2324                 {"comp-start",      required_argument, 0, LFS_COMP_START_OPT},
2325                 {"component-start", required_argument, 0, LFS_COMP_START_OPT},
2326 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2327                 /* This formerly implied "stripe-count", but was explicitly
2328                  * made "stripe-count" for consistency with other options,
2329                  * and to separate it from "mdt-count" when DNE arrives. */
2330                 {"count",               no_argument,            0, 'c'},
2331 #endif
2332                 {"stripe-count",        no_argument,            0, 'c'},
2333                 {"stripe_count",        no_argument,            0, 'c'},
2334                 {"directory",           no_argument,            0, 'd'},
2335                 {"default",             no_argument,            0, 'D'},
2336                 {"comp-end",            required_argument,      0, 'E'},
2337                 {"component-end",       required_argument,      0, 'E'},
2338                 {"fid",                 no_argument,            0, 'F'},
2339                 {"generation",          no_argument,            0, 'g'},
2340                 /* dirstripe {"mdt-hash",     required_argument, 0, 'H'}, */
2341 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2342                 /* This formerly implied "stripe-index", but was explicitly
2343                  * made "stripe-index" for consistency with other options,
2344                  * and to separate it from "mdt-index" when DNE arrives. */
2345                 {"index",               no_argument,            0, 'i'},
2346 #endif
2347                 {"stripe-index",        no_argument,            0, 'i'},
2348                 {"stripe_index",        no_argument,            0, 'i'},
2349                 {"comp-id",             required_argument,      0, 'I'},
2350                 {"component-id",        required_argument,      0, 'I'},
2351                 {"layout",              no_argument,            0, 'L'},
2352                 {"mdt",                 no_argument,            0, 'm'},
2353                 {"mdt-index",           no_argument,            0, 'm'},
2354                 {"mdt_index",           no_argument,            0, 'm'},
2355 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2356                 {"mdt-index",           no_argument,            0, 'M'},
2357                 {"mdt_index",           no_argument,            0, 'M'},
2358 #endif
2359 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2360                 /* This formerly implied "stripe-index", but was confusing
2361                  * with "file offset" (which will eventually be needed for
2362                  * with different layouts by offset), so deprecate it. */
2363                 {"offset",              no_argument,            0, 'o'},
2364 #endif
2365                 {"obd",                 required_argument,      0, 'O'},
2366                 {"ost",                 required_argument,      0, 'O'},
2367                 {"pool",                no_argument,            0, 'p'},
2368                 {"quiet",               no_argument,            0, 'q'},
2369                 {"recursive",           no_argument,            0, 'r'},
2370                 {"raw",                 no_argument,            0, 'R'},
2371 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2372                 /* This formerly implied "--stripe-size", but was confusing
2373                  * with "lfs find --size|-s", which means "file size", so use
2374                  * the consistent "--stripe-size|-S" for all commands. */
2375                 {"size",                no_argument,            0, 's'},
2376 #endif
2377                 {"stripe-size",         no_argument,            0, 'S'},
2378                 {"stripe_size",         no_argument,            0, 'S'},
2379                 /* dirstripe {"mdt-count",    required_argument, 0, 'T'}, */
2380                 {"verbose",             no_argument,            0, 'v'},
2381                 {0, 0, 0, 0}
2382         };
2383         int c, rc;
2384         char *end, *tmp;
2385
2386         while ((c = getopt_long(argc, argv, "cdDE:FghiI:LmMoO:pqrRsSv",
2387                                 long_opts, NULL)) != -1) {
2388                 switch (c) {
2389                 case 'c':
2390                         if (strcmp(argv[optind - 1], "--count") == 0)
2391                                 fprintf(stderr, "warning: '--count' deprecated,"
2392                                         " use '--stripe-count' instead\n");
2393                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2394                                 param->fp_verbose |= VERBOSE_COUNT;
2395                                 param->fp_max_depth = 0;
2396                         }
2397                         break;
2398                 case LFS_COMP_COUNT_OPT:
2399                         param->fp_verbose |= VERBOSE_COMP_COUNT;
2400                         param->fp_max_depth = 0;
2401                         break;
2402                 case LFS_COMP_FLAGS_OPT:
2403                         if (optarg != NULL) {
2404                                 rc = comp_name2flags(&param->fp_comp_flags,
2405                                                      optarg);
2406                                 if (rc != 0) {
2407                                         param->fp_verbose |=
2408                                                 VERBOSE_COMP_FLAGS;
2409                                         param->fp_max_depth = 0;
2410                                         optind--;
2411                                 } else {
2412                                         param->fp_check_comp_flags = 1;
2413                                 }
2414                         } else {
2415                                 param->fp_verbose |= VERBOSE_COMP_FLAGS;
2416                                 param->fp_max_depth = 0;
2417                         }
2418                         break;
2419                 case LFS_COMP_START_OPT:
2420                         if (optarg != NULL) {
2421                                 tmp = optarg;
2422                                 if (tmp[0] == '+') {
2423                                         param->fp_comp_start_sign = 1;
2424                                         tmp++;
2425                                 } else if (tmp[0] == '-') {
2426                                         param->fp_comp_start_sign = -1;
2427                                         tmp++;
2428                                 }
2429                                 rc = llapi_parse_size(tmp,
2430                                                 &param->fp_comp_start,
2431                                                 &param->fp_comp_start_units, 0);
2432                                 if (rc != 0) {
2433                                         param->fp_verbose |= VERBOSE_COMP_START;
2434                                         param->fp_max_depth = 0;
2435                                         optind--;
2436                                 } else {
2437                                         param->fp_check_comp_start = 1;
2438                                 }
2439                         } else {
2440                                 param->fp_verbose |= VERBOSE_COMP_START;
2441                                 param->fp_max_depth = 0;
2442                         }
2443                         break;
2444                 case 'd':
2445                         param->fp_max_depth = 0;
2446                         break;
2447                 case 'D':
2448                         param->fp_get_default_lmv = 1;
2449                         break;
2450                 case 'E':
2451                         if (optarg != NULL) {
2452                                 tmp = optarg;
2453                                 if (tmp[0] == '+') {
2454                                         param->fp_comp_end_sign = 1;
2455                                         tmp++;
2456                                 } else if (tmp[0] == '-') {
2457                                         param->fp_comp_end_sign = -1;
2458                                         tmp++;
2459                                 }
2460                                 rc = llapi_parse_size(tmp,
2461                                                 &param->fp_comp_end,
2462                                                 &param->fp_comp_end_units, 0);
2463                                 if (rc != 0) {
2464                                         param->fp_verbose |= VERBOSE_COMP_END;
2465                                         param->fp_max_depth = 0;
2466                                         optind--;
2467                                 } else {
2468                                         param->fp_check_comp_end = 1;
2469                                 }
2470                         } else {
2471                                 param->fp_verbose |= VERBOSE_COMP_END;
2472                                 param->fp_max_depth = 0;
2473                         }
2474                         break;
2475                 case 'F':
2476                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2477                                 param->fp_verbose |= VERBOSE_DFID;
2478                                 param->fp_max_depth = 0;
2479                         }
2480                         break;
2481                 case 'g':
2482                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2483                                 param->fp_verbose |= VERBOSE_GENERATION;
2484                                 param->fp_max_depth = 0;
2485                         }
2486                         break;
2487 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2488                 case 'o':
2489                         fprintf(stderr, "warning: '--offset|-o' deprecated, "
2490                                 "use '--stripe-index|-i' instead\n");
2491 #endif
2492                 case 'i':
2493 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
2494                         if (strcmp(argv[optind - 1], "--index") == 0)
2495                                 fprintf(stderr, "warning: '--index' deprecated"
2496                                         ", use '--stripe-index' instead\n");
2497 #endif
2498                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2499                                 param->fp_verbose |= VERBOSE_OFFSET;
2500                                 param->fp_max_depth = 0;
2501                         }
2502                         break;
2503                 case 'I':
2504                         if (optarg != NULL) {
2505                                 param->fp_comp_id = strtoul(optarg, &end, 0);
2506                                 if (*end != '\0') {
2507                                         param->fp_verbose |= VERBOSE_COMP_ID;
2508                                         param->fp_max_depth = 0;
2509                                         optind--;
2510                                 } else {
2511                                         param->fp_check_comp_id = 1;
2512                                 }
2513                         } else {
2514                                 param->fp_max_depth = 0;
2515                                 param->fp_verbose |= VERBOSE_COMP_ID;
2516                         }
2517                         break;
2518                 case 'L':
2519                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2520                                 param->fp_verbose |= VERBOSE_LAYOUT;
2521                                 param->fp_max_depth = 0;
2522                         }
2523                         break;
2524 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2525                 case 'M':
2526 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2527                         fprintf(stderr, "warning: '-M' deprecated"
2528                                 ", use '-m' instead\n");
2529 #endif
2530 #endif
2531                 case 'm':
2532                         if (!(param->fp_verbose & VERBOSE_DETAIL))
2533                                 param->fp_max_depth = 0;
2534                         param->fp_verbose |= VERBOSE_MDTINDEX;
2535                         break;
2536                 case 'O':
2537                         if (param->fp_obd_uuid) {
2538                                 fprintf(stderr,
2539                                         "error: %s: only one obduuid allowed",
2540                                         argv[0]);
2541                                 return CMD_HELP;
2542                         }
2543                         param->fp_obd_uuid = (struct obd_uuid *)optarg;
2544                         break;
2545                 case 'p':
2546                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2547                                 param->fp_verbose |= VERBOSE_POOL;
2548                                 param->fp_max_depth = 0;
2549                         }
2550                         break;
2551                 case 'q':
2552                         param->fp_quiet++;
2553                         break;
2554                 case 'r':
2555                         param->fp_recursive = 1;
2556                         break;
2557                 case 'R':
2558                         param->fp_raw = 1;
2559                         break;
2560 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2561                 case 's':
2562                         fprintf(stderr, "warning: '--size|-s' deprecated, "
2563                                 "use '--stripe-size|-S' instead\n");
2564 #endif /* LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0) */
2565                 case 'S':
2566                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2567                                 param->fp_verbose |= VERBOSE_SIZE;
2568                                 param->fp_max_depth = 0;
2569                         }
2570                         break;
2571                 case 'v':
2572                         param->fp_verbose = VERBOSE_DEFAULT | VERBOSE_DETAIL;
2573                         break;
2574                 default:
2575                         return CMD_HELP;
2576                 }
2577         }
2578
2579         if (optind >= argc)
2580                 return CMD_HELP;
2581
2582         if (param->fp_recursive)
2583                 param->fp_max_depth = -1;
2584         else if (param->fp_verbose & VERBOSE_DETAIL)
2585                 param->fp_max_depth = 1;
2586
2587         if (!param->fp_verbose)
2588                 param->fp_verbose = VERBOSE_DEFAULT;
2589         if (param->fp_quiet)
2590                 param->fp_verbose = VERBOSE_OBJID;
2591
2592         do {
2593                 rc = llapi_getstripe(argv[optind], param);
2594         } while (++optind < argc && !rc);
2595
2596         if (rc)
2597                 fprintf(stderr, "error: %s failed for %s.\n",
2598                         argv[0], argv[optind - 1]);
2599         return rc;
2600 }
2601
2602 static int lfs_tgts(int argc, char **argv)
2603 {
2604         char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
2605         struct find_param param;
2606         int index = 0, rc=0;
2607
2608         if (argc > 2)
2609                 return CMD_HELP;
2610
2611         if (argc == 2 && !realpath(argv[1], path)) {
2612                 rc = -errno;
2613                 fprintf(stderr, "error: invalid path '%s': %s\n",
2614                         argv[1], strerror(-rc));
2615                 return rc;
2616         }
2617
2618         while (!llapi_search_mounts(path, index++, mntdir, NULL)) {
2619                 /* Check if we have a mount point */
2620                 if (mntdir[0] == '\0')
2621                         continue;
2622
2623                 memset(&param, 0, sizeof(param));
2624                 if (!strcmp(argv[0], "mdts"))
2625                         param.fp_get_lmv = 1;
2626
2627                 rc = llapi_ostlist(mntdir, &param);
2628                 if (rc) {
2629                         fprintf(stderr, "error: %s: failed on %s\n",
2630                                 argv[0], mntdir);
2631                 }
2632                 if (path[0] != '\0')
2633                         break;
2634                 memset(mntdir, 0, PATH_MAX);
2635         }
2636
2637         return rc;
2638 }
2639
2640 static int lfs_getstripe(int argc, char **argv)
2641 {
2642         struct find_param param = { 0 };
2643
2644         param.fp_max_depth = 1;
2645         return lfs_getstripe_internal(argc, argv, &param);
2646 }
2647
2648 /* functions */
2649 static int lfs_getdirstripe(int argc, char **argv)
2650 {
2651         struct find_param param = { 0 };
2652         struct option long_opts[] = {
2653 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2654                 {"mdt-count",   no_argument,            0, 'c'},
2655 #endif
2656                 {"mdt-hash",    no_argument,            0, 'H'},
2657                 {"mdt-index",   no_argument,            0, 'i'},
2658                 {"recursive",   no_argument,            0, 'r'},
2659 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2660                 {"mdt-hash",    no_argument,            0, 't'},
2661 #endif
2662                 {"default",     no_argument,            0, 'D'},
2663                 {"obd",         required_argument,      0, 'O'},
2664                 {"mdt-count",   no_argument,            0, 'T'},
2665                 {0, 0, 0, 0}
2666         };
2667         int c, rc;
2668
2669         param.fp_get_lmv = 1;
2670
2671         while ((c = getopt_long(argc, argv,
2672                                 "cDHiO:rtT", long_opts, NULL)) != -1)
2673         {
2674                 switch (c) {
2675                 case 'O':
2676                         if (param.fp_obd_uuid) {
2677                                 fprintf(stderr,
2678                                         "error: %s: only one obduuid allowed",
2679                                         argv[0]);
2680                                 return CMD_HELP;
2681                         }
2682                         param.fp_obd_uuid = (struct obd_uuid *)optarg;
2683                         break;
2684 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2685                 case 'c':
2686 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 10, 50, 0)
2687                         fprintf(stderr, "warning: '-c' deprecated"
2688                                 ", use '-T' instead\n");
2689 #endif
2690 #endif
2691                 case 'T':
2692                         param.fp_verbose |= VERBOSE_COUNT;
2693                         break;
2694                 case 'i':
2695                         param.fp_verbose |= VERBOSE_OFFSET;
2696                         break;
2697 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2698                 case 't':
2699 #endif
2700                 case 'H':
2701                         param.fp_verbose |= VERBOSE_HASH_TYPE;
2702                         break;
2703                 case 'D':
2704                         param.fp_get_default_lmv = 1;
2705                         break;
2706                 case 'r':
2707                         param.fp_recursive = 1;
2708                         break;
2709                 default:
2710                         return CMD_HELP;
2711                 }
2712         }
2713
2714         if (optind >= argc)
2715                 return CMD_HELP;
2716
2717         if (param.fp_recursive)
2718                 param.fp_max_depth = -1;
2719
2720         if (!param.fp_verbose)
2721                 param.fp_verbose = VERBOSE_DEFAULT;
2722
2723         do {
2724                 rc = llapi_getstripe(argv[optind], &param);
2725         } while (++optind < argc && !rc);
2726
2727         if (rc)
2728                 fprintf(stderr, "error: %s failed for %s.\n",
2729                         argv[0], argv[optind - 1]);
2730         return rc;
2731 }
2732
2733 /* functions */
2734 static int lfs_setdirstripe(int argc, char **argv)
2735 {
2736         char                    *dname;
2737         int                     result;
2738         unsigned int            stripe_offset = -1;
2739         unsigned int            stripe_count = 1;
2740         enum lmv_hash_type      hash_type;
2741         char                    *end;
2742         int                     c;
2743         char                    *stripe_offset_opt = NULL;
2744         char                    *stripe_count_opt = NULL;
2745         char                    *stripe_hash_opt = NULL;
2746         char                    *mode_opt = NULL;
2747         bool                    default_stripe = false;
2748         mode_t                  mode = S_IRWXU | S_IRWXG | S_IRWXO;
2749         mode_t                  previous_mode = 0;
2750         bool                    delete = false;
2751
2752         struct option long_opts[] = {
2753 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2754                 {"count",       required_argument, 0, 'c'},
2755 #endif
2756                 {"mdt-count",   required_argument, 0, 'c'},
2757                 {"delete",      no_argument, 0, 'd'},
2758 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2759                 {"index",       required_argument, 0, 'i'},
2760 #endif
2761                 {"mdt-index",   required_argument, 0, 'i'},
2762                 {"mode",        required_argument, 0, 'm'},
2763 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2764                 {"hash-type",   required_argument, 0, 't'},
2765                 {"mdt-hash",    required_argument, 0, 't'},
2766 #endif
2767                 {"mdt-hash",    required_argument, 0, 'H'},
2768 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2769                 {"default_stripe", no_argument, 0, 'D'},
2770 #endif
2771                 {"default",     no_argument, 0, 'D'},
2772                 {0, 0, 0, 0}
2773         };
2774
2775         while ((c = getopt_long(argc, argv, "c:dDi:H:m:t:", long_opts,
2776                                 NULL)) >= 0) {
2777                 switch (c) {
2778                 case 0:
2779                         /* Long options. */
2780                         break;
2781                 case 'c':
2782 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2783                         if (strcmp(argv[optind - 1], "--count") == 0)
2784                                 fprintf(stderr, "warning: '--count' deprecated"
2785                                         ", use '--mdt-count' instead\n");
2786 #endif
2787                         stripe_count_opt = optarg;
2788                         break;
2789                 case 'd':
2790                         delete = true;
2791                         default_stripe = true;
2792                         break;
2793                 case 'D':
2794                         default_stripe = true;
2795                         break;
2796                 case 'i':
2797 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2798                         if (strcmp(argv[optind - 1], "--index") == 0)
2799                                 fprintf(stderr, "warning: '--index' deprecated"
2800                                         ", use '--mdt-index' instead\n");
2801 #endif
2802                         stripe_offset_opt = optarg;
2803                         break;
2804                 case 'm':
2805                         mode_opt = optarg;
2806                         break;
2807 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2808                 case 't':
2809 #endif
2810                 case 'H':
2811 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2812                         if (strcmp(argv[optind - 1], "--hash-type") == 0)
2813                                 fprintf(stderr, "warning: '--hash-type' "
2814                                         "deprecated, use '--mdt-hash' "
2815                                         "instead\n");
2816 #endif
2817                         stripe_hash_opt = optarg;
2818                         break;
2819                 default:
2820                         fprintf(stderr, "error: %s: option '%s' "
2821                                         "unrecognized\n",
2822                                         argv[0], argv[optind - 1]);
2823                         return CMD_HELP;
2824                 }
2825         }
2826
2827         if (optind == argc) {
2828                 fprintf(stderr, "error: %s: missing dirname\n",
2829                         argv[0]);
2830                 return CMD_HELP;
2831         }
2832
2833         if (!delete && stripe_offset_opt == NULL && stripe_count_opt == NULL) {
2834                 fprintf(stderr, "error: %s: missing stripe offset and count.\n",
2835                         argv[0]);
2836                 return CMD_HELP;
2837         }
2838
2839         if (stripe_offset_opt != NULL) {
2840                 /* get the stripe offset */
2841                 stripe_offset = strtoul(stripe_offset_opt, &end, 0);
2842                 if (*end != '\0') {
2843                         fprintf(stderr, "error: %s: bad stripe offset '%s'\n",
2844                                 argv[0], stripe_offset_opt);
2845                         return CMD_HELP;
2846                 }
2847         }
2848
2849         if (delete) {
2850                 if (stripe_offset_opt != NULL || stripe_count_opt != NULL) {
2851                         fprintf(stderr, "error: %s: cannot specify -d with -s,"
2852                                 " or -i options.\n", argv[0]);
2853                         return CMD_HELP;
2854                 } else {
2855                         stripe_count = 0;
2856                 }
2857         }
2858
2859
2860         if (mode_opt != NULL) {
2861                 mode = strtoul(mode_opt, &end, 8);
2862                 if (*end != '\0') {
2863                         fprintf(stderr, "error: %s: bad mode '%s'\n",
2864                                 argv[0], mode_opt);
2865                         return CMD_HELP;
2866                 }
2867                 previous_mode = umask(0);
2868         }
2869
2870         if (stripe_hash_opt == NULL) {
2871                 hash_type = LMV_HASH_TYPE_FNV_1A_64;
2872         } else {
2873                 hash_type = check_hashtype(stripe_hash_opt);
2874                 if (hash_type == 0) {
2875                         fprintf(stderr,
2876                                 "error: %s: bad stripe hash type '%s'\n",
2877                                 argv[0], stripe_hash_opt);
2878                         return CMD_HELP;
2879                 }
2880         }
2881
2882         /* get the stripe count */
2883         if (stripe_count_opt != NULL) {
2884                 stripe_count = strtoul(stripe_count_opt, &end, 0);
2885                 if (*end != '\0') {
2886                         fprintf(stderr, "error: %s: bad stripe count '%s'\n",
2887                                 argv[0], stripe_count_opt);
2888                         return CMD_HELP;
2889                 }
2890         }
2891
2892         dname = argv[optind];
2893         do {
2894                 if (default_stripe) {
2895                         result = llapi_dir_set_default_lmv_stripe(dname,
2896                                                     stripe_offset, stripe_count,
2897                                                     hash_type, NULL);
2898                 } else {
2899                         result = llapi_dir_create_pool(dname, mode,
2900                                                        stripe_offset,
2901                                                        stripe_count, hash_type,
2902                                                        NULL);
2903                 }
2904
2905                 if (result) {
2906                         fprintf(stderr, "error: %s: create stripe dir '%s' "
2907                                 "failed\n", argv[0], dname);
2908                         break;
2909                 }
2910                 dname = argv[++optind];
2911         } while (dname != NULL);
2912
2913         if (mode_opt != NULL)
2914                 umask(previous_mode);
2915
2916         return result;
2917 }
2918
2919 /* functions */
2920 static int lfs_rmentry(int argc, char **argv)
2921 {
2922         char *dname;
2923         int   index;
2924         int   result = 0;
2925
2926         if (argc <= 1) {
2927                 fprintf(stderr, "error: %s: missing dirname\n",
2928                         argv[0]);
2929                 return CMD_HELP;
2930         }
2931
2932         index = 1;
2933         dname = argv[index];
2934         while (dname != NULL) {
2935                 result = llapi_direntry_remove(dname);