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