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