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