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