Whamcloud - gitweb
LU-6245 utils: remove libcfs.h from lustre utilities code
[fs/lustre-release.git] / lustre / utils / lfs.c
1 /*
2  * GPL HEADER START
3  *
4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 only,
8  * as published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License version 2 for more details (a copy is included
14  * in the LICENSE file that accompanied this code).
15  *
16  * You should have received a copy of the GNU General Public License
17  * version 2 along with this program; If not, see
18  * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
19  *
20  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
21  * CA 95054 USA or visit www.sun.com if you need additional information or
22  * have any questions.
23  *
24  * GPL HEADER END
25  */
26 /*
27  * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
28  * Use is subject to license terms.
29  *
30  * Copyright (c) 2011, 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                         return CMD_HELP;
1054                 }
1055
1056                 param->lsp_is_specific = true;
1057                 param->lsp_stripe_count = nr_osts;
1058                 memcpy(param->lsp_osts, osts, sizeof(*osts) * nr_osts);
1059         }
1060
1061         for (fname = argv[optind]; fname != NULL; fname = argv[++optind]) {
1062                 if (migrate_mode) {
1063                         result = lfs_migrate(fname, migration_flags, param);
1064                 } else {
1065                         result = llapi_file_open_param(fname,
1066                                                        O_CREAT | O_WRONLY,
1067                                                        0644, param);
1068                         if (result >= 0) {
1069                                 close(result);
1070                                 result = 0;
1071                         }
1072                 }
1073                 if (result) {
1074                         /* Save the first error encountered. */
1075                         if (result2 == 0)
1076                                 result2 = result;
1077                         fprintf(stderr,
1078                                 "error: %s: %s stripe file '%s' failed\n",
1079                                 argv[0], migrate_mode ? "migrate" : "create",
1080                                 fname);
1081                         continue;
1082                 }
1083         }
1084
1085         free(param);
1086         return result2;
1087 }
1088
1089 static int lfs_poollist(int argc, char **argv)
1090 {
1091         if (argc != 2)
1092                 return CMD_HELP;
1093
1094         return llapi_poollist(argv[1]);
1095 }
1096
1097 static int set_time(time_t *time, time_t *set, char *str)
1098 {
1099         time_t t;
1100         int res = 0;
1101
1102         if (str[0] == '+')
1103                 res = 1;
1104         else if (str[0] == '-')
1105                 res = -1;
1106
1107         if (res)
1108                 str++;
1109
1110         t = strtol(str, NULL, 0);
1111         if (*time < t * 24 * 60 * 60) {
1112                 if (res)
1113                         str--;
1114                 fprintf(stderr, "Wrong time '%s' is specified.\n", str);
1115                 return INT_MAX;
1116         }
1117
1118         *set = *time - t * 24 * 60 * 60;
1119         return res;
1120 }
1121
1122 #define USER 0
1123 #define GROUP 1
1124
1125 static int name2id(unsigned int *id, char *name, int type)
1126 {
1127         if (type == USER) {
1128                 struct passwd *entry;
1129
1130                 if (!(entry = getpwnam(name))) {
1131                         if (!errno)
1132                                 errno = ENOENT;
1133                         return -1;
1134                 }
1135
1136                 *id = entry->pw_uid;
1137         } else {
1138                 struct group *entry;
1139
1140                 if (!(entry = getgrnam(name))) {
1141                         if (!errno)
1142                                 errno = ENOENT;
1143                         return -1;
1144                 }
1145
1146                 *id = entry->gr_gid;
1147         }
1148
1149         return 0;
1150 }
1151
1152 static int id2name(char **name, unsigned int id, int type)
1153 {
1154         if (type == USER) {
1155                 struct passwd *entry;
1156
1157                 if (!(entry = getpwuid(id))) {
1158                         if (!errno)
1159                                 errno = ENOENT;
1160                         return -1;
1161                 }
1162
1163                 *name = entry->pw_name;
1164         } else {
1165                 struct group *entry;
1166
1167                 if (!(entry = getgrgid(id))) {
1168                         if (!errno)
1169                                 errno = ENOENT;
1170                         return -1;
1171                 }
1172
1173                 *name = entry->gr_name;
1174         }
1175
1176         return 0;
1177 }
1178
1179 static int name2layout(__u32 *layout, char *name)
1180 {
1181         char *ptr, *lyt;
1182
1183         *layout = 0;
1184         for (ptr = name; ; ptr = NULL) {
1185                 lyt = strtok(ptr, ",");
1186                 if (lyt == NULL)
1187                         break;
1188                 if (strcmp(lyt, "released") == 0)
1189                         *layout |= LOV_PATTERN_F_RELEASED;
1190                 else if (strcmp(lyt, "raid0") == 0)
1191                         *layout |= LOV_PATTERN_RAID0;
1192                 else
1193                         return -1;
1194         }
1195         return 0;
1196 }
1197
1198 #define FIND_POOL_OPT 3
1199 static int lfs_find(int argc, char **argv)
1200 {
1201         int c, rc;
1202         int ret = 0;
1203         time_t t;
1204         struct find_param param = {
1205                 .fp_max_depth = -1,
1206                 .fp_quiet = 1,
1207         };
1208         struct option long_opts[] = {
1209                 {"atime",        required_argument, 0, 'A'},
1210                 {"stripe-count", required_argument, 0, 'c'},
1211                 {"stripe_count", required_argument, 0, 'c'},
1212                 {"ctime",        required_argument, 0, 'C'},
1213                 {"maxdepth",     required_argument, 0, 'D'},
1214                 {"gid",          required_argument, 0, 'g'},
1215                 {"group",        required_argument, 0, 'G'},
1216                 {"stripe-index", required_argument, 0, 'i'},
1217                 {"stripe_index", required_argument, 0, 'i'},
1218                 {"layout",       required_argument, 0, 'L'},
1219                 {"mdt",          required_argument, 0, 'm'},
1220                 {"mtime",        required_argument, 0, 'M'},
1221                 {"name",         required_argument, 0, 'n'},
1222      /* reserve {"or",           no_argument,     , 0, 'o'}, to match find(1) */
1223                 {"obd",          required_argument, 0, 'O'},
1224                 {"ost",          required_argument, 0, 'O'},
1225                 /* no short option for pool, p/P already used */
1226                 {"pool",         required_argument, 0, FIND_POOL_OPT},
1227                 {"print0",       no_argument,       0, 'p'},
1228                 {"print",        no_argument,       0, 'P'},
1229                 {"size",         required_argument, 0, 's'},
1230                 {"stripe-size",  required_argument, 0, 'S'},
1231                 {"stripe_size",  required_argument, 0, 'S'},
1232                 {"type",         required_argument, 0, 't'},
1233                 {"uid",          required_argument, 0, 'u'},
1234                 {"user",         required_argument, 0, 'U'},
1235                 {0, 0, 0, 0}
1236         };
1237         int pathstart = -1;
1238         int pathend = -1;
1239         int neg_opt = 0;
1240         time_t *xtime;
1241         int *xsign;
1242         int isoption;
1243         char *endptr;
1244
1245         time(&t);
1246
1247         /* when getopt_long_only() hits '!' it returns 1, puts "!" in optarg */
1248         while ((c = getopt_long_only(argc, argv,
1249                                      "-A:c:C:D:g:G:i:L:m:M:n:O:Ppqrs:S:t:u:U:v",
1250                                      long_opts, NULL)) >= 0) {
1251                 xtime = NULL;
1252                 xsign = NULL;
1253                 if (neg_opt)
1254                         --neg_opt;
1255                 /* '!' is part of option */
1256                 /* when getopt_long_only() finds a string which is not
1257                  * an option nor a known option argument it returns 1
1258                  * in that case if we already have found pathstart and pathend
1259                  * (i.e. we have the list of pathnames),
1260                  * the only supported value is "!"
1261                  */
1262                 isoption = (c != 1) || (strcmp(optarg, "!") == 0);
1263                 if (!isoption && pathend != -1) {
1264                         fprintf(stderr, "err: %s: filename|dirname must either "
1265                                         "precede options or follow options\n",
1266                                         argv[0]);
1267                         ret = CMD_HELP;
1268                         goto err;
1269                 }
1270                 if (!isoption && pathstart == -1)
1271                         pathstart = optind - 1;
1272                 if (isoption && pathstart != -1 && pathend == -1)
1273                         pathend = optind - 2;
1274                 switch (c) {
1275                 case 0:
1276                         /* Long options. */
1277                         break;
1278                 case 1:
1279                         /* unknown; opt is "!" or path component,
1280                          * checking done above.
1281                          */
1282                         if (strcmp(optarg, "!") == 0)
1283                                 neg_opt = 2;
1284                         break;
1285                 case 'A':
1286                         xtime = &param.fp_atime;
1287                         xsign = &param.fp_asign;
1288                         param.fp_exclude_atime = !!neg_opt;
1289                         /* no break, this falls through to 'C' for ctime */
1290                 case 'C':
1291                         if (c == 'C') {
1292                                 xtime = &param.fp_ctime;
1293                                 xsign = &param.fp_csign;
1294                                 param.fp_exclude_ctime = !!neg_opt;
1295                         }
1296                         /* no break, this falls through to 'M' for mtime */
1297                 case 'M':
1298                         if (c == 'M') {
1299                                 xtime = &param.fp_mtime;
1300                                 xsign = &param.fp_msign;
1301                                 param.fp_exclude_mtime = !!neg_opt;
1302                         }
1303                         rc = set_time(&t, xtime, optarg);
1304                         if (rc == INT_MAX) {
1305                                 ret = -1;
1306                                 goto err;
1307                         }
1308                         if (rc)
1309                                 *xsign = rc;
1310                         break;
1311                 case 'c':
1312                         if (optarg[0] == '+') {
1313                                 param.fp_stripe_count_sign = -1;
1314                                 optarg++;
1315                         } else if (optarg[0] == '-') {
1316                                 param.fp_stripe_count_sign =  1;
1317                                 optarg++;
1318                         }
1319
1320                         param.fp_stripe_count = strtoul(optarg, &endptr, 0);
1321                         if (*endptr != '\0') {
1322                                 fprintf(stderr,"error: bad stripe_count '%s'\n",
1323                                         optarg);
1324                                 ret = -1;
1325                                 goto err;
1326                         }
1327                         param.fp_check_stripe_count = 1;
1328                         param.fp_exclude_stripe_count = !!neg_opt;
1329                         break;
1330                 case 'D':
1331                         param.fp_max_depth = strtol(optarg, 0, 0);
1332                         break;
1333                 case 'g':
1334                 case 'G':
1335                         rc = name2id(&param.fp_gid, optarg, GROUP);
1336                         if (rc) {
1337                                 param.fp_gid = strtoul(optarg, &endptr, 10);
1338                                 if (*endptr != '\0') {
1339                                         fprintf(stderr, "Group/GID: %s cannot "
1340                                                 "be found.\n", optarg);
1341                                         ret = -1;
1342                                         goto err;
1343                                 }
1344                         }
1345                         param.fp_exclude_gid = !!neg_opt;
1346                         param.fp_check_gid = 1;
1347                         break;
1348                 case 'L':
1349                         ret = name2layout(&param.fp_layout, optarg);
1350                         if (ret)
1351                                 goto err;
1352                         param.fp_exclude_layout = !!neg_opt;
1353                         param.fp_check_layout = 1;
1354                         break;
1355                 case 'u':
1356                 case 'U':
1357                         rc = name2id(&param.fp_uid, optarg, USER);
1358                         if (rc) {
1359                                 param.fp_uid = strtoul(optarg, &endptr, 10);
1360                                 if (*endptr != '\0') {
1361                                         fprintf(stderr, "User/UID: %s cannot "
1362                                                 "be found.\n", optarg);
1363                                         ret = -1;
1364                                         goto err;
1365                                 }
1366                         }
1367                         param.fp_exclude_uid = !!neg_opt;
1368                         param.fp_check_uid = 1;
1369                         break;
1370                 case FIND_POOL_OPT:
1371                         if (strlen(optarg) > LOV_MAXPOOLNAME) {
1372                                 fprintf(stderr,
1373                                         "Pool name %s is too long"
1374                                         " (max is %d)\n", optarg,
1375                                         LOV_MAXPOOLNAME);
1376                                 ret = -1;
1377                                 goto err;
1378                         }
1379                         /* we do check for empty pool because empty pool
1380                          * is used to find V1 lov attributes */
1381                         strncpy(param.fp_poolname, optarg, LOV_MAXPOOLNAME);
1382                         param.fp_poolname[LOV_MAXPOOLNAME] = '\0';
1383                         param.fp_exclude_pool = !!neg_opt;
1384                         param.fp_check_pool = 1;
1385                         break;
1386                 case 'n':
1387                         param.fp_pattern = (char *)optarg;
1388                         param.fp_exclude_pattern = !!neg_opt;
1389                         break;
1390                 case 'm':
1391                 case 'i':
1392                 case 'O': {
1393                         char *buf, *token, *next, *p;
1394                         int len = 1;
1395                         void *tmp;
1396
1397                         buf = strdup(optarg);
1398                         if (buf == NULL) {
1399                                 ret = -ENOMEM;
1400                                 goto err;
1401                         }
1402
1403                         param.fp_exclude_obd = !!neg_opt;
1404
1405                         token = buf;
1406                         while (token && *token) {
1407                                 token = strchr(token, ',');
1408                                 if (token) {
1409                                         len++;
1410                                         token++;
1411                                 }
1412                         }
1413                         if (c == 'm') {
1414                                 param.fp_exclude_mdt = !!neg_opt;
1415                                 param.fp_num_alloc_mdts += len;
1416                                 tmp = realloc(param.fp_mdt_uuid,
1417                                               param.fp_num_alloc_mdts *
1418                                               sizeof(*param.fp_mdt_uuid));
1419                                 if (tmp == NULL) {
1420                                         ret = -ENOMEM;
1421                                         goto err_free;
1422                                 }
1423
1424                                 param.fp_mdt_uuid = tmp;
1425                         } else {
1426                                 param.fp_exclude_obd = !!neg_opt;
1427                                 param.fp_num_alloc_obds += len;
1428                                 tmp = realloc(param.fp_obd_uuid,
1429                                               param.fp_num_alloc_obds *
1430                                               sizeof(*param.fp_obd_uuid));
1431                                 if (tmp == NULL) {
1432                                         ret = -ENOMEM;
1433                                         goto err_free;
1434                                 }
1435
1436                                 param.fp_obd_uuid = tmp;
1437                         }
1438                         for (token = buf; token && *token; token = next) {
1439                                 struct obd_uuid *puuid;
1440                                 if (c == 'm') {
1441                                         puuid =
1442                                         &param.fp_mdt_uuid[param.fp_num_mdts++];
1443                                 } else {
1444                                         puuid =
1445                                         &param.fp_obd_uuid[param.fp_num_obds++];
1446                                 }
1447                                 p = strchr(token, ',');
1448                                 next = 0;
1449                                 if (p) {
1450                                         *p = 0;
1451                                         next = p+1;
1452                                 }
1453
1454                                 if (strlen(token) > sizeof(puuid->uuid) - 1) {
1455                                         ret = -E2BIG;
1456                                         goto err_free;
1457                                 }
1458
1459                                 strncpy(puuid->uuid, token,
1460                                         sizeof(puuid->uuid));
1461                         }
1462 err_free:
1463                         if (buf)
1464                                 free(buf);
1465                         break;
1466                 }
1467                 case 'p':
1468                         param.fp_zero_end = 1;
1469                         break;
1470                 case 'P':
1471                         break;
1472                 case 's':
1473                         if (optarg[0] == '+') {
1474                                 param.fp_size_sign = -1;
1475                                 optarg++;
1476                         } else if (optarg[0] == '-') {
1477                                 param.fp_size_sign =  1;
1478                                 optarg++;
1479                         }
1480
1481                         ret = llapi_parse_size(optarg, &param.fp_size,
1482                                                &param.fp_size_units, 0);
1483                         if (ret) {
1484                                 fprintf(stderr, "error: bad file size '%s'\n",
1485                                         optarg);
1486                                 goto err;
1487                         }
1488                         param.fp_check_size = 1;
1489                         param.fp_exclude_size = !!neg_opt;
1490                         break;
1491                 case 'S':
1492                         if (optarg[0] == '+') {
1493                                 param.fp_stripe_size_sign = -1;
1494                                 optarg++;
1495                         } else if (optarg[0] == '-') {
1496                                 param.fp_stripe_size_sign =  1;
1497                                 optarg++;
1498                         }
1499
1500                         ret = llapi_parse_size(optarg, &param.fp_stripe_size,
1501                                                &param.fp_stripe_size_units, 0);
1502                         if (ret) {
1503                                 fprintf(stderr, "error: bad stripe_size '%s'\n",
1504                                         optarg);
1505                                 goto err;
1506                         }
1507                         param.fp_check_stripe_size = 1;
1508                         param.fp_exclude_stripe_size = !!neg_opt;
1509                         break;
1510                 case 't':
1511                         param.fp_exclude_type = !!neg_opt;
1512                         switch (optarg[0]) {
1513                         case 'b':
1514                                 param.fp_type = S_IFBLK;
1515                                 break;
1516                         case 'c':
1517                                 param.fp_type = S_IFCHR;
1518                                 break;
1519                         case 'd':
1520                                 param.fp_type = S_IFDIR;
1521                                 break;
1522                         case 'f':
1523                                 param.fp_type = S_IFREG;
1524                                 break;
1525                         case 'l':
1526                                 param.fp_type = S_IFLNK;
1527                                 break;
1528                         case 'p':
1529                                 param.fp_type = S_IFIFO;
1530                                 break;
1531                         case 's':
1532                                 param.fp_type = S_IFSOCK;
1533                                 break;
1534                         default:
1535                                 fprintf(stderr, "error: %s: bad type '%s'\n",
1536                                         argv[0], optarg);
1537                                 ret = CMD_HELP;
1538                                 goto err;
1539                         };
1540                         break;
1541                 default:
1542                         ret = CMD_HELP;
1543                         goto err;
1544                 };
1545         }
1546
1547         if (pathstart == -1) {
1548                 fprintf(stderr, "error: %s: no filename|pathname\n",
1549                         argv[0]);
1550                 ret = CMD_HELP;
1551                 goto err;
1552         } else if (pathend == -1) {
1553                 /* no options */
1554                 pathend = argc;
1555         }
1556
1557         do {
1558                 rc = llapi_find(argv[pathstart], &param);
1559                 if (rc != 0 && ret == 0)
1560                         ret = rc;
1561         } while (++pathstart < pathend);
1562
1563         if (ret)
1564                 fprintf(stderr, "error: %s failed for %s.\n",
1565                         argv[0], argv[optind - 1]);
1566 err:
1567         if (param.fp_obd_uuid && param.fp_num_alloc_obds)
1568                 free(param.fp_obd_uuid);
1569
1570         if (param.fp_mdt_uuid && param.fp_num_alloc_mdts)
1571                 free(param.fp_mdt_uuid);
1572
1573         return ret;
1574 }
1575
1576 static int lfs_getstripe_internal(int argc, char **argv,
1577                                   struct find_param *param)
1578 {
1579         struct option long_opts[] = {
1580 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1581                 /* This formerly implied "stripe-count", but was explicitly
1582                  * made "stripe-count" for consistency with other options,
1583                  * and to separate it from "mdt-count" when DNE arrives. */
1584                 {"count",               no_argument,            0, 'c'},
1585 #endif
1586                 {"stripe-count",        no_argument,            0, 'c'},
1587                 {"stripe_count",        no_argument,            0, 'c'},
1588                 {"directory",           no_argument,            0, 'd'},
1589                 {"default",             no_argument,            0, 'D'},
1590                 {"generation",          no_argument,            0, 'g'},
1591 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1592                 /* This formerly implied "stripe-index", but was explicitly
1593                  * made "stripe-index" for consistency with other options,
1594                  * and to separate it from "mdt-index" when DNE arrives. */
1595                 {"index",               no_argument,            0, 'i'},
1596 #endif
1597                 {"stripe-index",        no_argument,            0, 'i'},
1598                 {"stripe_index",        no_argument,            0, 'i'},
1599                 {"layout",              no_argument,            0, 'L'},
1600                 {"mdt-index",           no_argument,            0, 'M'},
1601                 {"mdt_index",           no_argument,            0, 'M'},
1602 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1603                 /* This formerly implied "stripe-index", but was confusing
1604                  * with "file offset" (which will eventually be needed for
1605                  * with different layouts by offset), so deprecate it. */
1606                 {"offset",              no_argument,            0, 'o'},
1607 #endif
1608                 {"obd",                 required_argument,      0, 'O'},
1609                 {"ost",                 required_argument,      0, 'O'},
1610                 {"pool",                no_argument,            0, 'p'},
1611                 {"quiet",               no_argument,            0, 'q'},
1612                 {"recursive",           no_argument,            0, 'r'},
1613                 {"raw",                 no_argument,            0, 'R'},
1614 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1615                 /* This formerly implied "--stripe-size", but was confusing
1616                  * with "lfs find --size|-s", which means "file size", so use
1617                  * the consistent "--stripe-size|-S" for all commands. */
1618                 {"size",                no_argument,            0, 's'},
1619 #endif
1620                 {"stripe-size",         no_argument,            0, 'S'},
1621                 {"stripe_size",         no_argument,            0, 'S'},
1622                 {"verbose",             no_argument,            0, 'v'},
1623                 {0, 0, 0, 0}
1624         };
1625         int c, rc;
1626
1627         param->fp_max_depth = 1;
1628         while ((c = getopt_long(argc, argv, "cdDghiLMoO:pqrRsSv",
1629                                 long_opts, NULL)) != -1) {
1630                 switch (c) {
1631                 case 'O':
1632                         if (param->fp_obd_uuid) {
1633                                 fprintf(stderr,
1634                                         "error: %s: only one obduuid allowed",
1635                                         argv[0]);
1636                                 return CMD_HELP;
1637                         }
1638                         param->fp_obd_uuid = (struct obd_uuid *)optarg;
1639                         break;
1640                 case 'q':
1641                         param->fp_quiet++;
1642                         break;
1643                 case 'd':
1644                         param->fp_max_depth = 0;
1645                         break;
1646                 case 'D':
1647                         param->fp_get_default_lmv = 1;
1648                         break;
1649                 case 'r':
1650                         param->fp_recursive = 1;
1651                         break;
1652                 case 'v':
1653                         param->fp_verbose = VERBOSE_ALL | VERBOSE_DETAIL;
1654                         break;
1655                 case 'c':
1656 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1657                         if (strcmp(argv[optind - 1], "--count") == 0)
1658                                 fprintf(stderr, "warning: '--count' deprecated,"
1659                                         " use '--stripe-count' instead\n");
1660 #endif
1661                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1662                                 param->fp_verbose |= VERBOSE_COUNT;
1663                                 param->fp_max_depth = 0;
1664                         }
1665                         break;
1666 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1667                 case 's':
1668 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1669                         fprintf(stderr, "warning: '--size|-s' deprecated, "
1670                                 "use '--stripe-size|-S' instead\n");
1671 #endif
1672 #endif /* LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0) */
1673                 case 'S':
1674                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1675                                 param->fp_verbose |= VERBOSE_SIZE;
1676                                 param->fp_max_depth = 0;
1677                         }
1678                         break;
1679 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 53, 0)
1680                 case 'o':
1681                         fprintf(stderr, "warning: '--offset|-o' deprecated, "
1682                                 "use '--stripe-index|-i' instead\n");
1683 #endif
1684                 case 'i':
1685 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1686                         if (strcmp(argv[optind - 1], "--index") == 0)
1687                                 fprintf(stderr, "warning: '--index' deprecated"
1688                                         ", use '--stripe-index' instead\n");
1689 #endif
1690                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1691                                 param->fp_verbose |= VERBOSE_OFFSET;
1692                                 param->fp_max_depth = 0;
1693                         }
1694                         break;
1695                 case 'p':
1696                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1697                                 param->fp_verbose |= VERBOSE_POOL;
1698                                 param->fp_max_depth = 0;
1699                         }
1700                         break;
1701                 case 'g':
1702                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1703                                 param->fp_verbose |= VERBOSE_GENERATION;
1704                                 param->fp_max_depth = 0;
1705                         }
1706                         break;
1707                 case 'L':
1708                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
1709                                 param->fp_verbose |= VERBOSE_LAYOUT;
1710                                 param->fp_max_depth = 0;
1711                         }
1712                         break;
1713                 case 'M':
1714                         if (!(param->fp_verbose & VERBOSE_DETAIL))
1715                                 param->fp_max_depth = 0;
1716                         param->fp_verbose |= VERBOSE_MDTINDEX;
1717                         break;
1718                 case 'R':
1719                         param->fp_raw = 1;
1720                         break;
1721                 default:
1722                         return CMD_HELP;
1723                 }
1724         }
1725
1726         if (optind >= argc)
1727                 return CMD_HELP;
1728
1729         if (param->fp_recursive)
1730                 param->fp_max_depth = -1;
1731
1732         if (!param->fp_verbose)
1733                 param->fp_verbose = VERBOSE_ALL;
1734         if (param->fp_quiet)
1735                 param->fp_verbose = VERBOSE_OBJID;
1736
1737         do {
1738                 rc = llapi_getstripe(argv[optind], param);
1739         } while (++optind < argc && !rc);
1740
1741         if (rc)
1742                 fprintf(stderr, "error: %s failed for %s.\n",
1743                         argv[0], argv[optind - 1]);
1744         return rc;
1745 }
1746
1747 static int lfs_tgts(int argc, char **argv)
1748 {
1749         char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
1750         struct find_param param;
1751         int index = 0, rc=0;
1752
1753         if (argc > 2)
1754                 return CMD_HELP;
1755
1756         if (argc == 2 && !realpath(argv[1], path)) {
1757                 rc = -errno;
1758                 fprintf(stderr, "error: invalid path '%s': %s\n",
1759                         argv[1], strerror(-rc));
1760                 return rc;
1761         }
1762
1763         while (!llapi_search_mounts(path, index++, mntdir, NULL)) {
1764                 /* Check if we have a mount point */
1765                 if (mntdir[0] == '\0')
1766                         continue;
1767
1768                 memset(&param, 0, sizeof(param));
1769                 if (!strcmp(argv[0], "mdts"))
1770                         param.fp_get_lmv = 1;
1771
1772                 rc = llapi_ostlist(mntdir, &param);
1773                 if (rc) {
1774                         fprintf(stderr, "error: %s: failed on %s\n",
1775                                 argv[0], mntdir);
1776                 }
1777                 if (path[0] != '\0')
1778                         break;
1779                 memset(mntdir, 0, PATH_MAX);
1780         }
1781
1782         return rc;
1783 }
1784
1785 static int lfs_getstripe(int argc, char **argv)
1786 {
1787         struct find_param param = { 0 };
1788         return lfs_getstripe_internal(argc, argv, &param);
1789 }
1790
1791 /* functions */
1792 static int lfs_getdirstripe(int argc, char **argv)
1793 {
1794         struct find_param param = { 0 };
1795
1796         param.fp_get_lmv = 1;
1797         return lfs_getstripe_internal(argc, argv, &param);
1798 }
1799
1800 /* functions */
1801 static int lfs_setdirstripe(int argc, char **argv)
1802 {
1803         char                    *dname;
1804         int                     result;
1805         unsigned int            stripe_offset = -1;
1806         unsigned int            stripe_count = 1;
1807         enum lmv_hash_type      hash_type;
1808         char                    *end;
1809         int                     c;
1810         char                    *stripe_offset_opt = NULL;
1811         char                    *stripe_count_opt = NULL;
1812         char                    *stripe_hash_opt = NULL;
1813         char                    *mode_opt = NULL;
1814         bool                    default_stripe = false;
1815         mode_t                  mode = S_IRWXU | S_IRWXG | S_IRWXO;
1816         mode_t                  previous_mode = 0;
1817         bool                    delete = false;
1818
1819         struct option long_opts[] = {
1820                 {"count",       required_argument, 0, 'c'},
1821                 {"delete",      no_argument, 0, 'd'},
1822                 {"index",       required_argument, 0, 'i'},
1823                 {"mode",        required_argument, 0, 'm'},
1824                 {"hash-type",   required_argument, 0, 't'},
1825                 {"default_stripe", no_argument, 0, 'D'},
1826                 {0, 0, 0, 0}
1827         };
1828
1829         while ((c = getopt_long(argc, argv, "c:dDi:m:t:", long_opts,
1830                                 NULL)) >= 0) {
1831                 switch (c) {
1832                 case 0:
1833                         /* Long options. */
1834                         break;
1835                 case 'c':
1836                         stripe_count_opt = optarg;
1837                         break;
1838                 case 'd':
1839                         delete = true;
1840                         default_stripe = true;
1841                         break;
1842                 case 'D':
1843                         default_stripe = true;
1844                         break;
1845                 case 'i':
1846                         stripe_offset_opt = optarg;
1847                         break;
1848                 case 'm':
1849                         mode_opt = optarg;
1850                         break;
1851                 case 't':
1852                         stripe_hash_opt = optarg;
1853                         break;
1854                 default:
1855                         fprintf(stderr, "error: %s: option '%s' "
1856                                         "unrecognized\n",
1857                                         argv[0], argv[optind - 1]);
1858                         return CMD_HELP;
1859                 }
1860         }
1861
1862         if (optind == argc) {
1863                 fprintf(stderr, "error: %s: missing dirname\n",
1864                         argv[0]);
1865                 return CMD_HELP;
1866         }
1867
1868         if (!delete && stripe_offset_opt == NULL && stripe_count_opt == NULL) {
1869                 fprintf(stderr, "error: %s: missing stripe offset and count.\n",
1870                         argv[0]);
1871                 return CMD_HELP;
1872         }
1873
1874         if (stripe_offset_opt != NULL) {
1875                 /* get the stripe offset */
1876                 stripe_offset = strtoul(stripe_offset_opt, &end, 0);
1877                 if (*end != '\0') {
1878                         fprintf(stderr, "error: %s: bad stripe offset '%s'\n",
1879                                 argv[0], stripe_offset_opt);
1880                         return CMD_HELP;
1881                 }
1882         }
1883
1884         if (delete) {
1885                 if (stripe_offset_opt != NULL || stripe_count_opt != NULL) {
1886                         fprintf(stderr, "error: %s: cannot specify -d with -s,"
1887                                 " or -i options.\n", argv[0]);
1888                         return CMD_HELP;
1889                 } else {
1890                         stripe_count = 0;
1891                 }
1892         }
1893
1894
1895         if (mode_opt != NULL) {
1896                 mode = strtoul(mode_opt, &end, 8);
1897                 if (*end != '\0') {
1898                         fprintf(stderr, "error: %s: bad mode '%s'\n",
1899                                 argv[0], mode_opt);
1900                         return CMD_HELP;
1901                 }
1902                 previous_mode = umask(0);
1903         }
1904
1905         if (stripe_hash_opt == NULL ||
1906             strcmp(stripe_hash_opt, LMV_HASH_NAME_FNV_1A_64) == 0) {
1907                 hash_type = LMV_HASH_TYPE_FNV_1A_64;
1908         } else if (strcmp(stripe_hash_opt, LMV_HASH_NAME_ALL_CHARS) == 0) {
1909                 hash_type = LMV_HASH_TYPE_ALL_CHARS;
1910         } else {
1911                 fprintf(stderr, "error: %s: bad stripe hash type '%s'\n",
1912                         argv[0], stripe_hash_opt);
1913                 return CMD_HELP;
1914         }
1915
1916         /* get the stripe count */
1917         if (stripe_count_opt != NULL) {
1918                 stripe_count = strtoul(stripe_count_opt, &end, 0);
1919                 if (*end != '\0') {
1920                         fprintf(stderr, "error: %s: bad stripe count '%s'\n",
1921                                 argv[0], stripe_count_opt);
1922                         return CMD_HELP;
1923                 }
1924         }
1925
1926         dname = argv[optind];
1927         do {
1928                 if (default_stripe) {
1929                         result = llapi_dir_set_default_lmv_stripe(dname,
1930                                                     stripe_offset, stripe_count,
1931                                                     hash_type, NULL);
1932                 } else {
1933                         result = llapi_dir_create_pool(dname, mode,
1934                                                        stripe_offset,
1935                                                        stripe_count, hash_type,
1936                                                        NULL);
1937                 }
1938
1939                 if (result) {
1940                         fprintf(stderr, "error: %s: create stripe dir '%s' "
1941                                 "failed\n", argv[0], dname);
1942                         break;
1943                 }
1944                 dname = argv[++optind];
1945         } while (dname != NULL);
1946
1947         if (mode_opt != NULL)
1948                 umask(previous_mode);
1949
1950         return result;
1951 }
1952
1953 /* functions */
1954 static int lfs_rmentry(int argc, char **argv)
1955 {
1956         char *dname;
1957         int   index;
1958         int   result = 0;
1959
1960         if (argc <= 1) {
1961                 fprintf(stderr, "error: %s: missing dirname\n",
1962                         argv[0]);
1963                 return CMD_HELP;
1964         }
1965
1966         index = 1;
1967         dname = argv[index];
1968         while (dname != NULL) {
1969                 result = llapi_direntry_remove(dname);
1970                 if (result) {
1971                         fprintf(stderr, "error: %s: remove dir entry '%s' "
1972                                 "failed\n", argv[0], dname);
1973                         break;
1974                 }
1975                 dname = argv[++index];
1976         }
1977         return result;
1978 }
1979
1980 static int lfs_mv(int argc, char **argv)
1981 {
1982         struct  find_param param = {
1983                 .fp_max_depth = -1,
1984                 .fp_mdt_index = -1,
1985         };
1986         char   *end;
1987         int     c;
1988         int     rc = 0;
1989         struct option long_opts[] = {
1990                 {"mdt-index", required_argument, 0, 'M'},
1991                 {"verbose",     no_argument,       0, 'v'},
1992                 {0, 0, 0, 0}
1993         };
1994
1995         while ((c = getopt_long(argc, argv, "M:v", long_opts, NULL)) != -1) {
1996                 switch (c) {
1997                 case 'M': {
1998                         param.fp_mdt_index = strtoul(optarg, &end, 0);
1999                         if (*end != '\0') {
2000                                 fprintf(stderr, "%s: invalid MDT index'%s'\n",
2001                                         argv[0], optarg);
2002                                 return CMD_HELP;
2003                         }
2004                         break;
2005                 }
2006                 case 'v': {
2007                         param.fp_verbose = VERBOSE_DETAIL;
2008                         break;
2009                 }
2010                 default:
2011                         fprintf(stderr, "error: %s: unrecognized option '%s'\n",
2012                                 argv[0], argv[optind - 1]);
2013                         return CMD_HELP;
2014                 }
2015         }
2016
2017         if (param.fp_mdt_index == -1) {
2018                 fprintf(stderr, "%s: MDT index must be specified\n", argv[0]);
2019                 return CMD_HELP;
2020         }
2021
2022         if (optind >= argc) {
2023                 fprintf(stderr, "%s: missing operand path\n", argv[0]);
2024                 return CMD_HELP;
2025         }
2026
2027         param.fp_migrate = 1;
2028         rc = llapi_mv(argv[optind], &param);
2029         if (rc != 0)
2030                 fprintf(stderr, "%s: cannot migrate '%s' to MDT%04x: %s\n",
2031                         argv[0], argv[optind], param.fp_mdt_index,
2032                         strerror(-rc));
2033         return rc;
2034 }
2035
2036 static int lfs_osts(int argc, char **argv)
2037 {
2038         return lfs_tgts(argc, argv);
2039 }
2040
2041 static int lfs_mdts(int argc, char **argv)
2042 {
2043         return lfs_tgts(argc, argv);
2044 }
2045
2046 #define COOK(value)                                                     \
2047 ({                                                                      \
2048         int radix = 0;                                                  \
2049         while (value > 1024) {                                          \
2050                 value /= 1024;                                          \
2051                 radix++;                                                \
2052         }                                                               \
2053         radix;                                                          \
2054 })
2055 #define UUF     "%-20s"
2056 #define CSF     "%11s"
2057 #define CDF     "%11llu"
2058 #define HDF     "%8.1f%c"
2059 #define RSF     "%4s"
2060 #define RDF     "%3d%%"
2061
2062 static int showdf(char *mntdir, struct obd_statfs *stat,
2063                   char *uuid, int ishow, int cooked,
2064                   char *type, int index, int rc)
2065 {
2066         long long avail, used, total;
2067         double ratio = 0;
2068         char *suffix = "KMGTPEZY";
2069         /* Note if we have >2^64 bytes/fs these buffers will need to be grown */
2070         char tbuf[3 * sizeof(__u64)];
2071         char ubuf[3 * sizeof(__u64)];
2072         char abuf[3 * sizeof(__u64)];
2073         char rbuf[3 * sizeof(__u64)];
2074
2075         if (!uuid || !stat)
2076                 return -EINVAL;
2077
2078         switch (rc) {
2079         case 0:
2080                 if (ishow) {
2081                         avail = stat->os_ffree;
2082                         used = stat->os_files - stat->os_ffree;
2083                         total = stat->os_files;
2084                 } else {
2085                         int shift = cooked ? 0 : 10;
2086
2087                         avail = (stat->os_bavail * stat->os_bsize) >> shift;
2088                         used  = ((stat->os_blocks - stat->os_bfree) *
2089                                  stat->os_bsize) >> shift;
2090                         total = (stat->os_blocks * stat->os_bsize) >> shift;
2091                 }
2092
2093                 if ((used + avail) > 0)
2094                         ratio = (double)used / (double)(used + avail);
2095
2096                 if (cooked) {
2097                         int i;
2098                         double cook_val;
2099
2100                         cook_val = (double)total;
2101                         i = COOK(cook_val);
2102                         if (i > 0)
2103                                 sprintf(tbuf, HDF, cook_val, suffix[i - 1]);
2104                         else
2105                                 sprintf(tbuf, CDF, total);
2106
2107                         cook_val = (double)used;
2108                         i = COOK(cook_val);
2109                         if (i > 0)
2110                                 sprintf(ubuf, HDF, cook_val, suffix[i - 1]);
2111                         else
2112                                 sprintf(ubuf, CDF, used);
2113
2114                         cook_val = (double)avail;
2115                         i = COOK(cook_val);
2116                         if (i > 0)
2117                                 sprintf(abuf, HDF, cook_val, suffix[i - 1]);
2118                         else
2119                                 sprintf(abuf, CDF, avail);
2120                 } else {
2121                         sprintf(tbuf, CDF, total);
2122                         sprintf(ubuf, CDF, used);
2123                         sprintf(abuf, CDF, avail);
2124                 }
2125
2126                 sprintf(rbuf, RDF, (int)(ratio * 100 + 0.5));
2127                 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s",
2128                        uuid, tbuf, ubuf, abuf, rbuf, mntdir);
2129                 if (type)
2130                         printf("[%s:%d]\n", type, index);
2131                 else
2132                         printf("\n");
2133
2134                 break;
2135         case -ENODATA:
2136                 printf(UUF": inactive device\n", uuid);
2137                 break;
2138         default:
2139                 printf(UUF": %s\n", uuid, strerror(-rc));
2140                 break;
2141         }
2142
2143         return 0;
2144 }
2145
2146 struct ll_stat_type {
2147         int   st_op;
2148         char *st_name;
2149 };
2150
2151 static int mntdf(char *mntdir, char *fsname, char *pool, int ishow,
2152                 int cooked, int lazy)
2153 {
2154         struct obd_statfs stat_buf, sum = { .os_bsize = 1 };
2155         struct obd_uuid uuid_buf;
2156         char *poolname = NULL;
2157         struct ll_stat_type types[] = { { LL_STATFS_LMV, "MDT" },
2158                                         { LL_STATFS_LOV, "OST" },
2159                                         { 0, NULL } };
2160         struct ll_stat_type *tp;
2161         __u64 ost_ffree = 0;
2162         __u32 index;
2163         __u32 type;
2164         int rc;
2165
2166         if (pool) {
2167                 poolname = strchr(pool, '.');
2168                 if (poolname != NULL) {
2169                         if (strncmp(fsname, pool, strlen(fsname))) {
2170                                 fprintf(stderr, "filesystem name incorrect\n");
2171                                 return -ENODEV;
2172                         }
2173                         poolname++;
2174                 } else
2175                         poolname = pool;
2176         }
2177
2178         if (ishow)
2179                 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
2180                        "UUID", "Inodes", "IUsed", "IFree",
2181                        "IUse%", "Mounted on");
2182         else
2183                 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
2184                        "UUID", cooked ? "bytes" : "1K-blocks",
2185                        "Used", "Available", "Use%", "Mounted on");
2186
2187         for (tp = types; tp->st_name != NULL; tp++) {
2188                 for (index = 0; ; index++) {
2189                         memset(&stat_buf, 0, sizeof(struct obd_statfs));
2190                         memset(&uuid_buf, 0, sizeof(struct obd_uuid));
2191                         type = lazy ? tp->st_op | LL_STATFS_NODELAY : tp->st_op;
2192                         rc = llapi_obd_statfs(mntdir, type, index,
2193                                               &stat_buf, &uuid_buf);
2194                         if (rc == -ENODEV)
2195                                 break;
2196
2197                         if (rc == -EAGAIN)
2198                                 continue;
2199
2200                         if (poolname && tp->st_op == LL_STATFS_LOV &&
2201                             llapi_search_ost(fsname, poolname,
2202                                              obd_uuid2str(&uuid_buf)) != 1)
2203                                 continue;
2204
2205                         /* the llapi_obd_statfs() call may have returned with
2206                          * an error, but if it filled in uuid_buf we will at
2207                          * lease use that to print out a message for that OBD.
2208                          * If we didn't get anything in the uuid_buf, then fill
2209                          * it in so that we can print an error message. */
2210                         if (uuid_buf.uuid[0] == '\0')
2211                                 sprintf(uuid_buf.uuid, "%s%04x",
2212                                         tp->st_name, index);
2213                         showdf(mntdir, &stat_buf, obd_uuid2str(&uuid_buf),
2214                                ishow, cooked, tp->st_name, index, rc);
2215
2216                         if (rc == 0) {
2217                                 if (tp->st_op == LL_STATFS_LMV) {
2218                                         sum.os_ffree += stat_buf.os_ffree;
2219                                         sum.os_files += stat_buf.os_files;
2220                                 } else /* if (tp->st_op == LL_STATFS_LOV) */ {
2221                                         sum.os_blocks += stat_buf.os_blocks *
2222                                                 stat_buf.os_bsize;
2223                                         sum.os_bfree  += stat_buf.os_bfree *
2224                                                 stat_buf.os_bsize;
2225                                         sum.os_bavail += stat_buf.os_bavail *
2226                                                 stat_buf.os_bsize;
2227                                         ost_ffree += stat_buf.os_ffree;
2228                                 }
2229                         } else if (rc == -EINVAL || rc == -EFAULT) {
2230                                 break;
2231                         }
2232                 }
2233         }
2234
2235         /* If we don't have as many objects free on the OST as inodes
2236          * on the MDS, we reduce the total number of inodes to
2237          * compensate, so that the "inodes in use" number is correct.
2238          * Matches ll_statfs_internal() so the results are consistent. */
2239         if (ost_ffree < sum.os_ffree) {
2240                 sum.os_files = (sum.os_files - sum.os_ffree) + ost_ffree;
2241                 sum.os_ffree = ost_ffree;
2242         }
2243         printf("\n");
2244         showdf(mntdir, &sum, "filesystem summary:", ishow, cooked, NULL, 0, 0);
2245         printf("\n");
2246         return 0;
2247 }
2248
2249 static int lfs_df(int argc, char **argv)
2250 {
2251         char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
2252         int ishow = 0, cooked = 0;
2253         int lazy = 0;
2254         int c, rc = 0, index = 0;
2255         char fsname[PATH_MAX] = "", *pool_name = NULL;
2256         struct option long_opts[] = {
2257                 {"pool", required_argument, 0, 'p'},
2258                 {"lazy", 0, 0, 'l'},
2259                 {0, 0, 0, 0}
2260         };
2261
2262         while ((c = getopt_long(argc, argv, "hilp:", long_opts, NULL)) != -1) {
2263                 switch (c) {
2264                 case 'i':
2265                         ishow = 1;
2266                         break;
2267                 case 'h':
2268                         cooked = 1;
2269                         break;
2270                 case 'l':
2271                         lazy = 1;
2272                         break;
2273                 case 'p':
2274                         pool_name = optarg;
2275                         break;
2276                 default:
2277                         return CMD_HELP;
2278                 }
2279         }
2280         if (optind < argc && !realpath(argv[optind], path)) {
2281                 rc = -errno;
2282                 fprintf(stderr, "error: invalid path '%s': %s\n",
2283                         argv[optind], strerror(-rc));
2284                 return rc;
2285         }
2286
2287         while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
2288                 /* Check if we have a mount point */
2289                 if (mntdir[0] == '\0')
2290                         continue;
2291
2292                 rc = mntdf(mntdir, fsname, pool_name, ishow, cooked, lazy);
2293                 if (rc || path[0] != '\0')
2294                         break;
2295                 fsname[0] = '\0'; /* avoid matching in next loop */
2296                 mntdir[0] = '\0'; /* avoid matching in next loop */
2297         }
2298
2299         return rc;
2300 }
2301
2302 static int lfs_getname(int argc, char **argv)
2303 {
2304         char mntdir[PATH_MAX] = "", path[PATH_MAX] = "", fsname[PATH_MAX] = "";
2305         int rc = 0, index = 0, c;
2306         char buf[sizeof(struct obd_uuid)];
2307
2308         while ((c = getopt(argc, argv, "h")) != -1)
2309                 return CMD_HELP;
2310
2311         if (optind == argc) { /* no paths specified, get all paths. */
2312                 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
2313                         rc = llapi_getname(mntdir, buf, sizeof(buf));
2314                         if (rc < 0) {
2315                                 fprintf(stderr,
2316                                         "cannot get name for `%s': %s\n",
2317                                         mntdir, strerror(-rc));
2318                                 break;
2319                         }
2320
2321                         printf("%s %s\n", buf, mntdir);
2322
2323                         path[0] = fsname[0] = mntdir[0] = 0;
2324                 }
2325         } else { /* paths specified, only attempt to search these. */
2326                 for (; optind < argc; optind++) {
2327                         rc = llapi_getname(argv[optind], buf, sizeof(buf));
2328                         if (rc < 0) {
2329                                 fprintf(stderr,
2330                                         "cannot get name for `%s': %s\n",
2331                                         argv[optind], strerror(-rc));
2332                                 break;
2333                         }
2334
2335                         printf("%s %s\n", buf, argv[optind]);
2336                 }
2337         }
2338         return rc;
2339 }
2340
2341 static int lfs_check(int argc, char **argv)
2342 {
2343         int rc;
2344         char mntdir[PATH_MAX] = {'\0'};
2345         int num_types = 1;
2346         char *obd_types[2];
2347         char obd_type1[4];
2348         char obd_type2[4];
2349
2350         if (argc != 2)
2351                 return CMD_HELP;
2352
2353         obd_types[0] = obd_type1;
2354         obd_types[1] = obd_type2;
2355
2356         if (strcmp(argv[1], "osts") == 0) {
2357                 strcpy(obd_types[0], "osc");
2358         } else if (strcmp(argv[1], "mds") == 0) {
2359                 strcpy(obd_types[0], "mdc");
2360         } else if (strcmp(argv[1], "servers") == 0) {
2361                 num_types = 2;
2362                 strcpy(obd_types[0], "osc");
2363                 strcpy(obd_types[1], "mdc");
2364         } else {
2365                 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
2366                                 argv[0], argv[1]);
2367                         return CMD_HELP;
2368         }
2369
2370         rc = llapi_search_mounts(NULL, 0, mntdir, NULL);
2371         if (rc < 0 || mntdir[0] == '\0') {
2372                 fprintf(stderr, "No suitable Lustre mount found\n");
2373                 return rc;
2374         }
2375
2376         rc = llapi_target_check(num_types, obd_types, mntdir);
2377         if (rc)
2378                 fprintf(stderr, "error: %s: %s status failed\n",
2379                                 argv[0],argv[1]);
2380
2381         return rc;
2382
2383 }
2384
2385 static int lfs_join(int argc, char **argv)
2386 {
2387         fprintf(stderr, "join two lustre files into one.\n"
2388                         "obsolete, HEAD does not support it anymore.\n");
2389         return 0;
2390 }
2391
2392 #ifdef HAVE_SYS_QUOTA_H
2393 #define ARG2INT(nr, str, msg)                                           \
2394 do {                                                                    \
2395         char *endp;                                                     \
2396         nr = strtol(str, &endp, 0);                                     \
2397         if (*endp) {                                                    \
2398                 fprintf(stderr, "error: bad %s: %s\n", msg, str);       \
2399                 return CMD_HELP;                                        \
2400         }                                                               \
2401 } while (0)
2402
2403 #define ADD_OVERFLOW(a,b) ((a + b) < a) ? (a = ULONG_MAX) : (a = a + b)
2404
2405 /* Convert format time string "XXwXXdXXhXXmXXs" into seconds value
2406  * returns the value or ULONG_MAX on integer overflow or incorrect format
2407  * Notes:
2408  *        1. the order of specifiers is arbitrary (may be: 5w3s or 3s5w)
2409  *        2. specifiers may be encountered multiple times (2s3s is 5 seconds)
2410  *        3. empty integer value is interpreted as 0
2411  */
2412 static unsigned long str2sec(const char* timestr)
2413 {
2414         const char spec[] = "smhdw";
2415         const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
2416         unsigned long val = 0;
2417         char *tail;
2418
2419         if (strpbrk(timestr, spec) == NULL) {
2420                 /* no specifiers inside the time string,
2421                    should treat it as an integer value */
2422                 val = strtoul(timestr, &tail, 10);
2423                 return *tail ? ULONG_MAX : val;
2424         }
2425
2426         /* format string is XXwXXdXXhXXmXXs */
2427         while (*timestr) {
2428                 unsigned long v;
2429                 int ind;
2430                 char* ptr;
2431
2432                 v = strtoul(timestr, &tail, 10);
2433                 if (v == ULONG_MAX || *tail == '\0')
2434                         /* value too large (ULONG_MAX or more)
2435                            or missing specifier */
2436                         goto error;
2437
2438                 ptr = strchr(spec, *tail);
2439                 if (ptr == NULL)
2440                         /* unknown specifier */
2441                         goto error;
2442
2443                 ind = ptr - spec;
2444
2445                 /* check if product will overflow the type */
2446                 if (!(v < ULONG_MAX / mult[ind]))
2447                         goto error;
2448
2449                 ADD_OVERFLOW(val, mult[ind] * v);
2450                 if (val == ULONG_MAX)
2451                         goto error;
2452
2453                 timestr = tail + 1;
2454         }
2455
2456         return val;
2457
2458 error:
2459         return ULONG_MAX;
2460 }
2461
2462 #define ARG2ULL(nr, str, def_units)                                     \
2463 do {                                                                    \
2464         unsigned long long limit, units = def_units;                    \
2465         int rc;                                                         \
2466                                                                         \
2467         rc = llapi_parse_size(str, &limit, &units, 1);                  \
2468         if (rc < 0) {                                                   \
2469                 fprintf(stderr, "error: bad limit value %s\n", str);    \
2470                 return CMD_HELP;                                        \
2471         }                                                               \
2472         nr = limit;                                                     \
2473 } while (0)
2474
2475 static inline int has_times_option(int argc, char **argv)
2476 {
2477         int i;
2478
2479         for (i = 1; i < argc; i++)
2480                 if (!strcmp(argv[i], "-t"))
2481                         return 1;
2482
2483         return 0;
2484 }
2485
2486 int lfs_setquota_times(int argc, char **argv)
2487 {
2488         int c, rc;
2489         struct if_quotactl qctl;
2490         char *mnt, *obd_type = (char *)qctl.obd_type;
2491         struct obd_dqblk *dqb = &qctl.qc_dqblk;
2492         struct obd_dqinfo *dqi = &qctl.qc_dqinfo;
2493         struct option long_opts[] = {
2494                 {"block-grace",     required_argument, 0, 'b'},
2495                 {"group",           no_argument,       0, 'g'},
2496                 {"inode-grace",     required_argument, 0, 'i'},
2497                 {"times",           no_argument,       0, 't'},
2498                 {"user",            no_argument,       0, 'u'},
2499                 {0, 0, 0, 0}
2500         };
2501
2502         memset(&qctl, 0, sizeof(qctl));
2503         qctl.qc_cmd  = LUSTRE_Q_SETINFO;
2504         qctl.qc_type = UGQUOTA;
2505
2506         while ((c = getopt_long(argc, argv, "b:gi:tu", long_opts, NULL)) != -1) {
2507                 switch (c) {
2508                 case 'u':
2509                 case 'g':
2510                         if (qctl.qc_type != UGQUOTA) {
2511                                 fprintf(stderr, "error: -u and -g can't be used "
2512                                                 "more than once\n");
2513                                 return CMD_HELP;
2514                         }
2515                         qctl.qc_type = (c == 'u') ? USRQUOTA : GRPQUOTA;
2516                         break;
2517                 case 'b':
2518                         if ((dqi->dqi_bgrace = str2sec(optarg)) == ULONG_MAX) {
2519                                 fprintf(stderr, "error: bad block-grace: %s\n",
2520                                         optarg);
2521                                 return CMD_HELP;
2522                         }
2523                         dqb->dqb_valid |= QIF_BTIME;
2524                         break;
2525                 case 'i':
2526                         if ((dqi->dqi_igrace = str2sec(optarg)) == ULONG_MAX) {
2527                                 fprintf(stderr, "error: bad inode-grace: %s\n",
2528                                         optarg);
2529                                 return CMD_HELP;
2530                         }
2531                         dqb->dqb_valid |= QIF_ITIME;
2532                         break;
2533                 case 't': /* Yes, of course! */
2534                         break;
2535                 default: /* getopt prints error message for us when opterr != 0 */
2536                         return CMD_HELP;
2537                 }
2538         }
2539
2540         if (qctl.qc_type == UGQUOTA) {
2541                 fprintf(stderr, "error: neither -u nor -g specified\n");
2542                 return CMD_HELP;
2543         }
2544
2545         if (optind != argc - 1) {
2546                 fprintf(stderr, "error: unexpected parameters encountered\n");
2547                 return CMD_HELP;
2548         }
2549
2550         mnt = argv[optind];
2551         rc = llapi_quotactl(mnt, &qctl);
2552         if (rc) {
2553                 if (*obd_type)
2554                         fprintf(stderr, "%s %s ", obd_type,
2555                                 obd_uuid2str(&qctl.obd_uuid));
2556                 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
2557                 return rc;
2558         }
2559
2560         return 0;
2561 }
2562
2563 #define BSLIMIT (1 << 0)
2564 #define BHLIMIT (1 << 1)
2565 #define ISLIMIT (1 << 2)
2566 #define IHLIMIT (1 << 3)
2567
2568 int lfs_setquota(int argc, char **argv)
2569 {
2570         int c, rc;
2571         struct if_quotactl qctl;
2572         char *mnt, *obd_type = (char *)qctl.obd_type;
2573         struct obd_dqblk *dqb = &qctl.qc_dqblk;
2574         struct option long_opts[] = {
2575                 {"block-softlimit", required_argument, 0, 'b'},
2576                 {"block-hardlimit", required_argument, 0, 'B'},
2577                 {"group",           required_argument, 0, 'g'},
2578                 {"inode-softlimit", required_argument, 0, 'i'},
2579                 {"inode-hardlimit", required_argument, 0, 'I'},
2580                 {"user",            required_argument, 0, 'u'},
2581                 {0, 0, 0, 0}
2582         };
2583         unsigned limit_mask = 0;
2584         char *endptr;
2585
2586         if (has_times_option(argc, argv))
2587                 return lfs_setquota_times(argc, argv);
2588
2589         memset(&qctl, 0, sizeof(qctl));
2590         qctl.qc_cmd  = LUSTRE_Q_SETQUOTA;
2591         qctl.qc_type = UGQUOTA; /* UGQUOTA makes no sense for setquota,
2592                                  * so it can be used as a marker that qc_type
2593                                  * isn't reinitialized from command line */
2594
2595         while ((c = getopt_long(argc, argv, "b:B:g:i:I:u:", long_opts, NULL)) != -1) {
2596                 switch (c) {
2597                 case 'u':
2598                 case 'g':
2599                         if (qctl.qc_type != UGQUOTA) {
2600                                 fprintf(stderr, "error: -u and -g can't be used"
2601                                                 " more than once\n");
2602                                 return CMD_HELP;
2603                         }
2604                         qctl.qc_type = (c == 'u') ? USRQUOTA : GRPQUOTA;
2605                         rc = name2id(&qctl.qc_id, optarg,
2606                                      (qctl.qc_type == USRQUOTA) ? USER : GROUP);
2607                         if (rc) {
2608                                 qctl.qc_id = strtoul(optarg, &endptr, 10);
2609                                 if (*endptr != '\0') {
2610                                         fprintf(stderr, "error: can't find id "
2611                                                 "for name %s\n", optarg);
2612                                         return CMD_HELP;
2613                                 }
2614                         }
2615                         break;
2616                 case 'b':
2617                         ARG2ULL(dqb->dqb_bsoftlimit, optarg, 1024);
2618                         dqb->dqb_bsoftlimit >>= 10;
2619                         limit_mask |= BSLIMIT;
2620                         if (dqb->dqb_bsoftlimit &&
2621                             dqb->dqb_bsoftlimit <= 1024) /* <= 1M? */
2622                                 fprintf(stderr, "warning: block softlimit is "
2623                                         "smaller than the miminal qunit size, "
2624                                         "please see the help of setquota or "
2625                                         "Lustre manual for details.\n");
2626                         break;
2627                 case 'B':
2628                         ARG2ULL(dqb->dqb_bhardlimit, optarg, 1024);
2629                         dqb->dqb_bhardlimit >>= 10;
2630                         limit_mask |= BHLIMIT;
2631                         if (dqb->dqb_bhardlimit &&
2632                             dqb->dqb_bhardlimit <= 1024) /* <= 1M? */
2633                                 fprintf(stderr, "warning: block hardlimit is "
2634                                         "smaller than the miminal qunit size, "
2635                                         "please see the help of setquota or "
2636                                         "Lustre manual for details.\n");
2637                         break;
2638                 case 'i':
2639                         ARG2ULL(dqb->dqb_isoftlimit, optarg, 1);
2640                         limit_mask |= ISLIMIT;
2641                         if (dqb->dqb_isoftlimit &&
2642                             dqb->dqb_isoftlimit <= 1024) /* <= 1K inodes? */
2643                                 fprintf(stderr, "warning: inode softlimit is "
2644                                         "smaller than the miminal qunit size, "
2645                                         "please see the help of setquota or "
2646                                         "Lustre manual for details.\n");
2647                         break;
2648                 case 'I':
2649                         ARG2ULL(dqb->dqb_ihardlimit, optarg, 1);
2650                         limit_mask |= IHLIMIT;
2651                         if (dqb->dqb_ihardlimit &&
2652                             dqb->dqb_ihardlimit <= 1024) /* <= 1K inodes? */
2653                                 fprintf(stderr, "warning: inode hardlimit is "
2654                                         "smaller than the miminal qunit size, "
2655                                         "please see the help of setquota or "
2656                                         "Lustre manual for details.\n");
2657                         break;
2658                 default: /* getopt prints error message for us when opterr != 0 */
2659                         return CMD_HELP;
2660                 }
2661         }
2662
2663         if (qctl.qc_type == UGQUOTA) {
2664                 fprintf(stderr, "error: neither -u nor -g was specified\n");
2665                 return CMD_HELP;
2666         }
2667
2668         if (limit_mask == 0) {
2669                 fprintf(stderr, "error: at least one limit must be specified\n");
2670                 return CMD_HELP;
2671         }
2672
2673         if (optind != argc - 1) {
2674                 fprintf(stderr, "error: unexpected parameters encountered\n");
2675                 return CMD_HELP;
2676         }
2677
2678         mnt = argv[optind];
2679
2680         if ((!(limit_mask & BHLIMIT) ^ !(limit_mask & BSLIMIT)) ||
2681             (!(limit_mask & IHLIMIT) ^ !(limit_mask & ISLIMIT))) {
2682                 /* sigh, we can't just set blimits/ilimits */
2683                 struct if_quotactl tmp_qctl = {.qc_cmd  = LUSTRE_Q_GETQUOTA,
2684                                                .qc_type = qctl.qc_type,
2685                                                .qc_id   = qctl.qc_id};
2686
2687                 rc = llapi_quotactl(mnt, &tmp_qctl);
2688                 if (rc < 0) {
2689                         fprintf(stderr, "error: setquota failed while retrieving"
2690                                         " current quota settings (%s)\n",
2691                                         strerror(-rc));
2692                         return rc;
2693                 }
2694
2695                 if (!(limit_mask & BHLIMIT))
2696                         dqb->dqb_bhardlimit = tmp_qctl.qc_dqblk.dqb_bhardlimit;
2697                 if (!(limit_mask & BSLIMIT))
2698                         dqb->dqb_bsoftlimit = tmp_qctl.qc_dqblk.dqb_bsoftlimit;
2699                 if (!(limit_mask & IHLIMIT))
2700                         dqb->dqb_ihardlimit = tmp_qctl.qc_dqblk.dqb_ihardlimit;
2701                 if (!(limit_mask & ISLIMIT))
2702                         dqb->dqb_isoftlimit = tmp_qctl.qc_dqblk.dqb_isoftlimit;
2703
2704                 /* Keep grace times if we have got no softlimit arguments */
2705                 if ((limit_mask & BHLIMIT) && !(limit_mask & BSLIMIT)) {
2706                         dqb->dqb_valid |= QIF_BTIME;
2707                         dqb->dqb_btime = tmp_qctl.qc_dqblk.dqb_btime;
2708                 }
2709
2710                 if ((limit_mask & IHLIMIT) && !(limit_mask & ISLIMIT)) {
2711                         dqb->dqb_valid |= QIF_ITIME;
2712                         dqb->dqb_itime = tmp_qctl.qc_dqblk.dqb_itime;
2713                 }
2714         }
2715
2716         dqb->dqb_valid |= (limit_mask & (BHLIMIT | BSLIMIT)) ? QIF_BLIMITS : 0;
2717         dqb->dqb_valid |= (limit_mask & (IHLIMIT | ISLIMIT)) ? QIF_ILIMITS : 0;
2718
2719         rc = llapi_quotactl(mnt, &qctl);
2720         if (rc) {
2721                 if (*obd_type)
2722                         fprintf(stderr, "%s %s ", obd_type,
2723                                 obd_uuid2str(&qctl.obd_uuid));
2724                 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
2725                 return rc;
2726         }
2727
2728         return 0;
2729 }
2730
2731 static inline char *type2name(int check_type)
2732 {
2733         if (check_type == USRQUOTA)
2734                 return "user";
2735         else if (check_type == GRPQUOTA)
2736                 return "group";
2737         else
2738                 return "unknown";
2739 }
2740
2741 /* Converts seconds value into format string
2742  * result is returned in buf
2743  * Notes:
2744  *        1. result is in descenting order: 1w2d3h4m5s
2745  *        2. zero fields are not filled (except for p. 3): 5d1s
2746  *        3. zero seconds value is presented as "0s"
2747  */
2748 static char * __sec2str(time_t seconds, char *buf)
2749 {
2750         const char spec[] = "smhdw";
2751         const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
2752         unsigned long c;
2753         char *tail = buf;
2754         int i;
2755
2756         for (i = sizeof(mult) / sizeof(mult[0]) - 1 ; i >= 0; i--) {
2757                 c = seconds / mult[i];
2758
2759                 if (c > 0 || (i == 0 && buf == tail))
2760                         tail += snprintf(tail, 40-(tail-buf), "%lu%c", c, spec[i]);
2761
2762                 seconds %= mult[i];
2763         }
2764
2765         return tail;
2766 }
2767
2768 static void sec2str(time_t seconds, char *buf, int rc)
2769 {
2770         char *tail = buf;
2771
2772         if (rc)
2773                 *tail++ = '[';
2774
2775         tail = __sec2str(seconds, tail);
2776
2777         if (rc && tail - buf < 39) {
2778                 *tail++ = ']';
2779                 *tail++ = 0;
2780         }
2781 }
2782
2783 static void diff2str(time_t seconds, char *buf, time_t now)
2784 {
2785
2786         buf[0] = 0;
2787         if (!seconds)
2788                 return;
2789         if (seconds <= now) {
2790                 strcpy(buf, "none");
2791                 return;
2792         }
2793         __sec2str(seconds - now, buf);
2794 }
2795
2796 static void print_quota_title(char *name, struct if_quotactl *qctl,
2797                               bool human_readable)
2798 {
2799         printf("Disk quotas for %s %s (%cid %u):\n",
2800                type2name(qctl->qc_type), name,
2801                *type2name(qctl->qc_type), qctl->qc_id);
2802         printf("%15s%8s %7s%8s%8s%8s %7s%8s%8s\n",
2803                "Filesystem", human_readable ? "used" : "kbytes",
2804                "quota", "limit", "grace",
2805                "files", "quota", "limit", "grace");
2806 }
2807
2808 static void kbytes2str(__u64 num, char *buf, bool h)
2809 {
2810         if (!h) {
2811                 sprintf(buf, LPU64, num);
2812         } else {
2813                 if (num >> 30)
2814                         sprintf(buf, "%5.4gT", (double)num / (1 << 30));
2815                 else if (num >> 20)
2816                         sprintf(buf, "%5.4gG", (double)num / (1 << 20));
2817                 else if (num >> 10)
2818                         sprintf(buf, "%5.4gM", (double)num / (1 << 10));
2819                 else
2820                         sprintf(buf, LPU64"%s", num, "k");
2821         }
2822 }
2823
2824 static void print_quota(char *mnt, struct if_quotactl *qctl, int type,
2825                         int rc, bool h)
2826 {
2827         time_t now;
2828
2829         time(&now);
2830
2831         if (qctl->qc_cmd == LUSTRE_Q_GETQUOTA || qctl->qc_cmd == Q_GETOQUOTA) {
2832                 int bover = 0, iover = 0;
2833                 struct obd_dqblk *dqb = &qctl->qc_dqblk;
2834                 char numbuf[3][32];
2835                 char timebuf[40];
2836                 char strbuf[32];
2837
2838                 if (dqb->dqb_bhardlimit &&
2839                     lustre_stoqb(dqb->dqb_curspace) >= dqb->dqb_bhardlimit) {
2840                         bover = 1;
2841                 } else if (dqb->dqb_bsoftlimit && dqb->dqb_btime) {
2842                         if (dqb->dqb_btime > now) {
2843                                 bover = 2;
2844                         } else {
2845                                 bover = 3;
2846                         }
2847                 }
2848
2849                 if (dqb->dqb_ihardlimit &&
2850                     dqb->dqb_curinodes >= dqb->dqb_ihardlimit) {
2851                         iover = 1;
2852                 } else if (dqb->dqb_isoftlimit && dqb->dqb_itime) {
2853                         if (dqb->dqb_itime > now) {
2854                                 iover = 2;
2855                         } else {
2856                                 iover = 3;
2857                         }
2858                 }
2859
2860
2861                 if (strlen(mnt) > 15)
2862                         printf("%s\n%15s", mnt, "");
2863                 else
2864                         printf("%15s", mnt);
2865
2866                 if (bover)
2867                         diff2str(dqb->dqb_btime, timebuf, now);
2868
2869                 kbytes2str(lustre_stoqb(dqb->dqb_curspace), strbuf, h);
2870                 if (rc == -EREMOTEIO)
2871                         sprintf(numbuf[0], "%s*", strbuf);
2872                 else
2873                         sprintf(numbuf[0], (dqb->dqb_valid & QIF_SPACE) ?
2874                                 "%s" : "[%s]", strbuf);
2875
2876                 kbytes2str(dqb->dqb_bsoftlimit, strbuf, h);
2877                 if (type == QC_GENERAL)
2878                         sprintf(numbuf[1], (dqb->dqb_valid & QIF_BLIMITS) ?
2879                                 "%s" : "[%s]", strbuf);
2880                 else
2881                         sprintf(numbuf[1], "%s", "-");
2882
2883                 kbytes2str(dqb->dqb_bhardlimit, strbuf, h);
2884                 sprintf(numbuf[2], (dqb->dqb_valid & QIF_BLIMITS) ?
2885                         "%s" : "[%s]", strbuf);
2886
2887                 printf(" %7s%c %6s %7s %7s",
2888                        numbuf[0], bover ? '*' : ' ', numbuf[1],
2889                        numbuf[2], bover > 1 ? timebuf : "-");
2890
2891                 if (iover)
2892                         diff2str(dqb->dqb_itime, timebuf, now);
2893
2894                 sprintf(numbuf[0], (dqb->dqb_valid & QIF_INODES) ?
2895                         LPU64 : "["LPU64"]", dqb->dqb_curinodes);
2896
2897                 if (type == QC_GENERAL)
2898                         sprintf(numbuf[1], (dqb->dqb_valid & QIF_ILIMITS) ?
2899                                 LPU64 : "["LPU64"]", dqb->dqb_isoftlimit);
2900                 else
2901                         sprintf(numbuf[1], "%s", "-");
2902
2903                 sprintf(numbuf[2], (dqb->dqb_valid & QIF_ILIMITS) ?
2904                         LPU64 : "["LPU64"]", dqb->dqb_ihardlimit);
2905
2906                 if (type != QC_OSTIDX)
2907                         printf(" %7s%c %6s %7s %7s",
2908                                numbuf[0], iover ? '*' : ' ', numbuf[1],
2909                                numbuf[2], iover > 1 ? timebuf : "-");
2910                 else
2911                         printf(" %7s %7s %7s %7s", "-", "-", "-", "-");
2912                 printf("\n");
2913
2914         } else if (qctl->qc_cmd == LUSTRE_Q_GETINFO ||
2915                    qctl->qc_cmd == Q_GETOINFO) {
2916                 char bgtimebuf[40];
2917                 char igtimebuf[40];
2918
2919                 sec2str(qctl->qc_dqinfo.dqi_bgrace, bgtimebuf, rc);
2920                 sec2str(qctl->qc_dqinfo.dqi_igrace, igtimebuf, rc);
2921                 printf("Block grace time: %s; Inode grace time: %s\n",
2922                        bgtimebuf, igtimebuf);
2923         }
2924 }
2925
2926 static int print_obd_quota(char *mnt, struct if_quotactl *qctl, int is_mdt,
2927                            bool h, __u64 *total)
2928 {
2929         int rc = 0, rc1 = 0, count = 0;
2930         __u32 valid = qctl->qc_valid;
2931
2932         rc = llapi_get_obd_count(mnt, &count, is_mdt);
2933         if (rc) {
2934                 fprintf(stderr, "can not get %s count: %s\n",
2935                         is_mdt ? "mdt": "ost", strerror(-rc));
2936                 return rc;
2937         }
2938
2939         for (qctl->qc_idx = 0; qctl->qc_idx < count; qctl->qc_idx++) {
2940                 qctl->qc_valid = is_mdt ? QC_MDTIDX : QC_OSTIDX;
2941                 rc = llapi_quotactl(mnt, qctl);
2942                 if (rc) {
2943                         /* It is remote client case. */
2944                         if (-rc == EOPNOTSUPP) {
2945                                 rc = 0;
2946                                 goto out;
2947                         }
2948
2949                         if (!rc1)
2950                                 rc1 = rc;
2951                         fprintf(stderr, "quotactl %s%d failed.\n",
2952                                 is_mdt ? "mdt": "ost", qctl->qc_idx);
2953                         continue;
2954                 }
2955
2956                 print_quota(obd_uuid2str(&qctl->obd_uuid), qctl,
2957                             qctl->qc_valid, 0, h);
2958                 *total += is_mdt ? qctl->qc_dqblk.dqb_ihardlimit :
2959                                    qctl->qc_dqblk.dqb_bhardlimit;
2960         }
2961 out:
2962         qctl->qc_valid = valid;
2963         return rc ? : rc1;
2964 }
2965
2966 static int lfs_quota(int argc, char **argv)
2967 {
2968         int c;
2969         char *mnt, *name = NULL;
2970         struct if_quotactl qctl = { .qc_cmd = LUSTRE_Q_GETQUOTA,
2971                                     .qc_type = UGQUOTA };
2972         char *obd_type = (char *)qctl.obd_type;
2973         char *obd_uuid = (char *)qctl.obd_uuid.uuid;
2974         int rc, rc1 = 0, rc2 = 0, rc3 = 0,
2975             verbose = 0, pass = 0, quiet = 0, inacc;
2976         char *endptr;
2977         __u32 valid = QC_GENERAL, idx = 0;
2978         __u64 total_ialloc = 0, total_balloc = 0;
2979         bool human_readable = false;
2980
2981         while ((c = getopt(argc, argv, "gi:I:o:qtuvh")) != -1) {
2982                 switch (c) {
2983                 case 'u':
2984                         if (qctl.qc_type != UGQUOTA) {
2985                                 fprintf(stderr, "error: use either -u or -g\n");
2986                                 return CMD_HELP;
2987                         }
2988                         qctl.qc_type = USRQUOTA;
2989                         break;
2990                 case 'g':
2991                         if (qctl.qc_type != UGQUOTA) {
2992                                 fprintf(stderr, "error: use either -u or -g\n");
2993                                 return CMD_HELP;
2994                         }
2995                         qctl.qc_type = GRPQUOTA;
2996                         break;
2997                 case 't':
2998                         qctl.qc_cmd = LUSTRE_Q_GETINFO;
2999                         break;
3000                 case 'o':
3001                         valid = qctl.qc_valid = QC_UUID;
3002                         strlcpy(obd_uuid, optarg, sizeof(qctl.obd_uuid));
3003                         break;
3004                 case 'i':
3005                         valid = qctl.qc_valid = QC_MDTIDX;
3006                         idx = qctl.qc_idx = atoi(optarg);
3007                         break;
3008                 case 'I':
3009                         valid = qctl.qc_valid = QC_OSTIDX;
3010                         idx = qctl.qc_idx = atoi(optarg);
3011                         break;
3012                 case 'v':
3013                         verbose = 1;
3014                         break;
3015                 case 'q':
3016                         quiet = 1;
3017                         break;
3018                 case 'h':
3019                         human_readable = true;
3020                         break;
3021                 default:
3022                         fprintf(stderr, "error: %s: option '-%c' "
3023                                         "unrecognized\n", argv[0], c);
3024                         return CMD_HELP;
3025                 }
3026         }
3027
3028         /* current uid/gid info for "lfs quota /path/to/lustre/mount" */
3029         if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA && qctl.qc_type == UGQUOTA &&
3030             optind == argc - 1) {
3031 ug_output:
3032                 memset(&qctl, 0, sizeof(qctl)); /* spoiled by print_*_quota */
3033                 qctl.qc_cmd = LUSTRE_Q_GETQUOTA;
3034                 qctl.qc_valid = valid;
3035                 qctl.qc_idx = idx;
3036                 if (pass++ == 0) {
3037                         qctl.qc_type = USRQUOTA;
3038                         qctl.qc_id = geteuid();
3039                 } else {
3040                         qctl.qc_type = GRPQUOTA;
3041                         qctl.qc_id = getegid();
3042                 }
3043                 rc = id2name(&name, qctl.qc_id,
3044                              (qctl.qc_type == USRQUOTA) ? USER : GROUP);
3045                 if (rc)
3046                         name = "<unknown>";
3047         /* lfs quota -u username /path/to/lustre/mount */
3048         } else if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA) {
3049                 /* options should be followed by u/g-name and mntpoint */
3050                 if (optind + 2 != argc || qctl.qc_type == UGQUOTA) {
3051                         fprintf(stderr, "error: missing quota argument(s)\n");
3052                         return CMD_HELP;
3053                 }
3054
3055                 name = argv[optind++];
3056                 rc = name2id(&qctl.qc_id, name,
3057                              (qctl.qc_type == USRQUOTA) ? USER : GROUP);
3058                 if (rc) {
3059                         qctl.qc_id = strtoul(name, &endptr, 10);
3060                         if (*endptr != '\0') {
3061                                 fprintf(stderr, "error: can't find id for name "
3062                                         "%s\n", name);
3063                                 return CMD_HELP;
3064                         }
3065                 }
3066         } else if (optind + 1 != argc || qctl.qc_type == UGQUOTA) {
3067                 fprintf(stderr, "error: missing quota info argument(s)\n");
3068                 return CMD_HELP;
3069         }
3070
3071         mnt = argv[optind];
3072
3073         rc1 = llapi_quotactl(mnt, &qctl);
3074         if (rc1 < 0) {
3075                 switch (rc1) {
3076                 case -ESRCH:
3077                         fprintf(stderr, "%s quotas are not enabled.\n",
3078                                 qctl.qc_type == USRQUOTA ? "user" : "group");
3079                         goto out;
3080                 case -EPERM:
3081                         fprintf(stderr, "Permission denied.\n");
3082                 case -ENOENT:
3083                         /* We already got a "No such file..." message. */
3084                         goto out;
3085                 default:
3086                         fprintf(stderr, "Unexpected quotactl error: %s\n",
3087                                 strerror(-rc1));
3088                 }
3089         }
3090
3091         if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA && !quiet)
3092                 print_quota_title(name, &qctl, human_readable);
3093
3094         if (rc1 && *obd_type)
3095                 fprintf(stderr, "%s %s ", obd_type, obd_uuid);
3096
3097         if (qctl.qc_valid != QC_GENERAL)
3098                 mnt = "";
3099
3100         inacc = (qctl.qc_cmd == LUSTRE_Q_GETQUOTA) &&
3101                 ((qctl.qc_dqblk.dqb_valid & (QIF_LIMITS|QIF_USAGE)) !=
3102                  (QIF_LIMITS|QIF_USAGE));
3103
3104         print_quota(mnt, &qctl, QC_GENERAL, rc1, human_readable);
3105
3106         if (qctl.qc_valid == QC_GENERAL && qctl.qc_cmd != LUSTRE_Q_GETINFO &&
3107             verbose) {
3108                 char strbuf[32];
3109
3110                 rc2 = print_obd_quota(mnt, &qctl, 1, human_readable,
3111                                       &total_ialloc);
3112                 rc3 = print_obd_quota(mnt, &qctl, 0, human_readable,
3113                                       &total_balloc);
3114                 kbytes2str(total_balloc, strbuf, human_readable);
3115                 printf("Total allocated inode limit: "LPU64", total "
3116                        "allocated block limit: %s\n", total_ialloc, strbuf);
3117         }
3118
3119         if (rc1 || rc2 || rc3 || inacc)
3120                 printf("Some errors happened when getting quota info. "
3121                        "Some devices may be not working or deactivated. "
3122                        "The data in \"[]\" is inaccurate.\n");
3123
3124 out:
3125         if (pass == 1)
3126                 goto ug_output;
3127
3128         return rc1;
3129 }
3130 #endif /* HAVE_SYS_QUOTA_H! */
3131
3132 static int flushctx_ioctl(char *mp)
3133 {
3134         int fd, rc;
3135
3136         fd = open(mp, O_RDONLY);
3137         if (fd == -1) {
3138                 fprintf(stderr, "flushctx: error open %s: %s\n",
3139                         mp, strerror(errno));
3140                 return -1;
3141         }
3142
3143         rc = ioctl(fd, LL_IOC_FLUSHCTX);
3144         if (rc == -1)
3145                 fprintf(stderr, "flushctx: error ioctl %s: %s\n",
3146                         mp, strerror(errno));
3147
3148         close(fd);
3149         return rc;
3150 }
3151
3152 static int lfs_flushctx(int argc, char **argv)
3153 {
3154         int     kdestroy = 0, c;
3155         char    mntdir[PATH_MAX] = {'\0'};
3156         int     index = 0;
3157         int     rc = 0;
3158
3159         while ((c = getopt(argc, argv, "k")) != -1) {
3160                 switch (c) {
3161                 case 'k':
3162                         kdestroy = 1;
3163                         break;
3164                 default:
3165                         fprintf(stderr, "error: %s: option '-%c' "
3166                                         "unrecognized\n", argv[0], c);
3167                         return CMD_HELP;
3168                 }
3169         }
3170
3171         if (kdestroy) {
3172             if ((rc = system("kdestroy > /dev/null")) != 0) {
3173                 rc = WEXITSTATUS(rc);
3174                 fprintf(stderr, "error destroying tickets: %d, continuing\n", rc);
3175             }
3176         }
3177
3178         if (optind >= argc) {
3179                 /* flush for all mounted lustre fs. */
3180                 while (!llapi_search_mounts(NULL, index++, mntdir, NULL)) {
3181                         /* Check if we have a mount point */
3182                         if (mntdir[0] == '\0')
3183                                 continue;
3184
3185                         if (flushctx_ioctl(mntdir))
3186                                 rc = -1;
3187
3188                         mntdir[0] = '\0'; /* avoid matching in next loop */
3189                 }
3190         } else {
3191                 /* flush fs as specified */
3192                 while (optind < argc) {
3193                         if (flushctx_ioctl(argv[optind++]))
3194                                 rc = -1;
3195                 }
3196         }
3197         return rc;
3198 }
3199
3200 static int lfs_lsetfacl(int argc, char **argv)
3201 {
3202         argv[0]++;
3203         return(llapi_lsetfacl(argc, argv));
3204 }
3205
3206 static int lfs_lgetfacl(int argc, char **argv)
3207 {
3208         argv[0]++;
3209         return(llapi_lgetfacl(argc, argv));
3210 }
3211
3212 static int lfs_rsetfacl(int argc, char **argv)
3213 {
3214         argv[0]++;
3215         return(llapi_rsetfacl(argc, argv));
3216 }
3217
3218 static int lfs_rgetfacl(int argc, char **argv)
3219 {
3220         argv[0]++;
3221         return(llapi_rgetfacl(argc, argv));
3222 }
3223
3224 static int lfs_cp(int argc, char **argv)
3225 {
3226         return(llapi_cp(argc, argv));
3227 }
3228
3229 static int lfs_ls(int argc, char **argv)
3230 {
3231         return(llapi_ls(argc, argv));
3232 }
3233
3234 static int lfs_changelog(int argc, char **argv)
3235 {
3236         void *changelog_priv;
3237         struct changelog_rec *rec;
3238         long long startrec = 0, endrec = 0;
3239         char *mdd;
3240         struct option long_opts[] = {
3241                 {"follow", no_argument, 0, 'f'},
3242                 {0, 0, 0, 0}
3243         };
3244         char short_opts[] = "f";
3245         int rc, follow = 0;
3246
3247         while ((rc = getopt_long(argc, argv, short_opts,
3248                                 long_opts, NULL)) != -1) {
3249                 switch (rc) {
3250                 case 'f':
3251                         follow++;
3252                         break;
3253                 case '?':
3254                         return CMD_HELP;
3255                 default:
3256                         fprintf(stderr, "error: %s: option '%s' unrecognized\n",
3257                                 argv[0], argv[optind - 1]);
3258                         return CMD_HELP;
3259                 }
3260         }
3261         if (optind >= argc)
3262                 return CMD_HELP;
3263
3264         mdd = argv[optind++];
3265         if (argc > optind)
3266                 startrec = strtoll(argv[optind++], NULL, 10);
3267         if (argc > optind)
3268                 endrec = strtoll(argv[optind++], NULL, 10);
3269
3270         rc = llapi_changelog_start(&changelog_priv,
3271                                    CHANGELOG_FLAG_BLOCK |
3272                                    CHANGELOG_FLAG_JOBID |
3273                                    (follow ? CHANGELOG_FLAG_FOLLOW : 0),
3274                                    mdd, startrec);
3275         if (rc < 0) {
3276                 fprintf(stderr, "Can't start changelog: %s\n",
3277                         strerror(errno = -rc));
3278                 return rc;
3279         }
3280
3281         while ((rc = llapi_changelog_recv(changelog_priv, &rec)) == 0) {
3282                 time_t secs;
3283                 struct tm ts;
3284
3285                 if (endrec && rec->cr_index > endrec) {
3286                         llapi_changelog_free(&rec);
3287                         break;
3288                 }
3289                 if (rec->cr_index < startrec) {
3290                         llapi_changelog_free(&rec);
3291                         continue;
3292                 }
3293
3294                 secs = rec->cr_time >> 30;
3295                 gmtime_r(&secs, &ts);
3296                 printf(LPU64" %02d%-5s %02d:%02d:%02d.%06d %04d.%02d.%02d "
3297                        "0x%x t="DFID, rec->cr_index, rec->cr_type,
3298                        changelog_type2str(rec->cr_type),
3299                        ts.tm_hour, ts.tm_min, ts.tm_sec,
3300                        (int)(rec->cr_time & ((1<<30) - 1)),
3301                        ts.tm_year + 1900, ts.tm_mon + 1, ts.tm_mday,
3302                        rec->cr_flags & CLF_FLAGMASK, PFID(&rec->cr_tfid));
3303
3304                 if (rec->cr_flags & CLF_JOBID) {
3305                         struct changelog_ext_jobid *jid =
3306                                 changelog_rec_jobid(rec);
3307
3308                         if (jid->cr_jobid[0] != '\0')
3309                                 printf(" j=%s", jid->cr_jobid);
3310                 }
3311
3312                 if (rec->cr_namelen)
3313                         printf(" p="DFID" %.*s", PFID(&rec->cr_pfid),
3314                                rec->cr_namelen, changelog_rec_name(rec));
3315
3316                 if (rec->cr_flags & CLF_RENAME) {
3317                         struct changelog_ext_rename *rnm =
3318                                 changelog_rec_rename(rec);
3319
3320                         if (!fid_is_zero(&rnm->cr_sfid))
3321                                 printf(" s="DFID" sp="DFID" %.*s",
3322                                        PFID(&rnm->cr_sfid),
3323                                        PFID(&rnm->cr_spfid),
3324                                        (int)changelog_rec_snamelen(rec),
3325                                        changelog_rec_sname(rec));
3326                 }
3327                 printf("\n");
3328
3329                 llapi_changelog_free(&rec);
3330         }
3331
3332         llapi_changelog_fini(&changelog_priv);
3333
3334         if (rc < 0)
3335                 fprintf(stderr, "Changelog: %s\n", strerror(errno = -rc));
3336
3337         return (rc == 1 ? 0 : rc);
3338 }
3339
3340 static int lfs_changelog_clear(int argc, char **argv)
3341 {
3342         long long endrec;
3343         int rc;
3344
3345         if (argc != 4)
3346                 return CMD_HELP;
3347
3348         endrec = strtoll(argv[3], NULL, 10);
3349
3350         rc = llapi_changelog_clear(argv[1], argv[2], endrec);
3351         if (rc)
3352                 fprintf(stderr, "%s error: %s\n", argv[0],
3353                         strerror(errno = -rc));
3354         return rc;
3355 }
3356
3357 static int lfs_fid2path(int argc, char **argv)
3358 {
3359         struct option long_opts[] = {
3360                 {"cur", no_argument, 0, 'c'},
3361                 {"link", required_argument, 0, 'l'},
3362                 {"rec", required_argument, 0, 'r'},
3363                 {0, 0, 0, 0}
3364         };
3365         char  short_opts[] = "cl:r:";
3366         char *device, *fid, *path;
3367         long long recno = -1;
3368         int linkno = -1;
3369         int lnktmp;
3370         int printcur = 0;
3371         int rc = 0;
3372
3373         while ((rc = getopt_long(argc, argv, short_opts,
3374                                 long_opts, NULL)) != -1) {
3375                 switch (rc) {
3376                 case 'c':
3377                         printcur++;
3378                         break;
3379                 case 'l':
3380                         linkno = strtol(optarg, NULL, 10);
3381                         break;
3382                 case 'r':
3383                         recno = strtoll(optarg, NULL, 10);
3384                         break;
3385                 case '?':
3386                         return CMD_HELP;
3387                 default:
3388                         fprintf(stderr, "error: %s: option '%s' unrecognized\n",
3389                                 argv[0], argv[optind - 1]);
3390                         return CMD_HELP;
3391                 }
3392         }
3393
3394         if (argc < 3)
3395                 return CMD_HELP;
3396
3397         device = argv[optind++];
3398         path = calloc(1, PATH_MAX);
3399         if (path == NULL) {
3400                 fprintf(stderr, "error: Not enough memory\n");
3401                 return -errno;
3402         }
3403
3404         rc = 0;
3405         while (optind < argc) {
3406                 fid = argv[optind++];
3407
3408                 lnktmp = (linkno >= 0) ? linkno : 0;
3409                 while (1) {
3410                         int oldtmp = lnktmp;
3411                         long long rectmp = recno;
3412                         int rc2;
3413                         rc2 = llapi_fid2path(device, fid, path, PATH_MAX,
3414                                              &rectmp, &lnktmp);
3415                         if (rc2 < 0) {
3416                                 fprintf(stderr, "%s: error on FID %s: %s\n",
3417                                         argv[0], fid, strerror(errno = -rc2));
3418                                 if (rc == 0)
3419                                         rc = rc2;
3420                                 break;
3421                         }
3422
3423                         if (printcur)
3424                                 fprintf(stdout, "%lld ", rectmp);
3425                         if (device[0] == '/') {
3426                                 fprintf(stdout, "%s", device);
3427                                 if (device[strlen(device) - 1] != '/')
3428                                         fprintf(stdout, "/");
3429                         } else if (path[0] == '\0') {
3430                                 fprintf(stdout, "/");
3431                         }
3432                         fprintf(stdout, "%s\n", path);
3433
3434                         if (linkno >= 0)
3435                                 /* specified linkno */
3436                                 break;
3437                         if (oldtmp == lnktmp)
3438                                 /* no more links */
3439                                 break;
3440                 }
3441         }
3442
3443         free(path);
3444         return rc;
3445 }
3446
3447 static int lfs_path2fid(int argc, char **argv)
3448 {
3449         struct option     long_opts[] = {
3450                 {"parents", no_argument, 0, 'p'},
3451                 {0, 0, 0, 0}
3452         };
3453         char            **path;
3454         const char        short_opts[] = "p";
3455         const char       *sep = "";
3456         lustre_fid        fid;
3457         int               rc = 0;
3458         bool              show_parents = false;
3459
3460         while ((rc = getopt_long(argc, argv, short_opts,
3461                                  long_opts, NULL)) != -1) {
3462                 switch (rc) {
3463                 case 'p':
3464                         show_parents = true;
3465                         break;
3466                 default:
3467                         fprintf(stderr, "error: %s: option '%s' unrecognized\n",
3468                                 argv[0], argv[optind - 1]);
3469                         return CMD_HELP;
3470                 }
3471         }
3472
3473         if (optind > argc - 1)
3474                 return CMD_HELP;
3475         else if (optind < argc - 1)
3476                 sep = ": ";
3477
3478         rc = 0;
3479         for (path = argv + optind; *path != NULL; path++) {
3480                 int err = 0;
3481                 if (!show_parents) {
3482                         err = llapi_path2fid(*path, &fid);
3483                         if (!err)
3484                                 printf("%s%s"DFID"\n",
3485                                        *sep != '\0' ? *path : "", sep,
3486                                        PFID(&fid));
3487                 } else {
3488                         char            name[NAME_MAX + 1];
3489                         unsigned int    linkno = 0;
3490
3491                         while ((err = llapi_path2parent(*path, linkno, &fid,
3492                                                 name, sizeof(name))) == 0) {
3493                                 if (*sep != '\0' && linkno == 0)
3494                                         printf("%s%s", *path, sep);
3495
3496                                 printf("%s"DFID"/%s", linkno != 0 ? "\t" : "",
3497                                        PFID(&fid), name);
3498                                 linkno++;
3499                         }
3500
3501                         /* err == -ENODATA is end-of-loop */
3502                         if (linkno > 0 && err == -ENODATA) {
3503                                 printf("\n");
3504                                 err = 0;
3505                         }
3506                 }
3507
3508                 if (err) {
3509                         fprintf(stderr, "%s: can't get %sfid for %s: %s\n",
3510                                 argv[0], show_parents ? "parent " : "", *path,
3511                                 strerror(-err));
3512                         if (rc == 0) {
3513                                 rc = err;
3514                                 errno = -err;
3515                         }
3516                 }
3517         }
3518
3519         return rc;
3520 }
3521
3522 static int lfs_data_version(int argc, char **argv)
3523 {
3524         char *path;
3525         __u64 data_version;
3526         int fd;
3527         int rc;
3528         int c;
3529         int data_version_flags = LL_DV_RD_FLUSH; /* Read by default */
3530
3531         if (argc < 2)
3532                 return CMD_HELP;
3533
3534         while ((c = getopt(argc, argv, "nrw")) != -1) {
3535                 switch (c) {
3536                 case 'n':
3537                         data_version_flags = 0;
3538                         break;
3539                 case 'r':
3540                         data_version_flags |= LL_DV_RD_FLUSH;
3541                         break;
3542                 case 'w':
3543                         data_version_flags |= LL_DV_WR_FLUSH;
3544                         break;
3545                 default:
3546                         return CMD_HELP;
3547                 }
3548         }
3549         if (optind == argc)
3550                 return CMD_HELP;
3551
3552         path = argv[optind];
3553         fd = open(path, O_RDONLY);
3554         if (fd < 0)
3555                 err(errno, "cannot open file %s", path);
3556
3557         rc = llapi_get_data_version(fd, &data_version, data_version_flags);
3558         if (rc < 0)
3559                 err(errno, "cannot get version for %s", path);
3560         else
3561                 printf(LPU64 "\n", data_version);
3562
3563         close(fd);
3564         return rc;
3565 }
3566
3567 static int lfs_hsm_state(int argc, char **argv)
3568 {
3569         int rc;
3570         int i = 1;
3571         char *path;
3572         struct hsm_user_state hus;
3573
3574         if (argc < 2)
3575                 return CMD_HELP;
3576
3577         do {
3578                 path = argv[i];
3579
3580                 rc = llapi_hsm_state_get(path, &hus);
3581                 if (rc) {
3582                         fprintf(stderr, "can't get hsm state for %s: %s\n",
3583                                 path, strerror(errno = -rc));
3584                         return rc;
3585                 }
3586
3587                 /* Display path name and status flags */
3588                 printf("%s: (0x%08x)", path, hus.hus_states);
3589
3590                 if (hus.hus_states & HS_RELEASED)
3591                         printf(" released");
3592                 if (hus.hus_states & HS_EXISTS)
3593                         printf(" exists");
3594                 if (hus.hus_states & HS_DIRTY)
3595                         printf(" dirty");
3596                 if (hus.hus_states & HS_ARCHIVED)
3597                         printf(" archived");
3598                 /* Display user-settable flags */
3599                 if (hus.hus_states & HS_NORELEASE)
3600                         printf(" never_release");
3601                 if (hus.hus_states & HS_NOARCHIVE)
3602                         printf(" never_archive");
3603                 if (hus.hus_states & HS_LOST)
3604                         printf(" lost_from_hsm");
3605
3606                 if (hus.hus_archive_id != 0)
3607                         printf(", archive_id:%d", hus.hus_archive_id);
3608                 printf("\n");
3609
3610         } while (++i < argc);
3611
3612         return 0;
3613 }
3614
3615 #define LFS_HSM_SET   0
3616 #define LFS_HSM_CLEAR 1
3617
3618 /**
3619  * Generic function to set or clear HSM flags.
3620  * Used by hsm_set and hsm_clear.
3621  *
3622  * @mode  if LFS_HSM_SET, set the flags, if LFS_HSM_CLEAR, clear the flags.
3623  */
3624 static int lfs_hsm_change_flags(int argc, char **argv, int mode)
3625 {
3626         struct option long_opts[] = {
3627                 {"lost", 0, 0, 'l'},
3628                 {"norelease", 0, 0, 'r'},
3629                 {"noarchive", 0, 0, 'a'},
3630                 {"archived", 0, 0, 'A'},
3631                 {"dirty", 0, 0, 'd'},
3632                 {"exists", 0, 0, 'e'},
3633                 {0, 0, 0, 0}
3634         };
3635         char short_opts[] = "lraAde";
3636         __u64 mask = 0;
3637         int c, rc;
3638         char *path;
3639
3640         if (argc < 3)
3641                 return CMD_HELP;
3642
3643         while ((c = getopt_long(argc, argv, short_opts,
3644                                 long_opts, NULL)) != -1) {
3645                 switch (c) {
3646                 case 'l':
3647                         mask |= HS_LOST;
3648                         break;
3649                 case 'a':
3650                         mask |= HS_NOARCHIVE;
3651                         break;
3652                 case 'A':
3653                         mask |= HS_ARCHIVED;
3654                         break;
3655                 case 'r':
3656                         mask |= HS_NORELEASE;
3657                         break;
3658                 case 'd':
3659                         mask |= HS_DIRTY;
3660                         break;
3661                 case 'e':
3662                         mask |= HS_EXISTS;
3663                         break;
3664                 case '?':
3665                         return CMD_HELP;
3666                 default:
3667                         fprintf(stderr, "error: %s: option '%s' unrecognized\n",
3668                                 argv[0], argv[optind - 1]);
3669                         return CMD_HELP;
3670                 }
3671         }
3672
3673         /* User should have specified a flag */
3674         if (mask == 0)
3675                 return CMD_HELP;
3676
3677         while (optind < argc) {
3678
3679                 path = argv[optind];
3680
3681                 /* If mode == 0, this means we apply the mask. */
3682                 if (mode == LFS_HSM_SET)
3683                         rc = llapi_hsm_state_set(path, mask, 0, 0);
3684                 else
3685                         rc = llapi_hsm_state_set(path, 0, mask, 0);
3686
3687                 if (rc != 0) {
3688                         fprintf(stderr, "Can't change hsm flags for %s: %s\n",
3689                                 path, strerror(errno = -rc));
3690                         return rc;
3691                 }
3692                 optind++;
3693         }
3694
3695         return 0;
3696 }
3697
3698 static int lfs_hsm_action(int argc, char **argv)
3699 {
3700         int                              rc;
3701         int                              i = 1;
3702         char                            *path;
3703         struct hsm_current_action        hca;
3704         struct hsm_extent                he;
3705         enum hsm_user_action             hua;
3706         enum hsm_progress_states         hps;
3707
3708         if (argc < 2)
3709                 return CMD_HELP;
3710
3711         do {
3712                 path = argv[i];
3713
3714                 rc = llapi_hsm_current_action(path, &hca);
3715                 if (rc) {
3716                         fprintf(stderr, "can't get hsm action for %s: %s\n",
3717                                 path, strerror(errno = -rc));
3718                         return rc;
3719                 }
3720                 he = hca.hca_location;
3721                 hua = hca.hca_action;
3722                 hps = hca.hca_state;
3723
3724                 printf("%s: %s", path, hsm_user_action2name(hua));
3725
3726                 /* Skip file without action */
3727                 if (hca.hca_action == HUA_NONE) {
3728                         printf("\n");
3729                         continue;
3730                 }
3731
3732                 printf(" %s ", hsm_progress_state2name(hps));
3733
3734                 if ((hps == HPS_RUNNING) &&
3735                     (hua == HUA_ARCHIVE || hua == HUA_RESTORE))
3736                         printf("(%llu bytes moved)\n",
3737                                (unsigned long long)he.length);
3738                 else if ((he.offset + he.length) == LUSTRE_EOF)
3739                         printf("(from %llu to EOF)\n",
3740                                (unsigned long long)he.offset);
3741                 else
3742                         printf("(from %llu to %llu)\n",
3743                                (unsigned long long)he.offset,
3744                                (unsigned long long)(he.offset + he.length));
3745
3746         } while (++i < argc);
3747
3748         return 0;
3749 }
3750
3751 static int lfs_hsm_set(int argc, char **argv)
3752 {
3753         return lfs_hsm_change_flags(argc, argv, LFS_HSM_SET);
3754 }
3755
3756 static int lfs_hsm_clear(int argc, char **argv)
3757 {
3758         return lfs_hsm_change_flags(argc, argv, LFS_HSM_CLEAR);
3759 }
3760
3761 /**
3762  * Check file state and return its fid, to be used by lfs_hsm_request().
3763  *
3764  * \param[in]     file      Path to file to check
3765  * \param[in,out] fid       Pointer to allocated lu_fid struct.
3766  * \param[in,out] last_dev  Pointer to last device id used.
3767  *
3768  * \return 0 on success.
3769  */
3770 static int lfs_hsm_prepare_file(const char *file, struct lu_fid *fid,
3771                                 dev_t *last_dev)
3772 {
3773         struct stat     st;
3774         int             rc;
3775
3776         rc = lstat(file, &st);
3777         if (rc) {
3778                 fprintf(stderr, "Cannot stat %s: %s\n", file, strerror(errno));
3779                 return -errno;
3780         }
3781         /* Checking for regular file as archiving as posix copytool
3782          * rejects archiving files other than regular files
3783          */
3784         if (!S_ISREG(st.st_mode)) {
3785                 fprintf(stderr, "error: \"%s\" is not a regular file\n", file);
3786                 return CMD_HELP;
3787         }
3788         /* A request should be ... */
3789         if (*last_dev != st.st_dev && *last_dev != 0) {
3790                 fprintf(stderr, "All files should be "
3791                         "on the same filesystem: %s\n", file);
3792                 return -EINVAL;
3793         }
3794         *last_dev = st.st_dev;
3795
3796         rc = llapi_path2fid(file, fid);
3797         if (rc) {
3798                 fprintf(stderr, "Cannot read FID of %s: %s\n",
3799                         file, strerror(-rc));
3800                 return rc;
3801         }
3802         return 0;
3803 }
3804
3805 /* Fill an HSM HUR item with a given file name.
3806  *
3807  * If mntpath is set, then the filename is actually a FID, and no
3808  * lookup on the filesystem will be performed.
3809  *
3810  * \param[in]  hur         the user request to fill
3811  * \param[in]  idx         index of the item inside the HUR to fill
3812  * \param[in]  mntpath     mountpoint of Lustre
3813  * \param[in]  fname       filename (if mtnpath is NULL)
3814  *                         or FID (if mntpath is set)
3815  * \param[in]  last_dev    pointer to last device id used
3816  *
3817  * \retval 0 on success
3818  * \retval CMD_HELP or a negative errno on error
3819  */
3820 static int fill_hur_item(struct hsm_user_request *hur, unsigned int idx,
3821                          const char *mntpath, const char *fname,
3822                          dev_t *last_dev)
3823 {
3824         struct hsm_user_item *hui = &hur->hur_user_item[idx];
3825         int rc;
3826
3827         hui->hui_extent.length = -1;
3828
3829         if (mntpath != NULL) {
3830                 if (*fname == '[')
3831                         fname++;
3832                 rc = sscanf(fname, SFID, RFID(&hui->hui_fid));
3833                 if (rc == 3) {
3834                         rc = 0;
3835                 } else {
3836                         fprintf(stderr, "hsm: '%s' is not a valid FID\n",
3837                                 fname);
3838                         rc = -EINVAL;
3839                 }
3840         } else {
3841                 rc = lfs_hsm_prepare_file(fname, &hui->hui_fid, last_dev);
3842         }
3843
3844         if (rc == 0)
3845                 hur->hur_request.hr_itemcount++;
3846
3847         return rc;
3848 }
3849
3850 static int lfs_hsm_request(int argc, char **argv, int action)
3851 {
3852         struct option            long_opts[] = {
3853                 {"filelist", 1, 0, 'l'},
3854                 {"data", 1, 0, 'D'},
3855                 {"archive", 1, 0, 'a'},
3856                 {"mntpath", 1, 0, 'm'},
3857                 {0, 0, 0, 0}
3858         };
3859         dev_t                    last_dev = 0;
3860         char                     short_opts[] = "l:D:a:m:";
3861         struct hsm_user_request *hur, *oldhur;
3862         int                      c, i;
3863         size_t                   len;
3864         int                      nbfile;
3865         char                    *line = NULL;
3866         char                    *filelist = NULL;
3867         char                     fullpath[PATH_MAX];
3868         char                    *opaque = NULL;
3869         int                      opaque_len = 0;
3870         int                      archive_id = 0;
3871         FILE                    *fp;
3872         int                      nbfile_alloc = 0;
3873         char                    *some_file = NULL;
3874         char                    *mntpath = NULL;
3875         int                      rc;
3876
3877         if (argc < 2)
3878                 return CMD_HELP;
3879
3880         while ((c = getopt_long(argc, argv, short_opts,
3881                                 long_opts, NULL)) != -1) {
3882                 switch (c) {
3883                 case 'l':
3884                         filelist = optarg;
3885                         break;
3886                 case 'D':
3887                         opaque = optarg;
3888                         break;
3889                 case 'a':
3890                         if (action != HUA_ARCHIVE &&
3891                             action != HUA_REMOVE) {
3892                                 fprintf(stderr,
3893                                         "error: -a is supported only "
3894                                         "when archiving or removing\n");
3895                                 return CMD_HELP;
3896                         }
3897                         archive_id = atoi(optarg);
3898                         break;
3899                 case 'm':
3900                         if (some_file == NULL) {
3901                                 mntpath = optarg;
3902                                 some_file = strdup(optarg);
3903                         }
3904                         break;
3905                 case '?':
3906                         return CMD_HELP;
3907                 default:
3908                         fprintf(stderr, "error: %s: option '%s' unrecognized\n",
3909                                 argv[0], argv[optind - 1]);
3910                         return CMD_HELP;
3911                 }
3912         }
3913
3914         /* All remaining args are files, so we have at least nbfile */
3915         nbfile = argc - optind;
3916
3917         if ((nbfile == 0) && (filelist == NULL))
3918                 return CMD_HELP;
3919
3920         if (opaque != NULL)
3921                 opaque_len = strlen(opaque);
3922
3923         /* Alloc the request structure with enough place to store all files
3924          * from command line. */
3925         hur = llapi_hsm_user_request_alloc(nbfile, opaque_len);
3926         if (hur == NULL) {
3927                 fprintf(stderr, "Cannot create the request: %s\n",
3928                         strerror(errno));
3929                 return errno;
3930         }
3931         nbfile_alloc = nbfile;
3932
3933         hur->hur_request.hr_action = action;
3934         hur->hur_request.hr_archive_id = archive_id;
3935         hur->hur_request.hr_flags = 0;
3936
3937         /* All remaining args are files, add them */
3938         if (nbfile != 0 && some_file == NULL)
3939                 some_file = strdup(argv[optind]);
3940
3941         for (i = 0; i < nbfile; i++) {
3942                 rc = fill_hur_item(hur, i, mntpath, argv[optind + i],
3943                                    &last_dev);
3944                 if (rc)
3945                         goto out_free;
3946         }
3947
3948         /* from here stop using nb_file, use hur->hur_request.hr_itemcount */
3949
3950         /* If a filelist was specified, read the filelist from it. */
3951         if (filelist != NULL) {
3952                 fp = fopen(filelist, "r");
3953                 if (fp == NULL) {
3954                         fprintf(stderr, "Cannot read the file list %s: %s\n",
3955                                 filelist, strerror(errno));
3956                         rc = -errno;
3957                         goto out_free;
3958                 }
3959
3960                 while ((rc = getline(&line, &len, fp)) != -1) {
3961                         /* If allocated buffer was too small, get something
3962                          * larger */
3963                         if (nbfile_alloc <= hur->hur_request.hr_itemcount) {
3964                                 ssize_t size;
3965
3966                                 nbfile_alloc = nbfile_alloc * 2 + 1;
3967                                 oldhur = hur;
3968                                 hur = llapi_hsm_user_request_alloc(nbfile_alloc,
3969                                                                    opaque_len);
3970                                 if (hur == NULL) {
3971                                         fprintf(stderr, "hsm: cannot allocate "
3972                                                 "the request: %s\n",
3973                                                 strerror(errno));
3974                                         hur = oldhur;
3975                                         rc = -errno;
3976                                         fclose(fp);
3977                                         goto out_free;
3978                                 }
3979                                 size = hur_len(oldhur);
3980                                 if (size < 0) {
3981                                         fprintf(stderr, "hsm: cannot allocate "
3982                                                 "%u files + %u bytes data\n",
3983                                             oldhur->hur_request.hr_itemcount,
3984                                             oldhur->hur_request.hr_data_len);
3985                                         free(hur);
3986                                         hur = oldhur;
3987                                         rc = -E2BIG;
3988                                         fclose(fp);
3989                                         goto out_free;
3990                                 }
3991                                 memcpy(hur, oldhur, size);
3992                                 free(oldhur);
3993                         }
3994
3995                         /* Chop CR */
3996                         if (line[strlen(line) - 1] == '\n')
3997                                 line[strlen(line) - 1] = '\0';
3998
3999                         rc = fill_hur_item(hur, hur->hur_request.hr_itemcount,
4000                                            mntpath, line, &last_dev);
4001                         if (rc) {
4002                                 fclose(fp);
4003                                 goto out_free;
4004                         }
4005
4006                         if (some_file == NULL) {
4007                                 some_file = line;
4008                                 line = NULL;
4009                         }
4010                 }
4011
4012                 rc = fclose(fp);
4013                 free(line);
4014         }
4015
4016         /* If a --data was used, add it to the request */
4017         hur->hur_request.hr_data_len = opaque_len;
4018         if (opaque != NULL)
4019                 memcpy(hur_data(hur), opaque, opaque_len);
4020
4021         /* Send the HSM request */
4022         if (realpath(some_file, fullpath) == NULL) {
4023                 fprintf(stderr, "Could not find path '%s': %s\n",
4024                         some_file, strerror(errno));
4025         }
4026         rc = llapi_hsm_request(fullpath, hur);
4027         if (rc) {
4028                 fprintf(stderr, "Cannot send HSM request (use of %s): %s\n",
4029                         some_file, strerror(-rc));
4030                 goto out_free;
4031         }
4032
4033 out_free:
4034         free(some_file);
4035         free(hur);
4036         return rc;
4037 }
4038
4039 static int lfs_hsm_archive(int argc, char **argv)
4040 {
4041         return lfs_hsm_request(argc, argv, HUA_ARCHIVE);
4042 }
4043
4044 static int lfs_hsm_restore(int argc, char **argv)
4045 {
4046         return lfs_hsm_request(argc, argv, HUA_RESTORE);
4047 }
4048
4049 static int lfs_hsm_release(int argc, char **argv)
4050 {
4051         return lfs_hsm_request(argc, argv, HUA_RELEASE);
4052 }
4053
4054 static int lfs_hsm_remove(int argc, char **argv)
4055 {
4056         return lfs_hsm_request(argc, argv, HUA_REMOVE);
4057 }
4058
4059 static int lfs_hsm_cancel(int argc, char **argv)
4060 {
4061         return lfs_hsm_request(argc, argv, HUA_CANCEL);
4062 }
4063
4064 static int lfs_swap_layouts(int argc, char **argv)
4065 {
4066         if (argc != 3)
4067                 return CMD_HELP;
4068
4069         return llapi_swap_layouts(argv[1], argv[2], 0, 0,
4070                                   SWAP_LAYOUTS_KEEP_MTIME |
4071                                   SWAP_LAYOUTS_KEEP_ATIME);
4072 }
4073
4074 int main(int argc, char **argv)
4075 {
4076         int rc;
4077
4078         /* Ensure that liblustreapi constructor has run */
4079         if (!liblustreapi_initialized)
4080                 fprintf(stderr, "liblustreapi was not properly initialized\n");
4081
4082         setlinebuf(stdout);
4083
4084         Parser_init("lfs > ", cmdlist);
4085
4086         progname = argv[0]; /* Used in error messages */
4087         if (argc > 1) {
4088                 rc = Parser_execarg(argc - 1, argv + 1, cmdlist);
4089         } else {
4090                 rc = Parser_commands();
4091         }
4092
4093         return rc < 0 ? -rc : rc;
4094 }
4095
4096 #ifdef _LUSTRE_IDL_H_
4097 /* Everything we need here should be included by lustreapi.h. */
4098 # error "lfs should not depend on lustre_idl.h"
4099 #endif /* _LUSTRE_IDL_H_ */