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