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