Whamcloud - gitweb
LU-6210 utils: Use C99 struct initializers in lfs_mv()
[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         { .val = 'A',   .name = "atime",        .has_arg = required_argument },
1898         { .val = LFS_COMP_COUNT_OPT,
1899                         .name = "comp-count",   .has_arg = required_argument },
1900         { .val = LFS_COMP_COUNT_OPT,
1901                         .name = "component-count",
1902                                                 .has_arg = required_argument },
1903         { .val = LFS_COMP_FLAGS_OPT,
1904                         .name = "comp-flags",   .has_arg = required_argument },
1905         { .val = LFS_COMP_FLAGS_OPT,
1906                         .name = "component-flags",
1907                                                 .has_arg = required_argument },
1908         { .val = LFS_COMP_START_OPT,
1909                         .name = "comp-start",   .has_arg = required_argument },
1910         { .val = LFS_COMP_START_OPT,
1911                         .name = "component-start",
1912                                                 .has_arg = required_argument },
1913         { .val = 'c',   .name = "stripe-count", .has_arg = required_argument },
1914         { .val = 'c',   .name = "stripe_count", .has_arg = required_argument },
1915         { .val = 'C',   .name = "ctime",        .has_arg = required_argument },
1916         { .val = 'D',   .name = "maxdepth",     .has_arg = required_argument },
1917         { .val = 'E',   .name = "comp-end",     .has_arg = required_argument },
1918         { .val = 'E',   .name = "component-end",
1919                                                 .has_arg = required_argument },
1920         { .val = 'g',   .name = "gid",          .has_arg = required_argument },
1921         { .val = 'G',   .name = "group",        .has_arg = required_argument },
1922         { .val = 'H',   .name = "mdt-hash",     .has_arg = required_argument },
1923         { .val = 'i',   .name = "stripe-index", .has_arg = required_argument },
1924         { .val = 'i',   .name = "stripe_index", .has_arg = required_argument },
1925         /*{"component-id", required_argument, 0, 'I'},*/
1926         { .val = 'L',   .name = "layout",       .has_arg = required_argument },
1927         { .val = 'm',   .name = "mdt",          .has_arg = required_argument },
1928         { .val = 'm',   .name = "mdt-index",    .has_arg = required_argument },
1929         { .val = 'm',   .name = "mdt_index",    .has_arg = required_argument },
1930         { .val = 'M',   .name = "mtime",        .has_arg = required_argument },
1931         { .val = 'n',   .name = "name",         .has_arg = required_argument },
1932      /* reserve {"or",           no_argument,     , 0, 'o'}, to match find(1) */
1933         { .val = 'O',   .name = "obd",          .has_arg = required_argument },
1934         { .val = 'O',   .name = "ost",          .has_arg = required_argument },
1935         /* no short option for pool, p/P already used */
1936         { .val = LFS_POOL_OPT,
1937                         .name = "pool",         .has_arg = required_argument },
1938         { .val = 'p',   .name = "print0",       .has_arg = no_argument },
1939         { .val = 'P',   .name = "print",        .has_arg = no_argument },
1940         { .val = LFS_PROJID_OPT,
1941                         .name = "projid",       .has_arg = required_argument },
1942         { .val = 's',   .name = "size",         .has_arg = required_argument },
1943         { .val = 'S',   .name = "stripe-size",  .has_arg = required_argument },
1944         { .val = 'S',   .name = "stripe_size",  .has_arg = required_argument },
1945         { .val = 't',   .name = "type",         .has_arg = required_argument },
1946         { .val = 'T',   .name = "mdt-count",    .has_arg = required_argument },
1947         { .val = 'u',   .name = "uid",          .has_arg = required_argument },
1948         { .val = 'U',   .name = "user",         .has_arg = required_argument },
1949         { .name = NULL } };
1950         int pathstart = -1;
1951         int pathend = -1;
1952         int neg_opt = 0;
1953         time_t *xtime;
1954         int *xsign;
1955         int isoption;
1956         char *endptr;
1957
1958         time(&t);
1959
1960         /* when getopt_long_only() hits '!' it returns 1, puts "!" in optarg */
1961         while ((c = getopt_long_only(argc, argv,
1962                         "-A:c:C:D:E:g:G:H:i:L:m:M:n:O:Ppqrs:S:t:T:u:U:v",
1963                         long_opts, NULL)) >= 0) {
1964                 xtime = NULL;
1965                 xsign = NULL;
1966                 if (neg_opt)
1967                         --neg_opt;
1968                 /* '!' is part of option */
1969                 /* when getopt_long_only() finds a string which is not
1970                  * an option nor a known option argument it returns 1
1971                  * in that case if we already have found pathstart and pathend
1972                  * (i.e. we have the list of pathnames),
1973                  * the only supported value is "!"
1974                  */
1975                 isoption = (c != 1) || (strcmp(optarg, "!") == 0);
1976                 if (!isoption && pathend != -1) {
1977                         fprintf(stderr, "err: %s: filename|dirname must either "
1978                                         "precede options or follow options\n",
1979                                         argv[0]);
1980                         ret = CMD_HELP;
1981                         goto err;
1982                 }
1983                 if (!isoption && pathstart == -1)
1984                         pathstart = optind - 1;
1985                 if (isoption && pathstart != -1 && pathend == -1)
1986                         pathend = optind - 2;
1987                 switch (c) {
1988                 case 0:
1989                         /* Long options. */
1990                         break;
1991                 case 1:
1992                         /* unknown; opt is "!" or path component,
1993                          * checking done above.
1994                          */
1995                         if (strcmp(optarg, "!") == 0)
1996                                 neg_opt = 2;
1997                         break;
1998                 case 'A':
1999                         xtime = &param.fp_atime;
2000                         xsign = &param.fp_asign;
2001                         param.fp_exclude_atime = !!neg_opt;
2002                         /* no break, this falls through to 'C' for ctime */
2003                 case 'C':
2004                         if (c == 'C') {
2005                                 xtime = &param.fp_ctime;
2006                                 xsign = &param.fp_csign;
2007                                 param.fp_exclude_ctime = !!neg_opt;
2008                         }
2009                         /* no break, this falls through to 'M' for mtime */
2010                 case 'M':
2011                         if (c == 'M') {
2012                                 xtime = &param.fp_mtime;
2013                                 xsign = &param.fp_msign;
2014                                 param.fp_exclude_mtime = !!neg_opt;
2015                         }
2016                         rc = set_time(&t, xtime, optarg);
2017                         if (rc == INT_MAX) {
2018                                 ret = -1;
2019                                 goto err;
2020                         }
2021                         if (rc)
2022                                 *xsign = rc;
2023                         break;
2024                 case LFS_COMP_COUNT_OPT:
2025                         if (optarg[0] == '+') {
2026                                 param.fp_comp_count_sign = -1;
2027                                 optarg++;
2028                         } else if (optarg[0] == '-') {
2029                                 param.fp_comp_count_sign =  1;
2030                                 optarg++;
2031                         }
2032
2033                         param.fp_comp_count = strtoul(optarg, &endptr, 0);
2034                         if (*endptr != '\0') {
2035                                 fprintf(stderr, "error: bad component count "
2036                                         "'%s'\n", optarg);
2037                                 goto err;
2038                         }
2039                         param.fp_check_comp_count = 1;
2040                         param.fp_exclude_comp_count = !!neg_opt;
2041                         break;
2042                 case LFS_COMP_FLAGS_OPT:
2043                         rc = comp_str2flags(&param.fp_comp_flags, optarg);
2044                         if (rc || comp_flags_is_neg(param.fp_comp_flags)) {
2045                                 fprintf(stderr, "error: bad component flags "
2046                                         "'%s'\n", optarg);
2047                                 goto err;
2048                         }
2049                         param.fp_check_comp_flags = 1;
2050                         param.fp_exclude_comp_flags = !!neg_opt;
2051                         break;
2052                 case LFS_COMP_START_OPT:
2053                         if (optarg[0] == '+') {
2054                                 param.fp_comp_start_sign = -1;
2055                                 optarg++;
2056                         } else if (optarg[0] == '-') {
2057                                 param.fp_comp_start_sign =  1;
2058                                 optarg++;
2059                         }
2060
2061                         rc = llapi_parse_size(optarg, &param.fp_comp_start,
2062                                               &param.fp_comp_start_units, 0);
2063                         if (rc) {
2064                                 fprintf(stderr, "error: bad component start "
2065                                         "'%s'\n", optarg);
2066                                 goto err;
2067                         }
2068                         param.fp_check_comp_start = 1;
2069                         param.fp_exclude_comp_start = !!neg_opt;
2070                         break;
2071                 case 'c':
2072                         if (optarg[0] == '+') {
2073                                 param.fp_stripe_count_sign = -1;
2074                                 optarg++;
2075                         } else if (optarg[0] == '-') {
2076                                 param.fp_stripe_count_sign =  1;
2077                                 optarg++;
2078                         }
2079
2080                         param.fp_stripe_count = strtoul(optarg, &endptr, 0);
2081                         if (*endptr != '\0') {
2082                                 fprintf(stderr,"error: bad stripe_count '%s'\n",
2083                                         optarg);
2084                                 ret = -1;
2085                                 goto err;
2086                         }
2087                         param.fp_check_stripe_count = 1;
2088                         param.fp_exclude_stripe_count = !!neg_opt;
2089                         break;
2090                 case 'D':
2091                         param.fp_max_depth = strtol(optarg, 0, 0);
2092                         break;
2093                 case 'E':
2094                         if (optarg[0] == '+') {
2095                                 param.fp_comp_end_sign = -1;
2096                                 optarg++;
2097                         } else if (optarg[0] == '-') {
2098                                 param.fp_comp_end_sign =  1;
2099                                 optarg++;
2100                         }
2101
2102                         if (arg_is_eof(optarg)) {
2103                                 param.fp_comp_end = LUSTRE_EOF;
2104                                 param.fp_comp_end_units = 1;
2105                                 rc = 0;
2106                         } else {
2107                                 rc = llapi_parse_size(optarg,
2108                                                 &param.fp_comp_end,
2109                                                 &param.fp_comp_end_units, 0);
2110                         }
2111                         if (rc) {
2112                                 fprintf(stderr, "error: bad component end "
2113                                         "'%s'\n", optarg);
2114                                 goto err;
2115                         }
2116                         param.fp_check_comp_end = 1;
2117                         param.fp_exclude_comp_end = !!neg_opt;
2118                         break;
2119                 case 'g':
2120                 case 'G':
2121                         rc = name2gid(&param.fp_gid, optarg);
2122                         if (rc) {
2123                                 param.fp_gid = strtoul(optarg, &endptr, 10);
2124                                 if (*endptr != '\0') {
2125                                         fprintf(stderr, "Group/GID: %s cannot "
2126                                                 "be found.\n", optarg);
2127                                         ret = -1;
2128                                         goto err;
2129                                 }
2130                         }
2131                         param.fp_exclude_gid = !!neg_opt;
2132                         param.fp_check_gid = 1;
2133                         break;
2134                 case 'H':
2135                         param.fp_hash_type = check_hashtype(optarg);
2136                         if (param.fp_hash_type == 0) {
2137                                 fprintf(stderr, "error: bad hash_type '%s'\n",
2138                                         optarg);
2139                                 ret = -1;
2140                                 goto err;
2141                         }
2142                         param.fp_check_hash_type = 1;
2143                         param.fp_exclude_hash_type = !!neg_opt;
2144                         break;
2145                 case 'L':
2146                         ret = name2layout(&param.fp_layout, optarg);
2147                         if (ret)
2148                                 goto err;
2149                         param.fp_exclude_layout = !!neg_opt;
2150                         param.fp_check_layout = 1;
2151                         break;
2152                 case 'u':
2153                 case 'U':
2154                         rc = name2uid(&param.fp_uid, optarg);
2155                         if (rc) {
2156                                 param.fp_uid = strtoul(optarg, &endptr, 10);
2157                                 if (*endptr != '\0') {
2158                                         fprintf(stderr, "User/UID: %s cannot "
2159                                                 "be found.\n", optarg);
2160                                         ret = -1;
2161                                         goto err;
2162                                 }
2163                         }
2164                         param.fp_exclude_uid = !!neg_opt;
2165                         param.fp_check_uid = 1;
2166                         break;
2167                 case LFS_POOL_OPT:
2168                         if (strlen(optarg) > LOV_MAXPOOLNAME) {
2169                                 fprintf(stderr,
2170                                         "Pool name %s is too long"
2171                                         " (max is %d)\n", optarg,
2172                                         LOV_MAXPOOLNAME);
2173                                 ret = -1;
2174                                 goto err;
2175                         }
2176                         /* we do check for empty pool because empty pool
2177                          * is used to find V1 lov attributes */
2178                         strncpy(param.fp_poolname, optarg, LOV_MAXPOOLNAME);
2179                         param.fp_poolname[LOV_MAXPOOLNAME] = '\0';
2180                         param.fp_exclude_pool = !!neg_opt;
2181                         param.fp_check_pool = 1;
2182                         break;
2183                 case 'n':
2184                         param.fp_pattern = (char *)optarg;
2185                         param.fp_exclude_pattern = !!neg_opt;
2186                         break;
2187                 case 'm':
2188                 case 'i':
2189                 case 'O': {
2190                         char *buf, *token, *next, *p;
2191                         int len = 1;
2192                         void *tmp;
2193
2194                         buf = strdup(optarg);
2195                         if (buf == NULL) {
2196                                 ret = -ENOMEM;
2197                                 goto err;
2198                         }
2199
2200                         param.fp_exclude_obd = !!neg_opt;
2201
2202                         token = buf;
2203                         while (token && *token) {
2204                                 token = strchr(token, ',');
2205                                 if (token) {
2206                                         len++;
2207                                         token++;
2208                                 }
2209                         }
2210                         if (c == 'm') {
2211                                 param.fp_exclude_mdt = !!neg_opt;
2212                                 param.fp_num_alloc_mdts += len;
2213                                 tmp = realloc(param.fp_mdt_uuid,
2214                                               param.fp_num_alloc_mdts *
2215                                               sizeof(*param.fp_mdt_uuid));
2216                                 if (tmp == NULL) {
2217                                         ret = -ENOMEM;
2218                                         goto err_free;
2219                                 }
2220
2221                                 param.fp_mdt_uuid = tmp;
2222                         } else {
2223                                 param.fp_exclude_obd = !!neg_opt;
2224                                 param.fp_num_alloc_obds += len;
2225                                 tmp = realloc(param.fp_obd_uuid,
2226                                               param.fp_num_alloc_obds *
2227                                               sizeof(*param.fp_obd_uuid));
2228                                 if (tmp == NULL) {
2229                                         ret = -ENOMEM;
2230                                         goto err_free;
2231                                 }
2232
2233                                 param.fp_obd_uuid = tmp;
2234                         }
2235                         for (token = buf; token && *token; token = next) {
2236                                 struct obd_uuid *puuid;
2237                                 if (c == 'm') {
2238                                         puuid =
2239                                         &param.fp_mdt_uuid[param.fp_num_mdts++];
2240                                 } else {
2241                                         puuid =
2242                                         &param.fp_obd_uuid[param.fp_num_obds++];
2243                                 }
2244                                 p = strchr(token, ',');
2245                                 next = 0;
2246                                 if (p) {
2247                                         *p = 0;
2248                                         next = p+1;
2249                                 }
2250
2251                                 if (strlen(token) > sizeof(puuid->uuid) - 1) {
2252                                         ret = -E2BIG;
2253                                         goto err_free;
2254                                 }
2255
2256                                 strncpy(puuid->uuid, token,
2257                                         sizeof(puuid->uuid));
2258                         }
2259 err_free:
2260                         if (buf)
2261                                 free(buf);
2262                         break;
2263                 }
2264                 case 'p':
2265                         param.fp_zero_end = 1;
2266                         break;
2267                 case 'P':
2268                         break;
2269                 case LFS_PROJID_OPT:
2270                         rc = name2projid(&param.fp_projid, optarg);
2271                         if (rc) {
2272                                 param.fp_projid = strtoul(optarg, &endptr, 10);
2273                                 if (*endptr != '\0') {
2274                                         fprintf(stderr,
2275                                                 "Invalid project ID: %s",
2276                                                 optarg);
2277                                         ret = -1;
2278                                         goto err;
2279                                 }
2280                         }
2281                         param.fp_exclude_projid = !!neg_opt;
2282                         param.fp_check_projid = 1;
2283                         break;
2284                 case 's':
2285                         if (optarg[0] == '+') {
2286                                 param.fp_size_sign = -1;
2287                                 optarg++;
2288                         } else if (optarg[0] == '-') {
2289                                 param.fp_size_sign =  1;
2290                                 optarg++;
2291                         }
2292
2293                         ret = llapi_parse_size(optarg, &param.fp_size,
2294                                                &param.fp_size_units, 0);
2295                         if (ret) {
2296                                 fprintf(stderr, "error: bad file size '%s'\n",
2297                                         optarg);
2298                                 goto err;
2299                         }
2300                         param.fp_check_size = 1;
2301                         param.fp_exclude_size = !!neg_opt;
2302                         break;
2303                 case 'S':
2304                         if (optarg[0] == '+') {
2305                                 param.fp_stripe_size_sign = -1;
2306                                 optarg++;
2307                         } else if (optarg[0] == '-') {
2308                                 param.fp_stripe_size_sign =  1;
2309                                 optarg++;
2310                         }
2311
2312                         ret = llapi_parse_size(optarg, &param.fp_stripe_size,
2313                                                &param.fp_stripe_size_units, 0);
2314                         if (ret) {
2315                                 fprintf(stderr, "error: bad stripe_size '%s'\n",
2316                                         optarg);
2317                                 goto err;
2318                         }
2319                         param.fp_check_stripe_size = 1;
2320                         param.fp_exclude_stripe_size = !!neg_opt;
2321                         break;
2322                 case 't':
2323                         param.fp_exclude_type = !!neg_opt;
2324                         switch (optarg[0]) {
2325                         case 'b':
2326                                 param.fp_type = S_IFBLK;
2327                                 break;
2328                         case 'c':
2329                                 param.fp_type = S_IFCHR;
2330                                 break;
2331                         case 'd':
2332                                 param.fp_type = S_IFDIR;
2333                                 break;
2334                         case 'f':
2335                                 param.fp_type = S_IFREG;
2336                                 break;
2337                         case 'l':
2338                                 param.fp_type = S_IFLNK;
2339                                 break;
2340                         case 'p':
2341                                 param.fp_type = S_IFIFO;
2342                                 break;
2343                         case 's':
2344                                 param.fp_type = S_IFSOCK;
2345                                 break;
2346                         default:
2347                                 fprintf(stderr, "error: %s: bad type '%s'\n",
2348                                         argv[0], optarg);
2349                                 ret = CMD_HELP;
2350                                 goto err;
2351                         };
2352                         break;
2353                 case 'T':
2354                         if (optarg[0] == '+') {
2355                                 param.fp_mdt_count_sign = -1;
2356                                 optarg++;
2357                         } else if (optarg[0] == '-') {
2358                                 param.fp_mdt_count_sign =  1;
2359                                 optarg++;
2360                         }
2361
2362                         param.fp_mdt_count = strtoul(optarg, &endptr, 0);
2363                         if (*endptr != '\0') {
2364                                 fprintf(stderr, "error: bad mdt_count '%s'\n",
2365                                         optarg);
2366                                 ret = -1;
2367                                 goto err;
2368                         }
2369                         param.fp_check_mdt_count = 1;
2370                         param.fp_exclude_mdt_count = !!neg_opt;
2371                         break;
2372                 default:
2373                         ret = CMD_HELP;
2374                         goto err;
2375                 };
2376         }
2377
2378         if (pathstart == -1) {
2379                 fprintf(stderr, "error: %s: no filename|pathname\n",
2380                         argv[0]);
2381                 ret = CMD_HELP;
2382                 goto err;
2383         } else if (pathend == -1) {
2384                 /* no options */
2385                 pathend = argc;
2386         }
2387
2388         do {
2389                 rc = llapi_find(argv[pathstart], &param);
2390                 if (rc != 0 && ret == 0)
2391                         ret = rc;
2392         } while (++pathstart < pathend);
2393
2394         if (ret)
2395                 fprintf(stderr, "error: %s failed for %s.\n",
2396                         argv[0], argv[optind - 1]);
2397 err:
2398         if (param.fp_obd_uuid && param.fp_num_alloc_obds)
2399                 free(param.fp_obd_uuid);
2400
2401         if (param.fp_mdt_uuid && param.fp_num_alloc_mdts)
2402                 free(param.fp_mdt_uuid);
2403
2404         return ret;
2405 }
2406
2407 static int lfs_getstripe_internal(int argc, char **argv,
2408                                   struct find_param *param)
2409 {
2410         struct option long_opts[] = {
2411                 {"comp-count",          no_argument, 0, LFS_COMP_COUNT_OPT},
2412                 {"component-count",     no_argument, 0, LFS_COMP_COUNT_OPT},
2413                 {"comp-flags",      optional_argument, 0, LFS_COMP_FLAGS_OPT},
2414                 {"component-flags", optional_argument, 0, LFS_COMP_FLAGS_OPT},
2415                 {"comp-start",      optional_argument, 0, LFS_COMP_START_OPT},
2416                 {"component-start", optional_argument, 0, LFS_COMP_START_OPT},
2417 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2418                 /* This formerly implied "stripe-count", but was explicitly
2419                  * made "stripe-count" for consistency with other options,
2420                  * and to separate it from "mdt-count" when DNE arrives. */
2421                 {"count",               no_argument,            0, 'c'},
2422 #endif
2423                 {"stripe-count",        no_argument,            0, 'c'},
2424                 {"stripe_count",        no_argument,            0, 'c'},
2425                 {"directory",           no_argument,            0, 'd'},
2426                 {"default",             no_argument,            0, 'D'},
2427                 {"comp-end",            optional_argument,      0, 'E'},
2428                 {"component-end",       optional_argument,      0, 'E'},
2429                 {"fid",                 no_argument,            0, 'F'},
2430                 {"generation",          no_argument,            0, 'g'},
2431                 /* dirstripe {"mdt-hash",     required_argument, 0, 'H'}, */
2432 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2433                 /* This formerly implied "stripe-index", but was explicitly
2434                  * made "stripe-index" for consistency with other options,
2435                  * and to separate it from "mdt-index" when DNE arrives. */
2436                 {"index",               no_argument,            0, 'i'},
2437 #endif
2438                 {"stripe-index",        no_argument,            0, 'i'},
2439                 {"stripe_index",        no_argument,            0, 'i'},
2440                 {"comp-id",             optional_argument,      0, 'I'},
2441                 {"component-id",        optional_argument,      0, 'I'},
2442                 {"layout",              no_argument,            0, 'L'},
2443                 {"mdt",                 no_argument,            0, 'm'},
2444                 {"mdt-index",           no_argument,            0, 'm'},
2445                 {"mdt_index",           no_argument,            0, 'm'},
2446 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2447                 {"mdt-index",           no_argument,            0, 'M'},
2448                 {"mdt_index",           no_argument,            0, 'M'},
2449 #endif
2450 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2451                 /* This formerly implied "stripe-index", but was confusing
2452                  * with "file offset" (which will eventually be needed for
2453                  * with different layouts by offset), so deprecate it. */
2454                 {"offset",              no_argument,            0, 'o'},
2455 #endif
2456                 {"obd",                 required_argument,      0, 'O'},
2457                 {"ost",                 required_argument,      0, 'O'},
2458                 {"pool",                no_argument,            0, 'p'},
2459                 {"quiet",               no_argument,            0, 'q'},
2460                 {"recursive",           no_argument,            0, 'r'},
2461                 {"raw",                 no_argument,            0, 'R'},
2462 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2463                 /* This formerly implied "--stripe-size", but was confusing
2464                  * with "lfs find --size|-s", which means "file size", so use
2465                  * the consistent "--stripe-size|-S" for all commands. */
2466                 {"size",                no_argument,            0, 's'},
2467 #endif
2468                 {"stripe-size",         no_argument,            0, 'S'},
2469                 {"stripe_size",         no_argument,            0, 'S'},
2470                 /* dirstripe {"mdt-count",    required_argument, 0, 'T'}, */
2471                 {"verbose",             no_argument,            0, 'v'},
2472                 {"yaml",                no_argument,            0, 'y'},
2473                 {0, 0, 0, 0}
2474         };
2475         int c, rc;
2476         char *end, *tmp;
2477
2478         while ((c = getopt_long(argc, argv, "cdDE::FghiI::LmMoO:pqrRsSvy",
2479                                 long_opts, NULL)) != -1) {
2480                 switch (c) {
2481                 case 'c':
2482                         if (strcmp(argv[optind - 1], "--count") == 0)
2483                                 fprintf(stderr, "warning: '--count' deprecated,"
2484                                         " use '--stripe-count' instead\n");
2485                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2486                                 param->fp_verbose |= VERBOSE_COUNT;
2487                                 param->fp_max_depth = 0;
2488                         }
2489                         break;
2490                 case LFS_COMP_COUNT_OPT:
2491                         param->fp_verbose |= VERBOSE_COMP_COUNT;
2492                         param->fp_max_depth = 0;
2493                         break;
2494                 case LFS_COMP_FLAGS_OPT:
2495                         if (optarg != NULL) {
2496                                 __u32 *flags = &param->fp_comp_flags;
2497                                 rc = comp_str2flags(flags, optarg);
2498                                 if (rc != 0) {
2499                                         fprintf(stderr, "error: %s bad "
2500                                                 "component flags '%s'.\n",
2501                                                 argv[0], optarg);
2502                                         return CMD_HELP;
2503                                 } else {
2504                                         param->fp_check_comp_flags = 1;
2505                                         param->fp_exclude_comp_flags =
2506                                                 comp_flags_is_neg(*flags);
2507                                         comp_flags_clear_neg(flags);
2508                                 }
2509                         } else {
2510                                 param->fp_verbose |= VERBOSE_COMP_FLAGS;
2511                                 param->fp_max_depth = 0;
2512                         }
2513                         break;
2514                 case LFS_COMP_START_OPT:
2515                         if (optarg != NULL) {
2516                                 tmp = optarg;
2517                                 if (tmp[0] == '+') {
2518                                         param->fp_comp_start_sign = -1;
2519                                         tmp++;
2520                                 } else if (tmp[0] == '-') {
2521                                         param->fp_comp_start_sign = 1;
2522                                         tmp++;
2523                                 }
2524                                 rc = llapi_parse_size(tmp,
2525                                                 &param->fp_comp_start,
2526                                                 &param->fp_comp_start_units, 0);
2527                                 if (rc != 0) {
2528                                         fprintf(stderr, "error: %s bad "
2529                                                 "component start '%s'.\n",
2530                                                 argv[0], tmp);
2531                                         return CMD_HELP;
2532                                 } else {
2533                                         param->fp_check_comp_start = 1;
2534                                 }
2535                         } else {
2536                                 param->fp_verbose |= VERBOSE_COMP_START;
2537                                 param->fp_max_depth = 0;
2538                         }
2539                         break;
2540                 case 'd':
2541                         param->fp_max_depth = 0;
2542                         break;
2543                 case 'D':
2544                         param->fp_get_default_lmv = 1;
2545                         break;
2546                 case 'E':
2547                         if (optarg != NULL) {
2548                                 tmp = optarg;
2549                                 if (tmp[0] == '+') {
2550                                         param->fp_comp_end_sign = -1;
2551                                         tmp++;
2552                                 } else if (tmp[0] == '-') {
2553                                         param->fp_comp_end_sign = 1;
2554                                         tmp++;
2555                                 }
2556
2557                                 if (arg_is_eof(tmp)) {
2558                                         param->fp_comp_end = LUSTRE_EOF;
2559                                         param->fp_comp_end_units = 1;
2560                                         rc = 0;
2561                                 } else {
2562                                         rc = llapi_parse_size(tmp,
2563                                                 &param->fp_comp_end,
2564                                                 &param->fp_comp_end_units, 0);
2565                                 }
2566                                 if (rc != 0) {
2567                                         fprintf(stderr, "error: %s bad "
2568                                                 "component end '%s'.\n",
2569                                                 argv[0], tmp);
2570                                         return CMD_HELP;
2571                                 }
2572                                 param->fp_check_comp_end = 1;
2573                         } else {
2574                                 param->fp_verbose |= VERBOSE_COMP_END;
2575                                 param->fp_max_depth = 0;
2576                         }
2577                         break;
2578                 case 'F':
2579                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2580                                 param->fp_verbose |= VERBOSE_DFID;
2581                                 param->fp_max_depth = 0;
2582                         }
2583                         break;
2584                 case 'g':
2585                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2586                                 param->fp_verbose |= VERBOSE_GENERATION;
2587                                 param->fp_max_depth = 0;
2588                         }
2589                         break;
2590 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2591                 case 'o':
2592                         fprintf(stderr, "warning: '--offset|-o' deprecated, "
2593                                 "use '--stripe-index|-i' instead\n");
2594 #endif
2595                 case 'i':
2596 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
2597                         if (strcmp(argv[optind - 1], "--index") == 0)
2598                                 fprintf(stderr, "warning: '--index' deprecated"
2599                                         ", use '--stripe-index' instead\n");
2600 #endif
2601                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2602                                 param->fp_verbose |= VERBOSE_OFFSET;
2603                                 param->fp_max_depth = 0;
2604                         }
2605                         break;
2606                 case 'I':
2607                         if (optarg != NULL) {
2608                                 param->fp_comp_id = strtoul(optarg, &end, 0);
2609                                 if (*end != '\0' || param->fp_comp_id == 0 ||
2610                                     param->fp_comp_id > LCME_ID_MAX) {
2611                                         fprintf(stderr, "error: %s bad "
2612                                                 "component id '%s'\n",
2613                                                 argv[0], optarg);
2614                                         return CMD_HELP;
2615                                 } else {
2616                                         param->fp_check_comp_id = 1;
2617                                 }
2618                         } else {
2619                                 param->fp_max_depth = 0;
2620                                 param->fp_verbose |= VERBOSE_COMP_ID;
2621                         }
2622                         break;
2623                 case 'L':
2624                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2625                                 param->fp_verbose |= VERBOSE_LAYOUT;
2626                                 param->fp_max_depth = 0;
2627                         }
2628                         break;
2629 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2630                 case 'M':
2631 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2632                         fprintf(stderr, "warning: '-M' deprecated"
2633                                 ", use '-m' instead\n");
2634 #endif
2635 #endif
2636                 case 'm':
2637                         if (!(param->fp_verbose & VERBOSE_DETAIL))
2638                                 param->fp_max_depth = 0;
2639                         param->fp_verbose |= VERBOSE_MDTINDEX;
2640                         break;
2641                 case 'O':
2642                         if (param->fp_obd_uuid) {
2643                                 fprintf(stderr,
2644                                         "error: %s: only one obduuid allowed",
2645                                         argv[0]);
2646                                 return CMD_HELP;
2647                         }
2648                         param->fp_obd_uuid = (struct obd_uuid *)optarg;
2649                         break;
2650                 case 'p':
2651                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2652                                 param->fp_verbose |= VERBOSE_POOL;
2653                                 param->fp_max_depth = 0;
2654                         }
2655                         break;
2656                 case 'q':
2657                         param->fp_quiet++;
2658                         break;
2659                 case 'r':
2660                         param->fp_recursive = 1;
2661                         break;
2662                 case 'R':
2663                         param->fp_raw = 1;
2664                         break;
2665 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2666                 case 's':
2667                         fprintf(stderr, "warning: '--size|-s' deprecated, "
2668                                 "use '--stripe-size|-S' instead\n");
2669 #endif /* LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0) */
2670                 case 'S':
2671                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2672                                 param->fp_verbose |= VERBOSE_SIZE;
2673                                 param->fp_max_depth = 0;
2674                         }
2675                         break;
2676                 case 'v':
2677                         param->fp_verbose = VERBOSE_DEFAULT | VERBOSE_DETAIL;
2678                         break;
2679                 case 'y':
2680                         param->fp_yaml = 1;
2681                         break;
2682                 default:
2683                         return CMD_HELP;
2684                 }
2685         }
2686
2687         if (optind >= argc)
2688                 return CMD_HELP;
2689
2690         if (param->fp_recursive)
2691                 param->fp_max_depth = -1;
2692         else if (param->fp_verbose & VERBOSE_DETAIL)
2693                 param->fp_max_depth = 1;
2694
2695         if (!param->fp_verbose)
2696                 param->fp_verbose = VERBOSE_DEFAULT;
2697         if (param->fp_quiet)
2698                 param->fp_verbose = VERBOSE_OBJID;
2699
2700         do {
2701                 rc = llapi_getstripe(argv[optind], param);
2702         } while (++optind < argc && !rc);
2703
2704         if (rc)
2705                 fprintf(stderr, "error: %s failed for %s.\n",
2706                         argv[0], argv[optind - 1]);
2707         return rc;
2708 }
2709
2710 static int lfs_tgts(int argc, char **argv)
2711 {
2712         char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
2713         struct find_param param;
2714         int index = 0, rc=0;
2715
2716         if (argc > 2)
2717                 return CMD_HELP;
2718
2719         if (argc == 2 && !realpath(argv[1], path)) {
2720                 rc = -errno;
2721                 fprintf(stderr, "error: invalid path '%s': %s\n",
2722                         argv[1], strerror(-rc));
2723                 return rc;
2724         }
2725
2726         while (!llapi_search_mounts(path, index++, mntdir, NULL)) {
2727                 /* Check if we have a mount point */
2728                 if (mntdir[0] == '\0')
2729                         continue;
2730
2731                 memset(&param, 0, sizeof(param));
2732                 if (!strcmp(argv[0], "mdts"))
2733                         param.fp_get_lmv = 1;
2734
2735                 rc = llapi_ostlist(mntdir, &param);
2736                 if (rc) {
2737                         fprintf(stderr, "error: %s: failed on %s\n",
2738                                 argv[0], mntdir);
2739                 }
2740                 if (path[0] != '\0')
2741                         break;
2742                 memset(mntdir, 0, PATH_MAX);
2743         }
2744
2745         return rc;
2746 }
2747
2748 static int lfs_getstripe(int argc, char **argv)
2749 {
2750         struct find_param param = { 0 };
2751
2752         param.fp_max_depth = 1;
2753         return lfs_getstripe_internal(argc, argv, &param);
2754 }
2755
2756 /* functions */
2757 static int lfs_getdirstripe(int argc, char **argv)
2758 {
2759         struct find_param param = { 0 };
2760         struct option long_opts[] = {
2761 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2762                 {"mdt-count",   no_argument,            0, 'c'},
2763 #endif
2764                 {"mdt-hash",    no_argument,            0, 'H'},
2765                 {"mdt-index",   no_argument,            0, 'i'},
2766                 {"recursive",   no_argument,            0, 'r'},
2767 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2768                 {"mdt-hash",    no_argument,            0, 't'},
2769 #endif
2770                 {"default",     no_argument,            0, 'D'},
2771                 {"obd",         required_argument,      0, 'O'},
2772                 {"mdt-count",   no_argument,            0, 'T'},
2773                 {"yaml",        no_argument,            0, 'y'},
2774                 {0, 0, 0, 0}
2775         };
2776         int c, rc;
2777
2778         param.fp_get_lmv = 1;
2779
2780         while ((c = getopt_long(argc, argv,
2781                                 "cDHiO:rtTy", long_opts, NULL)) != -1)
2782         {
2783                 switch (c) {
2784                 case 'O':
2785                         if (param.fp_obd_uuid) {
2786                                 fprintf(stderr,
2787                                         "error: %s: only one obduuid allowed",
2788                                         argv[0]);
2789                                 return CMD_HELP;
2790                         }
2791                         param.fp_obd_uuid = (struct obd_uuid *)optarg;
2792                         break;
2793 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2794                 case 'c':
2795 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 10, 50, 0)
2796                         fprintf(stderr, "warning: '-c' deprecated"
2797                                 ", use '-T' instead\n");
2798 #endif
2799 #endif
2800                 case 'T':
2801                         param.fp_verbose |= VERBOSE_COUNT;
2802                         break;
2803                 case 'i':
2804                         param.fp_verbose |= VERBOSE_OFFSET;
2805                         break;
2806 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2807                 case 't':
2808 #endif
2809                 case 'H':
2810                         param.fp_verbose |= VERBOSE_HASH_TYPE;
2811                         break;
2812                 case 'D':
2813                         param.fp_get_default_lmv = 1;
2814                         break;
2815                 case 'r':
2816                         param.fp_recursive = 1;
2817                         break;
2818                 case 'y':
2819                         param.fp_yaml = 1;
2820                         break;
2821                 default:
2822                         return CMD_HELP;
2823                 }
2824         }
2825
2826         if (optind >= argc)
2827                 return CMD_HELP;
2828
2829         if (param.fp_recursive)
2830                 param.fp_max_depth = -1;
2831
2832         if (!param.fp_verbose)
2833                 param.fp_verbose = VERBOSE_DEFAULT;
2834
2835         do {
2836                 rc = llapi_getstripe(argv[optind], &param);
2837         } while (++optind < argc && !rc);
2838
2839         if (rc)
2840                 fprintf(stderr, "error: %s failed for %s.\n",
2841                         argv[0], argv[optind - 1]);
2842         return rc;
2843 }
2844
2845 /* functions */
2846 static int lfs_setdirstripe(int argc, char **argv)
2847 {
2848         char                    *dname;
2849         int                     result;
2850         unsigned int            stripe_offset = -1;
2851         unsigned int            stripe_count = 1;
2852         enum lmv_hash_type      hash_type;
2853         char                    *end;
2854         int                     c;
2855         char                    *stripe_offset_opt = NULL;
2856         char                    *stripe_count_opt = NULL;
2857         char                    *stripe_hash_opt = NULL;
2858         char                    *mode_opt = NULL;
2859         bool                    default_stripe = false;
2860         mode_t                  mode = S_IRWXU | S_IRWXG | S_IRWXO;
2861         mode_t                  previous_mode = 0;
2862         bool                    delete = false;
2863
2864         struct option long_opts[] = {
2865 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2866         { .val = 'c',   .name = "count",        .has_arg = required_argument },
2867 #endif
2868         { .val = 'c',   .name = "mdt-count",    .has_arg = required_argument },
2869         { .val = 'd',   .name = "delete",       .has_arg = no_argument },
2870 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2871         { .val = 'i',   .name = "index",        .has_arg = required_argument },
2872 #endif
2873         { .val = 'i',   .name = "mdt-index",    .has_arg = required_argument },
2874         { .val = 'm',   .name = "mode",         .has_arg = required_argument },
2875 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2876         { .val = 't',   .name = "hash-type",    .has_arg = required_argument },
2877         { .val = 't',   .name = "mdt-hash",     .has_arg = required_argument },
2878 #endif
2879                 {"mdt-hash",    required_argument, 0, 'H'},
2880 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2881         { .val = 'D',   .name = "default_stripe",
2882                                                 .has_arg = no_argument },
2883 #endif
2884         { .val = 'D',   .name = "default",      .has_arg = no_argument },
2885         { .name = NULL } };
2886
2887         while ((c = getopt_long(argc, argv, "c:dDi:H:m:t:", long_opts,
2888                                 NULL)) >= 0) {
2889                 switch (c) {
2890                 case 0:
2891                         /* Long options. */
2892                         break;
2893                 case 'c':
2894 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2895                         if (strcmp(argv[optind - 1], "--count") == 0)
2896                                 fprintf(stderr, "warning: '--count' deprecated"
2897                                         ", use '--mdt-count' instead\n");
2898 #endif
2899                         stripe_count_opt = optarg;
2900                         break;
2901                 case 'd':
2902                         delete = true;
2903                         default_stripe = true;
2904                         break;
2905                 case 'D':
2906                         default_stripe = true;
2907                         break;
2908                 case 'i':
2909 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2910                         if (strcmp(argv[optind - 1], "--index") == 0)
2911                                 fprintf(stderr, "warning: '--index' deprecated"
2912                                         ", use '--mdt-index' instead\n");
2913 #endif
2914                         stripe_offset_opt = optarg;
2915                         break;
2916                 case 'm':
2917                         mode_opt = optarg;
2918                         break;
2919 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2920                 case 't':
2921 #endif
2922                 case 'H':
2923 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2924                         if (strcmp(argv[optind - 1], "--hash-type") == 0)
2925                                 fprintf(stderr, "warning: '--hash-type' "
2926                                         "deprecated, use '--mdt-hash' "
2927                                         "instead\n");
2928 #endif
2929                         stripe_hash_opt = optarg;
2930                         break;
2931                 default:
2932                         fprintf(stderr, "error: %s: option '%s' "
2933                                         "unrecognized\n",
2934                                         argv[0], argv[optind - 1]);
2935                         return CMD_HELP;
2936                 }
2937         }
2938
2939         if (optind == argc) {
2940                 fprintf(stderr, "error: %s: missing dirname\n",
2941                         argv[0]);
2942                 return CMD_HELP;
2943         }
2944
2945         if (!delete && stripe_offset_opt == NULL && stripe_count_opt == NULL) {
2946                 fprintf(stderr, "error: %s: missing stripe offset and count.\n",
2947                         argv[0]);
2948                 return CMD_HELP;
2949         }
2950
2951         if (stripe_offset_opt != NULL) {
2952                 /* get the stripe offset */
2953                 stripe_offset = strtoul(stripe_offset_opt, &end, 0);
2954                 if (*end != '\0') {
2955                         fprintf(stderr, "error: %s: bad stripe offset '%s'\n",
2956                                 argv[0], stripe_offset_opt);
2957                         return CMD_HELP;
2958                 }
2959         }
2960
2961         if (delete) {
2962                 if (stripe_offset_opt != NULL || stripe_count_opt != NULL) {
2963                         fprintf(stderr, "error: %s: cannot specify -d with -s,"
2964                                 " or -i options.\n", argv[0]);
2965                         return CMD_HELP;
2966                 } else {
2967                         stripe_count = 0;
2968                 }
2969         }
2970
2971
2972         if (mode_opt != NULL) {
2973                 mode = strtoul(mode_opt, &end, 8);
2974                 if (*end != '\0') {
2975                         fprintf(stderr, "error: %s: bad mode '%s'\n",
2976                                 argv[0], mode_opt);
2977                         return CMD_HELP;
2978                 }
2979                 previous_mode = umask(0);
2980         }
2981
2982         if (stripe_hash_opt == NULL) {
2983                 hash_type = LMV_HASH_TYPE_FNV_1A_64;
2984         } else {
2985                 hash_type = check_hashtype(stripe_hash_opt);
2986                 if (hash_type == 0) {
2987                         fprintf(stderr,
2988                                 "error: %s: bad stripe hash type '%s'\n",
2989                                 argv[0], stripe_hash_opt);
2990                         return CMD_HELP;
2991                 }
2992         }
2993
2994         /* get the stripe count */
2995         if (stripe_count_opt != NULL) {
2996                 stripe_count = strtoul(stripe_count_opt, &end, 0);
2997                 if (*end != '\0') {
2998                         fprintf(stderr, "error: %s: bad stripe count '%s'\n",
2999                                 argv[0], stripe_count_opt);
3000                         return CMD_HELP;
3001                 }
3002         }
3003
3004         dname = argv[optind];
3005         do {
3006                 if (default_stripe) {
3007                         result = llapi_dir_set_default_lmv_stripe(dname,
3008                                                     stripe_offset, stripe_count,
3009                                                     hash_type, NULL);
3010                 } else {
3011                         result = llapi_dir_create_pool(dname, mode,
3012                                                        stripe_offset,
3013                                                        stripe_count, hash_type,
3014                                                        NULL);
3015                 }
3016
3017                 if (result) {
3018                         fprintf(stderr, "error: %s: create stripe dir '%s' "
3019                                 "failed\n", argv[0], dname);
3020                         break;
3021                 }
3022                 dname = argv[++optind];
3023         } while (dname != NULL);
3024
3025         if (mode_opt != NULL)
3026                 umask(previous_mode);
3027
3028         return result;
3029 }
3030
3031 /* functions */
3032 static int lfs_rmentry(int argc, char **argv)
3033 {
3034         char *dname;
3035         int   index;
3036         int   result = 0;
3037
3038         if (argc <= 1) {
3039                 fprintf(stderr, "error: %s: missing dirname\n",
3040                         argv[0]);
3041                 return CMD_HELP;
3042         }
3043
3044         index = 1;
3045         dname = argv[index];
3046         while (dname != NULL) {
3047                 result = llapi_direntry_remove(dname);
3048                 if (result) {
3049                         fprintf(stderr, "error: %s: remove dir entry '%s' "
3050                                 "failed\n", argv[0], dname);
3051                         break;
3052                 }
3053                 dname = argv[++index];
3054         }
3055         return result;
3056 }
3057
3058 static int lfs_mv(int argc, char **argv)
3059 {
3060         struct  find_param param = {
3061                 .fp_max_depth = -1,
3062                 .fp_mdt_index = -1,
3063         };
3064         char   *end;
3065         int     c;
3066         int     rc = 0;
3067         struct option long_opts[] = {
3068         { .val = 'M',   .name = "mdt-index",    .has_arg = required_argument },
3069         { .val = 'v',   .name = "verbose",      .has_arg = no_argument },
3070         { .name = NULL } };
3071
3072         while ((c = getopt_long(argc, argv, "M:v", long_opts, NULL)) != -1) {
3073                 switch (c) {
3074                 case 'M': {
3075                         param.fp_mdt_index = strtoul(optarg, &end, 0);
3076                         if (*end != '\0') {
3077                                 fprintf(stderr, "%s: invalid MDT index'%s'\n",
3078                                         argv[0], optarg);
3079                                 return CMD_HELP;
3080                         }
3081                         break;
3082                 }
3083                 case 'v': {
3084                         param.fp_verbose = VERBOSE_DETAIL;
3085                         break;
3086                 }
3087                 default:
3088                         fprintf(stderr, "error: %s: unrecognized option '%s'\n",
3089                                 argv[0], argv[optind - 1]);
3090                         return CMD_HELP;
3091                 }
3092         }
3093
3094         if (param.fp_mdt_index == -1) {
3095                 fprintf(stderr, "%s: MDT index must be specified\n", argv[0]);
3096                 return CMD_HELP;
3097         }
3098
3099         if (optind >= argc) {
3100                 fprintf(stderr, "%s: missing operand path\n", argv[0]);
3101                 return CMD_HELP;
3102         }
3103
3104         param.fp_migrate = 1;
3105         rc = llapi_migrate_mdt(argv[optind], &param);
3106         if (rc != 0)
3107                 fprintf(stderr, "%s: cannot migrate '%s' to MDT%04x: %s\n",
3108                         argv[0], argv[optind], param.fp_mdt_index,
3109                         strerror(-rc));
3110         return rc;
3111 }
3112
3113 static int lfs_osts(int argc, char **argv)
3114 {
3115         return lfs_tgts(argc, argv);
3116 }
3117
3118 static int lfs_mdts(int argc, char **argv)
3119 {
3120         return lfs_tgts(argc, argv);
3121 }
3122
3123 #define COOK(value)                                                     \
3124 ({                                                                      \
3125         int radix = 0;                                                  \
3126         while (value > 1024) {                                          \
3127                 value /= 1024;                                          \
3128                 radix++;                                                \
3129         }                                                               \
3130         radix;                                                          \
3131 })
3132 #define UUF     "%-20s"
3133 #define CSF     "%11s"
3134 #define CDF     "%11llu"
3135 #define HDF     "%8.1f%c"
3136 #define RSF     "%4s"
3137 #define RDF     "%3d%%"
3138
3139 enum mntdf_flags {
3140         MNTDF_INODES    = 0x0001,
3141         MNTDF_COOKED    = 0x0002,
3142         MNTDF_LAZY      = 0x0004,
3143         MNTDF_VERBOSE   = 0x0008,
3144 };
3145
3146 static int showdf(char *mntdir, struct obd_statfs *stat,
3147                   char *uuid, enum mntdf_flags flags,
3148                   char *type, int index, int rc)
3149 {
3150         long long avail, used, total;
3151         double ratio = 0;
3152         char *suffix = "KMGTPEZY";
3153         /* Note if we have >2^64 bytes/fs these buffers will need to be grown */
3154         char tbuf[3 * sizeof(__u64)];
3155         char ubuf[3 * sizeof(__u64)];
3156         char abuf[3 * sizeof(__u64)];
3157         char rbuf[3 * sizeof(__u64)];
3158
3159         if (!uuid || !stat)
3160                 return -EINVAL;
3161
3162         switch (rc) {
3163         case 0:
3164                 if (flags & MNTDF_INODES) {
3165                         avail = stat->os_ffree;
3166                         used = stat->os_files - stat->os_ffree;
3167                         total = stat->os_files;
3168                 } else {
3169                         int shift = flags & MNTDF_COOKED ? 0 : 10;
3170
3171                         avail = (stat->os_bavail * stat->os_bsize) >> shift;
3172                         used  = ((stat->os_blocks - stat->os_bfree) *
3173                                  stat->os_bsize) >> shift;
3174                         total = (stat->os_blocks * stat->os_bsize) >> shift;
3175                 }
3176
3177                 if ((used + avail) > 0)
3178                         ratio = (double)used / (double)(used + avail);
3179
3180                 if (flags & MNTDF_COOKED) {
3181                         int i;
3182                         double cook_val;
3183
3184                         cook_val = (double)total;
3185                         i = COOK(cook_val);
3186                         if (i > 0)
3187                                 snprintf(tbuf, sizeof(tbuf), HDF, cook_val,
3188                                          suffix[i - 1]);
3189                         else
3190                                 snprintf(tbuf, sizeof(tbuf), CDF, total);
3191
3192                         cook_val = (double)used;
3193                         i = COOK(cook_val);
3194                         if (i > 0)
3195                                 snprintf(ubuf, sizeof(ubuf), HDF, cook_val,
3196                                          suffix[i - 1]);
3197                         else
3198                                 snprintf(ubuf, sizeof(ubuf), CDF, used);
3199
3200                         cook_val = (double)avail;
3201                         i = COOK(cook_val);
3202                         if (i > 0)
3203                                 snprintf(abuf, sizeof(abuf), HDF, cook_val,
3204                                          suffix[i - 1]);
3205                         else
3206                                 snprintf(abuf, sizeof(abuf), CDF, avail);
3207                 } else {
3208                         snprintf(tbuf, sizeof(tbuf), CDF, total);
3209                         snprintf(ubuf, sizeof(tbuf), CDF, used);
3210                         snprintf(abuf, sizeof(tbuf), CDF, avail);
3211                 }
3212
3213                 sprintf(rbuf, RDF, (int)(ratio * 100 + 0.5));
3214                 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s",
3215                        uuid, tbuf, ubuf, abuf, rbuf, mntdir);
3216                 if (type)
3217                         printf("[%s:%d]", type, index);
3218
3219                 if (stat->os_state) {
3220                         /*
3221                          * Each character represents the matching
3222                          * OS_STATE_* bit.
3223                          */
3224                         const char state_names[] = "DRSI";
3225                         __u32      state;
3226                         __u32      i;
3227
3228                         printf(" ");
3229                         for (i = 0, state = stat->os_state;
3230                              state && i < sizeof(state_names); i++) {
3231                                 if (!(state & (1 << i)))
3232                                         continue;
3233                                 printf("%c", state_names[i]);
3234                                 state ^= 1 << i;
3235                         }
3236                 }
3237
3238                 printf("\n");
3239                 break;
3240         case -ENODATA:
3241                 printf(UUF": inactive device\n", uuid);
3242                 break;
3243         default:
3244                 printf(UUF": %s\n", uuid, strerror(-rc));
3245                 break;
3246         }
3247
3248         return 0;
3249 }
3250
3251 struct ll_stat_type {
3252         int   st_op;
3253         char *st_name;
3254 };
3255
3256 static int mntdf(char *mntdir, char *fsname, char *pool, enum mntdf_flags flags)
3257 {
3258         struct obd_statfs stat_buf, sum = { .os_bsize = 1 };
3259         struct obd_uuid uuid_buf;
3260         char *poolname = NULL;
3261         struct ll_stat_type types[] = { { LL_STATFS_LMV, "MDT" },
3262                                         { LL_STATFS_LOV, "OST" },
3263                                         { 0, NULL } };
3264         struct ll_stat_type *tp;
3265         __u64 ost_ffree = 0;
3266         __u32 index;
3267         __u32 type;
3268         int fd;
3269         int rc = 0;
3270         int rc2;
3271
3272         if (pool) {
3273                 poolname = strchr(pool, '.');
3274                 if (poolname != NULL) {
3275                         if (strncmp(fsname, pool, strlen(fsname))) {
3276                                 fprintf(stderr, "filesystem name incorrect\n");
3277                                 return -ENODEV;
3278                         }
3279                         poolname++;
3280                 } else
3281                         poolname = pool;
3282         }
3283
3284         fd = open(mntdir, O_RDONLY);
3285         if (fd < 0) {
3286                 rc = -errno;
3287                 fprintf(stderr, "%s: cannot open '%s': %s\n", progname, mntdir,
3288                         strerror(errno));
3289                 return rc;
3290         }
3291
3292         if (flags & MNTDF_INODES)
3293                 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
3294                        "UUID", "Inodes", "IUsed", "IFree",
3295                        "IUse%", "Mounted on");
3296         else
3297                 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
3298                        "UUID", flags & MNTDF_COOKED ? "bytes" : "1K-blocks",
3299                        "Used", "Available", "Use%", "Mounted on");
3300
3301         for (tp = types; tp->st_name != NULL; tp++) {
3302                 for (index = 0; ; index++) {
3303                         memset(&stat_buf, 0, sizeof(struct obd_statfs));
3304                         memset(&uuid_buf, 0, sizeof(struct obd_uuid));
3305                         type = flags & MNTDF_LAZY ?
3306                                 tp->st_op | LL_STATFS_NODELAY : tp->st_op;
3307                         rc2 = llapi_obd_fstatfs(fd, type, index,
3308                                                &stat_buf, &uuid_buf);
3309                         if (rc2 == -ENODEV)
3310                                 break;
3311                         if (rc2 == -EAGAIN)
3312                                 continue;
3313                         if (rc2 == -ENODATA) { /* Inactive device, OK. */
3314                                 if (!(flags & MNTDF_VERBOSE))
3315                                         continue;
3316                         } else if (rc2 < 0 && rc == 0) {
3317                                 rc = rc2;
3318                         }
3319
3320                         if (poolname && tp->st_op == LL_STATFS_LOV &&
3321                             llapi_search_ost(fsname, poolname,
3322                                              obd_uuid2str(&uuid_buf)) != 1)
3323                                 continue;
3324
3325                         /* the llapi_obd_statfs() call may have returned with
3326                          * an error, but if it filled in uuid_buf we will at
3327                          * lease use that to print out a message for that OBD.
3328                          * If we didn't get anything in the uuid_buf, then fill
3329                          * it in so that we can print an error message. */
3330                         if (uuid_buf.uuid[0] == '\0')
3331                                 snprintf(uuid_buf.uuid, sizeof(uuid_buf.uuid),
3332                                          "%s%04x", tp->st_name, index);
3333                         showdf(mntdir, &stat_buf, obd_uuid2str(&uuid_buf),
3334                                flags, tp->st_name, index, rc2);
3335
3336                         if (rc2 == 0) {
3337                                 if (tp->st_op == LL_STATFS_LMV) {
3338                                         sum.os_ffree += stat_buf.os_ffree;
3339                                         sum.os_files += stat_buf.os_files;
3340                                 } else /* if (tp->st_op == LL_STATFS_LOV) */ {
3341                                         sum.os_blocks += stat_buf.os_blocks *
3342                                                 stat_buf.os_bsize;
3343                                         sum.os_bfree  += stat_buf.os_bfree *
3344                                                 stat_buf.os_bsize;
3345                                         sum.os_bavail += stat_buf.os_bavail *
3346                                                 stat_buf.os_bsize;
3347                                         ost_ffree += stat_buf.os_ffree;
3348                                 }
3349                         }
3350                 }
3351         }
3352
3353         close(fd);
3354
3355         /* If we don't have as many objects free on the OST as inodes
3356          * on the MDS, we reduce the total number of inodes to
3357          * compensate, so that the "inodes in use" number is correct.
3358          * Matches ll_statfs_internal() so the results are consistent. */
3359         if (ost_ffree < sum.os_ffree) {
3360                 sum.os_files = (sum.os_files - sum.os_ffree) + ost_ffree;
3361                 sum.os_ffree = ost_ffree;
3362         }
3363         printf("\n");
3364         showdf(mntdir, &sum, "filesystem_summary:", flags, NULL, 0, 0);
3365         printf("\n");
3366
3367         return rc;
3368 }
3369
3370 static int lfs_df(int argc, char **argv)
3371 {
3372         char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
3373         enum mntdf_flags flags = 0;
3374         int c, rc = 0, index = 0;
3375         char fsname[PATH_MAX] = "", *pool_name = NULL;
3376         struct option long_opts[] = {
3377         { .val = 'h',   .name = "human-readable",
3378                                                 .has_arg = no_argument },
3379         { .val = 'i',   .name = "inodes",       .has_arg = no_argument },
3380         { .val = 'l',   .name = "lazy",         .has_arg = no_argument },
3381         { .val = 'p',   .name = "pool",         .has_arg = required_argument },
3382         { .val = 'v',   .name = "verbose",      .has_arg = no_argument },
3383         { .name = NULL} };
3384
3385         while ((c = getopt_long(argc, argv, "hilp:v", long_opts, NULL)) != -1) {
3386                 switch (c) {
3387                 case 'h':
3388                         flags |= MNTDF_COOKED;
3389                         break;
3390                 case 'i':
3391                         flags |= MNTDF_INODES;
3392                         break;
3393                 case 'l':
3394                         flags |= MNTDF_LAZY;
3395                         break;
3396                 case 'p':
3397                         pool_name = optarg;
3398                         break;
3399                 case 'v':
3400                         flags |= MNTDF_VERBOSE;
3401                         break;
3402                 default:
3403                         return CMD_HELP;
3404                 }
3405         }
3406         if (optind < argc && !realpath(argv[optind], path)) {
3407                 rc = -errno;
3408                 fprintf(stderr, "error: invalid path '%s': %s\n",
3409                         argv[optind], strerror(-rc));
3410                 return rc;
3411         }
3412
3413         while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
3414                 /* Check if we have a mount point */
3415                 if (mntdir[0] == '\0')
3416                         continue;
3417
3418                 rc = mntdf(mntdir, fsname, pool_name, flags);
3419                 if (rc || path[0] != '\0')
3420                         break;
3421                 fsname[0] = '\0'; /* avoid matching in next loop */
3422                 mntdir[0] = '\0'; /* avoid matching in next loop */
3423         }
3424
3425         return rc;
3426 }
3427
3428 static int lfs_getname(int argc, char **argv)
3429 {
3430         char mntdir[PATH_MAX] = "", path[PATH_MAX] = "", fsname[PATH_MAX] = "";
3431         int rc = 0, index = 0, c;
3432         char buf[sizeof(struct obd_uuid)];
3433
3434         while ((c = getopt(argc, argv, "h")) != -1)
3435                 return CMD_HELP;
3436
3437         if (optind == argc) { /* no paths specified, get all paths. */
3438                 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
3439                         rc = llapi_getname(mntdir, buf, sizeof(buf));
3440                         if (rc < 0) {
3441                                 fprintf(stderr,
3442                                         "cannot get name for `%s': %s\n",
3443                                         mntdir, strerror(-rc));
3444                                 break;
3445                         }
3446
3447                         printf("%s %s\n", buf, mntdir);
3448
3449                         path[0] = fsname[0] = mntdir[0] = 0;
3450                 }
3451         } else { /* paths specified, only attempt to search these. */
3452                 for (; optind < argc; optind++) {
3453                         rc = llapi_getname(argv[optind], buf, sizeof(buf));
3454                         if (rc < 0) {
3455                                 fprintf(stderr,
3456                                         "cannot get name for `%s': %s\n",
3457                                         argv[optind], strerror(-rc));
3458                                 break;
3459                         }
3460
3461                         printf("%s %s\n", buf, argv[optind]);
3462                 }
3463         }
3464         return rc;
3465 }
3466
3467 static int lfs_check(int argc, char **argv)
3468 {
3469         int rc;
3470         char mntdir[PATH_MAX] = {'\0'};
3471         int num_types = 1;
3472         char *obd_types[2];
3473         char obd_type1[4];
3474         char obd_type2[4];
3475
3476         if (argc != 2)
3477                 return CMD_HELP;
3478
3479         obd_types[0] = obd_type1;
3480         obd_types[1] = obd_type2;
3481
3482         if (strcmp(argv[1], "osts") == 0) {
3483                 strcpy(obd_types[0], "osc");
3484         } else if (strcmp(argv[1], "mds") == 0) {
3485                 strcpy(obd_types[0], "mdc");
3486         } else if (strcmp(argv[1], "servers") == 0) {
3487                 num_types = 2;
3488                 strcpy(obd_types[0], "osc");
3489                 strcpy(obd_types[1], "mdc");
3490         } else {
3491                 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
3492                                 argv[0], argv[1]);
3493                         return CMD_HELP;
3494         }
3495
3496         rc = llapi_search_mounts(NULL, 0, mntdir, NULL);
3497         if (rc < 0 || mntdir[0] == '\0') {
3498                 fprintf(stderr, "No suitable Lustre mount found\n");
3499                 return rc;
3500         }
3501
3502         rc = llapi_target_check(num_types, obd_types, mntdir);
3503         if (rc)
3504                 fprintf(stderr, "error: %s: %s status failed\n",
3505                                 argv[0],argv[1]);
3506
3507         return rc;
3508
3509 }
3510
3511 #ifdef HAVE_SYS_QUOTA_H
3512 #define ARG2INT(nr, str, msg)                                           \
3513 do {                                                                    \
3514         char *endp;                                                     \
3515         nr = strtol(str, &endp, 0);                                     \
3516         if (*endp) {                                                    \
3517                 fprintf(stderr, "error: bad %s: %s\n", msg, str);       \
3518                 return CMD_HELP;                                        \
3519         }                                                               \
3520 } while (0)
3521
3522 #define ADD_OVERFLOW(a,b) ((a + b) < a) ? (a = ULONG_MAX) : (a = a + b)
3523
3524 /* Convert format time string "XXwXXdXXhXXmXXs" into seconds value
3525  * returns the value or ULONG_MAX on integer overflow or incorrect format
3526  * Notes:
3527  *        1. the order of specifiers is arbitrary (may be: 5w3s or 3s5w)
3528  *        2. specifiers may be encountered multiple times (2s3s is 5 seconds)
3529  *        3. empty integer value is interpreted as 0
3530  */
3531 static unsigned long str2sec(const char* timestr)
3532 {
3533         const char spec[] = "smhdw";
3534         const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
3535         unsigned long val = 0;
3536         char *tail;
3537
3538         if (strpbrk(timestr, spec) == NULL) {
3539                 /* no specifiers inside the time string,
3540                    should treat it as an integer value */
3541                 val = strtoul(timestr, &tail, 10);
3542                 return *tail ? ULONG_MAX : val;
3543         }
3544
3545         /* format string is XXwXXdXXhXXmXXs */
3546         while (*timestr) {
3547                 unsigned long v;
3548                 int ind;
3549                 char* ptr;
3550
3551                 v = strtoul(timestr, &tail, 10);
3552                 if (v == ULONG_MAX || *tail == '\0')
3553                         /* value too large (ULONG_MAX or more)
3554                            or missing specifier */
3555                         goto error;
3556
3557                 ptr = strchr(spec, *tail);
3558                 if (ptr == NULL)
3559                         /* unknown specifier */
3560                         goto error;
3561
3562                 ind = ptr - spec;
3563
3564                 /* check if product will overflow the type */
3565                 if (!(v < ULONG_MAX / mult[ind]))
3566                         goto error;
3567
3568                 ADD_OVERFLOW(val, mult[ind] * v);
3569                 if (val == ULONG_MAX)
3570                         goto error;
3571
3572                 timestr = tail + 1;
3573         }
3574
3575         return val;
3576
3577 error:
3578         return ULONG_MAX;
3579 }
3580
3581 #define ARG2ULL(nr, str, def_units)                                     \
3582 do {                                                                    \
3583         unsigned long long limit, units = def_units;                    \
3584         int rc;                                                         \
3585                                                                         \
3586         rc = llapi_parse_size(str, &limit, &units, 1);                  \
3587         if (rc < 0) {                                                   \
3588                 fprintf(stderr, "error: bad limit value %s\n", str);    \
3589                 return CMD_HELP;                                        \
3590         }                                                               \
3591         nr = limit;                                                     \
3592 } while (0)
3593
3594 static inline int has_times_option(int argc, char **argv)
3595 {
3596         int i;
3597
3598         for (i = 1; i < argc; i++)
3599                 if (!strcmp(argv[i], "-t"))
3600                         return 1;
3601
3602         return 0;
3603 }
3604
3605 int lfs_setquota_times(int argc, char **argv)
3606 {
3607         int c, rc;
3608         struct if_quotactl qctl;
3609         char *mnt, *obd_type = (char *)qctl.obd_type;
3610         struct obd_dqblk *dqb = &qctl.qc_dqblk;
3611         struct obd_dqinfo *dqi = &qctl.qc_dqinfo;
3612         struct option long_opts[] = {
3613         { .val = 'b',   .name = "block-grace",  .has_arg = required_argument },
3614         { .val = 'g',   .name = "group",        .has_arg = no_argument },
3615         { .val = 'i',   .name = "inode-grace",  .has_arg = required_argument },
3616         { .val = 'p',   .name = "projid",       .has_arg = no_argument },
3617         { .val = 't',   .name = "times",        .has_arg = no_argument },
3618         { .val = 'u',   .name = "user",         .has_arg = no_argument },
3619         { .name = NULL } };
3620         int qtype;
3621
3622         memset(&qctl, 0, sizeof(qctl));
3623         qctl.qc_cmd  = LUSTRE_Q_SETINFO;
3624         qctl.qc_type = ALLQUOTA;
3625
3626         while ((c = getopt_long(argc, argv, "b:gi:ptu",
3627                                 long_opts, NULL)) != -1) {
3628                 switch (c) {
3629                 case 'u':
3630                         qtype = USRQUOTA;
3631                         goto quota_type;
3632                 case 'g':
3633                         qtype = GRPQUOTA;
3634                         goto quota_type;
3635                 case 'p':
3636                         qtype = PRJQUOTA;
3637 quota_type:
3638                         if (qctl.qc_type != ALLQUOTA) {
3639                                 fprintf(stderr, "error: -u/g/p can't be used "
3640                                                 "more than once\n");
3641                                 return CMD_HELP;
3642                         }
3643                         qctl.qc_type = qtype;
3644                         break;
3645                 case 'b':
3646                         if ((dqi->dqi_bgrace = str2sec(optarg)) == ULONG_MAX) {
3647                                 fprintf(stderr, "error: bad block-grace: %s\n",
3648                                         optarg);
3649                                 return CMD_HELP;
3650                         }
3651                         dqb->dqb_valid |= QIF_BTIME;
3652                         break;
3653                 case 'i':
3654                         if ((dqi->dqi_igrace = str2sec(optarg)) == ULONG_MAX) {
3655                                 fprintf(stderr, "error: bad inode-grace: %s\n",
3656                                         optarg);
3657                                 return CMD_HELP;
3658                         }
3659                         dqb->dqb_valid |= QIF_ITIME;
3660                         break;
3661                 case 't': /* Yes, of course! */
3662                         break;
3663                 default: /* getopt prints error message for us when opterr != 0 */
3664                         return CMD_HELP;
3665                 }
3666         }
3667
3668         if (qctl.qc_type == ALLQUOTA) {
3669                 fprintf(stderr, "error: neither -u, -g nor -p specified\n");
3670                 return CMD_HELP;
3671         }
3672
3673         if (optind != argc - 1) {
3674                 fprintf(stderr, "error: unexpected parameters encountered\n");
3675                 return CMD_HELP;
3676         }
3677
3678         mnt = argv[optind];
3679         rc = llapi_quotactl(mnt, &qctl);
3680         if (rc) {
3681                 if (*obd_type)
3682                         fprintf(stderr, "%s %s ", obd_type,
3683                                 obd_uuid2str(&qctl.obd_uuid));
3684                 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
3685                 return rc;
3686         }
3687
3688         return 0;
3689 }
3690
3691 #define BSLIMIT (1 << 0)
3692 #define BHLIMIT (1 << 1)
3693 #define ISLIMIT (1 << 2)
3694 #define IHLIMIT (1 << 3)
3695
3696 int lfs_setquota(int argc, char **argv)
3697 {
3698         int c, rc;
3699         struct if_quotactl qctl;
3700         char *mnt, *obd_type = (char *)qctl.obd_type;
3701         struct obd_dqblk *dqb = &qctl.qc_dqblk;
3702         struct option long_opts[] = {
3703                 {"block-softlimit", required_argument, 0, 'b'},
3704                 {"block-hardlimit", required_argument, 0, 'B'},
3705                 {"group",           required_argument, 0, 'g'},
3706                 {"inode-softlimit", required_argument, 0, 'i'},
3707                 {"inode-hardlimit", required_argument, 0, 'I'},
3708                 {"user",            required_argument, 0, 'u'},
3709                 {"projid",         required_argument, 0, 'p'},
3710                 {0, 0, 0, 0}
3711         };
3712         unsigned limit_mask = 0;
3713         char *endptr;
3714         int qtype;
3715
3716         if (has_times_option(argc, argv))
3717                 return lfs_setquota_times(argc, argv);
3718
3719         memset(&qctl, 0, sizeof(qctl));
3720         qctl.qc_cmd  = LUSTRE_Q_SETQUOTA;
3721         qctl.qc_type = ALLQUOTA; /* ALLQUOTA makes no sense for setquota,
3722                                   * so it can be used as a marker that qc_type
3723                                   * isn't reinitialized from command line */
3724
3725         while ((c = getopt_long(argc, argv, "b:B:g:i:I:p:u:",
3726                 long_opts, NULL)) != -1) {
3727                 switch (c) {
3728                 case 'u':
3729                         qtype = USRQUOTA;
3730                         rc = name2uid(&qctl.qc_id, optarg);
3731                         goto quota_type;
3732                 case 'g':
3733                         qtype = GRPQUOTA;
3734                         rc = name2gid(&qctl.qc_id, optarg);
3735                         goto quota_type;
3736                 case 'p':
3737                         qtype = PRJQUOTA;
3738                         rc = name2projid(&qctl.qc_id, optarg);
3739 quota_type:
3740                         if (qctl.qc_type != ALLQUOTA) {
3741                                 fprintf(stderr, "error: -u and -g can't be used"
3742                                                 " more than once\n");
3743                                 return CMD_HELP;
3744                         }
3745                         qctl.qc_type = qtype;
3746                         if (rc) {
3747                                 qctl.qc_id = strtoul(optarg, &endptr, 10);
3748                                 if (*endptr != '\0') {
3749                                         fprintf(stderr, "error: can't find id "
3750                                                 "for name %s\n", optarg);
3751                                         return CMD_HELP;
3752                                 }
3753                         }
3754                         break;
3755                 case 'b':
3756                         ARG2ULL(dqb->dqb_bsoftlimit, optarg, 1024);
3757                         dqb->dqb_bsoftlimit >>= 10;
3758                         limit_mask |= BSLIMIT;
3759                         if (dqb->dqb_bsoftlimit &&
3760                             dqb->dqb_bsoftlimit <= 1024) /* <= 1M? */
3761                                 fprintf(stderr, "warning: block softlimit is "
3762                                         "smaller than the miminal qunit size, "
3763                                         "please see the help of setquota or "
3764                                         "Lustre manual for details.\n");
3765                         break;
3766                 case 'B':
3767                         ARG2ULL(dqb->dqb_bhardlimit, optarg, 1024);
3768                         dqb->dqb_bhardlimit >>= 10;
3769                         limit_mask |= BHLIMIT;
3770                         if (dqb->dqb_bhardlimit &&
3771                             dqb->dqb_bhardlimit <= 1024) /* <= 1M? */
3772                                 fprintf(stderr, "warning: block hardlimit is "
3773                                         "smaller than the miminal qunit size, "
3774                                         "please see the help of setquota or "
3775                                         "Lustre manual for details.\n");
3776                         break;
3777                 case 'i':
3778                         ARG2ULL(dqb->dqb_isoftlimit, optarg, 1);
3779                         limit_mask |= ISLIMIT;
3780                         if (dqb->dqb_isoftlimit &&
3781                             dqb->dqb_isoftlimit <= 1024) /* <= 1K inodes? */
3782                                 fprintf(stderr, "warning: inode softlimit is "
3783                                         "smaller than the miminal qunit size, "
3784                                         "please see the help of setquota or "
3785                                         "Lustre manual for details.\n");
3786                         break;
3787                 case 'I':
3788                         ARG2ULL(dqb->dqb_ihardlimit, optarg, 1);
3789                         limit_mask |= IHLIMIT;
3790                         if (dqb->dqb_ihardlimit &&
3791                             dqb->dqb_ihardlimit <= 1024) /* <= 1K inodes? */
3792                                 fprintf(stderr, "warning: inode hardlimit is "
3793                                         "smaller than the miminal qunit size, "
3794                                         "please see the help of setquota or "
3795                                         "Lustre manual for details.\n");
3796                         break;
3797                 default: /* getopt prints error message for us when opterr != 0 */
3798                         return CMD_HELP;
3799                 }
3800         }
3801
3802         if (qctl.qc_type == ALLQUOTA) {
3803                 fprintf(stderr, "error: neither -u, -g nor -p was specified\n");
3804                 return CMD_HELP;
3805         }
3806
3807         if (limit_mask == 0) {
3808                 fprintf(stderr, "error: at least one limit must be specified\n");
3809                 return CMD_HELP;
3810         }
3811
3812         if (optind != argc - 1) {
3813                 fprintf(stderr, "error: unexpected parameters encountered\n");
3814                 return CMD_HELP;
3815         }
3816
3817         mnt = argv[optind];
3818
3819         if ((!(limit_mask & BHLIMIT) ^ !(limit_mask & BSLIMIT)) ||
3820             (!(limit_mask & IHLIMIT) ^ !(limit_mask & ISLIMIT))) {
3821                 /* sigh, we can't just set blimits/ilimits */
3822                 struct if_quotactl tmp_qctl = {.qc_cmd  = LUSTRE_Q_GETQUOTA,
3823                                                .qc_type = qctl.qc_type,
3824                                                .qc_id   = qctl.qc_id};
3825
3826                 rc = llapi_quotactl(mnt, &tmp_qctl);
3827                 if (rc < 0) {
3828                         fprintf(stderr, "error: setquota failed while retrieving"
3829                                         " current quota settings (%s)\n",
3830                                         strerror(-rc));
3831                         return rc;
3832                 }
3833
3834                 if (!(limit_mask & BHLIMIT))
3835                         dqb->dqb_bhardlimit = tmp_qctl.qc_dqblk.dqb_bhardlimit;
3836                 if (!(limit_mask & BSLIMIT))
3837                         dqb->dqb_bsoftlimit = tmp_qctl.qc_dqblk.dqb_bsoftlimit;
3838                 if (!(limit_mask & IHLIMIT))
3839                         dqb->dqb_ihardlimit = tmp_qctl.qc_dqblk.dqb_ihardlimit;
3840                 if (!(limit_mask & ISLIMIT))
3841                         dqb->dqb_isoftlimit = tmp_qctl.qc_dqblk.dqb_isoftlimit;
3842
3843                 /* Keep grace times if we have got no softlimit arguments */
3844                 if ((limit_mask & BHLIMIT) && !(limit_mask & BSLIMIT)) {
3845                         dqb->dqb_valid |= QIF_BTIME;
3846                         dqb->dqb_btime = tmp_qctl.qc_dqblk.dqb_btime;
3847                 }
3848
3849                 if ((limit_mask & IHLIMIT) && !(limit_mask & ISLIMIT)) {
3850                         dqb->dqb_valid |= QIF_ITIME;
3851                         dqb->dqb_itime = tmp_qctl.qc_dqblk.dqb_itime;
3852                 }
3853         }
3854
3855         dqb->dqb_valid |= (limit_mask & (BHLIMIT | BSLIMIT)) ? QIF_BLIMITS : 0;
3856         dqb->dqb_valid |= (limit_mask & (IHLIMIT | ISLIMIT)) ? QIF_ILIMITS : 0;
3857
3858         rc = llapi_quotactl(mnt, &qctl);
3859         if (rc) {
3860                 if (*obd_type)
3861                         fprintf(stderr, "%s %s ", obd_type,
3862                                 obd_uuid2str(&qctl.obd_uuid));
3863                 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
3864                 return rc;
3865         }
3866
3867         return 0;
3868 }
3869
3870 /* Converts seconds value into format string
3871  * result is returned in buf
3872  * Notes:
3873  *        1. result is in descenting order: 1w2d3h4m5s
3874  *        2. zero fields are not filled (except for p. 3): 5d1s
3875  *        3. zero seconds value is presented as "0s"
3876  */
3877 static char * __sec2str(time_t seconds, char *buf)
3878 {
3879         const char spec[] = "smhdw";
3880         const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
3881         unsigned long c;
3882         char *tail = buf;
3883         int i;
3884
3885         for (i = sizeof(mult) / sizeof(mult[0]) - 1 ; i >= 0; i--) {
3886                 c = seconds / mult[i];
3887
3888                 if (c > 0 || (i == 0 && buf == tail))
3889                         tail += snprintf(tail, 40-(tail-buf), "%lu%c", c, spec[i]);
3890
3891                 seconds %= mult[i];
3892         }
3893
3894         return tail;
3895 }
3896
3897 static void sec2str(time_t seconds, char *buf, int rc)
3898 {
3899         char *tail = buf;
3900
3901         if (rc)
3902                 *tail++ = '[';
3903
3904         tail = __sec2str(seconds, tail);
3905
3906         if (rc && tail - buf < 39) {
3907                 *tail++ = ']';
3908                 *tail++ = 0;
3909         }
3910 }
3911
3912 static void diff2str(time_t seconds, char *buf, time_t now)
3913 {
3914
3915         buf[0] = 0;
3916         if (!seconds)
3917                 return;
3918         if (seconds <= now) {
3919                 strcpy(buf, "none");
3920                 return;
3921         }
3922         __sec2str(seconds - now, buf);
3923 }
3924
3925 static void print_quota_title(char *name, struct if_quotactl *qctl,
3926                               bool human_readable)
3927 {
3928         printf("Disk quotas for %s %s (%cid %u):\n",
3929                qtype_name(qctl->qc_type), name,
3930                *qtype_name(qctl->qc_type), qctl->qc_id);
3931         printf("%15s%8s %7s%8s%8s%8s %7s%8s%8s\n",
3932                "Filesystem", human_readable ? "used" : "kbytes",
3933                "quota", "limit", "grace",
3934                "files", "quota", "limit", "grace");
3935 }
3936
3937 static void kbytes2str(__u64 num, char *buf, int buflen, bool h)
3938 {
3939         if (!h) {
3940                 snprintf(buf, buflen, "%ju", (uintmax_t)num);
3941         } else {
3942                 if (num >> 40)
3943                         snprintf(buf, buflen, "%5.4gP",
3944                                  (double)num / ((__u64)1 << 40));
3945                 else if (num >> 30)
3946                         snprintf(buf, buflen, "%5.4gT",
3947                                  (double)num / (1 << 30));
3948                 else if (num >> 20)
3949                         snprintf(buf, buflen, "%5.4gG",
3950                                  (double)num / (1 << 20));
3951                 else if (num >> 10)
3952                         snprintf(buf, buflen, "%5.4gM",
3953                                  (double)num / (1 << 10));
3954                 else
3955                         snprintf(buf, buflen, "%ju%s", (uintmax_t)num, "k");
3956         }
3957 }
3958
3959 #define STRBUF_LEN      32
3960 static void print_quota(char *mnt, struct if_quotactl *qctl, int type,
3961                         int rc, bool h)
3962 {
3963         time_t now;
3964
3965         time(&now);
3966
3967         if (qctl->qc_cmd == LUSTRE_Q_GETQUOTA || qctl->qc_cmd == Q_GETOQUOTA) {
3968                 int bover = 0, iover = 0;
3969                 struct obd_dqblk *dqb = &qctl->qc_dqblk;
3970                 char numbuf[3][STRBUF_LEN];
3971                 char timebuf[40];
3972                 char strbuf[STRBUF_LEN];
3973
3974                 if (dqb->dqb_bhardlimit &&
3975                     lustre_stoqb(dqb->dqb_curspace) >= dqb->dqb_bhardlimit) {
3976                         bover = 1;
3977                 } else if (dqb->dqb_bsoftlimit && dqb->dqb_btime) {
3978                         if (dqb->dqb_btime > now) {
3979                                 bover = 2;
3980                         } else {
3981                                 bover = 3;
3982                         }
3983                 }
3984
3985                 if (dqb->dqb_ihardlimit &&
3986                     dqb->dqb_curinodes >= dqb->dqb_ihardlimit) {
3987                         iover = 1;
3988                 } else if (dqb->dqb_isoftlimit && dqb->dqb_itime) {
3989                         if (dqb->dqb_itime > now) {
3990                                 iover = 2;
3991                         } else {
3992                                 iover = 3;
3993                         }
3994                 }
3995
3996
3997                 if (strlen(mnt) > 15)
3998                         printf("%s\n%15s", mnt, "");
3999                 else
4000                         printf("%15s", mnt);
4001
4002                 if (bover)
4003                         diff2str(dqb->dqb_btime, timebuf, now);
4004
4005                 kbytes2str(lustre_stoqb(dqb->dqb_curspace),
4006                            strbuf, sizeof(strbuf), h);
4007                 if (rc == -EREMOTEIO)
4008                         sprintf(numbuf[0], "%s*", strbuf);
4009                 else
4010                         sprintf(numbuf[0], (dqb->dqb_valid & QIF_SPACE) ?
4011                                 "%s" : "[%s]", strbuf);
4012
4013                 kbytes2str(dqb->dqb_bsoftlimit, strbuf, sizeof(strbuf), h);
4014                 if (type == QC_GENERAL)
4015                         sprintf(numbuf[1], (dqb->dqb_valid & QIF_BLIMITS) ?
4016                                 "%s" : "[%s]", strbuf);
4017                 else
4018                         sprintf(numbuf[1], "%s", "-");
4019
4020                 kbytes2str(dqb->dqb_bhardlimit, strbuf, sizeof(strbuf), h);
4021                 sprintf(numbuf[2], (dqb->dqb_valid & QIF_BLIMITS) ?
4022                         "%s" : "[%s]", strbuf);
4023
4024                 printf(" %7s%c %6s %7s %7s",
4025                        numbuf[0], bover ? '*' : ' ', numbuf[1],
4026                        numbuf[2], bover > 1 ? timebuf : "-");
4027
4028                 if (iover)
4029                         diff2str(dqb->dqb_itime, timebuf, now);
4030
4031                 sprintf(numbuf[0], (dqb->dqb_valid & QIF_INODES) ?
4032                         "%ju" : "[%ju]", (uintmax_t)dqb->dqb_curinodes);
4033
4034                 if (type == QC_GENERAL)
4035                         sprintf(numbuf[1], (dqb->dqb_valid & QIF_ILIMITS) ?
4036                                 "%ju" : "[%ju]",
4037                                 (uintmax_t)dqb->dqb_isoftlimit);
4038                 else
4039                         sprintf(numbuf[1], "%s", "-");
4040
4041                 sprintf(numbuf[2], (dqb->dqb_valid & QIF_ILIMITS) ?
4042                         "%ju" : "[%ju]", (uintmax_t)dqb->dqb_ihardlimit);
4043
4044                 if (type != QC_OSTIDX)
4045                         printf(" %7s%c %6s %7s %7s",
4046                                numbuf[0], iover ? '*' : ' ', numbuf[1],
4047                                numbuf[2], iover > 1 ? timebuf : "-");
4048                 else
4049                         printf(" %7s %7s %7s %7s", "-", "-", "-", "-");
4050                 printf("\n");
4051
4052         } else if (qctl->qc_cmd == LUSTRE_Q_GETINFO ||
4053                    qctl->qc_cmd == Q_GETOINFO) {
4054                 char bgtimebuf[40];
4055                 char igtimebuf[40];
4056
4057                 sec2str(qctl->qc_dqinfo.dqi_bgrace, bgtimebuf, rc);
4058                 sec2str(qctl->qc_dqinfo.dqi_igrace, igtimebuf, rc);
4059                 printf("Block grace time: %s; Inode grace time: %s\n",
4060                        bgtimebuf, igtimebuf);
4061         }
4062 }
4063
4064 static int print_obd_quota(char *mnt, struct if_quotactl *qctl, int is_mdt,
4065                            bool h, __u64 *total)
4066 {
4067         int rc = 0, rc1 = 0, count = 0;
4068         __u32 valid = qctl->qc_valid;
4069
4070         rc = llapi_get_obd_count(mnt, &count, is_mdt);
4071         if (rc) {
4072                 fprintf(stderr, "can not get %s count: %s\n",
4073                         is_mdt ? "mdt": "ost", strerror(-rc));
4074                 return rc;
4075         }
4076
4077         for (qctl->qc_idx = 0; qctl->qc_idx < count; qctl->qc_idx++) {
4078                 qctl->qc_valid = is_mdt ? QC_MDTIDX : QC_OSTIDX;
4079                 rc = llapi_quotactl(mnt, qctl);
4080                 if (rc) {
4081                         /* It is remote client case. */
4082                         if (rc == -EOPNOTSUPP) {
4083                                 rc = 0;
4084                                 goto out;
4085                         }
4086
4087                         if (!rc1)
4088                                 rc1 = rc;
4089                         fprintf(stderr, "quotactl %s%d failed.\n",
4090                                 is_mdt ? "mdt": "ost", qctl->qc_idx);
4091                         continue;
4092                 }
4093
4094                 print_quota(obd_uuid2str(&qctl->obd_uuid), qctl,
4095                             qctl->qc_valid, 0, h);
4096                 *total += is_mdt ? qctl->qc_dqblk.dqb_ihardlimit :
4097                                    qctl->qc_dqblk.dqb_bhardlimit;
4098         }
4099 out:
4100         qctl->qc_valid = valid;
4101         return rc ? : rc1;
4102 }
4103
4104 static int lfs_quota(int argc, char **argv)
4105 {
4106         int c;
4107         char *mnt, *name = NULL;
4108         struct if_quotactl qctl = { .qc_cmd = LUSTRE_Q_GETQUOTA,
4109                                     .qc_type = ALLQUOTA };
4110         char *obd_type = (char *)qctl.obd_type;
4111         char *obd_uuid = (char *)qctl.obd_uuid.uuid;
4112         int rc = 0, rc1 = 0, rc2 = 0, rc3 = 0,
4113             verbose = 0, pass = 0, quiet = 0, inacc;
4114         char *endptr;
4115         __u32 valid = QC_GENERAL, idx = 0;
4116         __u64 total_ialloc = 0, total_balloc = 0;
4117         bool human_readable = false;
4118         int qtype;
4119
4120         while ((c = getopt(argc, argv, "gi:I:o:pqtuvh")) != -1) {
4121                 switch (c) {
4122                 case 'u':
4123                         qtype = USRQUOTA;
4124                         goto quota_type;
4125                 case 'g':
4126                         qtype = GRPQUOTA;
4127                         goto quota_type;
4128                 case 'p':
4129                         qtype = PRJQUOTA;
4130 quota_type:
4131                         if (qctl.qc_type != ALLQUOTA) {
4132                                 fprintf(stderr, "error: use either -u or -g\n");
4133                                 return CMD_HELP;
4134                         }
4135                         qctl.qc_type = qtype;
4136                         break;
4137                 case 't':
4138                         qctl.qc_cmd = LUSTRE_Q_GETINFO;
4139                         break;
4140                 case 'o':
4141                         valid = qctl.qc_valid = QC_UUID;
4142                         strlcpy(obd_uuid, optarg, sizeof(qctl.obd_uuid));
4143                         break;
4144                 case 'i':
4145                         valid = qctl.qc_valid = QC_MDTIDX;
4146                         idx = qctl.qc_idx = atoi(optarg);
4147                         break;
4148                 case 'I':
4149                         valid = qctl.qc_valid = QC_OSTIDX;
4150                         idx = qctl.qc_idx = atoi(optarg);
4151                         break;
4152                 case 'v':
4153                         verbose = 1;
4154                         break;
4155                 case 'q':
4156                         quiet = 1;
4157                         break;
4158                 case 'h':
4159                         human_readable = true;
4160                         break;
4161                 default:
4162                         fprintf(stderr, "error: %s: option '-%c' "
4163                                         "unrecognized\n", argv[0], c);
4164                         return CMD_HELP;
4165                 }
4166         }
4167
4168         /* current uid/gid info for "lfs quota /path/to/lustre/mount" */
4169         if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA && qctl.qc_type == ALLQUOTA &&
4170             optind == argc - 1) {
4171 all_output:
4172                 memset(&qctl, 0, sizeof(qctl)); /* spoiled by print_*_quota */
4173                 qctl.qc_cmd = LUSTRE_Q_GETQUOTA;
4174                 qctl.qc_valid = valid;
4175                 qctl.qc_idx = idx;
4176                 qctl.qc_type = pass;
4177                 switch (qctl.qc_type) {
4178                 case USRQUOTA:
4179                         qctl.qc_id = geteuid();
4180                         rc = uid2name(&name, qctl.qc_id);
4181                         break;
4182                 case GRPQUOTA:
4183                         qctl.qc_id = getegid();
4184                         rc = gid2name(&name, qctl.qc_id);
4185                         break;
4186                 default:
4187                         rc = -ENOTSUP;
4188                         break;
4189                 }
4190                 if (rc)
4191                         name = "<unknown>";
4192                 pass++;
4193         /* lfs quota -u username /path/to/lustre/mount */
4194         } else if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA) {
4195                 /* options should be followed by u/g-name and mntpoint */
4196                 if (optind + 2 != argc || qctl.qc_type == ALLQUOTA) {
4197                         fprintf(stderr, "error: missing quota argument(s)\n");
4198                         return CMD_HELP;
4199                 }
4200
4201                 name = argv[optind++];
4202                 switch (qctl.qc_type) {
4203                 case USRQUOTA:
4204                         rc = name2uid(&qctl.qc_id, name);
4205                         break;
4206                 case GRPQUOTA:
4207                         rc = name2gid(&qctl.qc_id, name);
4208                         break;
4209                 case PRJQUOTA:
4210                         rc = name2projid(&qctl.qc_id, name);
4211                         break;
4212                 default:
4213                         rc = -ENOTSUP;
4214                         break;
4215                 }
4216                 if (rc) {
4217                         qctl.qc_id = strtoul(name, &endptr, 10);
4218                         if (*endptr != '\0') {
4219                                 fprintf(stderr, "error: can't find id for name: %s\n",
4220                                                 name);
4221                                 return CMD_HELP;
4222                         }
4223                 }
4224         } else if (optind + 1 != argc || qctl.qc_type == ALLQUOTA) {
4225                 fprintf(stderr, "error: missing quota info argument(s)\n");
4226                 return CMD_HELP;
4227         }
4228
4229         mnt = argv[optind];
4230         rc1 = llapi_quotactl(mnt, &qctl);
4231         if (rc1 < 0) {
4232                 switch (rc1) {
4233                 case -ESRCH:
4234                         fprintf(stderr, "%s quotas are not enabled.\n",
4235                                 qtype_name(qctl.qc_type));
4236                         goto out;
4237                 case -EPERM:
4238                         fprintf(stderr, "Permission denied.\n");
4239                 case -ENODEV:
4240                 case -ENOENT:
4241                         /* We already got error message. */
4242                         goto out;
4243                 default:
4244                         fprintf(stderr, "Unexpected quotactl error: %s\n",
4245                                 strerror(-rc1));
4246                 }
4247         }
4248
4249         if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA && !quiet)
4250                 print_quota_title(name, &qctl, human_readable);
4251
4252         if (rc1 && *obd_type)
4253                 fprintf(stderr, "%s %s ", obd_type, obd_uuid);
4254
4255         if (qctl.qc_valid != QC_GENERAL)
4256                 mnt = "";
4257
4258         inacc = (qctl.qc_cmd == LUSTRE_Q_GETQUOTA) &&
4259                 ((qctl.qc_dqblk.dqb_valid & (QIF_LIMITS|QIF_USAGE)) !=
4260                  (QIF_LIMITS|QIF_USAGE));
4261
4262         print_quota(mnt, &qctl, QC_GENERAL, rc1, human_readable);
4263
4264         if (qctl.qc_valid == QC_GENERAL && qctl.qc_cmd != LUSTRE_Q_GETINFO &&
4265             verbose) {
4266                 char strbuf[STRBUF_LEN];
4267
4268                 rc2 = print_obd_quota(mnt, &qctl, 1, human_readable,
4269                                       &total_ialloc);
4270                 rc3 = print_obd_quota(mnt, &qctl, 0, human_readable,
4271                                       &total_balloc);
4272                 kbytes2str(total_balloc, strbuf, sizeof(strbuf),
4273                            human_readable);
4274                 printf("Total allocated inode limit: %ju, total "
4275                        "allocated block limit: %s\n", (uintmax_t)total_ialloc,
4276                        strbuf);
4277         }
4278
4279         if (rc1 || rc2 || rc3 || inacc)
4280                 printf("Some errors happened when getting quota info. "
4281                        "Some devices may be not working or deactivated. "
4282                        "The data in \"[]\" is inaccurate.\n");
4283
4284 out:
4285         if (pass > 0 && pass < LL_MAXQUOTAS)
4286                 goto all_output;
4287
4288         return rc1;
4289 }
4290 #endif /* HAVE_SYS_QUOTA_H! */
4291
4292 static int flushctx_ioctl(char *mp)
4293 {
4294         int fd, rc;
4295
4296         fd = open(mp, O_RDONLY);
4297         if (fd == -1) {
4298                 fprintf(stderr, "flushctx: error open %s: %s\n",
4299                         mp, strerror(errno));
4300                 return -1;
4301         }
4302
4303         rc = ioctl(fd, LL_IOC_FLUSHCTX);
4304         if (rc == -1)
4305                 fprintf(stderr, "flushctx: error ioctl %s: %s\n",
4306                         mp, strerror(errno));
4307
4308         close(fd);
4309         return rc;
4310 }
4311
4312 static int lfs_flushctx(int argc, char **argv)
4313 {
4314         int     kdestroy = 0, c;
4315         char    mntdir[PATH_MAX] = {'\0'};
4316         int     index = 0;
4317         int     rc = 0;
4318
4319         while ((c = getopt(argc, argv, "k")) != -1) {
4320                 switch (c) {
4321                 case 'k':
4322                         kdestroy = 1;
4323                         break;
4324                 default:
4325                         fprintf(stderr, "error: %s: option '-%c' "
4326                                         "unrecognized\n", argv[0], c);
4327                         return CMD_HELP;
4328                 }
4329         }
4330
4331         if (kdestroy) {
4332             if ((rc = system("kdestroy > /dev/null")) != 0) {
4333                 rc = WEXITSTATUS(rc);
4334                 fprintf(stderr, "error destroying tickets: %d, continuing\n", rc);
4335             }
4336         }
4337
4338         if (optind >= argc) {
4339                 /* flush for all mounted lustre fs. */
4340                 while (!llapi_search_mounts(NULL, index++, mntdir, NULL)) {
4341                         /* Check if we have a mount point */
4342                         if (mntdir[0] == '\0')
4343                                 continue;
4344
4345                         if (flushctx_ioctl(mntdir))
4346                                 rc = -1;
4347
4348                         mntdir[0] = '\0'; /* avoid matching in next loop */
4349                 }
4350         } else {
4351                 /* flush fs as specified */
4352                 while (optind < argc) {
4353                         if (flushctx_ioctl(argv[optind++]))
4354                                 rc = -1;
4355                 }
4356         }
4357         return rc;
4358 }
4359
4360 static int lfs_cp(int argc, char **argv)
4361 {
4362         fprintf(stderr, "remote client copy file(s).\n"
4363                 "obsolete, does not support it anymore.\n");
4364         return 0;
4365 }
4366
4367 static int lfs_ls(int argc, char **argv)
4368 {
4369         fprintf(stderr, "remote client lists directory contents.\n"
4370                 "obsolete, does not support it anymore.\n");
4371         return 0;
4372 }
4373
4374 static int lfs_changelog(int argc, char **argv)
4375 {
4376         void *changelog_priv;
4377         struct changelog_rec *rec;
4378         long long startrec = 0, endrec = 0;
4379         char *mdd;
4380         struct option long_opts[] = {
4381                 {"follow", no_argument, 0, 'f'},
4382                 {0, 0, 0, 0}
4383         };
4384         char short_opts[] = "f";
4385         int rc, follow = 0;
4386
4387         while ((rc = getopt_long(argc, argv, short_opts,
4388                                 long_opts, NULL)) != -1) {
4389                 switch (rc) {
4390                 case 'f':
4391                         follow++;
4392                         break;
4393                 case '?':
4394                         return CMD_HELP;
4395                 default:
4396                         fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4397                                 argv[0], argv[optind - 1]);
4398                         return CMD_HELP;
4399                 }
4400         }
4401         if (optind >= argc)
4402                 return CMD_HELP;
4403
4404         mdd = argv[optind++];
4405         if (argc > optind)
4406                 startrec = strtoll(argv[optind++], NULL, 10);
4407         if (argc > optind)
4408                 endrec = strtoll(argv[optind++], NULL, 10);
4409
4410         rc = llapi_changelog_start(&changelog_priv,
4411                                    CHANGELOG_FLAG_BLOCK |
4412                                    CHANGELOG_FLAG_JOBID |
4413                                    (follow ? CHANGELOG_FLAG_FOLLOW : 0),
4414                                    mdd, startrec);
4415         if (rc < 0) {
4416                 fprintf(stderr, "Can't start changelog: %s\n",
4417                         strerror(errno = -rc));
4418                 return rc;
4419         }
4420
4421         while ((rc = llapi_changelog_recv(changelog_priv, &rec)) == 0) {
4422                 time_t secs;
4423                 struct tm ts;
4424
4425                 if (endrec && rec->cr_index > endrec) {
4426                         llapi_changelog_free(&rec);
4427                         break;
4428                 }
4429                 if (rec->cr_index < startrec) {
4430                         llapi_changelog_free(&rec);
4431                         continue;
4432                 }
4433
4434                 secs = rec->cr_time >> 30;
4435                 gmtime_r(&secs, &ts);
4436                 printf("%ju %02d%-5s %02d:%02d:%02d.%09d %04d.%02d.%02d "
4437                        "0x%x t="DFID, (uintmax_t)rec->cr_index, rec->cr_type,
4438                        changelog_type2str(rec->cr_type),
4439                        ts.tm_hour, ts.tm_min, ts.tm_sec,
4440                        (int)(rec->cr_time & ((1 << 30) - 1)),
4441                        ts.tm_year + 1900, ts.tm_mon + 1, ts.tm_mday,
4442                        rec->cr_flags & CLF_FLAGMASK, PFID(&rec->cr_tfid));
4443
4444                 if (rec->cr_flags & CLF_JOBID) {
4445                         struct changelog_ext_jobid *jid =
4446                                 changelog_rec_jobid(rec);
4447
4448                         if (jid->cr_jobid[0] != '\0')
4449                                 printf(" j=%s", jid->cr_jobid);
4450                 }
4451
4452                 if (rec->cr_namelen)
4453                         printf(" p="DFID" %.*s", PFID(&rec->cr_pfid),
4454                                rec->cr_namelen, changelog_rec_name(rec));
4455
4456                 if (rec->cr_flags & CLF_RENAME) {
4457                         struct changelog_ext_rename *rnm =
4458                                 changelog_rec_rename(rec);
4459
4460                         if (!fid_is_zero(&rnm->cr_sfid))
4461                                 printf(" s="DFID" sp="DFID" %.*s",
4462                                        PFID(&rnm->cr_sfid),
4463                                        PFID(&rnm->cr_spfid),
4464                                        (int)changelog_rec_snamelen(rec),
4465                                        changelog_rec_sname(rec));
4466                 }
4467                 printf("\n");
4468
4469                 llapi_changelog_free(&rec);
4470         }
4471
4472         llapi_changelog_fini(&changelog_priv);
4473
4474         if (rc < 0)
4475                 fprintf(stderr, "Changelog: %s\n", strerror(errno = -rc));
4476
4477         return (rc == 1 ? 0 : rc);
4478 }
4479
4480 static int lfs_changelog_clear(int argc, char **argv)
4481 {
4482         long long endrec;
4483         int rc;
4484
4485         if (argc != 4)
4486                 return CMD_HELP;
4487
4488         endrec = strtoll(argv[3], NULL, 10);
4489
4490         rc = llapi_changelog_clear(argv[1], argv[2], endrec);
4491
4492         if (rc == -EINVAL)
4493                 fprintf(stderr, "%s: record out of range: %llu\n",
4494                         argv[0], endrec);
4495         else if (rc == -ENOENT)
4496                 fprintf(stderr, "%s: no changelog user: %s\n",
4497                         argv[0], argv[2]);
4498         else if (rc)
4499                 fprintf(stderr, "%s error: %s\n", argv[0],
4500                         strerror(-rc));
4501
4502         if (rc)
4503                 errno = -rc;
4504
4505         return rc;
4506 }
4507
4508 static int lfs_fid2path(int argc, char **argv)
4509 {
4510         struct option long_opts[] = {
4511                 { .val = 'c',   .name = "cur",  .has_arg = no_argument },
4512                 { .val = 'l',   .name = "link", .has_arg = required_argument },
4513                 { .val = 'r',   .name = "rec",  .has_arg = required_argument },
4514                 { .name = NULL } };
4515         char  short_opts[] = "cl:r:";
4516         char *device, *fid, *path;
4517         long long recno = -1;
4518         int linkno = -1;
4519         int lnktmp;
4520         int printcur = 0;
4521         int rc = 0;
4522
4523         while ((rc = getopt_long(argc, argv, short_opts,
4524                 long_opts, NULL)) != -1) {
4525                 switch (rc) {
4526                 case 'c':
4527                         printcur++;
4528                         break;
4529                 case 'l':
4530                         linkno = strtol(optarg, NULL, 10);
4531                         break;
4532                 case 'r':
4533                         recno = strtoll(optarg, NULL, 10);
4534                         break;
4535                 case '?':
4536                         return CMD_HELP;
4537                 default:
4538                         fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4539                                 argv[0], argv[optind - 1]);
4540                         return CMD_HELP;
4541                 }
4542         }
4543
4544         if (argc < 3)
4545                 return CMD_HELP;
4546
4547         device = argv[optind++];
4548         path = calloc(1, PATH_MAX);
4549         if (path == NULL) {
4550                 fprintf(stderr, "error: Not enough memory\n");
4551                 return -errno;
4552         }
4553
4554         rc = 0;
4555         while (optind < argc) {
4556                 fid = argv[optind++];
4557
4558                 lnktmp = (linkno >= 0) ? linkno : 0;
4559                 while (1) {
4560                         int oldtmp = lnktmp;
4561                         long long rectmp = recno;
4562                         int rc2;
4563                         rc2 = llapi_fid2path(device, fid, path, PATH_MAX,
4564                                              &rectmp, &lnktmp);
4565                         if (rc2 < 0) {
4566                                 fprintf(stderr, "%s: error on FID %s: %s\n",
4567                                         argv[0], fid, strerror(errno = -rc2));
4568                                 if (rc == 0)
4569                                         rc = rc2;
4570                                 break;
4571                         }
4572
4573                         if (printcur)
4574                                 fprintf(stdout, "%lld ", rectmp);
4575                         if (device[0] == '/') {
4576                                 fprintf(stdout, "%s", device);
4577                                 if (device[strlen(device) - 1] != '/')
4578                                         fprintf(stdout, "/");
4579                         } else if (path[0] == '\0') {
4580                                 fprintf(stdout, "/");
4581                         }
4582                         fprintf(stdout, "%s\n", path);
4583
4584                         if (linkno >= 0)
4585                                 /* specified linkno */
4586                                 break;
4587                         if (oldtmp == lnktmp)
4588                                 /* no more links */
4589                                 break;
4590                 }
4591         }
4592
4593         free(path);
4594         return rc;
4595 }
4596
4597 static int lfs_path2fid(int argc, char **argv)
4598 {
4599         struct option     long_opts[] = {
4600                 {"parents", no_argument, 0, 'p'},
4601                 {0, 0, 0, 0}
4602         };
4603         char            **path;
4604         const char        short_opts[] = "p";
4605         const char       *sep = "";
4606         lustre_fid        fid;
4607         int               rc = 0;
4608         bool              show_parents = false;
4609
4610         while ((rc = getopt_long(argc, argv, short_opts,
4611                                  long_opts, NULL)) != -1) {
4612                 switch (rc) {
4613                 case 'p':
4614                         show_parents = true;
4615                         break;
4616                 default:
4617                         fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4618                                 argv[0], argv[optind - 1]);
4619                         return CMD_HELP;
4620                 }
4621         }
4622
4623         if (optind > argc - 1)
4624                 return CMD_HELP;
4625         else if (optind < argc - 1)
4626                 sep = ": ";
4627
4628         rc = 0;
4629         for (path = argv + optind; *path != NULL; path++) {
4630                 int err = 0;
4631                 if (!show_parents) {
4632                         err = llapi_path2fid(*path, &fid);
4633                         if (!err)
4634                                 printf("%s%s"DFID"\n",
4635                                        *sep != '\0' ? *path : "", sep,
4636                                        PFID(&fid));
4637                 } else {
4638                         char            name[NAME_MAX + 1];
4639                         unsigned int    linkno = 0;
4640
4641                         while ((err = llapi_path2parent(*path, linkno, &fid,
4642                                                 name, sizeof(name))) == 0) {
4643                                 if (*sep != '\0' && linkno == 0)
4644                                         printf("%s%s", *path, sep);
4645
4646                                 printf("%s"DFID"/%s", linkno != 0 ? "\t" : "",
4647                                        PFID(&fid), name);
4648                                 linkno++;
4649                         }
4650
4651                         /* err == -ENODATA is end-of-loop */
4652                         if (linkno > 0 && err == -ENODATA) {
4653                                 printf("\n");
4654                                 err = 0;
4655                         }
4656                 }
4657
4658                 if (err) {
4659                         fprintf(stderr, "%s: can't get %sfid for %s: %s\n",
4660                                 argv[0], show_parents ? "parent " : "", *path,
4661                                 strerror(-err));
4662                         if (rc == 0) {
4663                                 rc = err;
4664                                 errno = -err;
4665                         }
4666                 }
4667         }
4668
4669         return rc;
4670 }
4671
4672 static int lfs_data_version(int argc, char **argv)
4673 {
4674         char *path;
4675         __u64 data_version;
4676         int fd;
4677         int rc;
4678         int c;
4679         int data_version_flags = LL_DV_RD_FLUSH; /* Read by default */
4680
4681         if (argc < 2)
4682                 return CMD_HELP;
4683
4684         while ((c = getopt(argc, argv, "nrw")) != -1) {
4685                 switch (c) {
4686                 case 'n':
4687                         data_version_flags = 0;
4688                         break;
4689                 case 'r':
4690                         data_version_flags |= LL_DV_RD_FLUSH;
4691                         break;
4692                 case 'w':
4693                         data_version_flags |= LL_DV_WR_FLUSH;
4694                         break;
4695                 default:
4696                         return CMD_HELP;
4697                 }
4698         }
4699         if (optind == argc)
4700                 return CMD_HELP;
4701
4702         path = argv[optind];
4703         fd = open(path, O_RDONLY);
4704         if (fd < 0)
4705                 err(errno, "cannot open file %s", path);
4706
4707         rc = llapi_get_data_version(fd, &data_version, data_version_flags);
4708         if (rc < 0)
4709                 err(errno, "cannot get version for %s", path);
4710         else
4711                 printf("%ju" "\n", (uintmax_t)data_version);
4712
4713         close(fd);
4714         return rc;
4715 }
4716
4717 static int lfs_hsm_state(int argc, char **argv)
4718 {
4719         int rc;
4720         int i = 1;
4721         char *path;
4722         struct hsm_user_state hus;
4723
4724         if (argc < 2)
4725                 return CMD_HELP;
4726
4727         do {
4728                 path = argv[i];
4729
4730                 rc = llapi_hsm_state_get(path, &hus);
4731                 if (rc) {
4732                         fprintf(stderr, "can't get hsm state for %s: %s\n",
4733                                 path, strerror(errno = -rc));
4734                         return rc;
4735                 }
4736
4737                 /* Display path name and status flags */
4738                 printf("%s: (0x%08x)", path, hus.hus_states);
4739
4740                 if (hus.hus_states & HS_RELEASED)
4741                         printf(" released");
4742                 if (hus.hus_states & HS_EXISTS)
4743                         printf(" exists");
4744                 if (hus.hus_states & HS_DIRTY)
4745                         printf(" dirty");
4746                 if (hus.hus_states & HS_ARCHIVED)
4747                         printf(" archived");
4748                 /* Display user-settable flags */
4749                 if (hus.hus_states & HS_NORELEASE)
4750                         printf(" never_release");
4751                 if (hus.hus_states & HS_NOARCHIVE)
4752                         printf(" never_archive");
4753                 if (hus.hus_states & HS_LOST)
4754                         printf(" lost_from_hsm");
4755
4756                 if (hus.hus_archive_id != 0)
4757                         printf(", archive_id:%d", hus.hus_archive_id);
4758                 printf("\n");
4759
4760         } while (++i < argc);
4761
4762         return 0;
4763 }
4764
4765 #define LFS_HSM_SET   0
4766 #define LFS_HSM_CLEAR 1
4767
4768 /**
4769  * Generic function to set or clear HSM flags.
4770  * Used by hsm_set and hsm_clear.
4771  *
4772  * @mode  if LFS_HSM_SET, set the flags, if LFS_HSM_CLEAR, clear the flags.
4773  */
4774 static int lfs_hsm_change_flags(int argc, char **argv, int mode)
4775 {
4776         struct option long_opts[] = {
4777                 {"lost", 0, 0, 'l'},
4778                 {"norelease", 0, 0, 'r'},
4779                 {"noarchive", 0, 0, 'a'},
4780                 {"archived", 0, 0, 'A'},
4781                 {"dirty", 0, 0, 'd'},
4782                 {"exists", 0, 0, 'e'},
4783                 {0, 0, 0, 0}
4784         };
4785         char short_opts[] = "lraAde";
4786         __u64 mask = 0;
4787         int c, rc;
4788         char *path;
4789
4790         if (argc < 3)
4791                 return CMD_HELP;
4792
4793         while ((c = getopt_long(argc, argv, short_opts,
4794                                 long_opts, NULL)) != -1) {
4795                 switch (c) {
4796                 case 'l':
4797                         mask |= HS_LOST;
4798                         break;
4799                 case 'a':
4800                         mask |= HS_NOARCHIVE;
4801                         break;
4802                 case 'A':
4803                         mask |= HS_ARCHIVED;
4804                         break;
4805                 case 'r':
4806                         mask |= HS_NORELEASE;
4807                         break;
4808                 case 'd':
4809                         mask |= HS_DIRTY;
4810                         break;
4811                 case 'e':
4812                         mask |= HS_EXISTS;
4813                         break;
4814                 case '?':
4815                         return CMD_HELP;
4816                 default:
4817                         fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4818                                 argv[0], argv[optind - 1]);
4819                         return CMD_HELP;
4820                 }
4821         }
4822
4823         /* User should have specified a flag */
4824         if (mask == 0)
4825                 return CMD_HELP;
4826
4827         while (optind < argc) {
4828
4829                 path = argv[optind];
4830
4831                 /* If mode == 0, this means we apply the mask. */
4832                 if (mode == LFS_HSM_SET)
4833                         rc = llapi_hsm_state_set(path, mask, 0, 0);
4834                 else
4835                         rc = llapi_hsm_state_set(path, 0, mask, 0);
4836
4837                 if (rc != 0) {
4838                         fprintf(stderr, "Can't change hsm flags for %s: %s\n",
4839                                 path, strerror(errno = -rc));
4840                         return rc;
4841                 }
4842                 optind++;
4843         }
4844
4845         return 0;
4846 }
4847
4848 static int lfs_hsm_action(int argc, char **argv)
4849 {
4850         int                              rc;
4851         int                              i = 1;
4852         char                            *path;
4853         struct hsm_current_action        hca;
4854         struct hsm_extent                he;
4855         enum hsm_user_action             hua;
4856         enum hsm_progress_states         hps;
4857
4858         if (argc < 2)
4859                 return CMD_HELP;
4860
4861         do {
4862                 path = argv[i];
4863
4864                 rc = llapi_hsm_current_action(path, &hca);
4865                 if (rc) {
4866                         fprintf(stderr, "can't get hsm action for %s: %s\n",
4867                                 path, strerror(errno = -rc));
4868                         return rc;
4869                 }
4870                 he = hca.hca_location;
4871                 hua = hca.hca_action;
4872                 hps = hca.hca_state;
4873
4874                 printf("%s: %s", path, hsm_user_action2name(hua));
4875
4876                 /* Skip file without action */
4877                 if (hca.hca_action == HUA_NONE) {
4878                         printf("\n");
4879                         continue;
4880                 }
4881
4882                 printf(" %s ", hsm_progress_state2name(hps));
4883
4884                 if ((hps == HPS_RUNNING) &&
4885                     (hua == HUA_ARCHIVE || hua == HUA_RESTORE))
4886                         printf("(%llu bytes moved)\n",
4887                                (unsigned long long)he.length);
4888                 else if ((he.offset + he.length) == LUSTRE_EOF)
4889                         printf("(from %llu to EOF)\n",
4890                                (unsigned long long)he.offset);
4891                 else
4892                         printf("(from %llu to %llu)\n",
4893                                (unsigned long long)he.offset,
4894                                (unsigned long long)(he.offset + he.length));
4895
4896         } while (++i < argc);
4897
4898         return 0;
4899 }
4900
4901 static int lfs_hsm_set(int argc, char **argv)
4902 {
4903         return lfs_hsm_change_flags(argc, argv, LFS_HSM_SET);
4904 }
4905
4906 static int lfs_hsm_clear(int argc, char **argv)
4907 {
4908         return lfs_hsm_change_flags(argc, argv, LFS_HSM_CLEAR);
4909 }
4910
4911 /**
4912  * Check file state and return its fid, to be used by lfs_hsm_request().
4913  *
4914  * \param[in]     file      Path to file to check
4915  * \param[in,out] fid       Pointer to allocated lu_fid struct.
4916  * \param[in,out] last_dev  Pointer to last device id used.
4917  *
4918  * \return 0 on success.
4919  */
4920 static int lfs_hsm_prepare_file(const char *file, struct lu_fid *fid,
4921                                 dev_t *last_dev)
4922 {
4923         struct stat     st;
4924         int             rc;
4925
4926         rc = lstat(file, &st);
4927         if (rc) {
4928                 fprintf(stderr, "Cannot stat %s: %s\n", file, strerror(errno));
4929                 return -errno;
4930         }
4931         /* Checking for regular file as archiving as posix copytool
4932          * rejects archiving files other than regular files
4933          */
4934         if (!S_ISREG(st.st_mode)) {
4935                 fprintf(stderr, "error: \"%s\" is not a regular file\n", file);
4936                 return CMD_HELP;
4937         }
4938         /* A request should be ... */
4939         if (*last_dev != st.st_dev && *last_dev != 0) {
4940                 fprintf(stderr, "All files should be "
4941                         "on the same filesystem: %s\n", file);
4942                 return -EINVAL;
4943         }
4944         *last_dev = st.st_dev;
4945
4946         rc = llapi_path2fid(file, fid);
4947         if (rc) {
4948                 fprintf(stderr, "Cannot read FID of %s: %s\n",
4949                         file, strerror(-rc));
4950                 return rc;
4951         }
4952         return 0;
4953 }
4954
4955 /* Fill an HSM HUR item with a given file name.
4956  *
4957  * If mntpath is set, then the filename is actually a FID, and no
4958  * lookup on the filesystem will be performed.
4959  *
4960  * \param[in]  hur         the user request to fill
4961  * \param[in]  idx         index of the item inside the HUR to fill
4962  * \param[in]  mntpath     mountpoint of Lustre
4963  * \param[in]  fname       filename (if mtnpath is NULL)
4964  *                         or FID (if mntpath is set)
4965  * \param[in]  last_dev    pointer to last device id used
4966  *
4967  * \retval 0 on success
4968  * \retval CMD_HELP or a negative errno on error
4969  */
4970 static int fill_hur_item(struct hsm_user_request *hur, unsigned int idx,
4971                          const char *mntpath, const char *fname,
4972                          dev_t *last_dev)
4973 {
4974         struct hsm_user_item *hui = &hur->hur_user_item[idx];
4975         int rc;
4976
4977         hui->hui_extent.length = -1;
4978
4979         if (mntpath != NULL) {
4980                 if (*fname == '[')
4981                         fname++;
4982                 rc = sscanf(fname, SFID, RFID(&hui->hui_fid));
4983                 if (rc == 3) {
4984                         rc = 0;
4985                 } else {
4986                         fprintf(stderr, "hsm: '%s' is not a valid FID\n",
4987                                 fname);
4988                         rc = -EINVAL;
4989                 }
4990         } else {
4991                 rc = lfs_hsm_prepare_file(fname, &hui->hui_fid, last_dev);
4992         }
4993
4994         if (rc == 0)
4995                 hur->hur_request.hr_itemcount++;
4996
4997         return rc;
4998 }
4999
5000 static int lfs_hsm_request(int argc, char **argv, int action)
5001 {
5002         struct option            long_opts[] = {
5003                 {"filelist", 1, 0, 'l'},
5004                 {"data", 1, 0, 'D'},
5005                 {"archive", 1, 0, 'a'},
5006                 {"mntpath", 1, 0, 'm'},
5007                 {0, 0, 0, 0}
5008         };
5009         dev_t                    last_dev = 0;
5010         char                     short_opts[] = "l:D:a:m:";
5011         struct hsm_user_request *hur, *oldhur;
5012         int                      c, i;
5013         size_t                   len;
5014         int                      nbfile;
5015         char                    *line = NULL;
5016         char                    *filelist = NULL;
5017         char                     fullpath[PATH_MAX];
5018         char                    *opaque = NULL;
5019         int                      opaque_len = 0;
5020         int                      archive_id = 0;
5021         FILE                    *fp;
5022         int                      nbfile_alloc = 0;
5023         char                    *some_file = NULL;
5024         char                    *mntpath = NULL;
5025         int                      rc;
5026
5027         if (argc < 2)
5028                 return CMD_HELP;
5029
5030         while ((c = getopt_long(argc, argv, short_opts,
5031                                 long_opts, NULL)) != -1) {
5032                 switch (c) {
5033                 case 'l':
5034                         filelist = optarg;
5035                         break;
5036                 case 'D':
5037                         opaque = optarg;
5038                         break;
5039                 case 'a':
5040                         if (action != HUA_ARCHIVE &&
5041                             action != HUA_REMOVE) {
5042                                 fprintf(stderr,
5043                                         "error: -a is supported only "
5044                                         "when archiving or removing\n");
5045                                 return CMD_HELP;
5046                         }
5047                         archive_id = atoi(optarg);
5048                         break;
5049                 case 'm':
5050                         if (some_file == NULL) {
5051                                 mntpath = optarg;
5052                                 some_file = strdup(optarg);
5053                         }
5054                         break;
5055                 case '?':
5056                         return CMD_HELP;
5057                 default:
5058                         fprintf(stderr, "error: %s: option '%s' unrecognized\n",
5059                                 argv[0], argv[optind - 1]);
5060                         return CMD_HELP;
5061                 }
5062         }
5063
5064         /* All remaining args are files, so we have at least nbfile */
5065         nbfile = argc - optind;
5066
5067         if ((nbfile == 0) && (filelist == NULL))
5068                 return CMD_HELP;
5069
5070         if (opaque != NULL)
5071                 opaque_len = strlen(opaque);
5072
5073         /* Alloc the request structure with enough place to store all files
5074          * from command line. */
5075         hur = llapi_hsm_user_request_alloc(nbfile, opaque_len);
5076         if (hur == NULL) {
5077                 fprintf(stderr, "Cannot create the request: %s\n",
5078                         strerror(errno));
5079                 return errno;
5080         }
5081         nbfile_alloc = nbfile;
5082
5083         hur->hur_request.hr_action = action;
5084         hur->hur_request.hr_archive_id = archive_id;
5085         hur->hur_request.hr_flags = 0;
5086
5087         /* All remaining args are files, add them */
5088         if (nbfile != 0 && some_file == NULL)
5089                 some_file = strdup(argv[optind]);
5090
5091         for (i = 0; i < nbfile; i++) {
5092                 rc = fill_hur_item(hur, i, mntpath, argv[optind + i],
5093                                    &last_dev);
5094                 if (rc)
5095                         goto out_free;
5096         }
5097
5098         /* from here stop using nb_file, use hur->hur_request.hr_itemcount */
5099
5100         /* If a filelist was specified, read the filelist from it. */
5101         if (filelist != NULL) {
5102                 fp = fopen(filelist, "r");
5103                 if (fp == NULL) {
5104                         fprintf(stderr, "Cannot read the file list %s: %s\n",
5105                                 filelist, strerror(errno));
5106                         rc = -errno;
5107                         goto out_free;
5108                 }
5109
5110                 while ((rc = getline(&line, &len, fp)) != -1) {
5111                         /* If allocated buffer was too small, get something
5112                          * larger */
5113                         if (nbfile_alloc <= hur->hur_request.hr_itemcount) {
5114                                 ssize_t size;
5115
5116                                 nbfile_alloc = nbfile_alloc * 2 + 1;
5117                                 oldhur = hur;
5118                                 hur = llapi_hsm_user_request_alloc(nbfile_alloc,
5119                                                                    opaque_len);
5120                                 if (hur == NULL) {
5121                                         fprintf(stderr, "hsm: cannot allocate "
5122                                                 "the request: %s\n",
5123                                                 strerror(errno));
5124                                         hur = oldhur;
5125                                         rc = -errno;
5126                                         fclose(fp);
5127                                         goto out_free;
5128                                 }
5129                                 size = hur_len(oldhur);
5130                                 if (size < 0) {
5131                                         fprintf(stderr, "hsm: cannot allocate "
5132                                                 "%u files + %u bytes data\n",
5133                                             oldhur->hur_request.hr_itemcount,
5134                                             oldhur->hur_request.hr_data_len);
5135                                         free(hur);
5136                                         hur = oldhur;
5137                                         rc = -E2BIG;
5138                                         fclose(fp);
5139                                         goto out_free;
5140                                 }
5141                                 memcpy(hur, oldhur, size);
5142                                 free(oldhur);
5143                         }
5144
5145                         /* Chop CR */
5146                         if (line[strlen(line) - 1] == '\n')
5147                                 line[strlen(line) - 1] = '\0';
5148
5149                         rc = fill_hur_item(hur, hur->hur_request.hr_itemcount,
5150                                            mntpath, line, &last_dev);
5151                         if (rc) {
5152                                 fclose(fp);
5153                                 goto out_free;
5154                         }
5155
5156                         if (some_file == NULL) {
5157                                 some_file = line;
5158                                 line = NULL;
5159                         }
5160                 }
5161
5162                 rc = fclose(fp);
5163                 free(line);
5164         }
5165
5166         /* If a --data was used, add it to the request */
5167         hur->hur_request.hr_data_len = opaque_len;
5168         if (opaque != NULL)
5169                 memcpy(hur_data(hur), opaque, opaque_len);
5170
5171         /* Send the HSM request */
5172         if (realpath(some_file, fullpath) == NULL) {
5173                 fprintf(stderr, "Could not find path '%s': %s\n",
5174                         some_file, strerror(errno));
5175         }
5176         rc = llapi_hsm_request(fullpath, hur);
5177         if (rc) {
5178                 fprintf(stderr, "Cannot send HSM request (use of %s): %s\n",
5179                         some_file, strerror(-rc));
5180                 goto out_free;
5181         }
5182
5183 out_free:
5184         free(some_file);
5185         free(hur);
5186         return rc;
5187 }
5188
5189 static int lfs_hsm_archive(int argc, char **argv)
5190 {
5191         return lfs_hsm_request(argc, argv, HUA_ARCHIVE);
5192 }
5193
5194 static int lfs_hsm_restore(int argc, char **argv)
5195 {
5196         return lfs_hsm_request(argc, argv, HUA_RESTORE);
5197 }
5198
5199 static int lfs_hsm_release(int argc, char **argv)
5200 {
5201         return lfs_hsm_request(argc, argv, HUA_RELEASE);
5202 }
5203
5204 static int lfs_hsm_remove(int argc, char **argv)
5205 {
5206         return lfs_hsm_request(argc, argv, HUA_REMOVE);
5207 }
5208
5209 static int lfs_hsm_cancel(int argc, char **argv)
5210 {
5211         return lfs_hsm_request(argc, argv, HUA_CANCEL);
5212 }
5213
5214 static int lfs_swap_layouts(int argc, char **argv)
5215 {
5216         if (argc != 3)
5217                 return CMD_HELP;
5218
5219         return llapi_swap_layouts(argv[1], argv[2], 0, 0,
5220                                   SWAP_LAYOUTS_KEEP_MTIME |
5221                                   SWAP_LAYOUTS_KEEP_ATIME);
5222 }
5223
5224 static const char *const ladvise_names[] = LU_LADVISE_NAMES;
5225
5226 static enum lu_ladvise_type lfs_get_ladvice(const char *string)
5227 {
5228         enum lu_ladvise_type advice;
5229
5230         for (advice = 0;
5231              advice < ARRAY_SIZE(ladvise_names); advice++) {
5232                 if (ladvise_names[advice] == NULL)
5233                         continue;
5234                 if (strcmp(string, ladvise_names[advice]) == 0)
5235                         return advice;
5236         }
5237
5238         return LU_LADVISE_INVALID;
5239 }
5240
5241 static int lfs_ladvise(int argc, char **argv)
5242 {
5243         struct option            long_opts[] = {
5244                 {"advice",      required_argument,      0, 'a'},
5245                 {"background",  no_argument,            0, 'b'},
5246                 {"end",         required_argument,      0, 'e'},
5247                 {"start",       required_argument,      0, 's'},
5248                 {"length",      required_argument,      0, 'l'},
5249                 {0, 0, 0, 0}
5250         };
5251         char                     short_opts[] = "a:be:l:s:";
5252         int                      c;
5253         int                      rc = 0;
5254         const char              *path;
5255         int                      fd;
5256         struct llapi_lu_ladvise  advice;
5257         enum lu_ladvise_type     advice_type = LU_LADVISE_INVALID;
5258         unsigned long long       start = 0;
5259         unsigned long long       end = LUSTRE_EOF;
5260         unsigned long long       length = 0;
5261         unsigned long long       size_units;
5262         unsigned long long       flags = 0;
5263
5264         optind = 0;
5265         while ((c = getopt_long(argc, argv, short_opts,
5266                                 long_opts, NULL)) != -1) {
5267                 switch (c) {
5268                 case 'a':
5269                         advice_type = lfs_get_ladvice(optarg);
5270                         if (advice_type == LU_LADVISE_INVALID) {
5271                                 fprintf(stderr, "%s: invalid advice type "
5272                                         "'%s'\n", argv[0], optarg);
5273                                 fprintf(stderr, "Valid types:");
5274
5275                                 for (advice_type = 0;
5276                                      advice_type < ARRAY_SIZE(ladvise_names);
5277                                      advice_type++) {
5278                                         if (ladvise_names[advice_type] == NULL)
5279                                                 continue;
5280                                         fprintf(stderr, " %s",
5281                                                 ladvise_names[advice_type]);
5282                                 }
5283                                 fprintf(stderr, "\n");
5284
5285                                 return CMD_HELP;
5286                         }
5287                         break;
5288                 case 'b':
5289                         flags |= LF_ASYNC;
5290                         break;
5291                 case 'e':
5292                         size_units = 1;
5293                         rc = llapi_parse_size(optarg, &end,
5294                                               &size_units, 0);
5295                         if (rc) {
5296                                 fprintf(stderr, "%s: bad end offset '%s'\n",
5297                                         argv[0], optarg);
5298                                 return CMD_HELP;
5299                         }
5300                         break;
5301                 case 's':
5302                         size_units = 1;
5303                         rc = llapi_parse_size(optarg, &start,
5304                                               &size_units, 0);
5305                         if (rc) {
5306                                 fprintf(stderr, "%s: bad start offset "
5307                                         "'%s'\n", argv[0], optarg);
5308                                 return CMD_HELP;
5309                         }
5310                         break;
5311                 case 'l':
5312                         size_units = 1;
5313                         rc = llapi_parse_size(optarg, &length,
5314                                               &size_units, 0);
5315                         if (rc) {
5316                                 fprintf(stderr, "%s: bad length '%s'\n",
5317                                         argv[0], optarg);
5318                                 return CMD_HELP;
5319                         }
5320                         break;
5321                 case '?':
5322                         return CMD_HELP;
5323                 default:
5324                         fprintf(stderr, "%s: option '%s' unrecognized\n",
5325                                 argv[0], argv[optind - 1]);
5326                         return CMD_HELP;
5327                 }
5328         }
5329
5330         if (advice_type == LU_LADVISE_INVALID) {
5331                 fprintf(stderr, "%s: please give an advice type\n", argv[0]);
5332                 fprintf(stderr, "Valid types:");
5333                 for (advice_type = 0; advice_type < ARRAY_SIZE(ladvise_names);
5334                      advice_type++) {
5335                         if (ladvise_names[advice_type] == NULL)
5336                                 continue;
5337                         fprintf(stderr, " %s", ladvise_names[advice_type]);
5338                 }
5339                 fprintf(stderr, "\n");
5340                 return CMD_HELP;
5341         }
5342
5343         if (argc <= optind) {
5344                 fprintf(stderr, "%s: please give one or more file names\n",
5345                         argv[0]);
5346                 return CMD_HELP;
5347         }
5348
5349         if (end != LUSTRE_EOF && length != 0 && end != start + length) {
5350                 fprintf(stderr, "%s: conflicting arguments of -l and -e\n",
5351                         argv[0]);
5352                 return CMD_HELP;
5353         }
5354
5355         if (end == LUSTRE_EOF && length != 0)
5356                 end = start + length;
5357
5358         if (end <= start) {
5359                 fprintf(stderr, "%s: range [%llu, %llu] is invalid\n",
5360                         argv[0], start, end);
5361                 return CMD_HELP;
5362         }
5363
5364         while (optind < argc) {
5365                 int rc2;
5366
5367                 path = argv[optind++];
5368
5369                 fd = open(path, O_RDONLY);
5370                 if (fd < 0) {
5371                         fprintf(stderr, "%s: cannot open file '%s': %s\n",
5372                                 argv[0], path, strerror(errno));
5373                         rc2 = -errno;
5374                         goto next;
5375                 }
5376
5377                 advice.lla_start = start;
5378                 advice.lla_end = end;
5379                 advice.lla_advice = advice_type;
5380                 advice.lla_value1 = 0;
5381                 advice.lla_value2 = 0;
5382                 advice.lla_value3 = 0;
5383                 advice.lla_value4 = 0;
5384                 rc2 = llapi_ladvise(fd, flags, 1, &advice);
5385                 close(fd);
5386                 if (rc2 < 0) {
5387                         fprintf(stderr, "%s: cannot give advice '%s' to file "
5388                                 "'%s': %s\n", argv[0],
5389                                 ladvise_names[advice_type],
5390                                 path, strerror(errno));
5391                 }
5392 next:
5393                 if (rc == 0 && rc2 < 0)
5394                         rc = rc2;
5395         }
5396         return rc;
5397 }
5398
5399 static int lfs_list_commands(int argc, char **argv)
5400 {
5401         char buffer[81] = ""; /* 80 printable chars + terminating NUL */
5402
5403         Parser_list_commands(cmdlist, buffer, sizeof(buffer), NULL, 0, 4);
5404
5405         return 0;
5406 }
5407
5408 int main(int argc, char **argv)
5409 {
5410         int rc;
5411
5412         /* Ensure that liblustreapi constructor has run */
5413         if (!liblustreapi_initialized)
5414                 fprintf(stderr, "liblustreapi was not properly initialized\n");
5415
5416         setlinebuf(stdout);
5417
5418         Parser_init("lfs > ", cmdlist);
5419
5420         progname = argv[0]; /* Used in error messages */
5421         if (argc > 1) {
5422                 rc = Parser_execarg(argc - 1, argv + 1, cmdlist);
5423         } else {
5424                 rc = Parser_commands();
5425         }
5426
5427         return rc < 0 ? -rc : rc;
5428 }
5429
5430 #ifdef _LUSTRE_IDL_H_
5431 /* Everything we need here should be included by lustreapi.h. */
5432 # error "lfs should not depend on lustre_idl.h"
5433 #endif /* _LUSTRE_IDL_H_ */