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