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