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