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