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