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