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