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