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