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