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