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