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