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