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