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