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