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