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