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