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