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