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