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