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