Whamcloud - gitweb
fd2229b00f05812246744592ebee86cd4205eee3
[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.gnu.org/licenses/gpl-2.0.html
19  *
20  * GPL HEADER END
21  */
22 /*
23  * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
24  * Use is subject to license terms.
25  *
26  * Copyright (c) 2011, 2016, Intel Corporation.
27  */
28 /*
29  * This file is part of Lustre, http://www.lustre.org/
30  * Lustre is a trademark of Sun Microsystems, Inc.
31  *
32  * lustre/utils/lfs.c
33  *
34  * Author: Peter J. Braam <braam@clusterfs.com>
35  * Author: Phil Schwan <phil@clusterfs.com>
36  * Author: Robert Read <rread@clusterfs.com>
37  */
38
39 /* for O_DIRECTORY */
40 #ifndef _GNU_SOURCE
41 #define _GNU_SOURCE
42 #endif
43
44 #include <stdlib.h>
45 #include <stdio.h>
46 #include <getopt.h>
47 #include <string.h>
48 #include <mntent.h>
49 #include <unistd.h>
50 #include <errno.h>
51 #include <err.h>
52 #include <pwd.h>
53 #include <grp.h>
54 #include <sys/ioctl.h>
55 #include <sys/quota.h>
56 #include <sys/time.h>
57 #include <sys/types.h>
58 #include <sys/stat.h>
59 #include <fcntl.h>
60 #include <dirent.h>
61 #include <time.h>
62 #include <ctype.h>
63 #include "lfs_project.h"
64
65 #include <libcfs/util/string.h>
66 #include <libcfs/util/ioctl.h>
67 #include <libcfs/util/parser.h>
68 #include <lustre/lustreapi.h>
69 #include <lustre_ver.h>
70 #include <linux/lustre_param.h>
71
72 #ifndef ARRAY_SIZE
73 # define ARRAY_SIZE(a) ((sizeof(a)) / (sizeof((a)[0])))
74 #endif /* !ARRAY_SIZE */
75
76 /* all functions */
77 static int lfs_setstripe(int argc, char **argv);
78 static int lfs_find(int argc, char **argv);
79 static int lfs_getstripe(int argc, char **argv);
80 static int lfs_getdirstripe(int argc, char **argv);
81 static int lfs_setdirstripe(int argc, char **argv);
82 static int lfs_rmentry(int argc, char **argv);
83 static int lfs_osts(int argc, char **argv);
84 static int lfs_mdts(int argc, char **argv);
85 static int lfs_df(int argc, char **argv);
86 static int lfs_getname(int argc, char **argv);
87 static int lfs_check(int argc, char **argv);
88 #ifdef HAVE_SYS_QUOTA_H
89 static int lfs_setquota(int argc, char **argv);
90 static int lfs_quota(int argc, char **argv);
91 static int lfs_project(int argc, char **argv);
92 #endif
93 static int lfs_flushctx(int argc, char **argv);
94 static int lfs_cp(int argc, char **argv);
95 static int lfs_ls(int argc, char **argv);
96 static int lfs_poollist(int argc, char **argv);
97 static int lfs_changelog(int argc, char **argv);
98 static int lfs_changelog_clear(int argc, char **argv);
99 static int lfs_fid2path(int argc, char **argv);
100 static int lfs_path2fid(int argc, char **argv);
101 static int lfs_data_version(int argc, char **argv);
102 static int lfs_hsm_state(int argc, char **argv);
103 static int lfs_hsm_set(int argc, char **argv);
104 static int lfs_hsm_clear(int argc, char **argv);
105 static int lfs_hsm_action(int argc, char **argv);
106 static int lfs_hsm_archive(int argc, char **argv);
107 static int lfs_hsm_restore(int argc, char **argv);
108 static int lfs_hsm_release(int argc, char **argv);
109 static int lfs_hsm_remove(int argc, char **argv);
110 static int lfs_hsm_cancel(int argc, char **argv);
111 static int lfs_swap_layouts(int argc, char **argv);
112 static int lfs_mv(int argc, char **argv);
113 static int lfs_ladvise(int argc, char **argv);
114 static int lfs_list_commands(int argc, char **argv);
115
116 /* Setstripe and migrate share mostly the same parameters */
117 #define SSM_CMD_COMMON(cmd) \
118         "usage: "cmd" [--component-end|-E <comp_end>]\n"                \
119         "                 [--stripe-count|-c <stripe_count>]\n"         \
120         "                 [--stripe-index|-i <start_ost_idx>]\n"        \
121         "                 [--stripe-size|-S <stripe_size>]\n"           \
122         "                 [--pool|-p <pool_name>]\n"                    \
123         "                 [--ost|-o <ost_indices>]\n"
124
125 #define SSM_HELP_COMMON \
126         "\tstripe_count: Number of OSTs to stripe over (0=fs default, -1 all)\n" \
127         "\tstart_ost_idx: OST index of first stripe (-1=default round robin)\n"\
128         "\tstripe_size:  Number of bytes on each OST (0=fs default)\n" \
129         "\t              Can be specified with K, M or G (for KB, MB, GB\n" \
130         "\t              respectively)\n"                               \
131         "\tpool_name:    Name of OST pool to use (default none)\n"      \
132         "\tost_indices:  List of OST indices, can be repeated multiple times\n"\
133         "\t              Indices be specified in a format of:\n"        \
134         "\t                -o <ost_1>,<ost_i>-<ost_j>,<ost_n>\n"        \
135         "\t              Or:\n"                                         \
136         "\t                -o <ost_1> -o <ost_i>-<ost_j> -o <ost_n>\n"  \
137         "\t              If --pool is set with --ost, then the OSTs\n"  \
138         "\t              must be the members of the pool.\n"            \
139         "\tcomp_end:     Extent end of component, start after previous end.\n"\
140         "\t              Can be specified with K, M or G (for KB, MB, GB\n" \
141         "\t              respectively, -1 for EOF). Must be a multiple of\n"\
142         "\t              stripe_size.\n"
143
144
145 #define MIGRATE_USAGE                                                   \
146         SSM_CMD_COMMON("migrate  ")                                     \
147         "                 [--block|-b]\n"                               \
148         "                 [--non-block|-n]\n"                           \
149         "                 <filename>\n"                                 \
150         SSM_HELP_COMMON                                                 \
151         "\n"                                                            \
152         "\tblock:        Block file access during data migration (default)\n" \
153         "\tnon-block:    Abort migrations if concurrent access is detected\n" \
154
155 #define SETDIRSTRIPE_USAGE                                      \
156         "               [--mdt-count|-c stripe_count>\n"        \
157         "               [--mdt-index|-i mdt_index]\n"           \
158         "               [--mdt-hash|-H mdt_hash]\n"             \
159         "               [--default|-D] [--mode|-m mode] <dir>\n"        \
160         "\tstripe_count: stripe count of the striped directory\n"       \
161         "\tmdt_index: MDT index of first stripe\n"                      \
162         "\tmdt_hash:  hash type of the striped directory. mdt types:\n" \
163         "       fnv_1a_64 FNV-1a hash algorithm (default)\n"            \
164         "       all_char  sum of characters % MDT_COUNT (not recommended)\n" \
165         "\tdefault_stripe: set default dirstripe of the directory\n"    \
166         "\tmode: the mode of the directory\n"
167
168 static bool              file_lease_supported = true;
169
170 /* all available commands */
171 command_t cmdlist[] = {
172         {"setstripe", lfs_setstripe, 0,
173          "To create a file with specified striping/composite layout, or\n"
174          "create/replace the default layout on an existing directory:\n"
175          SSM_CMD_COMMON("setstripe")
176          "                 <directory|filename>\n"
177          " or\n"
178          "To add component(s) to an existing composite file:\n"
179          SSM_CMD_COMMON("setstripe --component-add")
180          SSM_HELP_COMMON
181          "To totally delete the default striping from an existing directory:\n"
182          "usage: setstripe -d <directory>\n"
183          " or\n"
184          "To delete the last component(s) from an existing composite file\n"
185          "(note that this will also delete any data in those components):\n"
186          "usage: setstripe --component-del [--component-id|-I <comp_id>]\n"
187          "                               [--component-flags|-F <comp_flags>]\n"
188          "                               <filename>\n"
189          "\tcomp_id:     Unique component ID to delete\n"
190          "\tcomp_flags:  'init' indicating all instantiated components\n"
191          "\t             '^init' indicating all uninstantiated components\n"
192          "\t-I and -F cannot be specified at the same time\n"},
193         {"getstripe", lfs_getstripe, 0,
194          "To list the striping info for a given file or files in a\n"
195          "directory or recursively for all files in a directory tree.\n"
196          "usage: getstripe [--ost|-O <uuid>] [--quiet|-q] [--verbose|-v]\n"
197          "                 [--stripe-count|-c] [--stripe-index|-i]\n"
198          "                 [--pool|-p] [--stripe-size|-S] [--directory|-d]\n"
199          "                 [--mdt|-m] [--recursive|-r] [--raw|-R] [--yaml|-y]\n"
200          "                 [--layout|-L] [--fid|-F] [--generation|-g]\n"
201          "                 [--component-id[=comp_id]|-I[comp_id]]\n"
202          "                 [--component-flags[=comp_flags]]\n"
203          "                 [--component-count]\n"
204          "                 [--component-start[=[+-]comp_start]]\n"
205          "                 [--component-end[=[+-]comp_end]|-E[[+-]comp_end]]\n"
206          "                 <directory|filename> ..."},
207         {"setdirstripe", lfs_setdirstripe, 0,
208          "To create a striped directory on a specified MDT. This can only\n"
209          "be done on MDT0 with the right of administrator.\n"
210          "usage: setdirstripe [OPTION] <directory>\n"
211          SETDIRSTRIPE_USAGE},
212         {"getdirstripe", lfs_getdirstripe, 0,
213          "To list the striping info for a given directory\n"
214          "or recursively for all directories in a directory tree.\n"
215          "usage: getdirstripe [--obd|-O <uuid>] [--mdt-count|-c]\n"
216          "                    [--mdt-index|-i] [--mdt-hash|-t]\n"
217          "                    [--recursive|-r] [--yaml|-y]\n"
218          "                    [--default|-D] <dir> ..."},
219         {"mkdir", lfs_setdirstripe, 0,
220          "To create a striped directory on a specified MDT. This can only\n"
221          "be done on MDT0 with the right of administrator.\n"
222          "usage: mkdir [OPTION] <directory>\n"
223          SETDIRSTRIPE_USAGE},
224         {"rm_entry", lfs_rmentry, 0,
225          "To remove the name entry of the remote directory. Note: This\n"
226          "command will only delete the name entry, i.e. the remote directory\n"
227          "will become inaccessable after this command. This can only be done\n"
228          "by the administrator\n"
229          "usage: rm_entry <dir>\n"},
230         {"pool_list", lfs_poollist, 0,
231          "List pools or pool OSTs\n"
232          "usage: pool_list <fsname>[.<pool>] | <pathname>\n"},
233         {"find", lfs_find, 0,
234          "find files matching given attributes recursively in directory tree.\n"
235          "usage: find <directory|filename> ...\n"
236          "     [[!] --atime|-A [+-]N] [[!] --ctime|-C [+-]N]\n"
237          "     [[!] --mtime|-M [+-]N] [[!] --mdt|-m <uuid|index,...>]\n"
238          "     [--maxdepth|-D N] [[!] --name|-n <pattern>]\n"
239          "     [[!] --ost|-O <uuid|index,...>] [--print|-p] [--print0|-P]\n"
240          "     [[!] --size|-s [+-]N[bkMGTPE]]\n"
241          "     [[!] --stripe-count|-c [+-]<stripes>]\n"
242          "     [[!] --stripe-index|-i <index,...>]\n"
243          "     [[!] --stripe-size|-S [+-]N[kMGT]] [[!] --type|-t <filetype>]\n"
244          "     [[!] --gid|-g|--group|-G <gid>|<gname>]\n"
245          "     [[!] --uid|-u|--user|-U <uid>|<uname>] [[!] --pool <pool>]\n"
246          "     [[!] --projid <projid>]\n"
247          "     [[!] --layout|-L released,raid0]\n"
248          "     [[!] --component-count [+-]<comp_cnt>]\n"
249          "     [[!] --component-start [+-]N[kMGTPE]]\n"
250          "     [[!] --component-end|-E [+-]N[kMGTPE]]\n"
251          "     [[!] --component-flags <comp_flags>]\n"
252          "     [[!] --mdt-count|-T [+-]<stripes>]\n"
253          "     [[!] --mdt-hash|-H <hashtype>\n"
254          "\t !: used before an option indicates 'NOT' requested attribute\n"
255          "\t -: used before a value indicates less than requested value\n"
256          "\t +: used before a value indicates more than requested value\n"
257          "\tmdt-hash:   hash type of the striped directory.\n"
258          "\t            fnv_1a_64 FNV-1a hash algorithm\n"
259          "\t            all_char  sum of characters % MDT_COUNT\n"},
260         {"check", lfs_check, 0,
261          "Display the status of MDS or OSTs (as specified in the command)\n"
262          "or all the servers (MDS and OSTs).\n"
263          "usage: check <osts|mds|servers>"},
264         {"osts", lfs_osts, 0, "list OSTs connected to client "
265          "[for specified path only]\n" "usage: osts [path]"},
266         {"mdts", lfs_mdts, 0, "list MDTs connected to client "
267          "[for specified path only]\n" "usage: mdts [path]"},
268         {"df", lfs_df, 0,
269          "report filesystem disk space usage or inodes usage"
270          "of each MDS and all OSDs or a batch belonging to a specific pool .\n"
271          "Usage: df [-i] [-h] [--lazy|-l] [--pool|-p <fsname>[.<pool>] [path]"},
272         {"getname", lfs_getname, 0, "list instances and specified mount points "
273          "[for specified path only]\n"
274          "Usage: getname [-h]|[path ...] "},
275 #ifdef HAVE_SYS_QUOTA_H
276         {"setquota", lfs_setquota, 0, "Set filesystem quotas.\n"
277          "usage: setquota <-u|-g|-p> <uname>|<uid>|<gname>|<gid>|<projid>\n"
278          "                -b <block-softlimit> -B <block-hardlimit>\n"
279          "                -i <inode-softlimit> -I <inode-hardlimit> <filesystem>\n"
280          "       setquota <-u|--user|-g|--group|-p|--projid> <uname>|<uid>|<gname>|<gid>|<projid>\n"
281          "                [--block-softlimit <block-softlimit>]\n"
282          "                [--block-hardlimit <block-hardlimit>]\n"
283          "                [--inode-softlimit <inode-softlimit>]\n"
284          "                [--inode-hardlimit <inode-hardlimit>] <filesystem>\n"
285          "       setquota [-t] <-u|--user|-g|--group|-p|--projid>\n"
286          "                [--block-grace <block-grace>]\n"
287          "                [--inode-grace <inode-grace>] <filesystem>\n"
288          "       -b can be used instead of --block-softlimit/--block-grace\n"
289          "       -B can be used instead of --block-hardlimit\n"
290          "       -i can be used instead of --inode-softlimit/--inode-grace\n"
291          "       -I can be used instead of --inode-hardlimit\n\n"
292          "Note: The total quota space will be split into many qunits and\n"
293          "      balanced over all server targets, the minimal qunit size is\n"
294          "      1M bytes for block space and 1K inodes for inode space.\n\n"
295          "      Quota space rebalancing process will stop when this mininum\n"
296          "      value is reached. As a result, quota exceeded can be returned\n"
297          "      while many targets still have 1MB or 1K inodes of spare\n"
298          "      quota space."},
299         {"quota", lfs_quota, 0, "Display disk usage and limits.\n"
300          "usage: quota [-q] [-v] [-h] [-o <obd_uuid>|-i <mdt_idx>|-I "
301                        "<ost_idx>]\n"
302          "             [<-u|-g|-p> <uname>|<uid>|<gname>|<gid>|<projid>] <filesystem>\n"
303          "       quota [-o <obd_uuid>|-i <mdt_idx>|-I <ost_idx>] -t <-u|-g|-p> <filesystem>"},
304         {"project", lfs_project, 0,
305          "Change or list project attribute for specified file or directory.\n"
306          "usage: project [-d|-r] <file|directory...>\n"
307          "         list project ID and flags on file(s) or directories\n"
308          "       project [-p id] [-s] [-r] <file|directory...>\n"
309          "         set project ID and/or inherit flag for specified file(s) or directories\n"
310          "       project -c [-d|-r [-p id] [-0]] <file|directory...>\n"
311          "         check project ID and flags on file(s) or directories, print outliers\n"
312          "       project -C [-r] [-k] <file|directory...>\n"
313          "         clear the project inherit flag and ID on the file or directory\n"
314         },
315 #endif
316         {"flushctx", lfs_flushctx, 0, "Flush security context for current user.\n"
317          "usage: flushctx [-k] [mountpoint...]"},
318         {"cp", lfs_cp, 0,
319          "Remote user copy files and directories.\n"
320          "usage: cp [OPTION]... [-T] SOURCE DEST\n\tcp [OPTION]... SOURCE... DIRECTORY\n\tcp [OPTION]... -t DIRECTORY SOURCE..."},
321         {"ls", lfs_ls, 0,
322          "Remote user list directory contents.\n"
323          "usage: ls [OPTION]... [FILE]..."},
324         {"changelog", lfs_changelog, 0,
325          "Show the metadata changes on an MDT."
326          "\nusage: changelog <mdtname> [startrec [endrec]]"},
327         {"changelog_clear", lfs_changelog_clear, 0,
328          "Indicate that old changelog records up to <endrec> are no longer of "
329          "interest to consumer <id>, allowing the system to free up space.\n"
330          "An <endrec> of 0 means all records.\n"
331          "usage: changelog_clear <mdtname> <id> <endrec>"},
332         {"fid2path", lfs_fid2path, 0,
333          "Resolve the full path(s) for given FID(s). For a specific hardlink "
334          "specify link number <linkno>.\n"
335         /* "For a historical link name, specify changelog record <recno>.\n" */
336          "usage: fid2path [--link <linkno>] <fsname|rootpath> <fid> ..."
337                 /* [ --rec <recno> ] */ },
338         {"path2fid", lfs_path2fid, 0, "Display the fid(s) for a given path(s).\n"
339          "usage: path2fid [--parents] <path> ..."},
340         {"data_version", lfs_data_version, 0, "Display file data version for "
341          "a given path.\n" "usage: data_version -[n|r|w] <path>"},
342         {"hsm_state", lfs_hsm_state, 0, "Display the HSM information (states, "
343          "undergoing actions) for given files.\n usage: hsm_state <file> ..."},
344         {"hsm_set", lfs_hsm_set, 0, "Set HSM user flag on specified files.\n"
345          "usage: hsm_set [--norelease] [--noarchive] [--dirty] [--exists] "
346          "[--archived] [--lost] [--archive-id NUM] <file> ..."},
347         {"hsm_clear", lfs_hsm_clear, 0, "Clear HSM user flag on specified "
348          "files.\n"
349          "usage: hsm_clear [--norelease] [--noarchive] [--dirty] [--exists] "
350          "[--archived] [--lost] <file> ..."},
351         {"hsm_action", lfs_hsm_action, 0, "Display current HSM request for "
352          "given files.\n" "usage: hsm_action <file> ..."},
353         {"hsm_archive", lfs_hsm_archive, 0,
354          "Archive file to external storage.\n"
355          "usage: hsm_archive [--filelist FILELIST] [--data DATA] [--archive NUM] "
356          "<file> ..."},
357         {"hsm_restore", lfs_hsm_restore, 0,
358          "Restore file from external storage.\n"
359          "usage: hsm_restore [--filelist FILELIST] [--data DATA] <file> ..."},
360         {"hsm_release", lfs_hsm_release, 0,
361          "Release files from Lustre.\n"
362          "usage: hsm_release [--filelist FILELIST] [--data DATA] <file> ..."},
363         {"hsm_remove", lfs_hsm_remove, 0,
364          "Remove file copy from external storage.\n"
365          "usage: hsm_remove [--filelist FILELIST] [--data DATA]\n"
366          "                  [--mntpath MOUNTPATH] [--archive NUM] <file|FID> ...\n"
367          "\n"
368          "Note: To remove files from the archive that have been deleted on\n"
369          "Lustre, set mntpath and optionally archive. In that case, all the\n"
370          "positional arguments and entries in the file list must be FIDs."
371         },
372         {"hsm_cancel", lfs_hsm_cancel, 0,
373          "Cancel requests related to specified files.\n"
374          "usage: hsm_cancel [--filelist FILELIST] [--data DATA] <file> ..."},
375         {"swap_layouts", lfs_swap_layouts, 0, "Swap layouts between 2 files.\n"
376          "usage: swap_layouts <path1> <path2>"},
377         {"migrate", lfs_setstripe, 0,
378          "migrate a directory between MDTs.\n"
379          "usage: migrate --mdt-index <mdt_idx> [--verbose|-v] "
380          "<directory>\n"
381          "\tmdt_idx:      index of the destination MDT\n"
382          "\n"
383          "migrate file objects from one OST "
384          "layout\nto another (may be not safe with concurent writes).\n"
385          "usage: migrate  "
386          "[--stripe-count|-c] <stripe_count>\n"
387          "              [--stripe-index|-i] <start_ost_index>\n"
388          "              [--stripe-size|-S] <stripe_size>\n"
389          "              [--pool|-p] <pool_name>\n"
390          "              [--ost-list|-o] <ost_indices>\n"
391          "              [--block|-b]\n"
392          "              [--non-block|-n]\n"
393          "              <file|directory>\n"
394          "\tstripe_count:     number of OSTs to stripe a file over\n"
395          "\tstripe_ost_index: index of the first OST to stripe a file over\n"
396          "\tstripe_size:      number of bytes to store before moving to the next OST\n"
397          "\tpool_name:        name of the predefined pool of OSTs\n"
398          "\tost_indices:      OSTs to stripe over, in order\n"
399          "\tblock:            wait for the operation to return before continuing\n"
400          "\tnon-block:        do not wait for the operation to return.\n"},
401         {"mv", lfs_mv, 0,
402          "To move directories between MDTs. This command is deprecated, "
403          "use \"migrate\" instead.\n"
404          "usage: mv <directory|filename> [--mdt-index|-M] <mdt_index> "
405          "[--verbose|-v]\n"},
406         {"ladvise", lfs_ladvise, 0,
407          "Provide servers with advice about access patterns for a file.\n"
408          "usage: ladvise [--advice|-a ADVICE] [--start|-s START[kMGT]]\n"
409          "               [--background|-b]\n"
410          "               {[--end|-e END[kMGT]] | [--length|-l LENGTH[kMGT]]}\n"
411          "               <file> ...\n"},
412         {"help", Parser_help, 0, "help"},
413         {"exit", Parser_quit, 0, "quit"},
414         {"quit", Parser_quit, 0, "quit"},
415         {"--version", Parser_version, 0,
416          "output build version of the utility and exit"},
417         {"--list-commands", lfs_list_commands, 0,
418          "list commands supported by the utility and exit"},
419         { 0, 0, 0, NULL }
420 };
421
422
423 #define MIGRATION_NONBLOCK      1
424
425 static int check_hashtype(const char *hashtype)
426 {
427         int i;
428
429         for (i = LMV_HASH_TYPE_ALL_CHARS; i < LMV_HASH_TYPE_MAX; i++)
430                 if (strcmp(hashtype, mdt_hash_name[i]) == 0)
431                         return i;
432
433         return 0;
434 }
435
436 /**
437  * Internal helper for migrate_copy_data(). Check lease and report error if
438  * need be.
439  *
440  * \param[in]  fd           File descriptor on which to check the lease.
441  * \param[out] lease_broken Set to true if the lease was broken.
442  * \param[in]  group_locked Whether a group lock was taken or not.
443  * \param[in]  path         Name of the file being processed, for error
444  *                          reporting
445  *
446  * \retval 0       Migration can keep on going.
447  * \retval -errno  Error occurred, abort migration.
448  */
449 static int check_lease(int fd, bool *lease_broken, bool group_locked,
450                        const char *path)
451 {
452         int rc;
453
454         if (!file_lease_supported)
455                 return 0;
456
457         rc = llapi_lease_check(fd);
458         if (rc > 0)
459                 return 0; /* llapi_check_lease returns > 0 on success. */
460
461         if (!group_locked) {
462                 fprintf(stderr, "%s: cannot migrate '%s': file busy\n",
463                         progname, path);
464                 rc = rc ? rc : -EAGAIN;
465         } else {
466                 fprintf(stderr, "%s: external attempt to access file '%s' "
467                         "blocked until migration ends.\n", progname, path);
468                 rc = 0;
469         }
470         *lease_broken = true;
471         return rc;
472 }
473
474 static int migrate_copy_data(int fd_src, int fd_dst, size_t buf_size,
475                              bool group_locked, const char *fname)
476 {
477         void    *buf = NULL;
478         ssize_t  rsize = -1;
479         ssize_t  wsize = 0;
480         size_t   rpos = 0;
481         size_t   wpos = 0;
482         off_t    bufoff = 0;
483         int      rc;
484         bool     lease_broken = false;
485
486         /* Use a page-aligned buffer for direct I/O */
487         rc = posix_memalign(&buf, getpagesize(), buf_size);
488         if (rc != 0)
489                 return -rc;
490
491         while (1) {
492                 /* read new data only if we have written all
493                  * previously read data */
494                 if (wpos == rpos) {
495                         if (!lease_broken) {
496                                 rc = check_lease(fd_src, &lease_broken,
497                                                  group_locked, fname);
498                                 if (rc < 0)
499                                         goto out;
500                         }
501                         rsize = read(fd_src, buf, buf_size);
502                         if (rsize < 0) {
503                                 rc = -errno;
504                                 fprintf(stderr, "%s: %s: read failed: %s\n",
505                                         progname, fname, strerror(-rc));
506                                 goto out;
507                         }
508                         rpos += rsize;
509                         bufoff = 0;
510                 }
511                 /* eof ? */
512                 if (rsize == 0)
513                         break;
514
515                 wsize = write(fd_dst, buf + bufoff, rpos - wpos);
516                 if (wsize < 0) {
517                         rc = -errno;
518                         fprintf(stderr,
519                                 "%s: %s: write failed on volatile: %s\n",
520                                 progname, fname, strerror(-rc));
521                         goto out;
522                 }
523                 wpos += wsize;
524                 bufoff += wsize;
525         }
526
527         rc = fsync(fd_dst);
528         if (rc < 0) {
529                 rc = -errno;
530                 fprintf(stderr, "%s: %s: fsync failed: %s\n",
531                         progname, fname, strerror(-rc));
532         }
533
534 out:
535         free(buf);
536         return rc;
537 }
538
539 static int migrate_copy_timestamps(int fdv, const struct stat *st)
540 {
541         struct timeval  tv[2] = {
542                 {.tv_sec = st->st_atime},
543                 {.tv_sec = st->st_mtime}
544         };
545
546         return futimes(fdv, tv);
547 }
548
549 static int migrate_block(int fd, int fdv, const struct stat *st,
550                          size_t buf_size, const char *name)
551 {
552         __u64   dv1;
553         int     gid;
554         int     rc;
555         int     rc2;
556
557         rc = llapi_get_data_version(fd, &dv1, LL_DV_RD_FLUSH);
558         if (rc < 0) {
559                 fprintf(stderr, "%s: %s: cannot get dataversion: %s\n",
560                         progname, name, strerror(-rc));
561                 return rc;
562         }
563
564         do
565                 gid = random();
566         while (gid == 0);
567
568         /* The grouplock blocks all concurrent accesses to the file.
569          * It has to be taken after llapi_get_data_version as it would
570          * block it too. */
571         rc = llapi_group_lock(fd, gid);
572         if (rc < 0) {
573                 fprintf(stderr, "%s: %s: cannot get group lock: %s\n",
574                         progname, name, strerror(-rc));
575                 return rc;
576         }
577
578         rc = migrate_copy_data(fd, fdv, buf_size, true, name);
579         if (rc < 0) {
580                 fprintf(stderr, "%s: %s: data copy failed\n", progname, name);
581                 goto out_unlock;
582         }
583
584         /* Make sure we keep original atime/mtime values */
585         rc = migrate_copy_timestamps(fdv, st);
586         if (rc < 0) {
587                 fprintf(stderr, "%s: %s: timestamp copy failed\n",
588                         progname, name);
589                 goto out_unlock;
590         }
591
592         /* swap layouts
593          * for a migration we need to check data version on file did
594          * not change.
595          *
596          * Pass in gid=0 since we already own grouplock. */
597         rc = llapi_fswap_layouts_grouplock(fd, fdv, dv1, 0, 0,
598                                            SWAP_LAYOUTS_CHECK_DV1);
599         if (rc == -EAGAIN) {
600                 fprintf(stderr, "%s: %s: dataversion changed during copy, "
601                         "migration aborted\n", progname, name);
602                 goto out_unlock;
603         } else if (rc < 0) {
604                 fprintf(stderr, "%s: %s: cannot swap layouts: %s\n", progname,
605                         name, strerror(-rc));
606                 goto out_unlock;
607         }
608
609 out_unlock:
610         rc2 = llapi_group_unlock(fd, gid);
611         if (rc2 < 0 && rc == 0) {
612                 fprintf(stderr, "%s: %s: putting group lock failed: %s\n",
613                         progname, name, strerror(-rc2));
614                 rc = rc2;
615         }
616
617         return rc;
618 }
619
620 static int migrate_nonblock(int fd, int fdv, const struct stat *st,
621                             size_t buf_size, const char *name)
622 {
623         __u64   dv1;
624         __u64   dv2;
625         int     rc;
626
627         rc = llapi_get_data_version(fd, &dv1, LL_DV_RD_FLUSH);
628         if (rc < 0) {
629                 fprintf(stderr, "%s: %s: cannot get data version: %s\n",
630                         progname, name, strerror(-rc));
631                 return rc;
632         }
633
634         rc = migrate_copy_data(fd, fdv, buf_size, false, name);
635         if (rc < 0) {
636                 fprintf(stderr, "%s: %s: data copy failed\n", progname, name);
637                 return rc;
638         }
639
640         rc = llapi_get_data_version(fd, &dv2, LL_DV_RD_FLUSH);
641         if (rc != 0) {
642                 fprintf(stderr, "%s: %s: cannot get data version: %s\n",
643                         progname, name, strerror(-rc));
644                 return rc;
645         }
646
647         if (dv1 != dv2) {
648                 rc = -EAGAIN;
649                 fprintf(stderr, "%s: %s: data version changed during "
650                                 "migration\n",
651                         progname, name);
652                 return rc;
653         }
654
655         /* Make sure we keep original atime/mtime values */
656         rc = migrate_copy_timestamps(fdv, st);
657         if (rc < 0) {
658                 fprintf(stderr, "%s: %s: timestamp copy failed\n",
659                         progname, name);
660                 return rc;
661         }
662
663         /* Atomically put lease, swap layouts and close.
664          * for a migration we need to check data version on file did
665          * not change. */
666         rc = llapi_fswap_layouts(fd, fdv, 0, 0, SWAP_LAYOUTS_CLOSE);
667         if (rc < 0) {
668                 fprintf(stderr, "%s: %s: cannot swap layouts: %s\n",
669                         progname, name, strerror(-rc));
670                 return rc;
671         }
672
673         return 0;
674 }
675
676 static int lfs_component_set(char *fname, int comp_id, __u32 flags)
677 {
678         return -ENOTSUP;
679 }
680
681 static int lfs_component_del(char *fname, __u32 comp_id, __u32 flags)
682 {
683         int     rc = 0;
684
685         if (flags != 0 && comp_id != 0)
686                 return -EINVAL;
687
688         /* LCME_FL_INIT is the only supported flag in PFL */
689         if (flags != 0) {
690                 if (flags & ~LCME_KNOWN_FLAGS) {
691                         fprintf(stderr, "Invalid component flags %#x\n", flags);
692                         return -EINVAL;
693                 }
694         } else if (comp_id > LCME_ID_MAX) {
695                 fprintf(stderr, "Invalid component id %u\n", comp_id);
696                 return -EINVAL;
697         }
698
699         rc = llapi_layout_file_comp_del(fname, comp_id, flags);
700         if (rc)
701                 fprintf(stderr, "Delete component %#x from %s failed. %s\n",
702                         comp_id, fname, strerror(errno));
703         return rc;
704 }
705
706 static int lfs_component_add(char *fname, struct llapi_layout *layout)
707 {
708         int     rc;
709
710         if (layout == NULL)
711                 return -EINVAL;
712
713         rc = llapi_layout_file_comp_add(fname, layout);
714         if (rc)
715                 fprintf(stderr, "Add layout component(s) to %s failed. %s\n",
716                         fname, strerror(errno));
717         return rc;
718 }
719
720 static int lfs_component_create(char *fname, int open_flags, mode_t open_mode,
721                                 struct llapi_layout *layout)
722 {
723         struct stat     st;
724         int     fd;
725
726         if (layout == NULL)
727                 return -EINVAL;
728
729         fd = lstat(fname, &st);
730         if (fd == 0 && S_ISDIR(st.st_mode))
731                 open_flags = O_DIRECTORY | O_RDONLY;
732
733         fd = llapi_layout_file_open(fname, open_flags, open_mode, layout);
734         if (fd < 0)
735                 fprintf(stderr, "%s %s failed. %s\n",
736                         S_ISDIR(st.st_mode) ?
737                                 "Set default composite layout to " :
738                                 "Create composite file",
739                         fname, strerror(errno));
740         return fd;
741 }
742
743 static int lfs_migrate(char *name, __u64 migration_flags,
744                        struct llapi_stripe_param *param,
745                        struct llapi_layout *layout)
746 {
747         int                      fd = -1;
748         int                      fdv = -1;
749         char                     parent[PATH_MAX];
750         int                      mdt_index;
751         int                      random_value;
752         char                     volatile_file[sizeof(parent) +
753                                                LUSTRE_VOLATILE_HDR_LEN +
754                                                2 * sizeof(mdt_index) +
755                                                2 * sizeof(random_value) + 4];
756         char                    *ptr;
757         int                      rc;
758         struct lov_user_md      *lum = NULL;
759         int                      lum_size;
760         int                      buf_size = 1024 * 1024 * 4;
761         bool                     have_lease_rdlck = false;
762         struct stat              st;
763         struct stat              stv;
764
765         /* find the right size for the IO and allocate the buffer */
766         lum_size = lov_user_md_size(LOV_MAX_STRIPE_COUNT, LOV_USER_MAGIC_V3);
767         lum = malloc(lum_size);
768         if (lum == NULL) {
769                 rc = -ENOMEM;
770                 goto free;
771         }
772
773         rc = llapi_file_get_stripe(name, lum);
774         /* failure can happen for many reasons and some may be not real errors
775          * (eg: no stripe)
776          * in case of a real error, a later call will fail with better
777          * error management */
778         if (rc == 0) {
779                 if ((lum->lmm_magic == LOV_USER_MAGIC_V1 ||
780                      lum->lmm_magic == LOV_USER_MAGIC_V3) &&
781                     lum->lmm_stripe_size != 0)
782                         buf_size = lum->lmm_stripe_size;
783         }
784
785         /* open file, direct io */
786         /* even if the file is only read, WR mode is nedeed to allow
787          * layout swap on fd */
788         fd = open(name, O_RDWR | O_DIRECT);
789         if (fd == -1) {
790                 rc = -errno;
791                 fprintf(stderr, "%s: %s: cannot open: %s\n", progname, name,
792                         strerror(-rc));
793                 goto free;
794         }
795
796         if (file_lease_supported) {
797                 rc = llapi_lease_get(fd, LL_LEASE_RDLCK);
798                 if (rc == -EOPNOTSUPP) {
799                         /* Older servers do not support file lease.
800                          * Disable related checks. This opens race conditions
801                          * as explained in LU-4840 */
802                         file_lease_supported = false;
803                 } else if (rc < 0) {
804                         fprintf(stderr, "%s: %s: cannot get open lease: %s\n",
805                                 progname, name, strerror(-rc));
806                         goto error;
807                 } else {
808                         have_lease_rdlck = true;
809                 }
810         }
811
812         /* search for file directory pathname */
813         if (strlen(name) > sizeof(parent)-1) {
814                 rc = -E2BIG;
815                 goto error;
816         }
817         strncpy(parent, name, sizeof(parent));
818         ptr = strrchr(parent, '/');
819         if (ptr == NULL) {
820                 if (getcwd(parent, sizeof(parent)) == NULL) {
821                         rc = -errno;
822                         goto error;
823                 }
824         } else {
825                 if (ptr == parent)
826                         strcpy(parent, "/");
827                 else
828                         *ptr = '\0';
829         }
830
831         rc = llapi_file_fget_mdtidx(fd, &mdt_index);
832         if (rc < 0) {
833                 fprintf(stderr, "%s: %s: cannot get MDT index: %s\n",
834                         progname, name, strerror(-rc));
835                 goto error;
836         }
837
838         do {
839                 int open_flags = O_WRONLY | O_CREAT | O_EXCL | O_NOFOLLOW;
840                 mode_t open_mode = S_IRUSR | S_IWUSR;
841
842                 random_value = random();
843                 rc = snprintf(volatile_file, sizeof(volatile_file),
844                               "%s/%s:%.4X:%.4X", parent, LUSTRE_VOLATILE_HDR,
845                               mdt_index, random_value);
846                 if (rc >= sizeof(volatile_file)) {
847                         rc = -E2BIG;
848                         goto error;
849                 }
850
851                 /* create, open a volatile file, use caching (ie no directio) */
852                 if (param != NULL)
853                         fdv = llapi_file_open_param(volatile_file, open_flags,
854                                                     open_mode, param);
855                 else if (layout != NULL)
856                         fdv = lfs_component_create(volatile_file, open_flags,
857                                                    open_mode, layout);
858                 else
859                         fdv = -EINVAL;
860         } while (fdv == -EEXIST);
861
862         if (fdv < 0) {
863                 rc = fdv;
864                 fprintf(stderr, "%s: %s: cannot create volatile file in"
865                                 " directory: %s\n",
866                         progname, parent, strerror(-rc));
867                 goto error;
868         }
869
870         /* In case the MDT does not support creation of volatile files
871          * we should try to unlink it. */
872         (void)unlink(volatile_file);
873
874         /* Not-owner (root?) special case.
875          * Need to set owner/group of volatile file like original.
876          * This will allow to pass related check during layout_swap.
877          */
878         rc = fstat(fd, &st);
879         if (rc != 0) {
880                 rc = -errno;
881                 fprintf(stderr, "%s: %s: cannot stat: %s\n", progname, name,
882                         strerror(errno));
883                 goto error;
884         }
885         rc = fstat(fdv, &stv);
886         if (rc != 0) {
887                 rc = -errno;
888                 fprintf(stderr, "%s: %s: cannot stat: %s\n", progname,
889                         volatile_file, strerror(errno));
890                 goto error;
891         }
892         if (st.st_uid != stv.st_uid || st.st_gid != stv.st_gid) {
893                 rc = fchown(fdv, st.st_uid, st.st_gid);
894                 if (rc != 0) {
895                         rc = -errno;
896                         fprintf(stderr, "%s: %s: cannot chown: %s\n", progname,
897                                 name, strerror(errno));
898                         goto error;
899                 }
900         }
901
902         if (migration_flags & MIGRATION_NONBLOCK && file_lease_supported) {
903                 rc = migrate_nonblock(fd, fdv, &st, buf_size, name);
904                 if (rc == 0) {
905                         have_lease_rdlck = false;
906                         fdv = -1; /* The volatile file is closed as we put the
907                                    * lease in non-blocking mode. */
908                 }
909         } else {
910                 /* Blocking mode (forced if servers do not support file lease).
911                  * It is also the default mode, since we cannot distinguish
912                  * between a broken lease and a server that does not support
913                  * atomic swap/close (LU-6785) */
914                 rc = migrate_block(fd, fdv, &st, buf_size, name);
915         }
916
917 error:
918         if (have_lease_rdlck)
919                 llapi_lease_put(fd);
920
921         if (fd >= 0)
922                 close(fd);
923
924         if (fdv >= 0)
925                 close(fdv);
926
927 free:
928         if (lum)
929                 free(lum);
930
931         return rc;
932 }
933
934 /**
935  * Parse a string containing an OST index list into an array of integers.
936  *
937  * The input string contains a comma delimited list of individual
938  * indices and ranges, for example "1,2-4,7". Add the indices into the
939  * \a osts array and remove duplicates.
940  *
941  * \param[out] osts    array to store indices in
942  * \param[in] size     size of \a osts array
943  * \param[in] offset   starting index in \a osts
944  * \param[in] arg      string containing OST index list
945  *
946  * \retval positive    number of indices in \a osts
947  * \retval -EINVAL     unable to parse \a arg
948  */
949 static int parse_targets(__u32 *osts, int size, int offset, char *arg)
950 {
951         int rc;
952         int nr = offset;
953         int slots = size - offset;
954         char *ptr = NULL;
955         bool end_of_loop;
956
957         if (arg == NULL)
958                 return -EINVAL;
959
960         end_of_loop = false;
961         while (!end_of_loop) {
962                 int start_index;
963                 int end_index;
964                 int i;
965                 char *endptr = NULL;
966
967                 rc = -EINVAL;
968
969                 ptr = strchrnul(arg, ',');
970
971                 end_of_loop = *ptr == '\0';
972                 *ptr = '\0';
973
974                 start_index = strtol(arg, &endptr, 0);
975                 if (endptr == arg) /* no data at all */
976                         break;
977                 if (*endptr != '-' && *endptr != '\0') /* has invalid data */
978                         break;
979                 if (start_index < 0)
980                         break;
981
982                 end_index = start_index;
983                 if (*endptr == '-') {
984                         end_index = strtol(endptr + 1, &endptr, 0);
985                         if (*endptr != '\0')
986                                 break;
987                         if (end_index < start_index)
988                                 break;
989                 }
990
991                 for (i = start_index; i <= end_index && slots > 0; i++) {
992                         int j;
993
994                         /* remove duplicate */
995                         for (j = 0; j < offset; j++) {
996                                 if (osts[j] == i)
997                                         break;
998                         }
999                         if (j == offset) { /* no duplicate */
1000                                 osts[nr++] = i;
1001                                 --slots;
1002                         }
1003                 }
1004                 if (slots == 0 && i < end_index)
1005                         break;
1006
1007                 *ptr = ',';
1008                 arg = ++ptr;
1009                 offset = nr;
1010                 rc = 0;
1011         }
1012         if (!end_of_loop && ptr != NULL)
1013                 *ptr = ',';
1014
1015         return rc < 0 ? rc : nr;
1016 }
1017
1018 struct lfs_setstripe_args {
1019         unsigned long long       lsa_comp_end;
1020         unsigned long long       lsa_stripe_size;
1021         int                      lsa_stripe_count;
1022         int                      lsa_stripe_off;
1023         __u32                    lsa_comp_flags;
1024         int                      lsa_nr_osts;
1025         __u32                   *lsa_osts;
1026         char                    *lsa_pool_name;
1027 };
1028
1029 static inline void setstripe_args_init(struct lfs_setstripe_args *lsa)
1030 {
1031         memset(lsa, 0, sizeof(*lsa));
1032         lsa->lsa_stripe_off = -1;
1033 }
1034
1035 static inline bool setstripe_args_specified(struct lfs_setstripe_args *lsa)
1036 {
1037         return (lsa->lsa_stripe_size != 0 || lsa->lsa_stripe_count != 0 ||
1038                 lsa->lsa_stripe_off != -1 || lsa->lsa_pool_name != NULL ||
1039                 lsa->lsa_comp_end != 0);
1040 }
1041
1042 static int comp_args_to_layout(struct llapi_layout **composite,
1043                                struct lfs_setstripe_args *lsa)
1044 {
1045         struct llapi_layout *layout = *composite;
1046         uint64_t prev_end = 0;
1047         int i = 0, rc;
1048
1049         if (layout == NULL) {
1050                 layout = llapi_layout_alloc();
1051                 if (layout == NULL) {
1052                         fprintf(stderr, "Alloc llapi_layout failed. %s\n",
1053                                 strerror(errno));
1054                         return -ENOMEM;
1055                 }
1056                 *composite = layout;
1057         } else {
1058                 uint64_t start;
1059
1060                 /* Get current component extent, current component
1061                  * must be the tail component. */
1062                 rc = llapi_layout_comp_extent_get(layout, &start, &prev_end);
1063                 if (rc) {
1064                         fprintf(stderr, "Get comp extent failed. %s\n",
1065                                 strerror(errno));
1066                         return rc;
1067                 }
1068
1069                 rc = llapi_layout_comp_add(layout);
1070                 if (rc) {
1071                         fprintf(stderr, "Add component failed. %s\n",
1072                                 strerror(errno));
1073                         return rc;
1074                 }
1075         }
1076
1077         rc = llapi_layout_comp_extent_set(layout, prev_end, lsa->lsa_comp_end);
1078         if (rc) {
1079                 fprintf(stderr, "Set extent [%lu, %llu) failed. %s\n",
1080                         prev_end, lsa->lsa_comp_end, strerror(errno));
1081                 return rc;
1082         }
1083
1084         if (lsa->lsa_stripe_size != 0) {
1085                 rc = llapi_layout_stripe_size_set(layout,
1086                                                   lsa->lsa_stripe_size);
1087                 if (rc) {
1088                         fprintf(stderr, "Set stripe size %llu failed. %s\n",
1089                                 lsa->lsa_stripe_size, strerror(errno));
1090                         return rc;
1091                 }
1092         }
1093
1094         if (lsa->lsa_stripe_count != 0) {
1095                 rc = llapi_layout_stripe_count_set(layout,
1096                                                    lsa->lsa_stripe_count == -1 ?
1097                                                    LLAPI_LAYOUT_WIDE :
1098                                                    lsa->lsa_stripe_count);
1099                 if (rc) {
1100                         fprintf(stderr, "Set stripe count %d failed. %s\n",
1101                                 lsa->lsa_stripe_count, strerror(errno));
1102                         return rc;
1103                 }
1104         }
1105
1106         if (lsa->lsa_pool_name != NULL) {
1107                 rc = llapi_layout_pool_name_set(layout, lsa->lsa_pool_name);
1108                 if (rc) {
1109                         fprintf(stderr, "Set pool name: %s failed. %s\n",
1110                                 lsa->lsa_pool_name, strerror(errno));
1111                         return rc;
1112                 }
1113         }
1114
1115         if (lsa->lsa_nr_osts > 0) {
1116                 if (lsa->lsa_stripe_count > 0 &&
1117                     lsa->lsa_nr_osts != lsa->lsa_stripe_count) {
1118                         fprintf(stderr, "stripe_count(%d) != nr_osts(%d)\n",
1119                                 lsa->lsa_stripe_count, lsa->lsa_nr_osts);
1120                         return -EINVAL;
1121                 }
1122                 for (i = 0; i < lsa->lsa_nr_osts; i++) {
1123                         rc = llapi_layout_ost_index_set(layout, i,
1124                                                         lsa->lsa_osts[i]);
1125                         if (rc)
1126                                 break;
1127                 }
1128         } else if (lsa->lsa_stripe_off != -1) {
1129                 rc = llapi_layout_ost_index_set(layout, 0, lsa->lsa_stripe_off);
1130         }
1131         if (rc) {
1132                 fprintf(stderr, "Set ost index %d failed. %s\n",
1133                         i, strerror(errno));
1134                 return rc;
1135         }
1136
1137         return 0;
1138 }
1139
1140 /* In 'lfs setstripe --component-add' mode, we need to fetch the extent
1141  * end of the last component in the existing file, and adjust the
1142  * first extent start of the components to be added accordingly. */
1143 static int adjust_first_extent(char *fname, struct llapi_layout *layout)
1144 {
1145         struct llapi_layout *head;
1146         uint64_t start, end, stripe_size, prev_end = 0;
1147         int rc;
1148
1149         if (layout == NULL)
1150                 return -EINVAL;
1151
1152         errno = 0;
1153         head = llapi_layout_get_by_path(fname, 0);
1154         if (head == NULL) {
1155                 fprintf(stderr, "Read layout from %s failed. %s\n",
1156                         fname, strerror(errno));
1157                 return -EINVAL;
1158         } else if (errno == ENODATA) {
1159                 /* file without LOVEA, this component-add will be turned
1160                  * into a component-create. */
1161                 llapi_layout_free(head);
1162                 return -ENODATA;
1163         } else {
1164                 /* Current component of 'head' should be tail of component
1165                  * list by default, but we do an extra move cursor operation
1166                  * here to test if the layout is non-composite. */
1167                 rc = llapi_layout_comp_use(head, LLAPI_LAYOUT_COMP_USE_LAST);
1168                 if (rc < 0) {
1169                         fprintf(stderr, "'%s' isn't a composite file?\n",
1170                                 fname);
1171                         llapi_layout_free(head);
1172                         return rc;
1173                 }
1174         }
1175
1176         rc = llapi_layout_comp_extent_get(head, &start, &prev_end);
1177         if (rc) {
1178                 fprintf(stderr, "Get prev extent failed. %s\n",
1179                         strerror(errno));
1180                 llapi_layout_free(head);
1181                 return rc;
1182         }
1183
1184         llapi_layout_free(head);
1185
1186         /* Make sure we use the first component of the layout to be added. */
1187         rc = llapi_layout_comp_use(layout, LLAPI_LAYOUT_COMP_USE_FIRST);
1188         if (rc < 0) {
1189                 fprintf(stderr, "Move component cursor failed. %s\n",
1190                         strerror(errno));
1191                 return rc;
1192         }
1193
1194         rc = llapi_layout_comp_extent_get(layout, &start, &end);
1195         if (rc) {
1196                 fprintf(stderr, "Get extent failed. %s\n", strerror(errno));
1197                 return rc;
1198         }
1199
1200         if (start > prev_end || end <= prev_end) {
1201                 fprintf(stderr, "First extent to be set [%lu, %lu) isn't "
1202                         "adjacent with the existing file extent end: %lu\n",
1203                         start, end, prev_end);
1204                 return -EINVAL;
1205         }
1206
1207         rc = llapi_layout_stripe_size_get(layout, &stripe_size);
1208         if (rc) {
1209                 fprintf(stderr, "Get stripe size failed. %s\n",
1210                         strerror(errno));
1211                 return rc;
1212         }
1213
1214         if (stripe_size != LLAPI_LAYOUT_DEFAULT &&
1215             (prev_end & (stripe_size - 1))) {
1216                 fprintf(stderr, "Stripe size %lu not aligned with %lu\n",
1217                         stripe_size, prev_end);
1218                 return -EINVAL;
1219         }
1220
1221         rc = llapi_layout_comp_extent_set(layout, prev_end, end);
1222         if (rc) {
1223                 fprintf(stderr, "Set component extent [%lu, %lu) failed. %s\n",
1224                         prev_end, end, strerror(errno));
1225                 return rc;
1226         }
1227
1228         return 0;
1229 }
1230
1231 static inline bool comp_flags_is_neg(__u32 flags)
1232 {
1233         return flags & LCME_FL_NEG;
1234 }
1235
1236 static inline void comp_flags_set_neg(__u32 *flags)
1237 {
1238         *flags |= LCME_FL_NEG;
1239 }
1240
1241 static inline void comp_flags_clear_neg(__u32 *flags)
1242 {
1243         *flags &= ~LCME_FL_NEG;
1244 }
1245
1246 static int comp_str2flags(__u32 *flags, char *string)
1247 {
1248         char *name;
1249         __u32 neg_flags = 0;
1250
1251         if (string == NULL)
1252                 return -EINVAL;
1253
1254         *flags = 0;
1255         for (name = strtok(string, ","); name; name = strtok(NULL, ",")) {
1256                 bool found = false;
1257                 int i;
1258
1259                 for (i = 0; i < ARRAY_SIZE(comp_flags_table); i++) {
1260                         __u32 comp_flag = comp_flags_table[i].cfn_flag;
1261                         const char *comp_name = comp_flags_table[i].cfn_name;
1262
1263                         if (strcmp(name, comp_name) == 0) {
1264                                 *flags |= comp_flag;
1265                                 found = true;
1266                         } else if (strncmp(name, "^", 1) == 0 &&
1267                                    strcmp(name + 1, comp_name) == 0) {
1268                                 neg_flags |= comp_flag;
1269                                 found = true;
1270                         }
1271                 }
1272                 if (!found) {
1273                         llapi_printf(LLAPI_MSG_ERROR, "Component flag "
1274                                      "'%s' is not supported.\n", name);
1275                         return -EINVAL;
1276                 }
1277         }
1278
1279         if (*flags == 0 && neg_flags == 0)
1280                 return -EINVAL;
1281         /* don't support mixed flags for now */
1282         if (*flags && neg_flags)
1283                 return -EINVAL;
1284
1285         if (neg_flags) {
1286                 *flags = neg_flags;
1287                 comp_flags_set_neg(flags);
1288         }
1289
1290         return 0;
1291 }
1292
1293 static inline bool arg_is_eof(char *arg)
1294 {
1295         return !strncmp(arg, "-1", strlen("-1")) ||
1296                !strncmp(arg, "EOF", strlen("EOF")) ||
1297                !strncmp(arg, "eof", strlen("eof"));
1298 }
1299
1300 enum {
1301         LFS_POOL_OPT = 3,
1302         LFS_COMP_COUNT_OPT,
1303         LFS_COMP_START_OPT,
1304         LFS_COMP_FLAGS_OPT,
1305         LFS_COMP_DEL_OPT,
1306         LFS_COMP_SET_OPT,
1307         LFS_COMP_ADD_OPT,
1308         LFS_PROJID_OPT,
1309 };
1310
1311 /* functions */
1312 static int lfs_setstripe(int argc, char **argv)
1313 {
1314         struct lfs_setstripe_args        lsa;
1315         struct llapi_stripe_param       *param = NULL;
1316         struct find_param                migrate_mdt_param = {
1317                 .fp_max_depth = -1,
1318                 .fp_mdt_index = -1,
1319         };
1320         char                            *fname;
1321         int                              result;
1322         int                              result2 = 0;
1323         char                            *end;
1324         int                              c;
1325         int                              delete = 0;
1326         char                            *mdt_idx_arg = NULL;
1327         unsigned long long               size_units = 1;
1328         bool                             migrate_mode = false;
1329         bool                             migration_block = false;
1330         __u64                            migration_flags = 0;
1331         __u32                            osts[LOV_MAX_STRIPE_COUNT] = { 0 };
1332         int                              comp_del = 0, comp_set = 0;
1333         int                              comp_add = 0;
1334         __u32                            comp_id = 0;
1335         struct llapi_layout             *layout = NULL;
1336
1337         struct option long_opts[] = {
1338                 /* --block is only valid in migrate mode */
1339         { .val = 'b',   .name = "block",        .has_arg = no_argument},
1340         { .val = LFS_COMP_ADD_OPT,
1341                         .name = "comp-add",     .has_arg = no_argument},
1342         { .val = LFS_COMP_ADD_OPT,
1343                         .name = "component-add",
1344                                                 .has_arg = no_argument},
1345         { .val = LFS_COMP_DEL_OPT,
1346                         .name = "comp-del",     .has_arg = no_argument},
1347         { .val = LFS_COMP_DEL_OPT,
1348                         .name = "component-del",
1349                                                 .has_arg = no_argument},
1350         { .val = LFS_COMP_FLAGS_OPT,
1351                         .name = "comp-flags",   .has_arg = required_argument},
1352         { .val = LFS_COMP_FLAGS_OPT,
1353                         .name = "component-flags",
1354                                                 .has_arg = required_argument},
1355         { .val = LFS_COMP_SET_OPT,
1356                         .name = "comp-set",     .has_arg = no_argument},
1357         { .val = LFS_COMP_SET_OPT,
1358                         .name = "component-set",
1359                                                 .has_arg = no_argument},
1360 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
1361         /* This formerly implied "stripe-count", but was explicitly
1362          * made "stripe-count" for consistency with other options,
1363          * and to separate it from "mdt-count" when DNE arrives. */
1364         { .val = 'c',   .name = "count",        .has_arg = required_argument },
1365 #endif
1366         { .val = 'c',   .name = "stripe-count", .has_arg = required_argument},
1367         { .val = 'c',   .name = "stripe_count", .has_arg = required_argument},
1368         { .val = 'd',   .name = "delete",       .has_arg = no_argument},
1369         { .val = 'E',   .name = "comp-end",     .has_arg = required_argument},
1370         { .val = 'E',   .name = "component-end",
1371                                                 .has_arg = required_argument},
1372         /* dirstripe {"mdt-hash",     required_argument, 0, 'H'}, */
1373 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
1374         /* This formerly implied "stripe-index", but was explicitly
1375          * made "stripe-index" for consistency with other options,
1376          * and to separate it from "mdt-index" when DNE arrives. */
1377         { .val = 'i',   .name = "index",        .has_arg = required_argument },
1378 #endif
1379         { .val = 'i',   .name = "stripe-index", .has_arg = required_argument},
1380         { .val = 'i',   .name = "stripe_index", .has_arg = required_argument},
1381         { .val = 'I',   .name = "comp-id",      .has_arg = required_argument},
1382         { .val = 'I',   .name = "component-id", .has_arg = required_argument},
1383         { .val = 'm',   .name = "mdt",          .has_arg = required_argument},
1384         { .val = 'm',   .name = "mdt-index",    .has_arg = required_argument},
1385         { .val = 'm',   .name = "mdt_index",    .has_arg = required_argument},
1386         /* --non-block is only valid in migrate mode */
1387         { .val = 'n',   .name = "non-block",    .has_arg = no_argument},
1388         { .val = 'o',   .name = "ost",          .has_arg = required_argument},
1389 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
1390         { .val = 'o',   .name = "ost-list",     .has_arg = required_argument },
1391         { .val = 'o',   .name = "ost_list",     .has_arg = required_argument },
1392 #endif
1393         { .val = 'p',   .name = "pool",         .has_arg = required_argument },
1394 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
1395         /* This formerly implied "--stripe-size", but was confusing
1396          * with "lfs find --size|-s", which means "file size", so use
1397          * the consistent "--stripe-size|-S" for all commands. */
1398         { .val = 's',   .name = "size",         .has_arg = required_argument },
1399 #endif
1400         { .val = 'S',   .name = "stripe-size",  .has_arg = required_argument },
1401         { .val = 'S',   .name = "stripe_size",  .has_arg = required_argument },
1402         /* dirstripe {"mdt-count",    required_argument, 0, 'T'}, */
1403         /* --verbose is only valid in migrate mode */
1404         { .val = 'v',   .name = "verbose",      .has_arg = no_argument },
1405         { .val = LFS_COMP_ADD_OPT,
1406                         .name = "component-add",
1407                                                 .has_arg = no_argument },
1408         { .val = LFS_COMP_DEL_OPT,
1409                         .name = "component-del",
1410                                                 .has_arg = no_argument },
1411         { .val = LFS_COMP_FLAGS_OPT,
1412                         .name = "component-flags",
1413                                                 .has_arg = required_argument },
1414         { .val = LFS_COMP_SET_OPT,
1415                         .name = "component-set",
1416                                                 .has_arg = no_argument },
1417         { .name = NULL } };
1418
1419         setstripe_args_init(&lsa);
1420
1421         if (strcmp(argv[0], "migrate") == 0)
1422                 migrate_mode = true;
1423
1424         while ((c = getopt_long(argc, argv, "bc:dE:i:I:m:no:p:s:S:v",
1425                                 long_opts, NULL)) >= 0) {
1426                 switch (c) {
1427                 case 0:
1428                         /* Long options. */
1429                         break;
1430                 case LFS_COMP_ADD_OPT:
1431                         comp_add = 1;
1432                         break;
1433                 case LFS_COMP_DEL_OPT:
1434                         comp_del = 1;
1435                         break;
1436                 case LFS_COMP_FLAGS_OPT:
1437                         result = comp_str2flags(&lsa.lsa_comp_flags, optarg);
1438                         if (result != 0) {
1439                                 fprintf(stderr, "error: %s: bad comp flags "
1440                                         "'%s'\n", argv[0], optarg);
1441                                 goto error;
1442                         }
1443                         break;
1444                 case LFS_COMP_SET_OPT:
1445                         comp_set = 1;
1446                         break;
1447                 case 'b':
1448                         if (!migrate_mode) {
1449                                 fprintf(stderr, "--block is valid only for"
1450                                                 " migrate mode\n");
1451                                 goto error;
1452                         }
1453                         migration_block = true;
1454                         break;
1455                 case 'c':
1456 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1457                         if (strcmp(argv[optind - 1], "--count") == 0)
1458                                 fprintf(stderr, "warning: '--count' deprecated"
1459                                         ", use '--stripe-count' instead\n");
1460 #endif
1461                         lsa.lsa_stripe_count = strtoul(optarg, &end, 0);
1462                         if (*end != '\0') {
1463                                 fprintf(stderr, "error: %s: bad stripe count "
1464                                         "'%s'\n", argv[0], optarg);
1465                                 goto error;
1466                         }
1467                         break;
1468                 case 'd':
1469                         /* delete the default striping pattern */
1470                         delete = 1;
1471                         break;
1472                 case 'E':
1473                         if (lsa.lsa_comp_end != 0) {
1474                                 result = comp_args_to_layout(&layout, &lsa);
1475                                 if (result)
1476                                         goto error;
1477
1478                                 setstripe_args_init(&lsa);
1479                         }
1480
1481                         if (arg_is_eof(optarg)) {
1482                                 lsa.lsa_comp_end = LUSTRE_EOF;
1483                         } else {
1484                                 result = llapi_parse_size(optarg,
1485                                                         &lsa.lsa_comp_end,
1486                                                         &size_units, 0);
1487                                 if (result) {
1488                                         fprintf(stderr, "error: %s: "
1489                                                 "bad component end '%s'\n",
1490                                                 argv[0], optarg);
1491                                         goto error;
1492                                 }
1493                         }
1494                         break;
1495                 case 'i':
1496                         if (strcmp(argv[optind - 1], "--index") == 0)
1497                                 fprintf(stderr, "warning: '--index' deprecated"
1498                                         ", use '--stripe-index' instead\n");
1499                         lsa.lsa_stripe_off = strtol(optarg, &end, 0);
1500                         if (*end != '\0') {
1501                                 fprintf(stderr, "error: %s: bad stripe offset "
1502                                         "'%s'\n", argv[0], optarg);
1503                                 goto error;
1504                         }
1505                         break;
1506                 case 'I':
1507                         comp_id = strtoul(optarg, &end, 0);
1508                         if (*end != '\0' || comp_id == 0 ||
1509                             comp_id > LCME_ID_MAX) {
1510                                 fprintf(stderr, "error: %s: bad comp ID "
1511                                         "'%s'\n", argv[0], optarg);
1512                                 goto error;
1513                         }
1514                         break;
1515                 case 'm':
1516                         if (!migrate_mode) {
1517                                 fprintf(stderr, "--mdt-index is valid only for"
1518                                                 " migrate mode\n");
1519                                 goto error;
1520                         }
1521                         mdt_idx_arg = optarg;
1522                         break;
1523                 case 'n':
1524                         if (!migrate_mode) {
1525                                 fprintf(stderr, "--non-block is valid only for"
1526                                                 " migrate mode\n");
1527                                 goto error;
1528                         }
1529                         migration_flags |= MIGRATION_NONBLOCK;
1530                         break;
1531                 case 'o':
1532                         lsa.lsa_nr_osts = parse_targets(osts,
1533                                                 sizeof(osts) / sizeof(__u32),
1534                                                 lsa.lsa_nr_osts, optarg);
1535                         if (lsa.lsa_nr_osts < 0) {
1536                                 fprintf(stderr,
1537                                         "error: %s: bad OST indices '%s'\n",
1538                                         argv[0], optarg);
1539                                 goto error;
1540                         }
1541
1542                         lsa.lsa_osts = osts;
1543                         if (lsa.lsa_stripe_off == -1)
1544                                 lsa.lsa_stripe_off = osts[0];
1545                         break;
1546                 case 'p':
1547                         if (optarg == NULL)
1548                                 goto error;
1549                         lsa.lsa_pool_name = optarg;
1550                         break;
1551 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
1552                 case 's':
1553 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
1554                         fprintf(stderr, "warning: '--size|-s' deprecated, "
1555                                 "use '--stripe-size|-S' instead\n");
1556 #endif
1557 #endif /* LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0) */
1558                 case 'S':
1559                         result = llapi_parse_size(optarg, &lsa.lsa_stripe_size,
1560                                                   &size_units, 0);
1561                         if (result) {
1562                                 fprintf(stderr, "error: %s: bad stripe size "
1563                                         "'%s'\n", argv[0], optarg);
1564                                 goto error;
1565                         }
1566                         break;
1567                 case 'v':
1568                         if (!migrate_mode) {
1569                                 fprintf(stderr, "--verbose is valid only for"
1570                                                 " migrate mode\n");
1571                                 goto error;
1572                         }
1573                         migrate_mdt_param.fp_verbose = VERBOSE_DETAIL;
1574                         break;
1575                 default:
1576                         goto error;
1577                 }
1578         }
1579
1580         fname = argv[optind];
1581
1582         if (lsa.lsa_comp_end != 0) {
1583                 result = comp_args_to_layout(&layout, &lsa);
1584                 if (result)
1585                         goto error;
1586         }
1587
1588         if (optind == argc) {
1589                 fprintf(stderr, "error: %s: missing filename|dirname\n",
1590                         argv[0]);
1591                 goto error;
1592         }
1593
1594         /* Only LCME_FL_INIT flags is used in PFL, and it shouldn't be
1595          * altered by user space tool, so we don't need to support the
1596          * --component-set for this moment. */
1597         if (comp_set != 0) {
1598                 fprintf(stderr, "error: %s: --component-set isn't supported.\n",
1599                         argv[0]);
1600                 goto error;
1601         }
1602
1603         if ((delete + comp_set + comp_del + comp_add) > 1) {
1604                 fprintf(stderr, "error: %s: can't specify --component-set, "
1605                         "--component-del, --component-add or -d together\n",
1606                         argv[0]);
1607                 goto error;
1608         }
1609
1610         if (delete && (setstripe_args_specified(&lsa) || comp_id != 0 ||
1611                        lsa.lsa_comp_flags != 0 || layout != NULL)) {
1612                 fprintf(stderr, "error: %s: can't specify -d with "
1613                         "-s, -c, -o, -p, -I, -F or -E options\n",
1614                         argv[0]);
1615                 goto error;
1616         }
1617
1618         if ((comp_set || comp_del) &&
1619             (setstripe_args_specified(&lsa) || layout != NULL)) {
1620                 fprintf(stderr, "error: %s: can't specify --component-del or "
1621                         "--component-set with -s, -c, -o, -p or -E options.\n",
1622                         argv[0]);
1623                 goto error;
1624         }
1625
1626         if (comp_del && comp_id != 0 && lsa.lsa_comp_flags != 0) {
1627                 fprintf(stderr, "error: %s: can't specify both -I and -F for "
1628                         "--component-del option.\n", argv[0]);
1629                 goto error;
1630         }
1631
1632         if (comp_add || comp_del) {
1633                 struct stat st;
1634
1635                 result = lstat(fname, &st);
1636                 if (result == 0 && S_ISDIR(st.st_mode)) {
1637                         fprintf(stderr, "error: %s: can't use --component-add "
1638                                 "or --component-del for directory.\n",
1639                                 argv[0]);
1640                         goto error;
1641                 }
1642         }
1643
1644         if (comp_add) {
1645                 if (layout == NULL) {
1646                         fprintf(stderr, "error: %s: -E option must be present"
1647                                 "in --component-add mode.\n", argv[0]);
1648                         goto error;
1649                 }
1650                 result = adjust_first_extent(fname, layout);
1651                 if (result == -ENODATA)
1652                         comp_add = 0;
1653                 else if (result != 0)
1654                         goto error;
1655         }
1656
1657         if (mdt_idx_arg != NULL && optind > 3) {
1658                 fprintf(stderr, "error: %s: cannot specify -m with other "
1659                         "options\n", argv[0]);
1660                 goto error;
1661         }
1662
1663         if ((migration_flags & MIGRATION_NONBLOCK) && migration_block) {
1664                 fprintf(stderr,
1665                         "error: %s: cannot specify --non-block and --block\n",
1666                         argv[0]);
1667                 goto error;
1668         }
1669
1670         if (!comp_del && !comp_set && comp_id != 0) {
1671                 fprintf(stderr, "error: %s: -I can only be used with "
1672                         "--component-del.\n", argv[0]);
1673                 goto error;
1674         }
1675
1676         if (mdt_idx_arg != NULL) {
1677                 /* initialize migrate mdt parameters */
1678                 migrate_mdt_param.fp_mdt_index = strtoul(mdt_idx_arg, &end, 0);
1679                 if (*end != '\0') {
1680                         fprintf(stderr, "error: %s: bad MDT index '%s'\n",
1681                                 argv[0], mdt_idx_arg);
1682                         goto error;
1683                 }
1684                 migrate_mdt_param.fp_migrate = 1;
1685         } else if (layout == NULL) {
1686                 /* initialize stripe parameters */
1687                 param = calloc(1, offsetof(typeof(*param),
1688                                lsp_osts[lsa.lsa_nr_osts]));
1689                 if (param == NULL) {
1690                         fprintf(stderr, "error: %s: %s\n", argv[0],
1691                                 strerror(ENOMEM));
1692                         goto error;
1693                 }
1694
1695                 param->lsp_stripe_size = lsa.lsa_stripe_size;
1696                 param->lsp_stripe_offset = lsa.lsa_stripe_off;
1697                 param->lsp_stripe_count = lsa.lsa_stripe_count;
1698                 param->lsp_stripe_pattern = 0;
1699                 param->lsp_pool = lsa.lsa_pool_name;
1700                 param->lsp_is_specific = false;
1701                 if (lsa.lsa_nr_osts > 0) {
1702                         if (lsa.lsa_stripe_count > 0 &&
1703                             lsa.lsa_nr_osts != lsa.lsa_stripe_count) {
1704                                 fprintf(stderr, "error: %s: stripe count '%d' "
1705                                         "doesn't match the number of OSTs: %d\n"
1706                                         , argv[0], lsa.lsa_stripe_count,
1707                                         lsa.lsa_nr_osts);
1708                                 free(param);
1709                                 goto error;
1710                         }
1711
1712                         param->lsp_is_specific = true;
1713                         param->lsp_stripe_count = lsa.lsa_nr_osts;
1714                         memcpy(param->lsp_osts, osts,
1715                                sizeof(*osts) * lsa.lsa_nr_osts);
1716                 }
1717         }
1718
1719         for (fname = argv[optind]; fname != NULL; fname = argv[++optind]) {
1720                 char *op;
1721                 if (mdt_idx_arg != NULL) {
1722                         result = llapi_migrate_mdt(fname, &migrate_mdt_param);
1723                         op = "migrate mdt objects of";
1724                 } else if (migrate_mode) {
1725                         result = lfs_migrate(fname, migration_flags, param,
1726                                              layout);
1727                         op = "migrate ost objects of";
1728                 } else if (comp_set != 0) {
1729                         result = lfs_component_set(fname, comp_id,
1730                                                    lsa.lsa_comp_flags);
1731                         op = "modify component flags of";
1732                 } else if (comp_del != 0) {
1733                         result = lfs_component_del(fname, comp_id,
1734                                                    lsa.lsa_comp_flags);
1735                         op = "delete component of";
1736                 } else if (comp_add != 0) {
1737                         result = lfs_component_add(fname, layout);
1738                         op = "add component to";
1739                 } else if (layout != NULL) {
1740                         result = lfs_component_create(fname, O_CREAT | O_WRONLY,
1741                                                       0644, layout);
1742                         if (result >= 0) {
1743                                 close(result);
1744                                 result = 0;
1745                         }
1746                         op = "create composite";
1747                 } else {
1748                         result = llapi_file_open_param(fname,
1749                                                        O_CREAT | O_WRONLY,
1750                                                        0644, param);
1751                         if (result >= 0) {
1752                                 close(result);
1753                                 result = 0;
1754                         }
1755                         op = "create striped";
1756                 }
1757                 if (result) {
1758                         /* Save the first error encountered. */
1759                         if (result2 == 0)
1760                                 result2 = result;
1761                         fprintf(stderr, "error: %s: %s file '%s' failed: %s\n",
1762                                 argv[0], op, fname,
1763                                 lsa.lsa_pool_name != NULL && result == EINVAL ?
1764                                 "OST not in pool?" : strerror(errno));
1765                         continue;
1766                 }
1767         }
1768
1769         free(param);
1770         llapi_layout_free(layout);
1771         return result2;
1772 error:
1773         llapi_layout_free(layout);
1774         return CMD_HELP;
1775 }
1776
1777 static int lfs_poollist(int argc, char **argv)
1778 {
1779         if (argc != 2)
1780                 return CMD_HELP;
1781
1782         return llapi_poollist(argv[1]);
1783 }
1784
1785 static int set_time(time_t *time, time_t *set, char *str)
1786 {
1787         time_t t;
1788         int res = 0;
1789
1790         if (str[0] == '+')
1791                 res = 1;
1792         else if (str[0] == '-')
1793                 res = -1;
1794
1795         if (res)
1796                 str++;
1797
1798         t = strtol(str, NULL, 0);
1799         if (*time < t * 24 * 60 * 60) {
1800                 if (res)
1801                         str--;
1802                 fprintf(stderr, "Wrong time '%s' is specified.\n", str);
1803                 return INT_MAX;
1804         }
1805
1806         *set = *time - t * 24 * 60 * 60;
1807         return res;
1808 }
1809 static int name2uid(unsigned int *id, const char *name)
1810 {
1811         struct passwd *passwd;
1812
1813         passwd = getpwnam(name);
1814         if (passwd == NULL)
1815                 return -ENOENT;
1816         *id = passwd->pw_uid;
1817
1818         return 0;
1819 }
1820
1821 static int name2gid(unsigned int *id, const char *name)
1822 {
1823         struct group *group;
1824
1825         group = getgrnam(name);
1826         if (group == NULL)
1827                 return -ENOENT;
1828         *id = group->gr_gid;
1829
1830         return 0;
1831 }
1832
1833 static inline int name2projid(unsigned int *id, const char *name)
1834 {
1835         return -ENOTSUP;
1836 }
1837
1838 static int uid2name(char **name, unsigned int id)
1839 {
1840         struct passwd *passwd;
1841
1842         passwd = getpwuid(id);
1843         if (passwd == NULL)
1844                 return -ENOENT;
1845         *name = passwd->pw_name;
1846
1847         return 0;
1848 }
1849
1850 static inline int gid2name(char **name, unsigned int id)
1851 {
1852         struct group *group;
1853
1854         group = getgrgid(id);
1855         if (group == NULL)
1856                 return -ENOENT;
1857         *name = group->gr_name;
1858
1859         return 0;
1860 }
1861
1862 static int name2layout(__u32 *layout, char *name)
1863 {
1864         char *ptr, *lyt;
1865
1866         *layout = 0;
1867         for (ptr = name; ; ptr = NULL) {
1868                 lyt = strtok(ptr, ",");
1869                 if (lyt == NULL)
1870                         break;
1871                 if (strcmp(lyt, "released") == 0)
1872                         *layout |= LOV_PATTERN_F_RELEASED;
1873                 else if (strcmp(lyt, "raid0") == 0)
1874                         *layout |= LOV_PATTERN_RAID0;
1875                 else
1876                         return -1;
1877         }
1878         return 0;
1879 }
1880
1881 static int lfs_find(int argc, char **argv)
1882 {
1883         int c, rc;
1884         int ret = 0;
1885         time_t t;
1886         struct find_param param = {
1887                 .fp_max_depth = -1,
1888                 .fp_quiet = 1,
1889         };
1890         struct option long_opts[] = {
1891                 {"atime",        required_argument, 0, 'A'},
1892                 {"comp-count",   required_argument, 0, LFS_COMP_COUNT_OPT},
1893                 {"component-count", required_argument, 0, LFS_COMP_COUNT_OPT},
1894                 {"comp-flags",   required_argument, 0, LFS_COMP_FLAGS_OPT},
1895                 {"component-flags", required_argument, 0, LFS_COMP_FLAGS_OPT},
1896                 {"comp-start",   required_argument, 0, LFS_COMP_START_OPT},
1897                 {"component-start", required_argument, 0, LFS_COMP_START_OPT},
1898                 {"stripe-count", required_argument, 0, 'c'},
1899                 {"stripe_count", required_argument, 0, 'c'},
1900                 {"ctime",        required_argument, 0, 'C'},
1901                 {"maxdepth",     required_argument, 0, 'D'},
1902                 {"comp-end",     required_argument, 0, 'E'},
1903                 {"component-end", required_argument, 0, 'E'},
1904                 {"gid",          required_argument, 0, 'g'},
1905                 {"group",        required_argument, 0, 'G'},
1906                 {"mdt-hash",     required_argument, 0, 'H'},
1907                 {"stripe-index", required_argument, 0, 'i'},
1908                 {"stripe_index", required_argument, 0, 'i'},
1909                 /*{"component-id", required_argument, 0, 'I'},*/
1910                 {"layout",       required_argument, 0, 'L'},
1911                 {"mdt",          required_argument, 0, 'm'},
1912                 {"mdt-index",    required_argument, 0, 'm'},
1913                 {"mdt_index",    required_argument, 0, 'm'},
1914                 {"mtime",        required_argument, 0, 'M'},
1915                 {"name",         required_argument, 0, 'n'},
1916      /* reserve {"or",           no_argument,     , 0, 'o'}, to match find(1) */
1917                 {"obd",          required_argument, 0, 'O'},
1918                 {"ost",          required_argument, 0, 'O'},
1919                 /* no short option for pool, p/P already used */
1920                 {"pool",         required_argument, 0, LFS_POOL_OPT},
1921                 {"print0",       no_argument,       0, 'p'},
1922                 {"print",        no_argument,       0, 'P'},
1923                 {"projid",       required_argument, 0, LFS_PROJID_OPT},
1924                 {"size",         required_argument, 0, 's'},
1925                 {"stripe-size",  required_argument, 0, 'S'},
1926                 {"stripe_size",  required_argument, 0, 'S'},
1927                 {"type",         required_argument, 0, 't'},
1928                 {"mdt-count",    required_argument, 0, 'T'},
1929                 {"uid",          required_argument, 0, 'u'},
1930                 {"user",         required_argument, 0, 'U'},
1931                 {0, 0, 0, 0}
1932         };
1933         int pathstart = -1;
1934         int pathend = -1;
1935         int neg_opt = 0;
1936         time_t *xtime;
1937         int *xsign;
1938         int isoption;
1939         char *endptr;
1940
1941         time(&t);
1942
1943         /* when getopt_long_only() hits '!' it returns 1, puts "!" in optarg */
1944         while ((c = getopt_long_only(argc, argv,
1945                         "-A:c:C:D:E:g:G:H:i:L:m:M:n:O:Ppqrs:S:t:T:u:U:v",
1946                         long_opts, NULL)) >= 0) {
1947                 xtime = NULL;
1948                 xsign = NULL;
1949                 if (neg_opt)
1950                         --neg_opt;
1951                 /* '!' is part of option */
1952                 /* when getopt_long_only() finds a string which is not
1953                  * an option nor a known option argument it returns 1
1954                  * in that case if we already have found pathstart and pathend
1955                  * (i.e. we have the list of pathnames),
1956                  * the only supported value is "!"
1957                  */
1958                 isoption = (c != 1) || (strcmp(optarg, "!") == 0);
1959                 if (!isoption && pathend != -1) {
1960                         fprintf(stderr, "err: %s: filename|dirname must either "
1961                                         "precede options or follow options\n",
1962                                         argv[0]);
1963                         ret = CMD_HELP;
1964                         goto err;
1965                 }
1966                 if (!isoption && pathstart == -1)
1967                         pathstart = optind - 1;
1968                 if (isoption && pathstart != -1 && pathend == -1)
1969                         pathend = optind - 2;
1970                 switch (c) {
1971                 case 0:
1972                         /* Long options. */
1973                         break;
1974                 case 1:
1975                         /* unknown; opt is "!" or path component,
1976                          * checking done above.
1977                          */
1978                         if (strcmp(optarg, "!") == 0)
1979                                 neg_opt = 2;
1980                         break;
1981                 case 'A':
1982                         xtime = &param.fp_atime;
1983                         xsign = &param.fp_asign;
1984                         param.fp_exclude_atime = !!neg_opt;
1985                         /* no break, this falls through to 'C' for ctime */
1986                 case 'C':
1987                         if (c == 'C') {
1988                                 xtime = &param.fp_ctime;
1989                                 xsign = &param.fp_csign;
1990                                 param.fp_exclude_ctime = !!neg_opt;
1991                         }
1992                         /* no break, this falls through to 'M' for mtime */
1993                 case 'M':
1994                         if (c == 'M') {
1995                                 xtime = &param.fp_mtime;
1996                                 xsign = &param.fp_msign;
1997                                 param.fp_exclude_mtime = !!neg_opt;
1998                         }
1999                         rc = set_time(&t, xtime, optarg);
2000                         if (rc == INT_MAX) {
2001                                 ret = -1;
2002                                 goto err;
2003                         }
2004                         if (rc)
2005                                 *xsign = rc;
2006                         break;
2007                 case LFS_COMP_COUNT_OPT:
2008                         if (optarg[0] == '+') {
2009                                 param.fp_comp_count_sign = -1;
2010                                 optarg++;
2011                         } else if (optarg[0] == '-') {
2012                                 param.fp_comp_count_sign =  1;
2013                                 optarg++;
2014                         }
2015
2016                         param.fp_comp_count = strtoul(optarg, &endptr, 0);
2017                         if (*endptr != '\0') {
2018                                 fprintf(stderr, "error: bad component count "
2019                                         "'%s'\n", optarg);
2020                                 goto err;
2021                         }
2022                         param.fp_check_comp_count = 1;
2023                         param.fp_exclude_comp_count = !!neg_opt;
2024                         break;
2025                 case LFS_COMP_FLAGS_OPT:
2026                         rc = comp_str2flags(&param.fp_comp_flags, optarg);
2027                         if (rc || comp_flags_is_neg(param.fp_comp_flags)) {
2028                                 fprintf(stderr, "error: bad component flags "
2029                                         "'%s'\n", optarg);
2030                                 goto err;
2031                         }
2032                         param.fp_check_comp_flags = 1;
2033                         param.fp_exclude_comp_flags = !!neg_opt;
2034                         break;
2035                 case LFS_COMP_START_OPT:
2036                         if (optarg[0] == '+') {
2037                                 param.fp_comp_start_sign = -1;
2038                                 optarg++;
2039                         } else if (optarg[0] == '-') {
2040                                 param.fp_comp_start_sign =  1;
2041                                 optarg++;
2042                         }
2043
2044                         rc = llapi_parse_size(optarg, &param.fp_comp_start,
2045                                               &param.fp_comp_start_units, 0);
2046                         if (rc) {
2047                                 fprintf(stderr, "error: bad component start "
2048                                         "'%s'\n", optarg);
2049                                 goto err;
2050                         }
2051                         param.fp_check_comp_start = 1;
2052                         param.fp_exclude_comp_start = !!neg_opt;
2053                         break;
2054                 case 'c':
2055                         if (optarg[0] == '+') {
2056                                 param.fp_stripe_count_sign = -1;
2057                                 optarg++;
2058                         } else if (optarg[0] == '-') {
2059                                 param.fp_stripe_count_sign =  1;
2060                                 optarg++;
2061                         }
2062
2063                         param.fp_stripe_count = strtoul(optarg, &endptr, 0);
2064                         if (*endptr != '\0') {
2065                                 fprintf(stderr,"error: bad stripe_count '%s'\n",
2066                                         optarg);
2067                                 ret = -1;
2068                                 goto err;
2069                         }
2070                         param.fp_check_stripe_count = 1;
2071                         param.fp_exclude_stripe_count = !!neg_opt;
2072                         break;
2073                 case 'D':
2074                         param.fp_max_depth = strtol(optarg, 0, 0);
2075                         break;
2076                 case 'E':
2077                         if (optarg[0] == '+') {
2078                                 param.fp_comp_end_sign = -1;
2079                                 optarg++;
2080                         } else if (optarg[0] == '-') {
2081                                 param.fp_comp_end_sign =  1;
2082                                 optarg++;
2083                         }
2084
2085                         if (arg_is_eof(optarg)) {
2086                                 param.fp_comp_end = LUSTRE_EOF;
2087                                 param.fp_comp_end_units = 1;
2088                                 rc = 0;
2089                         } else {
2090                                 rc = llapi_parse_size(optarg,
2091                                                 &param.fp_comp_end,
2092                                                 &param.fp_comp_end_units, 0);
2093                         }
2094                         if (rc) {
2095                                 fprintf(stderr, "error: bad component end "
2096                                         "'%s'\n", optarg);
2097                                 goto err;
2098                         }
2099                         param.fp_check_comp_end = 1;
2100                         param.fp_exclude_comp_end = !!neg_opt;
2101                         break;
2102                 case 'g':
2103                 case 'G':
2104                         rc = name2gid(&param.fp_gid, optarg);
2105                         if (rc) {
2106                                 param.fp_gid = strtoul(optarg, &endptr, 10);
2107                                 if (*endptr != '\0') {
2108                                         fprintf(stderr, "Group/GID: %s cannot "
2109                                                 "be found.\n", optarg);
2110                                         ret = -1;
2111                                         goto err;
2112                                 }
2113                         }
2114                         param.fp_exclude_gid = !!neg_opt;
2115                         param.fp_check_gid = 1;
2116                         break;
2117                 case 'H':
2118                         param.fp_hash_type = check_hashtype(optarg);
2119                         if (param.fp_hash_type == 0) {
2120                                 fprintf(stderr, "error: bad hash_type '%s'\n",
2121                                         optarg);
2122                                 ret = -1;
2123                                 goto err;
2124                         }
2125                         param.fp_check_hash_type = 1;
2126                         param.fp_exclude_hash_type = !!neg_opt;
2127                         break;
2128                 case 'L':
2129                         ret = name2layout(&param.fp_layout, optarg);
2130                         if (ret)
2131                                 goto err;
2132                         param.fp_exclude_layout = !!neg_opt;
2133                         param.fp_check_layout = 1;
2134                         break;
2135                 case 'u':
2136                 case 'U':
2137                         rc = name2uid(&param.fp_uid, optarg);
2138                         if (rc) {
2139                                 param.fp_uid = strtoul(optarg, &endptr, 10);
2140                                 if (*endptr != '\0') {
2141                                         fprintf(stderr, "User/UID: %s cannot "
2142                                                 "be found.\n", optarg);
2143                                         ret = -1;
2144                                         goto err;
2145                                 }
2146                         }
2147                         param.fp_exclude_uid = !!neg_opt;
2148                         param.fp_check_uid = 1;
2149                         break;
2150                 case LFS_POOL_OPT:
2151                         if (strlen(optarg) > LOV_MAXPOOLNAME) {
2152                                 fprintf(stderr,
2153                                         "Pool name %s is too long"
2154                                         " (max is %d)\n", optarg,
2155                                         LOV_MAXPOOLNAME);
2156                                 ret = -1;
2157                                 goto err;
2158                         }
2159                         /* we do check for empty pool because empty pool
2160                          * is used to find V1 lov attributes */
2161                         strncpy(param.fp_poolname, optarg, LOV_MAXPOOLNAME);
2162                         param.fp_poolname[LOV_MAXPOOLNAME] = '\0';
2163                         param.fp_exclude_pool = !!neg_opt;
2164                         param.fp_check_pool = 1;
2165                         break;
2166                 case 'n':
2167                         param.fp_pattern = (char *)optarg;
2168                         param.fp_exclude_pattern = !!neg_opt;
2169                         break;
2170                 case 'm':
2171                 case 'i':
2172                 case 'O': {
2173                         char *buf, *token, *next, *p;
2174                         int len = 1;
2175                         void *tmp;
2176
2177                         buf = strdup(optarg);
2178                         if (buf == NULL) {
2179                                 ret = -ENOMEM;
2180                                 goto err;
2181                         }
2182
2183                         param.fp_exclude_obd = !!neg_opt;
2184
2185                         token = buf;
2186                         while (token && *token) {
2187                                 token = strchr(token, ',');
2188                                 if (token) {
2189                                         len++;
2190                                         token++;
2191                                 }
2192                         }
2193                         if (c == 'm') {
2194                                 param.fp_exclude_mdt = !!neg_opt;
2195                                 param.fp_num_alloc_mdts += len;
2196                                 tmp = realloc(param.fp_mdt_uuid,
2197                                               param.fp_num_alloc_mdts *
2198                                               sizeof(*param.fp_mdt_uuid));
2199                                 if (tmp == NULL) {
2200                                         ret = -ENOMEM;
2201                                         goto err_free;
2202                                 }
2203
2204                                 param.fp_mdt_uuid = tmp;
2205                         } else {
2206                                 param.fp_exclude_obd = !!neg_opt;
2207                                 param.fp_num_alloc_obds += len;
2208                                 tmp = realloc(param.fp_obd_uuid,
2209                                               param.fp_num_alloc_obds *
2210                                               sizeof(*param.fp_obd_uuid));
2211                                 if (tmp == NULL) {
2212                                         ret = -ENOMEM;
2213                                         goto err_free;
2214                                 }
2215
2216                                 param.fp_obd_uuid = tmp;
2217                         }
2218                         for (token = buf; token && *token; token = next) {
2219                                 struct obd_uuid *puuid;
2220                                 if (c == 'm') {
2221                                         puuid =
2222                                         &param.fp_mdt_uuid[param.fp_num_mdts++];
2223                                 } else {
2224                                         puuid =
2225                                         &param.fp_obd_uuid[param.fp_num_obds++];
2226                                 }
2227                                 p = strchr(token, ',');
2228                                 next = 0;
2229                                 if (p) {
2230                                         *p = 0;
2231                                         next = p+1;
2232                                 }
2233
2234                                 if (strlen(token) > sizeof(puuid->uuid) - 1) {
2235                                         ret = -E2BIG;
2236                                         goto err_free;
2237                                 }
2238
2239                                 strncpy(puuid->uuid, token,
2240                                         sizeof(puuid->uuid));
2241                         }
2242 err_free:
2243                         if (buf)
2244                                 free(buf);
2245                         break;
2246                 }
2247                 case 'p':
2248                         param.fp_zero_end = 1;
2249                         break;
2250                 case 'P':
2251                         break;
2252                 case LFS_PROJID_OPT:
2253                         rc = name2projid(&param.fp_projid, optarg);
2254                         if (rc) {
2255                                 param.fp_projid = strtoul(optarg, &endptr, 10);
2256                                 if (*endptr != '\0') {
2257                                         fprintf(stderr,
2258                                                 "Invalid project ID: %s",
2259                                                 optarg);
2260                                         ret = -1;
2261                                         goto err;
2262                                 }
2263                         }
2264                         param.fp_exclude_projid = !!neg_opt;
2265                         param.fp_check_projid = 1;
2266                         break;
2267                 case 's':
2268                         if (optarg[0] == '+') {
2269                                 param.fp_size_sign = -1;
2270                                 optarg++;
2271                         } else if (optarg[0] == '-') {
2272                                 param.fp_size_sign =  1;
2273                                 optarg++;
2274                         }
2275
2276                         ret = llapi_parse_size(optarg, &param.fp_size,
2277                                                &param.fp_size_units, 0);
2278                         if (ret) {
2279                                 fprintf(stderr, "error: bad file size '%s'\n",
2280                                         optarg);
2281                                 goto err;
2282                         }
2283                         param.fp_check_size = 1;
2284                         param.fp_exclude_size = !!neg_opt;
2285                         break;
2286                 case 'S':
2287                         if (optarg[0] == '+') {
2288                                 param.fp_stripe_size_sign = -1;
2289                                 optarg++;
2290                         } else if (optarg[0] == '-') {
2291                                 param.fp_stripe_size_sign =  1;
2292                                 optarg++;
2293                         }
2294
2295                         ret = llapi_parse_size(optarg, &param.fp_stripe_size,
2296                                                &param.fp_stripe_size_units, 0);
2297                         if (ret) {
2298                                 fprintf(stderr, "error: bad stripe_size '%s'\n",
2299                                         optarg);
2300                                 goto err;
2301                         }
2302                         param.fp_check_stripe_size = 1;
2303                         param.fp_exclude_stripe_size = !!neg_opt;
2304                         break;
2305                 case 't':
2306                         param.fp_exclude_type = !!neg_opt;
2307                         switch (optarg[0]) {
2308                         case 'b':
2309                                 param.fp_type = S_IFBLK;
2310                                 break;
2311                         case 'c':
2312                                 param.fp_type = S_IFCHR;
2313                                 break;
2314                         case 'd':
2315                                 param.fp_type = S_IFDIR;
2316                                 break;
2317                         case 'f':
2318                                 param.fp_type = S_IFREG;
2319                                 break;
2320                         case 'l':
2321                                 param.fp_type = S_IFLNK;
2322                                 break;
2323                         case 'p':
2324                                 param.fp_type = S_IFIFO;
2325                                 break;
2326                         case 's':
2327                                 param.fp_type = S_IFSOCK;
2328                                 break;
2329                         default:
2330                                 fprintf(stderr, "error: %s: bad type '%s'\n",
2331                                         argv[0], optarg);
2332                                 ret = CMD_HELP;
2333                                 goto err;
2334                         };
2335                         break;
2336                 case 'T':
2337                         if (optarg[0] == '+') {
2338                                 param.fp_mdt_count_sign = -1;
2339                                 optarg++;
2340                         } else if (optarg[0] == '-') {
2341                                 param.fp_mdt_count_sign =  1;
2342                                 optarg++;
2343                         }
2344
2345                         param.fp_mdt_count = strtoul(optarg, &endptr, 0);
2346                         if (*endptr != '\0') {
2347                                 fprintf(stderr, "error: bad mdt_count '%s'\n",
2348                                         optarg);
2349                                 ret = -1;
2350                                 goto err;
2351                         }
2352                         param.fp_check_mdt_count = 1;
2353                         param.fp_exclude_mdt_count = !!neg_opt;
2354                         break;
2355                 default:
2356                         ret = CMD_HELP;
2357                         goto err;
2358                 };
2359         }
2360
2361         if (pathstart == -1) {
2362                 fprintf(stderr, "error: %s: no filename|pathname\n",
2363                         argv[0]);
2364                 ret = CMD_HELP;
2365                 goto err;
2366         } else if (pathend == -1) {
2367                 /* no options */
2368                 pathend = argc;
2369         }
2370
2371         do {
2372                 rc = llapi_find(argv[pathstart], &param);
2373                 if (rc != 0 && ret == 0)
2374                         ret = rc;
2375         } while (++pathstart < pathend);
2376
2377         if (ret)
2378                 fprintf(stderr, "error: %s failed for %s.\n",
2379                         argv[0], argv[optind - 1]);
2380 err:
2381         if (param.fp_obd_uuid && param.fp_num_alloc_obds)
2382                 free(param.fp_obd_uuid);
2383
2384         if (param.fp_mdt_uuid && param.fp_num_alloc_mdts)
2385                 free(param.fp_mdt_uuid);
2386
2387         return ret;
2388 }
2389
2390 static int lfs_getstripe_internal(int argc, char **argv,
2391                                   struct find_param *param)
2392 {
2393         struct option long_opts[] = {
2394                 {"comp-count",          no_argument, 0, LFS_COMP_COUNT_OPT},
2395                 {"component-count",     no_argument, 0, LFS_COMP_COUNT_OPT},
2396                 {"comp-flags",      optional_argument, 0, LFS_COMP_FLAGS_OPT},
2397                 {"component-flags", optional_argument, 0, LFS_COMP_FLAGS_OPT},
2398                 {"comp-start",      optional_argument, 0, LFS_COMP_START_OPT},
2399                 {"component-start", optional_argument, 0, LFS_COMP_START_OPT},
2400 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2401                 /* This formerly implied "stripe-count", but was explicitly
2402                  * made "stripe-count" for consistency with other options,
2403                  * and to separate it from "mdt-count" when DNE arrives. */
2404                 {"count",               no_argument,            0, 'c'},
2405 #endif
2406                 {"stripe-count",        no_argument,            0, 'c'},
2407                 {"stripe_count",        no_argument,            0, 'c'},
2408                 {"directory",           no_argument,            0, 'd'},
2409                 {"default",             no_argument,            0, 'D'},
2410                 {"comp-end",            optional_argument,      0, 'E'},
2411                 {"component-end",       optional_argument,      0, 'E'},
2412                 {"fid",                 no_argument,            0, 'F'},
2413                 {"generation",          no_argument,            0, 'g'},
2414                 /* dirstripe {"mdt-hash",     required_argument, 0, 'H'}, */
2415 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2416                 /* This formerly implied "stripe-index", but was explicitly
2417                  * made "stripe-index" for consistency with other options,
2418                  * and to separate it from "mdt-index" when DNE arrives. */
2419                 {"index",               no_argument,            0, 'i'},
2420 #endif
2421                 {"stripe-index",        no_argument,            0, 'i'},
2422                 {"stripe_index",        no_argument,            0, 'i'},
2423                 {"comp-id",             optional_argument,      0, 'I'},
2424                 {"component-id",        optional_argument,      0, 'I'},
2425                 {"layout",              no_argument,            0, 'L'},
2426                 {"mdt",                 no_argument,            0, 'm'},
2427                 {"mdt-index",           no_argument,            0, 'm'},
2428                 {"mdt_index",           no_argument,            0, 'm'},
2429 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2430                 {"mdt-index",           no_argument,            0, 'M'},
2431                 {"mdt_index",           no_argument,            0, 'M'},
2432 #endif
2433 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2434                 /* This formerly implied "stripe-index", but was confusing
2435                  * with "file offset" (which will eventually be needed for
2436                  * with different layouts by offset), so deprecate it. */
2437                 {"offset",              no_argument,            0, 'o'},
2438 #endif
2439                 {"obd",                 required_argument,      0, 'O'},
2440                 {"ost",                 required_argument,      0, 'O'},
2441                 {"pool",                no_argument,            0, 'p'},
2442                 {"quiet",               no_argument,            0, 'q'},
2443                 {"recursive",           no_argument,            0, 'r'},
2444                 {"raw",                 no_argument,            0, 'R'},
2445 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2446                 /* This formerly implied "--stripe-size", but was confusing
2447                  * with "lfs find --size|-s", which means "file size", so use
2448                  * the consistent "--stripe-size|-S" for all commands. */
2449                 {"size",                no_argument,            0, 's'},
2450 #endif
2451                 {"stripe-size",         no_argument,            0, 'S'},
2452                 {"stripe_size",         no_argument,            0, 'S'},
2453                 /* dirstripe {"mdt-count",    required_argument, 0, 'T'}, */
2454                 {"verbose",             no_argument,            0, 'v'},
2455                 {"yaml",                no_argument,            0, 'y'},
2456                 {0, 0, 0, 0}
2457         };
2458         int c, rc;
2459         char *end, *tmp;
2460
2461         while ((c = getopt_long(argc, argv, "cdDE::FghiI::LmMoO:pqrRsSvy",
2462                                 long_opts, NULL)) != -1) {
2463                 switch (c) {
2464                 case 'c':
2465                         if (strcmp(argv[optind - 1], "--count") == 0)
2466                                 fprintf(stderr, "warning: '--count' deprecated,"
2467                                         " use '--stripe-count' instead\n");
2468                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2469                                 param->fp_verbose |= VERBOSE_COUNT;
2470                                 param->fp_max_depth = 0;
2471                         }
2472                         break;
2473                 case LFS_COMP_COUNT_OPT:
2474                         param->fp_verbose |= VERBOSE_COMP_COUNT;
2475                         param->fp_max_depth = 0;
2476                         break;
2477                 case LFS_COMP_FLAGS_OPT:
2478                         if (optarg != NULL) {
2479                                 __u32 *flags = &param->fp_comp_flags;
2480                                 rc = comp_str2flags(flags, optarg);
2481                                 if (rc != 0) {
2482                                         fprintf(stderr, "error: %s bad "
2483                                                 "component flags '%s'.\n",
2484                                                 argv[0], optarg);
2485                                         return CMD_HELP;
2486                                 } else {
2487                                         param->fp_check_comp_flags = 1;
2488                                         param->fp_exclude_comp_flags =
2489                                                 comp_flags_is_neg(*flags);
2490                                         comp_flags_clear_neg(flags);
2491                                 }
2492                         } else {
2493                                 param->fp_verbose |= VERBOSE_COMP_FLAGS;
2494                                 param->fp_max_depth = 0;
2495                         }
2496                         break;
2497                 case LFS_COMP_START_OPT:
2498                         if (optarg != NULL) {
2499                                 tmp = optarg;
2500                                 if (tmp[0] == '+') {
2501                                         param->fp_comp_start_sign = -1;
2502                                         tmp++;
2503                                 } else if (tmp[0] == '-') {
2504                                         param->fp_comp_start_sign = 1;
2505                                         tmp++;
2506                                 }
2507                                 rc = llapi_parse_size(tmp,
2508                                                 &param->fp_comp_start,
2509                                                 &param->fp_comp_start_units, 0);
2510                                 if (rc != 0) {
2511                                         fprintf(stderr, "error: %s bad "
2512                                                 "component start '%s'.\n",
2513                                                 argv[0], tmp);
2514                                         return CMD_HELP;
2515                                 } else {
2516                                         param->fp_check_comp_start = 1;
2517                                 }
2518                         } else {
2519                                 param->fp_verbose |= VERBOSE_COMP_START;
2520                                 param->fp_max_depth = 0;
2521                         }
2522                         break;
2523                 case 'd':
2524                         param->fp_max_depth = 0;
2525                         break;
2526                 case 'D':
2527                         param->fp_get_default_lmv = 1;
2528                         break;
2529                 case 'E':
2530                         if (optarg != NULL) {
2531                                 tmp = optarg;
2532                                 if (tmp[0] == '+') {
2533                                         param->fp_comp_end_sign = -1;
2534                                         tmp++;
2535                                 } else if (tmp[0] == '-') {
2536                                         param->fp_comp_end_sign = 1;
2537                                         tmp++;
2538                                 }
2539
2540                                 if (arg_is_eof(tmp)) {
2541                                         param->fp_comp_end = LUSTRE_EOF;
2542                                         param->fp_comp_end_units = 1;
2543                                         rc = 0;
2544                                 } else {
2545                                         rc = llapi_parse_size(tmp,
2546                                                 &param->fp_comp_end,
2547                                                 &param->fp_comp_end_units, 0);
2548                                 }
2549                                 if (rc != 0) {
2550                                         fprintf(stderr, "error: %s bad "
2551                                                 "component end '%s'.\n",
2552                                                 argv[0], tmp);
2553                                         return CMD_HELP;
2554                                 }
2555                                 param->fp_check_comp_end = 1;
2556                         } else {
2557                                 param->fp_verbose |= VERBOSE_COMP_END;
2558                                 param->fp_max_depth = 0;
2559                         }
2560                         break;
2561                 case 'F':
2562                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2563                                 param->fp_verbose |= VERBOSE_DFID;
2564                                 param->fp_max_depth = 0;
2565                         }
2566                         break;
2567                 case 'g':
2568                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2569                                 param->fp_verbose |= VERBOSE_GENERATION;
2570                                 param->fp_max_depth = 0;
2571                         }
2572                         break;
2573 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2574                 case 'o':
2575                         fprintf(stderr, "warning: '--offset|-o' deprecated, "
2576                                 "use '--stripe-index|-i' instead\n");
2577 #endif
2578                 case 'i':
2579 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 6, 53, 0)
2580                         if (strcmp(argv[optind - 1], "--index") == 0)
2581                                 fprintf(stderr, "warning: '--index' deprecated"
2582                                         ", use '--stripe-index' instead\n");
2583 #endif
2584                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2585                                 param->fp_verbose |= VERBOSE_OFFSET;
2586                                 param->fp_max_depth = 0;
2587                         }
2588                         break;
2589                 case 'I':
2590                         if (optarg != NULL) {
2591                                 param->fp_comp_id = strtoul(optarg, &end, 0);
2592                                 if (*end != '\0' || param->fp_comp_id == 0 ||
2593                                     param->fp_comp_id > LCME_ID_MAX) {
2594                                         fprintf(stderr, "error: %s bad "
2595                                                 "component id '%s'\n",
2596                                                 argv[0], optarg);
2597                                         return CMD_HELP;
2598                                 } else {
2599                                         param->fp_check_comp_id = 1;
2600                                 }
2601                         } else {
2602                                 param->fp_max_depth = 0;
2603                                 param->fp_verbose |= VERBOSE_COMP_ID;
2604                         }
2605                         break;
2606                 case 'L':
2607                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2608                                 param->fp_verbose |= VERBOSE_LAYOUT;
2609                                 param->fp_max_depth = 0;
2610                         }
2611                         break;
2612 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2613                 case 'M':
2614 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2615                         fprintf(stderr, "warning: '-M' deprecated"
2616                                 ", use '-m' instead\n");
2617 #endif
2618 #endif
2619                 case 'm':
2620                         if (!(param->fp_verbose & VERBOSE_DETAIL))
2621                                 param->fp_max_depth = 0;
2622                         param->fp_verbose |= VERBOSE_MDTINDEX;
2623                         break;
2624                 case 'O':
2625                         if (param->fp_obd_uuid) {
2626                                 fprintf(stderr,
2627                                         "error: %s: only one obduuid allowed",
2628                                         argv[0]);
2629                                 return CMD_HELP;
2630                         }
2631                         param->fp_obd_uuid = (struct obd_uuid *)optarg;
2632                         break;
2633                 case 'p':
2634                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2635                                 param->fp_verbose |= VERBOSE_POOL;
2636                                 param->fp_max_depth = 0;
2637                         }
2638                         break;
2639                 case 'q':
2640                         param->fp_quiet++;
2641                         break;
2642                 case 'r':
2643                         param->fp_recursive = 1;
2644                         break;
2645                 case 'R':
2646                         param->fp_raw = 1;
2647                         break;
2648 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0)
2649                 case 's':
2650                         fprintf(stderr, "warning: '--size|-s' deprecated, "
2651                                 "use '--stripe-size|-S' instead\n");
2652 #endif /* LUSTRE_VERSION_CODE < OBD_OCD_VERSION(2, 9, 59, 0) */
2653                 case 'S':
2654                         if (!(param->fp_verbose & VERBOSE_DETAIL)) {
2655                                 param->fp_verbose |= VERBOSE_SIZE;
2656                                 param->fp_max_depth = 0;
2657                         }
2658                         break;
2659                 case 'v':
2660                         param->fp_verbose = VERBOSE_DEFAULT | VERBOSE_DETAIL;
2661                         break;
2662                 case 'y':
2663                         param->fp_yaml = 1;
2664                         break;
2665                 default:
2666                         return CMD_HELP;
2667                 }
2668         }
2669
2670         if (optind >= argc)
2671                 return CMD_HELP;
2672
2673         if (param->fp_recursive)
2674                 param->fp_max_depth = -1;
2675         else if (param->fp_verbose & VERBOSE_DETAIL)
2676                 param->fp_max_depth = 1;
2677
2678         if (!param->fp_verbose)
2679                 param->fp_verbose = VERBOSE_DEFAULT;
2680         if (param->fp_quiet)
2681                 param->fp_verbose = VERBOSE_OBJID;
2682
2683         do {
2684                 rc = llapi_getstripe(argv[optind], param);
2685         } while (++optind < argc && !rc);
2686
2687         if (rc)
2688                 fprintf(stderr, "error: %s failed for %s.\n",
2689                         argv[0], argv[optind - 1]);
2690         return rc;
2691 }
2692
2693 static int lfs_tgts(int argc, char **argv)
2694 {
2695         char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
2696         struct find_param param;
2697         int index = 0, rc=0;
2698
2699         if (argc > 2)
2700                 return CMD_HELP;
2701
2702         if (argc == 2 && !realpath(argv[1], path)) {
2703                 rc = -errno;
2704                 fprintf(stderr, "error: invalid path '%s': %s\n",
2705                         argv[1], strerror(-rc));
2706                 return rc;
2707         }
2708
2709         while (!llapi_search_mounts(path, index++, mntdir, NULL)) {
2710                 /* Check if we have a mount point */
2711                 if (mntdir[0] == '\0')
2712                         continue;
2713
2714                 memset(&param, 0, sizeof(param));
2715                 if (!strcmp(argv[0], "mdts"))
2716                         param.fp_get_lmv = 1;
2717
2718                 rc = llapi_ostlist(mntdir, &param);
2719                 if (rc) {
2720                         fprintf(stderr, "error: %s: failed on %s\n",
2721                                 argv[0], mntdir);
2722                 }
2723                 if (path[0] != '\0')
2724                         break;
2725                 memset(mntdir, 0, PATH_MAX);
2726         }
2727
2728         return rc;
2729 }
2730
2731 static int lfs_getstripe(int argc, char **argv)
2732 {
2733         struct find_param param = { 0 };
2734
2735         param.fp_max_depth = 1;
2736         return lfs_getstripe_internal(argc, argv, &param);
2737 }
2738
2739 /* functions */
2740 static int lfs_getdirstripe(int argc, char **argv)
2741 {
2742         struct find_param param = { 0 };
2743         struct option long_opts[] = {
2744 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2745                 {"mdt-count",   no_argument,            0, 'c'},
2746 #endif
2747                 {"mdt-hash",    no_argument,            0, 'H'},
2748                 {"mdt-index",   no_argument,            0, 'i'},
2749                 {"recursive",   no_argument,            0, 'r'},
2750 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2751                 {"mdt-hash",    no_argument,            0, 't'},
2752 #endif
2753                 {"default",     no_argument,            0, 'D'},
2754                 {"obd",         required_argument,      0, 'O'},
2755                 {"mdt-count",   no_argument,            0, 'T'},
2756                 {"yaml",        no_argument,            0, 'y'},
2757                 {0, 0, 0, 0}
2758         };
2759         int c, rc;
2760
2761         param.fp_get_lmv = 1;
2762
2763         while ((c = getopt_long(argc, argv,
2764                                 "cDHiO:rtTy", long_opts, NULL)) != -1)
2765         {
2766                 switch (c) {
2767                 case 'O':
2768                         if (param.fp_obd_uuid) {
2769                                 fprintf(stderr,
2770                                         "error: %s: only one obduuid allowed",
2771                                         argv[0]);
2772                                 return CMD_HELP;
2773                         }
2774                         param.fp_obd_uuid = (struct obd_uuid *)optarg;
2775                         break;
2776 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2777                 case 'c':
2778 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 10, 50, 0)
2779                         fprintf(stderr, "warning: '-c' deprecated"
2780                                 ", use '-T' instead\n");
2781 #endif
2782 #endif
2783                 case 'T':
2784                         param.fp_verbose |= VERBOSE_COUNT;
2785                         break;
2786                 case 'i':
2787                         param.fp_verbose |= VERBOSE_OFFSET;
2788                         break;
2789 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2790                 case 't':
2791 #endif
2792                 case 'H':
2793                         param.fp_verbose |= VERBOSE_HASH_TYPE;
2794                         break;
2795                 case 'D':
2796                         param.fp_get_default_lmv = 1;
2797                         break;
2798                 case 'r':
2799                         param.fp_recursive = 1;
2800                         break;
2801                 case 'y':
2802                         param.fp_yaml = 1;
2803                         break;
2804                 default:
2805                         return CMD_HELP;
2806                 }
2807         }
2808
2809         if (optind >= argc)
2810                 return CMD_HELP;
2811
2812         if (param.fp_recursive)
2813                 param.fp_max_depth = -1;
2814
2815         if (!param.fp_verbose)
2816                 param.fp_verbose = VERBOSE_DEFAULT;
2817
2818         do {
2819                 rc = llapi_getstripe(argv[optind], &param);
2820         } while (++optind < argc && !rc);
2821
2822         if (rc)
2823                 fprintf(stderr, "error: %s failed for %s.\n",
2824                         argv[0], argv[optind - 1]);
2825         return rc;
2826 }
2827
2828 /* functions */
2829 static int lfs_setdirstripe(int argc, char **argv)
2830 {
2831         char                    *dname;
2832         int                     result;
2833         unsigned int            stripe_offset = -1;
2834         unsigned int            stripe_count = 1;
2835         enum lmv_hash_type      hash_type;
2836         char                    *end;
2837         int                     c;
2838         char                    *stripe_offset_opt = NULL;
2839         char                    *stripe_count_opt = NULL;
2840         char                    *stripe_hash_opt = NULL;
2841         char                    *mode_opt = NULL;
2842         bool                    default_stripe = false;
2843         mode_t                  mode = S_IRWXU | S_IRWXG | S_IRWXO;
2844         mode_t                  previous_mode = 0;
2845         bool                    delete = false;
2846
2847         struct option long_opts[] = {
2848 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2849         { .val = 'c',   .name = "count",        .has_arg = required_argument },
2850 #endif
2851         { .val = 'c',   .name = "mdt-count",    .has_arg = required_argument },
2852         { .val = 'd',   .name = "delete",       .has_arg = no_argument },
2853 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2854         { .val = 'i',   .name = "index",        .has_arg = required_argument },
2855 #endif
2856         { .val = 'i',   .name = "mdt-index",    .has_arg = required_argument },
2857         { .val = 'm',   .name = "mode",         .has_arg = required_argument },
2858 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2859         { .val = 't',   .name = "hash-type",    .has_arg = required_argument },
2860         { .val = 't',   .name = "mdt-hash",     .has_arg = required_argument },
2861 #endif
2862                 {"mdt-hash",    required_argument, 0, 'H'},
2863 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2864         { .val = 'D',   .name = "default_stripe",
2865                                                 .has_arg = no_argument },
2866 #endif
2867         { .val = 'D',   .name = "default",      .has_arg = no_argument },
2868         { .name = NULL } };
2869
2870         while ((c = getopt_long(argc, argv, "c:dDi:H:m:t:", long_opts,
2871                                 NULL)) >= 0) {
2872                 switch (c) {
2873                 case 0:
2874                         /* Long options. */
2875                         break;
2876                 case 'c':
2877 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2878                         if (strcmp(argv[optind - 1], "--count") == 0)
2879                                 fprintf(stderr, "warning: '--count' deprecated"
2880                                         ", use '--mdt-count' instead\n");
2881 #endif
2882                         stripe_count_opt = optarg;
2883                         break;
2884                 case 'd':
2885                         delete = true;
2886                         default_stripe = true;
2887                         break;
2888                 case 'D':
2889                         default_stripe = true;
2890                         break;
2891                 case 'i':
2892 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2893                         if (strcmp(argv[optind - 1], "--index") == 0)
2894                                 fprintf(stderr, "warning: '--index' deprecated"
2895                                         ", use '--mdt-index' instead\n");
2896 #endif
2897                         stripe_offset_opt = optarg;
2898                         break;
2899                 case 'm':
2900                         mode_opt = optarg;
2901                         break;
2902 #if LUSTRE_VERSION_CODE < OBD_OCD_VERSION(3, 0, 53, 0)
2903                 case 't':
2904 #endif
2905                 case 'H':
2906 #if LUSTRE_VERSION_CODE >= OBD_OCD_VERSION(2, 11, 53, 0)
2907                         if (strcmp(argv[optind - 1], "--hash-type") == 0)
2908                                 fprintf(stderr, "warning: '--hash-type' "
2909                                         "deprecated, use '--mdt-hash' "
2910                                         "instead\n");
2911 #endif
2912                         stripe_hash_opt = optarg;
2913                         break;
2914                 default:
2915                         fprintf(stderr, "error: %s: option '%s' "
2916                                         "unrecognized\n",
2917                                         argv[0], argv[optind - 1]);
2918                         return CMD_HELP;
2919                 }
2920         }
2921
2922         if (optind == argc) {
2923                 fprintf(stderr, "error: %s: missing dirname\n",
2924                         argv[0]);
2925                 return CMD_HELP;
2926         }
2927
2928         if (!delete && stripe_offset_opt == NULL && stripe_count_opt == NULL) {
2929                 fprintf(stderr, "error: %s: missing stripe offset and count.\n",
2930                         argv[0]);
2931                 return CMD_HELP;
2932         }
2933
2934         if (stripe_offset_opt != NULL) {
2935                 /* get the stripe offset */
2936                 stripe_offset = strtoul(stripe_offset_opt, &end, 0);
2937                 if (*end != '\0') {
2938                         fprintf(stderr, "error: %s: bad stripe offset '%s'\n",
2939                                 argv[0], stripe_offset_opt);
2940                         return CMD_HELP;
2941                 }
2942         }
2943
2944         if (delete) {
2945                 if (stripe_offset_opt != NULL || stripe_count_opt != NULL) {
2946                         fprintf(stderr, "error: %s: cannot specify -d with -s,"
2947                                 " or -i options.\n", argv[0]);
2948                         return CMD_HELP;
2949                 } else {
2950                         stripe_count = 0;
2951                 }
2952         }
2953
2954
2955         if (mode_opt != NULL) {
2956                 mode = strtoul(mode_opt, &end, 8);
2957                 if (*end != '\0') {
2958                         fprintf(stderr, "error: %s: bad mode '%s'\n",
2959                                 argv[0], mode_opt);
2960                         return CMD_HELP;
2961                 }
2962                 previous_mode = umask(0);
2963         }
2964
2965         if (stripe_hash_opt == NULL) {
2966                 hash_type = LMV_HASH_TYPE_FNV_1A_64;
2967         } else {
2968                 hash_type = check_hashtype(stripe_hash_opt);
2969                 if (hash_type == 0) {
2970                         fprintf(stderr,
2971                                 "error: %s: bad stripe hash type '%s'\n",
2972                                 argv[0], stripe_hash_opt);
2973                         return CMD_HELP;
2974                 }
2975         }
2976
2977         /* get the stripe count */
2978         if (stripe_count_opt != NULL) {
2979                 stripe_count = strtoul(stripe_count_opt, &end, 0);
2980                 if (*end != '\0') {
2981                         fprintf(stderr, "error: %s: bad stripe count '%s'\n",
2982                                 argv[0], stripe_count_opt);
2983                         return CMD_HELP;
2984                 }
2985         }
2986
2987         dname = argv[optind];
2988         do {
2989                 if (default_stripe) {
2990                         result = llapi_dir_set_default_lmv_stripe(dname,
2991                                                     stripe_offset, stripe_count,
2992                                                     hash_type, NULL);
2993                 } else {
2994                         result = llapi_dir_create_pool(dname, mode,
2995                                                        stripe_offset,
2996                                                        stripe_count, hash_type,
2997                                                        NULL);
2998                 }
2999
3000                 if (result) {
3001                         fprintf(stderr, "error: %s: create stripe dir '%s' "
3002                                 "failed\n", argv[0], dname);
3003                         break;
3004                 }
3005                 dname = argv[++optind];
3006         } while (dname != NULL);
3007
3008         if (mode_opt != NULL)
3009                 umask(previous_mode);
3010
3011         return result;
3012 }
3013
3014 /* functions */
3015 static int lfs_rmentry(int argc, char **argv)
3016 {
3017         char *dname;
3018         int   index;
3019         int   result = 0;
3020
3021         if (argc <= 1) {
3022                 fprintf(stderr, "error: %s: missing dirname\n",
3023                         argv[0]);
3024                 return CMD_HELP;
3025         }
3026
3027         index = 1;
3028         dname = argv[index];
3029         while (dname != NULL) {
3030                 result = llapi_direntry_remove(dname);
3031                 if (result) {
3032                         fprintf(stderr, "error: %s: remove dir entry '%s' "
3033                                 "failed\n", argv[0], dname);
3034                         break;
3035                 }
3036                 dname = argv[++index];
3037         }
3038         return result;
3039 }
3040
3041 static int lfs_mv(int argc, char **argv)
3042 {
3043         struct  find_param param = {
3044                 .fp_max_depth = -1,
3045                 .fp_mdt_index = -1,
3046         };
3047         char   *end;
3048         int     c;
3049         int     rc = 0;
3050         struct option long_opts[] = {
3051                 {"mdt-index", required_argument, 0, 'M'},
3052                 {"verbose",     no_argument,       0, 'v'},
3053                 {0, 0, 0, 0}
3054         };
3055
3056         while ((c = getopt_long(argc, argv, "M:v", long_opts, NULL)) != -1) {
3057                 switch (c) {
3058                 case 'M': {
3059                         param.fp_mdt_index = strtoul(optarg, &end, 0);
3060                         if (*end != '\0') {
3061                                 fprintf(stderr, "%s: invalid MDT index'%s'\n",
3062                                         argv[0], optarg);
3063                                 return CMD_HELP;
3064                         }
3065                         break;
3066                 }
3067                 case 'v': {
3068                         param.fp_verbose = VERBOSE_DETAIL;
3069                         break;
3070                 }
3071                 default:
3072                         fprintf(stderr, "error: %s: unrecognized option '%s'\n",
3073                                 argv[0], argv[optind - 1]);
3074                         return CMD_HELP;
3075                 }
3076         }
3077
3078         if (param.fp_mdt_index == -1) {
3079                 fprintf(stderr, "%s: MDT index must be specified\n", argv[0]);
3080                 return CMD_HELP;
3081         }
3082
3083         if (optind >= argc) {
3084                 fprintf(stderr, "%s: missing operand path\n", argv[0]);
3085                 return CMD_HELP;
3086         }
3087
3088         param.fp_migrate = 1;
3089         rc = llapi_migrate_mdt(argv[optind], &param);
3090         if (rc != 0)
3091                 fprintf(stderr, "%s: cannot migrate '%s' to MDT%04x: %s\n",
3092                         argv[0], argv[optind], param.fp_mdt_index,
3093                         strerror(-rc));
3094         return rc;
3095 }
3096
3097 static int lfs_osts(int argc, char **argv)
3098 {
3099         return lfs_tgts(argc, argv);
3100 }
3101
3102 static int lfs_mdts(int argc, char **argv)
3103 {
3104         return lfs_tgts(argc, argv);
3105 }
3106
3107 #define COOK(value)                                                     \
3108 ({                                                                      \
3109         int radix = 0;                                                  \
3110         while (value > 1024) {                                          \
3111                 value /= 1024;                                          \
3112                 radix++;                                                \
3113         }                                                               \
3114         radix;                                                          \
3115 })
3116 #define UUF     "%-20s"
3117 #define CSF     "%11s"
3118 #define CDF     "%11llu"
3119 #define HDF     "%8.1f%c"
3120 #define RSF     "%4s"
3121 #define RDF     "%3d%%"
3122
3123 enum mntdf_flags {
3124         MNTDF_INODES    = 0x0001,
3125         MNTDF_COOKED    = 0x0002,
3126         MNTDF_LAZY      = 0x0004,
3127         MNTDF_VERBOSE   = 0x0008,
3128 };
3129
3130 static int showdf(char *mntdir, struct obd_statfs *stat,
3131                   char *uuid, enum mntdf_flags flags,
3132                   char *type, int index, int rc)
3133 {
3134         long long avail, used, total;
3135         double ratio = 0;
3136         char *suffix = "KMGTPEZY";
3137         /* Note if we have >2^64 bytes/fs these buffers will need to be grown */
3138         char tbuf[3 * sizeof(__u64)];
3139         char ubuf[3 * sizeof(__u64)];
3140         char abuf[3 * sizeof(__u64)];
3141         char rbuf[3 * sizeof(__u64)];
3142
3143         if (!uuid || !stat)
3144                 return -EINVAL;
3145
3146         switch (rc) {
3147         case 0:
3148                 if (flags & MNTDF_INODES) {
3149                         avail = stat->os_ffree;
3150                         used = stat->os_files - stat->os_ffree;
3151                         total = stat->os_files;
3152                 } else {
3153                         int shift = flags & MNTDF_COOKED ? 0 : 10;
3154
3155                         avail = (stat->os_bavail * stat->os_bsize) >> shift;
3156                         used  = ((stat->os_blocks - stat->os_bfree) *
3157                                  stat->os_bsize) >> shift;
3158                         total = (stat->os_blocks * stat->os_bsize) >> shift;
3159                 }
3160
3161                 if ((used + avail) > 0)
3162                         ratio = (double)used / (double)(used + avail);
3163
3164                 if (flags & MNTDF_COOKED) {
3165                         int i;
3166                         double cook_val;
3167
3168                         cook_val = (double)total;
3169                         i = COOK(cook_val);
3170                         if (i > 0)
3171                                 snprintf(tbuf, sizeof(tbuf), HDF, cook_val,
3172                                          suffix[i - 1]);
3173                         else
3174                                 snprintf(tbuf, sizeof(tbuf), CDF, total);
3175
3176                         cook_val = (double)used;
3177                         i = COOK(cook_val);
3178                         if (i > 0)
3179                                 snprintf(ubuf, sizeof(ubuf), HDF, cook_val,
3180                                          suffix[i - 1]);
3181                         else
3182                                 snprintf(ubuf, sizeof(ubuf), CDF, used);
3183
3184                         cook_val = (double)avail;
3185                         i = COOK(cook_val);
3186                         if (i > 0)
3187                                 snprintf(abuf, sizeof(abuf), HDF, cook_val,
3188                                          suffix[i - 1]);
3189                         else
3190                                 snprintf(abuf, sizeof(abuf), CDF, avail);
3191                 } else {
3192                         snprintf(tbuf, sizeof(tbuf), CDF, total);
3193                         snprintf(ubuf, sizeof(tbuf), CDF, used);
3194                         snprintf(abuf, sizeof(tbuf), CDF, avail);
3195                 }
3196
3197                 sprintf(rbuf, RDF, (int)(ratio * 100 + 0.5));
3198                 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s",
3199                        uuid, tbuf, ubuf, abuf, rbuf, mntdir);
3200                 if (type)
3201                         printf("[%s:%d]", type, index);
3202
3203                 if (stat->os_state) {
3204                         /*
3205                          * Each character represents the matching
3206                          * OS_STATE_* bit.
3207                          */
3208                         const char state_names[] = "DRSI";
3209                         __u32      state;
3210                         __u32      i;
3211
3212                         printf(" ");
3213                         for (i = 0, state = stat->os_state;
3214                              state && i < sizeof(state_names); i++) {
3215                                 if (!(state & (1 << i)))
3216                                         continue;
3217                                 printf("%c", state_names[i]);
3218                                 state ^= 1 << i;
3219                         }
3220                 }
3221
3222                 printf("\n");
3223                 break;
3224         case -ENODATA:
3225                 printf(UUF": inactive device\n", uuid);
3226                 break;
3227         default:
3228                 printf(UUF": %s\n", uuid, strerror(-rc));
3229                 break;
3230         }
3231
3232         return 0;
3233 }
3234
3235 struct ll_stat_type {
3236         int   st_op;
3237         char *st_name;
3238 };
3239
3240 static int mntdf(char *mntdir, char *fsname, char *pool, enum mntdf_flags flags)
3241 {
3242         struct obd_statfs stat_buf, sum = { .os_bsize = 1 };
3243         struct obd_uuid uuid_buf;
3244         char *poolname = NULL;
3245         struct ll_stat_type types[] = { { LL_STATFS_LMV, "MDT" },
3246                                         { LL_STATFS_LOV, "OST" },
3247                                         { 0, NULL } };
3248         struct ll_stat_type *tp;
3249         __u64 ost_ffree = 0;
3250         __u32 index;
3251         __u32 type;
3252         int fd;
3253         int rc = 0;
3254         int rc2;
3255
3256         if (pool) {
3257                 poolname = strchr(pool, '.');
3258                 if (poolname != NULL) {
3259                         if (strncmp(fsname, pool, strlen(fsname))) {
3260                                 fprintf(stderr, "filesystem name incorrect\n");
3261                                 return -ENODEV;
3262                         }
3263                         poolname++;
3264                 } else
3265                         poolname = pool;
3266         }
3267
3268         fd = open(mntdir, O_RDONLY);
3269         if (fd < 0) {
3270                 rc = -errno;
3271                 fprintf(stderr, "%s: cannot open '%s': %s\n", progname, mntdir,
3272                         strerror(errno));
3273                 return rc;
3274         }
3275
3276         if (flags & MNTDF_INODES)
3277                 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
3278                        "UUID", "Inodes", "IUsed", "IFree",
3279                        "IUse%", "Mounted on");
3280         else
3281                 printf(UUF" "CSF" "CSF" "CSF" "RSF" %-s\n",
3282                        "UUID", flags & MNTDF_COOKED ? "bytes" : "1K-blocks",
3283                        "Used", "Available", "Use%", "Mounted on");
3284
3285         for (tp = types; tp->st_name != NULL; tp++) {
3286                 for (index = 0; ; index++) {
3287                         memset(&stat_buf, 0, sizeof(struct obd_statfs));
3288                         memset(&uuid_buf, 0, sizeof(struct obd_uuid));
3289                         type = flags & MNTDF_LAZY ?
3290                                 tp->st_op | LL_STATFS_NODELAY : tp->st_op;
3291                         rc2 = llapi_obd_fstatfs(fd, type, index,
3292                                                &stat_buf, &uuid_buf);
3293                         if (rc2 == -ENODEV)
3294                                 break;
3295                         if (rc2 == -EAGAIN)
3296                                 continue;
3297                         if (rc2 == -ENODATA) { /* Inactive device, OK. */
3298                                 if (!(flags & MNTDF_VERBOSE))
3299                                         continue;
3300                         } else if (rc2 < 0 && rc == 0) {
3301                                 rc = rc2;
3302                         }
3303
3304                         if (poolname && tp->st_op == LL_STATFS_LOV &&
3305                             llapi_search_ost(fsname, poolname,
3306                                              obd_uuid2str(&uuid_buf)) != 1)
3307                                 continue;
3308
3309                         /* the llapi_obd_statfs() call may have returned with
3310                          * an error, but if it filled in uuid_buf we will at
3311                          * lease use that to print out a message for that OBD.
3312                          * If we didn't get anything in the uuid_buf, then fill
3313                          * it in so that we can print an error message. */
3314                         if (uuid_buf.uuid[0] == '\0')
3315                                 snprintf(uuid_buf.uuid, sizeof(uuid_buf.uuid),
3316                                          "%s%04x", tp->st_name, index);
3317                         showdf(mntdir, &stat_buf, obd_uuid2str(&uuid_buf),
3318                                flags, tp->st_name, index, rc2);
3319
3320                         if (rc2 == 0) {
3321                                 if (tp->st_op == LL_STATFS_LMV) {
3322                                         sum.os_ffree += stat_buf.os_ffree;
3323                                         sum.os_files += stat_buf.os_files;
3324                                 } else /* if (tp->st_op == LL_STATFS_LOV) */ {
3325                                         sum.os_blocks += stat_buf.os_blocks *
3326                                                 stat_buf.os_bsize;
3327                                         sum.os_bfree  += stat_buf.os_bfree *
3328                                                 stat_buf.os_bsize;
3329                                         sum.os_bavail += stat_buf.os_bavail *
3330                                                 stat_buf.os_bsize;
3331                                         ost_ffree += stat_buf.os_ffree;
3332                                 }
3333                         }
3334                 }
3335         }
3336
3337         close(fd);
3338
3339         /* If we don't have as many objects free on the OST as inodes
3340          * on the MDS, we reduce the total number of inodes to
3341          * compensate, so that the "inodes in use" number is correct.
3342          * Matches ll_statfs_internal() so the results are consistent. */
3343         if (ost_ffree < sum.os_ffree) {
3344                 sum.os_files = (sum.os_files - sum.os_ffree) + ost_ffree;
3345                 sum.os_ffree = ost_ffree;
3346         }
3347         printf("\n");
3348         showdf(mntdir, &sum, "filesystem_summary:", flags, NULL, 0, 0);
3349         printf("\n");
3350
3351         return rc;
3352 }
3353
3354 static int lfs_df(int argc, char **argv)
3355 {
3356         char mntdir[PATH_MAX] = {'\0'}, path[PATH_MAX] = {'\0'};
3357         enum mntdf_flags flags = 0;
3358         int c, rc = 0, index = 0;
3359         char fsname[PATH_MAX] = "", *pool_name = NULL;
3360         struct option long_opts[] = {
3361         { .val = 'h',   .name = "human-readable",
3362                                                 .has_arg = no_argument },
3363         { .val = 'i',   .name = "inodes",       .has_arg = no_argument },
3364         { .val = 'l',   .name = "lazy",         .has_arg = no_argument },
3365         { .val = 'p',   .name = "pool",         .has_arg = required_argument },
3366         { .val = 'v',   .name = "verbose",      .has_arg = no_argument },
3367         { .name = NULL} };
3368
3369         while ((c = getopt_long(argc, argv, "hilp:v", long_opts, NULL)) != -1) {
3370                 switch (c) {
3371                 case 'h':
3372                         flags |= MNTDF_COOKED;
3373                         break;
3374                 case 'i':
3375                         flags |= MNTDF_INODES;
3376                         break;
3377                 case 'l':
3378                         flags |= MNTDF_LAZY;
3379                         break;
3380                 case 'p':
3381                         pool_name = optarg;
3382                         break;
3383                 case 'v':
3384                         flags |= MNTDF_VERBOSE;
3385                         break;
3386                 default:
3387                         return CMD_HELP;
3388                 }
3389         }
3390         if (optind < argc && !realpath(argv[optind], path)) {
3391                 rc = -errno;
3392                 fprintf(stderr, "error: invalid path '%s': %s\n",
3393                         argv[optind], strerror(-rc));
3394                 return rc;
3395         }
3396
3397         while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
3398                 /* Check if we have a mount point */
3399                 if (mntdir[0] == '\0')
3400                         continue;
3401
3402                 rc = mntdf(mntdir, fsname, pool_name, flags);
3403                 if (rc || path[0] != '\0')
3404                         break;
3405                 fsname[0] = '\0'; /* avoid matching in next loop */
3406                 mntdir[0] = '\0'; /* avoid matching in next loop */
3407         }
3408
3409         return rc;
3410 }
3411
3412 static int lfs_getname(int argc, char **argv)
3413 {
3414         char mntdir[PATH_MAX] = "", path[PATH_MAX] = "", fsname[PATH_MAX] = "";
3415         int rc = 0, index = 0, c;
3416         char buf[sizeof(struct obd_uuid)];
3417
3418         while ((c = getopt(argc, argv, "h")) != -1)
3419                 return CMD_HELP;
3420
3421         if (optind == argc) { /* no paths specified, get all paths. */
3422                 while (!llapi_search_mounts(path, index++, mntdir, fsname)) {
3423                         rc = llapi_getname(mntdir, buf, sizeof(buf));
3424                         if (rc < 0) {
3425                                 fprintf(stderr,
3426                                         "cannot get name for `%s': %s\n",
3427                                         mntdir, strerror(-rc));
3428                                 break;
3429                         }
3430
3431                         printf("%s %s\n", buf, mntdir);
3432
3433                         path[0] = fsname[0] = mntdir[0] = 0;
3434                 }
3435         } else { /* paths specified, only attempt to search these. */
3436                 for (; optind < argc; optind++) {
3437                         rc = llapi_getname(argv[optind], buf, sizeof(buf));
3438                         if (rc < 0) {
3439                                 fprintf(stderr,
3440                                         "cannot get name for `%s': %s\n",
3441                                         argv[optind], strerror(-rc));
3442                                 break;
3443                         }
3444
3445                         printf("%s %s\n", buf, argv[optind]);
3446                 }
3447         }
3448         return rc;
3449 }
3450
3451 static int lfs_check(int argc, char **argv)
3452 {
3453         int rc;
3454         char mntdir[PATH_MAX] = {'\0'};
3455         int num_types = 1;
3456         char *obd_types[2];
3457         char obd_type1[4];
3458         char obd_type2[4];
3459
3460         if (argc != 2)
3461                 return CMD_HELP;
3462
3463         obd_types[0] = obd_type1;
3464         obd_types[1] = obd_type2;
3465
3466         if (strcmp(argv[1], "osts") == 0) {
3467                 strcpy(obd_types[0], "osc");
3468         } else if (strcmp(argv[1], "mds") == 0) {
3469                 strcpy(obd_types[0], "mdc");
3470         } else if (strcmp(argv[1], "servers") == 0) {
3471                 num_types = 2;
3472                 strcpy(obd_types[0], "osc");
3473                 strcpy(obd_types[1], "mdc");
3474         } else {
3475                 fprintf(stderr, "error: %s: option '%s' unrecognized\n",
3476                                 argv[0], argv[1]);
3477                         return CMD_HELP;
3478         }
3479
3480         rc = llapi_search_mounts(NULL, 0, mntdir, NULL);
3481         if (rc < 0 || mntdir[0] == '\0') {
3482                 fprintf(stderr, "No suitable Lustre mount found\n");
3483                 return rc;
3484         }
3485
3486         rc = llapi_target_check(num_types, obd_types, mntdir);
3487         if (rc)
3488                 fprintf(stderr, "error: %s: %s status failed\n",
3489                                 argv[0],argv[1]);
3490
3491         return rc;
3492
3493 }
3494
3495 #ifdef HAVE_SYS_QUOTA_H
3496 #define ARG2INT(nr, str, msg)                                           \
3497 do {                                                                    \
3498         char *endp;                                                     \
3499         nr = strtol(str, &endp, 0);                                     \
3500         if (*endp) {                                                    \
3501                 fprintf(stderr, "error: bad %s: %s\n", msg, str);       \
3502                 return CMD_HELP;                                        \
3503         }                                                               \
3504 } while (0)
3505
3506 #define ADD_OVERFLOW(a,b) ((a + b) < a) ? (a = ULONG_MAX) : (a = a + b)
3507
3508 /* Convert format time string "XXwXXdXXhXXmXXs" into seconds value
3509  * returns the value or ULONG_MAX on integer overflow or incorrect format
3510  * Notes:
3511  *        1. the order of specifiers is arbitrary (may be: 5w3s or 3s5w)
3512  *        2. specifiers may be encountered multiple times (2s3s is 5 seconds)
3513  *        3. empty integer value is interpreted as 0
3514  */
3515 static unsigned long str2sec(const char* timestr)
3516 {
3517         const char spec[] = "smhdw";
3518         const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
3519         unsigned long val = 0;
3520         char *tail;
3521
3522         if (strpbrk(timestr, spec) == NULL) {
3523                 /* no specifiers inside the time string,
3524                    should treat it as an integer value */
3525                 val = strtoul(timestr, &tail, 10);
3526                 return *tail ? ULONG_MAX : val;
3527         }
3528
3529         /* format string is XXwXXdXXhXXmXXs */
3530         while (*timestr) {
3531                 unsigned long v;
3532                 int ind;
3533                 char* ptr;
3534
3535                 v = strtoul(timestr, &tail, 10);
3536                 if (v == ULONG_MAX || *tail == '\0')
3537                         /* value too large (ULONG_MAX or more)
3538                            or missing specifier */
3539                         goto error;
3540
3541                 ptr = strchr(spec, *tail);
3542                 if (ptr == NULL)
3543                         /* unknown specifier */
3544                         goto error;
3545
3546                 ind = ptr - spec;
3547
3548                 /* check if product will overflow the type */
3549                 if (!(v < ULONG_MAX / mult[ind]))
3550                         goto error;
3551
3552                 ADD_OVERFLOW(val, mult[ind] * v);
3553                 if (val == ULONG_MAX)
3554                         goto error;
3555
3556                 timestr = tail + 1;
3557         }
3558
3559         return val;
3560
3561 error:
3562         return ULONG_MAX;
3563 }
3564
3565 #define ARG2ULL(nr, str, def_units)                                     \
3566 do {                                                                    \
3567         unsigned long long limit, units = def_units;                    \
3568         int rc;                                                         \
3569                                                                         \
3570         rc = llapi_parse_size(str, &limit, &units, 1);                  \
3571         if (rc < 0) {                                                   \
3572                 fprintf(stderr, "error: bad limit value %s\n", str);    \
3573                 return CMD_HELP;                                        \
3574         }                                                               \
3575         nr = limit;                                                     \
3576 } while (0)
3577
3578 static inline int has_times_option(int argc, char **argv)
3579 {
3580         int i;
3581
3582         for (i = 1; i < argc; i++)
3583                 if (!strcmp(argv[i], "-t"))
3584                         return 1;
3585
3586         return 0;
3587 }
3588
3589 int lfs_setquota_times(int argc, char **argv)
3590 {
3591         int c, rc;
3592         struct if_quotactl qctl;
3593         char *mnt, *obd_type = (char *)qctl.obd_type;
3594         struct obd_dqblk *dqb = &qctl.qc_dqblk;
3595         struct obd_dqinfo *dqi = &qctl.qc_dqinfo;
3596         struct option long_opts[] = {
3597         { .val = 'b',   .name = "block-grace",  .has_arg = required_argument },
3598         { .val = 'g',   .name = "group",        .has_arg = no_argument },
3599         { .val = 'i',   .name = "inode-grace",  .has_arg = required_argument },
3600         { .val = 'p',   .name = "projid",       .has_arg = no_argument },
3601         { .val = 't',   .name = "times",        .has_arg = no_argument },
3602         { .val = 'u',   .name = "user",         .has_arg = no_argument },
3603         { .name = NULL } };
3604         int qtype;
3605
3606         memset(&qctl, 0, sizeof(qctl));
3607         qctl.qc_cmd  = LUSTRE_Q_SETINFO;
3608         qctl.qc_type = ALLQUOTA;
3609
3610         while ((c = getopt_long(argc, argv, "b:gi:ptu",
3611                                 long_opts, NULL)) != -1) {
3612                 switch (c) {
3613                 case 'u':
3614                         qtype = USRQUOTA;
3615                         goto quota_type;
3616                 case 'g':
3617                         qtype = GRPQUOTA;
3618                         goto quota_type;
3619                 case 'p':
3620                         qtype = PRJQUOTA;
3621 quota_type:
3622                         if (qctl.qc_type != ALLQUOTA) {
3623                                 fprintf(stderr, "error: -u/g/p can't be used "
3624                                                 "more than once\n");
3625                                 return CMD_HELP;
3626                         }
3627                         qctl.qc_type = qtype;
3628                         break;
3629                 case 'b':
3630                         if ((dqi->dqi_bgrace = str2sec(optarg)) == ULONG_MAX) {
3631                                 fprintf(stderr, "error: bad block-grace: %s\n",
3632                                         optarg);
3633                                 return CMD_HELP;
3634                         }
3635                         dqb->dqb_valid |= QIF_BTIME;
3636                         break;
3637                 case 'i':
3638                         if ((dqi->dqi_igrace = str2sec(optarg)) == ULONG_MAX) {
3639                                 fprintf(stderr, "error: bad inode-grace: %s\n",
3640                                         optarg);
3641                                 return CMD_HELP;
3642                         }
3643                         dqb->dqb_valid |= QIF_ITIME;
3644                         break;
3645                 case 't': /* Yes, of course! */
3646                         break;
3647                 default: /* getopt prints error message for us when opterr != 0 */
3648                         return CMD_HELP;
3649                 }
3650         }
3651
3652         if (qctl.qc_type == ALLQUOTA) {
3653                 fprintf(stderr, "error: neither -u, -g nor -p specified\n");
3654                 return CMD_HELP;
3655         }
3656
3657         if (optind != argc - 1) {
3658                 fprintf(stderr, "error: unexpected parameters encountered\n");
3659                 return CMD_HELP;
3660         }
3661
3662         mnt = argv[optind];
3663         rc = llapi_quotactl(mnt, &qctl);
3664         if (rc) {
3665                 if (*obd_type)
3666                         fprintf(stderr, "%s %s ", obd_type,
3667                                 obd_uuid2str(&qctl.obd_uuid));
3668                 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
3669                 return rc;
3670         }
3671
3672         return 0;
3673 }
3674
3675 #define BSLIMIT (1 << 0)
3676 #define BHLIMIT (1 << 1)
3677 #define ISLIMIT (1 << 2)
3678 #define IHLIMIT (1 << 3)
3679
3680 int lfs_setquota(int argc, char **argv)
3681 {
3682         int c, rc;
3683         struct if_quotactl qctl;
3684         char *mnt, *obd_type = (char *)qctl.obd_type;
3685         struct obd_dqblk *dqb = &qctl.qc_dqblk;
3686         struct option long_opts[] = {
3687                 {"block-softlimit", required_argument, 0, 'b'},
3688                 {"block-hardlimit", required_argument, 0, 'B'},
3689                 {"group",           required_argument, 0, 'g'},
3690                 {"inode-softlimit", required_argument, 0, 'i'},
3691                 {"inode-hardlimit", required_argument, 0, 'I'},
3692                 {"user",            required_argument, 0, 'u'},
3693                 {"projid",         required_argument, 0, 'p'},
3694                 {0, 0, 0, 0}
3695         };
3696         unsigned limit_mask = 0;
3697         char *endptr;
3698         int qtype;
3699
3700         if (has_times_option(argc, argv))
3701                 return lfs_setquota_times(argc, argv);
3702
3703         memset(&qctl, 0, sizeof(qctl));
3704         qctl.qc_cmd  = LUSTRE_Q_SETQUOTA;
3705         qctl.qc_type = ALLQUOTA; /* ALLQUOTA makes no sense for setquota,
3706                                   * so it can be used as a marker that qc_type
3707                                   * isn't reinitialized from command line */
3708
3709         while ((c = getopt_long(argc, argv, "b:B:g:i:I:p:u:",
3710                 long_opts, NULL)) != -1) {
3711                 switch (c) {
3712                 case 'u':
3713                         qtype = USRQUOTA;
3714                         rc = name2uid(&qctl.qc_id, optarg);
3715                         goto quota_type;
3716                 case 'g':
3717                         qtype = GRPQUOTA;
3718                         rc = name2gid(&qctl.qc_id, optarg);
3719                         goto quota_type;
3720                 case 'p':
3721                         qtype = PRJQUOTA;
3722                         rc = name2projid(&qctl.qc_id, optarg);
3723 quota_type:
3724                         if (qctl.qc_type != ALLQUOTA) {
3725                                 fprintf(stderr, "error: -u and -g can't be used"
3726                                                 " more than once\n");
3727                                 return CMD_HELP;
3728                         }
3729                         qctl.qc_type = qtype;
3730                         if (rc) {
3731                                 qctl.qc_id = strtoul(optarg, &endptr, 10);
3732                                 if (*endptr != '\0') {
3733                                         fprintf(stderr, "error: can't find id "
3734                                                 "for name %s\n", optarg);
3735                                         return CMD_HELP;
3736                                 }
3737                         }
3738                         break;
3739                 case 'b':
3740                         ARG2ULL(dqb->dqb_bsoftlimit, optarg, 1024);
3741                         dqb->dqb_bsoftlimit >>= 10;
3742                         limit_mask |= BSLIMIT;
3743                         if (dqb->dqb_bsoftlimit &&
3744                             dqb->dqb_bsoftlimit <= 1024) /* <= 1M? */
3745                                 fprintf(stderr, "warning: block softlimit is "
3746                                         "smaller than the miminal qunit size, "
3747                                         "please see the help of setquota or "
3748                                         "Lustre manual for details.\n");
3749                         break;
3750                 case 'B':
3751                         ARG2ULL(dqb->dqb_bhardlimit, optarg, 1024);
3752                         dqb->dqb_bhardlimit >>= 10;
3753                         limit_mask |= BHLIMIT;
3754                         if (dqb->dqb_bhardlimit &&
3755                             dqb->dqb_bhardlimit <= 1024) /* <= 1M? */
3756                                 fprintf(stderr, "warning: block hardlimit is "
3757                                         "smaller than the miminal qunit size, "
3758                                         "please see the help of setquota or "
3759                                         "Lustre manual for details.\n");
3760                         break;
3761                 case 'i':
3762                         ARG2ULL(dqb->dqb_isoftlimit, optarg, 1);
3763                         limit_mask |= ISLIMIT;
3764                         if (dqb->dqb_isoftlimit &&
3765                             dqb->dqb_isoftlimit <= 1024) /* <= 1K inodes? */
3766                                 fprintf(stderr, "warning: inode softlimit is "
3767                                         "smaller than the miminal qunit size, "
3768                                         "please see the help of setquota or "
3769                                         "Lustre manual for details.\n");
3770                         break;
3771                 case 'I':
3772                         ARG2ULL(dqb->dqb_ihardlimit, optarg, 1);
3773                         limit_mask |= IHLIMIT;
3774                         if (dqb->dqb_ihardlimit &&
3775                             dqb->dqb_ihardlimit <= 1024) /* <= 1K inodes? */
3776                                 fprintf(stderr, "warning: inode hardlimit is "
3777                                         "smaller than the miminal qunit size, "
3778                                         "please see the help of setquota or "
3779                                         "Lustre manual for details.\n");
3780                         break;
3781                 default: /* getopt prints error message for us when opterr != 0 */
3782                         return CMD_HELP;
3783                 }
3784         }
3785
3786         if (qctl.qc_type == ALLQUOTA) {
3787                 fprintf(stderr, "error: neither -u, -g nor -p was specified\n");
3788                 return CMD_HELP;
3789         }
3790
3791         if (limit_mask == 0) {
3792                 fprintf(stderr, "error: at least one limit must be specified\n");
3793                 return CMD_HELP;
3794         }
3795
3796         if (optind != argc - 1) {
3797                 fprintf(stderr, "error: unexpected parameters encountered\n");
3798                 return CMD_HELP;
3799         }
3800
3801         mnt = argv[optind];
3802
3803         if ((!(limit_mask & BHLIMIT) ^ !(limit_mask & BSLIMIT)) ||
3804             (!(limit_mask & IHLIMIT) ^ !(limit_mask & ISLIMIT))) {
3805                 /* sigh, we can't just set blimits/ilimits */
3806                 struct if_quotactl tmp_qctl = {.qc_cmd  = LUSTRE_Q_GETQUOTA,
3807                                                .qc_type = qctl.qc_type,
3808                                                .qc_id   = qctl.qc_id};
3809
3810                 rc = llapi_quotactl(mnt, &tmp_qctl);
3811                 if (rc < 0) {
3812                         fprintf(stderr, "error: setquota failed while retrieving"
3813                                         " current quota settings (%s)\n",
3814                                         strerror(-rc));
3815                         return rc;
3816                 }
3817
3818                 if (!(limit_mask & BHLIMIT))
3819                         dqb->dqb_bhardlimit = tmp_qctl.qc_dqblk.dqb_bhardlimit;
3820                 if (!(limit_mask & BSLIMIT))
3821                         dqb->dqb_bsoftlimit = tmp_qctl.qc_dqblk.dqb_bsoftlimit;
3822                 if (!(limit_mask & IHLIMIT))
3823                         dqb->dqb_ihardlimit = tmp_qctl.qc_dqblk.dqb_ihardlimit;
3824                 if (!(limit_mask & ISLIMIT))
3825                         dqb->dqb_isoftlimit = tmp_qctl.qc_dqblk.dqb_isoftlimit;
3826
3827                 /* Keep grace times if we have got no softlimit arguments */
3828                 if ((limit_mask & BHLIMIT) && !(limit_mask & BSLIMIT)) {
3829                         dqb->dqb_valid |= QIF_BTIME;
3830                         dqb->dqb_btime = tmp_qctl.qc_dqblk.dqb_btime;
3831                 }
3832
3833                 if ((limit_mask & IHLIMIT) && !(limit_mask & ISLIMIT)) {
3834                         dqb->dqb_valid |= QIF_ITIME;
3835                         dqb->dqb_itime = tmp_qctl.qc_dqblk.dqb_itime;
3836                 }
3837         }
3838
3839         dqb->dqb_valid |= (limit_mask & (BHLIMIT | BSLIMIT)) ? QIF_BLIMITS : 0;
3840         dqb->dqb_valid |= (limit_mask & (IHLIMIT | ISLIMIT)) ? QIF_ILIMITS : 0;
3841
3842         rc = llapi_quotactl(mnt, &qctl);
3843         if (rc) {
3844                 if (*obd_type)
3845                         fprintf(stderr, "%s %s ", obd_type,
3846                                 obd_uuid2str(&qctl.obd_uuid));
3847                 fprintf(stderr, "setquota failed: %s\n", strerror(-rc));
3848                 return rc;
3849         }
3850
3851         return 0;
3852 }
3853
3854 /* Converts seconds value into format string
3855  * result is returned in buf
3856  * Notes:
3857  *        1. result is in descenting order: 1w2d3h4m5s
3858  *        2. zero fields are not filled (except for p. 3): 5d1s
3859  *        3. zero seconds value is presented as "0s"
3860  */
3861 static char * __sec2str(time_t seconds, char *buf)
3862 {
3863         const char spec[] = "smhdw";
3864         const unsigned long mult[] = {1, 60, 60*60, 24*60*60, 7*24*60*60};
3865         unsigned long c;
3866         char *tail = buf;
3867         int i;
3868
3869         for (i = sizeof(mult) / sizeof(mult[0]) - 1 ; i >= 0; i--) {
3870                 c = seconds / mult[i];
3871
3872                 if (c > 0 || (i == 0 && buf == tail))
3873                         tail += snprintf(tail, 40-(tail-buf), "%lu%c", c, spec[i]);
3874
3875                 seconds %= mult[i];
3876         }
3877
3878         return tail;
3879 }
3880
3881 static void sec2str(time_t seconds, char *buf, int rc)
3882 {
3883         char *tail = buf;
3884
3885         if (rc)
3886                 *tail++ = '[';
3887
3888         tail = __sec2str(seconds, tail);
3889
3890         if (rc && tail - buf < 39) {
3891                 *tail++ = ']';
3892                 *tail++ = 0;
3893         }
3894 }
3895
3896 static void diff2str(time_t seconds, char *buf, time_t now)
3897 {
3898
3899         buf[0] = 0;
3900         if (!seconds)
3901                 return;
3902         if (seconds <= now) {
3903                 strcpy(buf, "none");
3904                 return;
3905         }
3906         __sec2str(seconds - now, buf);
3907 }
3908
3909 static void print_quota_title(char *name, struct if_quotactl *qctl,
3910                               bool human_readable)
3911 {
3912         printf("Disk quotas for %s %s (%cid %u):\n",
3913                qtype_name(qctl->qc_type), name,
3914                *qtype_name(qctl->qc_type), qctl->qc_id);
3915         printf("%15s%8s %7s%8s%8s%8s %7s%8s%8s\n",
3916                "Filesystem", human_readable ? "used" : "kbytes",
3917                "quota", "limit", "grace",
3918                "files", "quota", "limit", "grace");
3919 }
3920
3921 static void kbytes2str(__u64 num, char *buf, int buflen, bool h)
3922 {
3923         if (!h) {
3924                 snprintf(buf, buflen, "%ju", (uintmax_t)num);
3925         } else {
3926                 if (num >> 40)
3927                         snprintf(buf, buflen, "%5.4gP",
3928                                  (double)num / ((__u64)1 << 40));
3929                 else if (num >> 30)
3930                         snprintf(buf, buflen, "%5.4gT",
3931                                  (double)num / (1 << 30));
3932                 else if (num >> 20)
3933                         snprintf(buf, buflen, "%5.4gG",
3934                                  (double)num / (1 << 20));
3935                 else if (num >> 10)
3936                         snprintf(buf, buflen, "%5.4gM",
3937                                  (double)num / (1 << 10));
3938                 else
3939                         snprintf(buf, buflen, "%ju%s", (uintmax_t)num, "k");
3940         }
3941 }
3942
3943 #define STRBUF_LEN      32
3944 static void print_quota(char *mnt, struct if_quotactl *qctl, int type,
3945                         int rc, bool h)
3946 {
3947         time_t now;
3948
3949         time(&now);
3950
3951         if (qctl->qc_cmd == LUSTRE_Q_GETQUOTA || qctl->qc_cmd == Q_GETOQUOTA) {
3952                 int bover = 0, iover = 0;
3953                 struct obd_dqblk *dqb = &qctl->qc_dqblk;
3954                 char numbuf[3][STRBUF_LEN];
3955                 char timebuf[40];
3956                 char strbuf[STRBUF_LEN];
3957
3958                 if (dqb->dqb_bhardlimit &&
3959                     lustre_stoqb(dqb->dqb_curspace) >= dqb->dqb_bhardlimit) {
3960                         bover = 1;
3961                 } else if (dqb->dqb_bsoftlimit && dqb->dqb_btime) {
3962                         if (dqb->dqb_btime > now) {
3963                                 bover = 2;
3964                         } else {
3965                                 bover = 3;
3966                         }
3967                 }
3968
3969                 if (dqb->dqb_ihardlimit &&
3970                     dqb->dqb_curinodes >= dqb->dqb_ihardlimit) {
3971                         iover = 1;
3972                 } else if (dqb->dqb_isoftlimit && dqb->dqb_itime) {
3973                         if (dqb->dqb_itime > now) {
3974                                 iover = 2;
3975                         } else {
3976                                 iover = 3;
3977                         }
3978                 }
3979
3980
3981                 if (strlen(mnt) > 15)
3982                         printf("%s\n%15s", mnt, "");
3983                 else
3984                         printf("%15s", mnt);
3985
3986                 if (bover)
3987                         diff2str(dqb->dqb_btime, timebuf, now);
3988
3989                 kbytes2str(lustre_stoqb(dqb->dqb_curspace),
3990                            strbuf, sizeof(strbuf), h);
3991                 if (rc == -EREMOTEIO)
3992                         sprintf(numbuf[0], "%s*", strbuf);
3993                 else
3994                         sprintf(numbuf[0], (dqb->dqb_valid & QIF_SPACE) ?
3995                                 "%s" : "[%s]", strbuf);
3996
3997                 kbytes2str(dqb->dqb_bsoftlimit, strbuf, sizeof(strbuf), h);
3998                 if (type == QC_GENERAL)
3999                         sprintf(numbuf[1], (dqb->dqb_valid & QIF_BLIMITS) ?
4000                                 "%s" : "[%s]", strbuf);
4001                 else
4002                         sprintf(numbuf[1], "%s", "-");
4003
4004                 kbytes2str(dqb->dqb_bhardlimit, strbuf, sizeof(strbuf), h);
4005                 sprintf(numbuf[2], (dqb->dqb_valid & QIF_BLIMITS) ?
4006                         "%s" : "[%s]", strbuf);
4007
4008                 printf(" %7s%c %6s %7s %7s",
4009                        numbuf[0], bover ? '*' : ' ', numbuf[1],
4010                        numbuf[2], bover > 1 ? timebuf : "-");
4011
4012                 if (iover)
4013                         diff2str(dqb->dqb_itime, timebuf, now);
4014
4015                 sprintf(numbuf[0], (dqb->dqb_valid & QIF_INODES) ?
4016                         "%ju" : "[%ju]", (uintmax_t)dqb->dqb_curinodes);
4017
4018                 if (type == QC_GENERAL)
4019                         sprintf(numbuf[1], (dqb->dqb_valid & QIF_ILIMITS) ?
4020                                 "%ju" : "[%ju]",
4021                                 (uintmax_t)dqb->dqb_isoftlimit);
4022                 else
4023                         sprintf(numbuf[1], "%s", "-");
4024
4025                 sprintf(numbuf[2], (dqb->dqb_valid & QIF_ILIMITS) ?
4026                         "%ju" : "[%ju]", (uintmax_t)dqb->dqb_ihardlimit);
4027
4028                 if (type != QC_OSTIDX)
4029                         printf(" %7s%c %6s %7s %7s",
4030                                numbuf[0], iover ? '*' : ' ', numbuf[1],
4031                                numbuf[2], iover > 1 ? timebuf : "-");
4032                 else
4033                         printf(" %7s %7s %7s %7s", "-", "-", "-", "-");
4034                 printf("\n");
4035
4036         } else if (qctl->qc_cmd == LUSTRE_Q_GETINFO ||
4037                    qctl->qc_cmd == Q_GETOINFO) {
4038                 char bgtimebuf[40];
4039                 char igtimebuf[40];
4040
4041                 sec2str(qctl->qc_dqinfo.dqi_bgrace, bgtimebuf, rc);
4042                 sec2str(qctl->qc_dqinfo.dqi_igrace, igtimebuf, rc);
4043                 printf("Block grace time: %s; Inode grace time: %s\n",
4044                        bgtimebuf, igtimebuf);
4045         }
4046 }
4047
4048 static int print_obd_quota(char *mnt, struct if_quotactl *qctl, int is_mdt,
4049                            bool h, __u64 *total)
4050 {
4051         int rc = 0, rc1 = 0, count = 0;
4052         __u32 valid = qctl->qc_valid;
4053
4054         rc = llapi_get_obd_count(mnt, &count, is_mdt);
4055         if (rc) {
4056                 fprintf(stderr, "can not get %s count: %s\n",
4057                         is_mdt ? "mdt": "ost", strerror(-rc));
4058                 return rc;
4059         }
4060
4061         for (qctl->qc_idx = 0; qctl->qc_idx < count; qctl->qc_idx++) {
4062                 qctl->qc_valid = is_mdt ? QC_MDTIDX : QC_OSTIDX;
4063                 rc = llapi_quotactl(mnt, qctl);
4064                 if (rc) {
4065                         /* It is remote client case. */
4066                         if (rc == -EOPNOTSUPP) {
4067                                 rc = 0;
4068                                 goto out;
4069                         }
4070
4071                         if (!rc1)
4072                                 rc1 = rc;
4073                         fprintf(stderr, "quotactl %s%d failed.\n",
4074                                 is_mdt ? "mdt": "ost", qctl->qc_idx);
4075                         continue;
4076                 }
4077
4078                 print_quota(obd_uuid2str(&qctl->obd_uuid), qctl,
4079                             qctl->qc_valid, 0, h);
4080                 *total += is_mdt ? qctl->qc_dqblk.dqb_ihardlimit :
4081                                    qctl->qc_dqblk.dqb_bhardlimit;
4082         }
4083 out:
4084         qctl->qc_valid = valid;
4085         return rc ? : rc1;
4086 }
4087
4088 static int get_print_quota(char *mnt, char *name, struct if_quotactl *qctl,
4089                            int verbose, int quiet, bool human_readable)
4090 {
4091         int rc1 = 0, rc2 = 0, rc3 = 0;
4092         char *obd_type = (char *)qctl->obd_type;
4093         char *obd_uuid = (char *)qctl->obd_uuid.uuid;
4094         __u64 total_ialloc = 0, total_balloc = 0;
4095         int inacc;
4096
4097         rc1 = llapi_quotactl(mnt, qctl);
4098         if (rc1 < 0) {
4099                 switch (rc1) {
4100                 case -ESRCH:
4101                         fprintf(stderr, "%s quotas are not enabled.\n",
4102                                 qtype_name(qctl->qc_type));
4103                         goto out;
4104                 case -EPERM:
4105                         fprintf(stderr, "Permission denied.\n");
4106                 case -ENODEV:
4107                 case -ENOENT:
4108                         /* We already got error message. */
4109                         goto out;
4110                 default:
4111                         fprintf(stderr, "Unexpected quotactl error: %s\n",
4112                                 strerror(-rc1));
4113                 }
4114         }
4115
4116         if (qctl->qc_cmd == LUSTRE_Q_GETQUOTA && !quiet)
4117                 print_quota_title(name, qctl, human_readable);
4118
4119         if (rc1 && *obd_type)
4120                 fprintf(stderr, "%s %s ", obd_type, obd_uuid);
4121
4122         if (qctl->qc_valid != QC_GENERAL)
4123                 mnt = "";
4124
4125         inacc = (qctl->qc_cmd == LUSTRE_Q_GETQUOTA) &&
4126                 ((qctl->qc_dqblk.dqb_valid & (QIF_LIMITS|QIF_USAGE)) !=
4127                  (QIF_LIMITS|QIF_USAGE));
4128
4129         print_quota(mnt, qctl, QC_GENERAL, rc1, human_readable);
4130
4131         if (qctl->qc_valid == QC_GENERAL && qctl->qc_cmd != LUSTRE_Q_GETINFO &&
4132             verbose) {
4133                 char strbuf[STRBUF_LEN];
4134
4135                 rc2 = print_obd_quota(mnt, qctl, 1, human_readable,
4136                                       &total_ialloc);
4137                 rc3 = print_obd_quota(mnt, qctl, 0, human_readable,
4138                                       &total_balloc);
4139                 kbytes2str(total_balloc, strbuf, sizeof(strbuf),
4140                            human_readable);
4141                 printf("Total allocated inode limit: %ju, total "
4142                        "allocated block limit: %s\n", (uintmax_t)total_ialloc,
4143                        strbuf);
4144         }
4145
4146         if (rc1 || rc2 || rc3 || inacc)
4147                 printf("Some errors happened when getting quota info. "
4148                        "Some devices may be not working or deactivated. "
4149                        "The data in \"[]\" is inaccurate.\n");
4150 out:
4151         return rc1;
4152
4153 }
4154
4155 static int lfs_project(int argc, char **argv)
4156 {
4157         int ret = 0, err = 0, c, i;
4158         struct project_handle_control phc = { 0 };
4159         enum lfs_project_ops_t op;
4160
4161         phc.newline = true;
4162         phc.assign_projid = false;
4163         /* default action */
4164         op = LFS_PROJECT_LIST;
4165
4166         while ((c = getopt(argc, argv, "p:cCsdkr0")) != -1) {
4167                 switch (c) {
4168                 case 'c':
4169                         if (op != LFS_PROJECT_LIST) {
4170                                 fprintf(stderr,
4171                                         "%s: cannot specify '-c' '-C' '-s' together\n",
4172                                         progname);
4173                                 return CMD_HELP;
4174                         }
4175
4176                         op = LFS_PROJECT_CHECK;
4177                         break;
4178                 case 'C':
4179                         if (op != LFS_PROJECT_LIST) {
4180                                 fprintf(stderr,
4181                                         "%s: cannot specify '-c' '-C' '-s' together\n",
4182                                         progname);
4183                                 return CMD_HELP;
4184                         }
4185
4186                         op = LFS_PROJECT_CLEAR;
4187                         break;
4188                 case 's':
4189                         if (op != LFS_PROJECT_LIST) {
4190                                 fprintf(stderr,
4191                                         "%s: cannot specify '-c' '-C' '-s' together\n",
4192                                         progname);
4193                                 return CMD_HELP;
4194                         }
4195
4196                         phc.set_inherit = true;
4197                         op = LFS_PROJECT_SET;
4198                         break;
4199                 case 'd':
4200                         phc.dironly = true;
4201                         break;
4202                 case 'k':
4203                         phc.keep_projid = true;
4204                         break;
4205                 case 'r':
4206                         phc.recursive = true;
4207                         break;
4208                 case 'p':
4209                         phc.projid = strtoul(optarg, NULL, 0);
4210                         phc.assign_projid = true;
4211
4212                         break;
4213                 case '0':
4214                         phc.newline = false;
4215                         break;
4216                 default:
4217                         fprintf(stderr, "%s: invalid option '%c'\n",
4218                                 progname, optopt);
4219                         return CMD_HELP;
4220                 }
4221         }
4222
4223         if (phc.assign_projid && op == LFS_PROJECT_LIST) {
4224                 op = LFS_PROJECT_SET;
4225                 phc.set_projid = true;
4226         } else if (phc.assign_projid && op == LFS_PROJECT_SET) {
4227                 phc.set_projid = true;
4228         }
4229
4230         switch (op) {
4231         case LFS_PROJECT_CHECK:
4232                 if (phc.keep_projid) {
4233                         fprintf(stderr,
4234                                 "%s: '-k' is useless together with '-c'\n",
4235                                 progname);
4236                         return CMD_HELP;
4237                 }
4238                 break;
4239         case LFS_PROJECT_CLEAR:
4240                 if (!phc.newline) {
4241                         fprintf(stderr,
4242                                 "%s: '-0' is useless together with '-C'\n",
4243                                 progname);
4244                         return CMD_HELP;
4245                 }
4246                 if (phc.assign_projid) {
4247                         fprintf(stderr,
4248                                 "%s: '-p' is useless together with '-C'\n",
4249                                 progname);
4250                         return CMD_HELP;
4251                 }
4252                 break;
4253         case LFS_PROJECT_SET:
4254                 if (!phc.newline) {
4255                         fprintf(stderr,
4256                                 "%s: '-0' is useless together with '-s'\n",
4257                                 progname);
4258                         return CMD_HELP;
4259                 }
4260                 if (phc.keep_projid) {
4261                         fprintf(stderr,
4262                                 "%s: '-k' is useless together with '-s'\n",
4263                                 progname);
4264                         return CMD_HELP;
4265                 }
4266                 break;
4267         default:
4268                 if (!phc.newline) {
4269                         fprintf(stderr,
4270                                 "%s: '-0' is useless for list operations\n",
4271                                 progname);
4272                         return CMD_HELP;
4273                 }
4274                 break;
4275         }
4276
4277         argv += optind;
4278         argc -= optind;
4279         if (argc == 0) {
4280                 fprintf(stderr, "%s: missing file or directory target(s)\n",
4281                         progname);
4282                 return CMD_HELP;
4283         }
4284
4285         for (i = 0; i < argc; i++) {
4286                 switch (op) {
4287                 case LFS_PROJECT_CHECK:
4288                         err = lfs_project_check(argv[i], &phc);
4289                         break;
4290                 case LFS_PROJECT_LIST:
4291                         err = lfs_project_list(argv[i], &phc);
4292                         break;
4293                 case LFS_PROJECT_CLEAR:
4294                         err = lfs_project_clear(argv[i], &phc);
4295                         break;
4296                 case LFS_PROJECT_SET:
4297                         err = lfs_project_set(argv[i], &phc);
4298                         break;
4299                 default:
4300                         break;
4301                 }
4302                 if (err && !ret)
4303                         ret = err;
4304         }
4305
4306         return ret;
4307 }
4308
4309 static int lfs_quota(int argc, char **argv)
4310 {
4311         int c;
4312         char *mnt, *name = NULL;
4313         struct if_quotactl qctl = { .qc_cmd = LUSTRE_Q_GETQUOTA,
4314                                     .qc_type = ALLQUOTA };
4315         char *obd_uuid = (char *)qctl.obd_uuid.uuid;
4316         int rc = 0, rc1 = 0, verbose = 0, quiet = 0;
4317         char *endptr;
4318         __u32 valid = QC_GENERAL, idx = 0;
4319         bool human_readable = false;
4320         int qtype;
4321
4322         while ((c = getopt(argc, argv, "gi:I:o:pqtuvh")) != -1) {
4323                 switch (c) {
4324                 case 'u':
4325                         qtype = USRQUOTA;
4326                         goto quota_type;
4327                 case 'g':
4328                         qtype = GRPQUOTA;
4329                         goto quota_type;
4330                 case 'p':
4331                         qtype = PRJQUOTA;
4332 quota_type:
4333                         if (qctl.qc_type != ALLQUOTA) {
4334                                 fprintf(stderr, "error: use either -u or -g\n");
4335                                 return CMD_HELP;
4336                         }
4337                         qctl.qc_type = qtype;
4338                         break;
4339                 case 't':
4340                         qctl.qc_cmd = LUSTRE_Q_GETINFO;
4341                         break;
4342                 case 'o':
4343                         valid = qctl.qc_valid = QC_UUID;
4344                         strlcpy(obd_uuid, optarg, sizeof(qctl.obd_uuid));
4345                         break;
4346                 case 'i':
4347                         valid = qctl.qc_valid = QC_MDTIDX;
4348                         idx = qctl.qc_idx = atoi(optarg);
4349                         break;
4350                 case 'I':
4351                         valid = qctl.qc_valid = QC_OSTIDX;
4352                         idx = qctl.qc_idx = atoi(optarg);
4353                         break;
4354                 case 'v':
4355                         verbose = 1;
4356                         break;
4357                 case 'q':
4358                         quiet = 1;
4359                         break;
4360                 case 'h':
4361                         human_readable = true;
4362                         break;
4363                 default:
4364                         fprintf(stderr, "error: %s: option '-%c' "
4365                                         "unrecognized\n", argv[0], c);
4366                         return CMD_HELP;
4367                 }
4368         }
4369
4370         /* current uid/gid info for "lfs quota /path/to/lustre/mount" */
4371         if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA && qctl.qc_type == ALLQUOTA &&
4372             optind == argc - 1) {
4373
4374                 qctl.qc_cmd = LUSTRE_Q_GETQUOTA;
4375                 qctl.qc_valid = valid;
4376                 qctl.qc_idx = idx;
4377
4378                 for (qtype = USRQUOTA; qtype <= GRPQUOTA; qtype++) {
4379                         qctl.qc_type = qtype;
4380                         if (qtype == USRQUOTA) {
4381                                 qctl.qc_id = geteuid();
4382                                 rc = uid2name(&name, qctl.qc_id);
4383                         } else {
4384                                 qctl.qc_id = getegid();
4385                                 rc = gid2name(&name, qctl.qc_id);
4386                         }
4387                         if (rc)
4388                                 name = "<unknown>";
4389                         mnt = argv[optind];
4390                         rc1 = get_print_quota(mnt, name, &qctl, verbose, quiet,
4391                                               human_readable);
4392                         if (rc1 && !rc)
4393                                 rc = rc1;
4394                 }
4395                 return rc;
4396         /* lfs quota -u username /path/to/lustre/mount */
4397         } else if (qctl.qc_cmd == LUSTRE_Q_GETQUOTA) {
4398                 /* options should be followed by u/g-name and mntpoint */
4399                 if (optind + 2 != argc || qctl.qc_type == ALLQUOTA) {
4400                         fprintf(stderr, "error: missing quota argument(s)\n");
4401                         return CMD_HELP;
4402                 }
4403
4404                 name = argv[optind++];
4405                 switch (qctl.qc_type) {
4406                 case USRQUOTA:
4407                         rc = name2uid(&qctl.qc_id, name);
4408                         break;
4409                 case GRPQUOTA:
4410                         rc = name2gid(&qctl.qc_id, name);
4411                         break;
4412                 case PRJQUOTA:
4413                         rc = name2projid(&qctl.qc_id, name);
4414                         break;
4415                 default:
4416                         rc = -ENOTSUP;
4417                         break;
4418                 }
4419                 if (rc) {
4420                         qctl.qc_id = strtoul(name, &endptr, 10);
4421                         if (*endptr != '\0') {
4422                                 fprintf(stderr, "error: can't find id for name: %s\n",
4423                                                 name);
4424                                 return CMD_HELP;
4425                         }
4426                 }
4427         } else if (optind + 1 != argc || qctl.qc_type == ALLQUOTA) {
4428                 fprintf(stderr, "error: missing quota info argument(s)\n");
4429                 return CMD_HELP;
4430         }
4431
4432         mnt = argv[optind];
4433         rc = get_print_quota(mnt, name, &qctl, verbose, quiet,
4434                              human_readable);
4435         return rc;
4436 }
4437 #endif /* HAVE_SYS_QUOTA_H! */
4438
4439 static int flushctx_ioctl(char *mp)
4440 {
4441         int fd, rc;
4442
4443         fd = open(mp, O_RDONLY);
4444         if (fd == -1) {
4445                 fprintf(stderr, "flushctx: error open %s: %s\n",
4446                         mp, strerror(errno));
4447                 return -1;
4448         }
4449
4450         rc = ioctl(fd, LL_IOC_FLUSHCTX);
4451         if (rc == -1)
4452                 fprintf(stderr, "flushctx: error ioctl %s: %s\n",
4453                         mp, strerror(errno));
4454
4455         close(fd);
4456         return rc;
4457 }
4458
4459 static int lfs_flushctx(int argc, char **argv)
4460 {
4461         int     kdestroy = 0, c;
4462         char    mntdir[PATH_MAX] = {'\0'};
4463         int     index = 0;
4464         int     rc = 0;
4465
4466         while ((c = getopt(argc, argv, "k")) != -1) {
4467                 switch (c) {
4468                 case 'k':
4469                         kdestroy = 1;
4470                         break;
4471                 default:
4472                         fprintf(stderr, "error: %s: option '-%c' "
4473                                         "unrecognized\n", argv[0], c);
4474                         return CMD_HELP;
4475                 }
4476         }
4477
4478         if (kdestroy) {
4479             if ((rc = system("kdestroy > /dev/null")) != 0) {
4480                 rc = WEXITSTATUS(rc);
4481                 fprintf(stderr, "error destroying tickets: %d, continuing\n", rc);
4482             }
4483         }
4484
4485         if (optind >= argc) {
4486                 /* flush for all mounted lustre fs. */
4487                 while (!llapi_search_mounts(NULL, index++, mntdir, NULL)) {
4488                         /* Check if we have a mount point */
4489                         if (mntdir[0] == '\0')
4490                                 continue;
4491
4492                         if (flushctx_ioctl(mntdir))
4493                                 rc = -1;
4494
4495                         mntdir[0] = '\0'; /* avoid matching in next loop */
4496                 }
4497         } else {
4498                 /* flush fs as specified */
4499                 while (optind < argc) {
4500                         if (flushctx_ioctl(argv[optind++]))
4501                                 rc = -1;
4502                 }
4503         }
4504         return rc;
4505 }
4506
4507 static int lfs_cp(int argc, char **argv)
4508 {
4509         fprintf(stderr, "remote client copy file(s).\n"
4510                 "obsolete, does not support it anymore.\n");
4511         return 0;
4512 }
4513
4514 static int lfs_ls(int argc, char **argv)
4515 {
4516         fprintf(stderr, "remote client lists directory contents.\n"
4517                 "obsolete, does not support it anymore.\n");
4518         return 0;
4519 }
4520
4521 static int lfs_changelog(int argc, char **argv)
4522 {
4523         void *changelog_priv;
4524         struct changelog_rec *rec;
4525         long long startrec = 0, endrec = 0;
4526         char *mdd;
4527         struct option long_opts[] = {
4528                 {"follow", no_argument, 0, 'f'},
4529                 {0, 0, 0, 0}
4530         };
4531         char short_opts[] = "f";
4532         int rc, follow = 0;
4533
4534         while ((rc = getopt_long(argc, argv, short_opts,
4535                                 long_opts, NULL)) != -1) {
4536                 switch (rc) {
4537                 case 'f':
4538                         follow++;
4539                         break;
4540                 case '?':
4541                         return CMD_HELP;
4542                 default:
4543                         fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4544                                 argv[0], argv[optind - 1]);
4545                         return CMD_HELP;
4546                 }
4547         }
4548         if (optind >= argc)
4549                 return CMD_HELP;
4550
4551         mdd = argv[optind++];
4552         if (argc > optind)
4553                 startrec = strtoll(argv[optind++], NULL, 10);
4554         if (argc > optind)
4555                 endrec = strtoll(argv[optind++], NULL, 10);
4556
4557         rc = llapi_changelog_start(&changelog_priv,
4558                                    CHANGELOG_FLAG_BLOCK |
4559                                    CHANGELOG_FLAG_JOBID |
4560                                    (follow ? CHANGELOG_FLAG_FOLLOW : 0),
4561                                    mdd, startrec);
4562         if (rc < 0) {
4563                 fprintf(stderr, "Can't start changelog: %s\n",
4564                         strerror(errno = -rc));
4565                 return rc;
4566         }
4567
4568         while ((rc = llapi_changelog_recv(changelog_priv, &rec)) == 0) {
4569                 time_t secs;
4570                 struct tm ts;
4571
4572                 if (endrec && rec->cr_index > endrec) {
4573                         llapi_changelog_free(&rec);
4574                         break;
4575                 }
4576                 if (rec->cr_index < startrec) {
4577                         llapi_changelog_free(&rec);
4578                         continue;
4579                 }
4580
4581                 secs = rec->cr_time >> 30;
4582                 gmtime_r(&secs, &ts);
4583                 printf("%ju %02d%-5s %02d:%02d:%02d.%09d %04d.%02d.%02d "
4584                        "0x%x t="DFID, (uintmax_t)rec->cr_index, rec->cr_type,
4585                        changelog_type2str(rec->cr_type),
4586                        ts.tm_hour, ts.tm_min, ts.tm_sec,
4587                        (int)(rec->cr_time & ((1 << 30) - 1)),
4588                        ts.tm_year + 1900, ts.tm_mon + 1, ts.tm_mday,
4589                        rec->cr_flags & CLF_FLAGMASK, PFID(&rec->cr_tfid));
4590
4591                 if (rec->cr_flags & CLF_JOBID) {
4592                         struct changelog_ext_jobid *jid =
4593                                 changelog_rec_jobid(rec);
4594
4595                         if (jid->cr_jobid[0] != '\0')
4596                                 printf(" j=%s", jid->cr_jobid);
4597                 }
4598
4599                 if (rec->cr_namelen)
4600                         printf(" p="DFID" %.*s", PFID(&rec->cr_pfid),
4601                                rec->cr_namelen, changelog_rec_name(rec));
4602
4603                 if (rec->cr_flags & CLF_RENAME) {
4604                         struct changelog_ext_rename *rnm =
4605                                 changelog_rec_rename(rec);
4606
4607                         if (!fid_is_zero(&rnm->cr_sfid))
4608                                 printf(" s="DFID" sp="DFID" %.*s",
4609                                        PFID(&rnm->cr_sfid),
4610                                        PFID(&rnm->cr_spfid),
4611                                        (int)changelog_rec_snamelen(rec),
4612                                        changelog_rec_sname(rec));
4613                 }
4614                 printf("\n");
4615
4616                 llapi_changelog_free(&rec);
4617         }
4618
4619         llapi_changelog_fini(&changelog_priv);
4620
4621         if (rc < 0)
4622                 fprintf(stderr, "Changelog: %s\n", strerror(errno = -rc));
4623
4624         return (rc == 1 ? 0 : rc);
4625 }
4626
4627 static int lfs_changelog_clear(int argc, char **argv)
4628 {
4629         long long endrec;
4630         int rc;
4631
4632         if (argc != 4)
4633                 return CMD_HELP;
4634
4635         endrec = strtoll(argv[3], NULL, 10);
4636
4637         rc = llapi_changelog_clear(argv[1], argv[2], endrec);
4638
4639         if (rc == -EINVAL)
4640                 fprintf(stderr, "%s: record out of range: %llu\n",
4641                         argv[0], endrec);
4642         else if (rc == -ENOENT)
4643                 fprintf(stderr, "%s: no changelog user: %s\n",
4644                         argv[0], argv[2]);
4645         else if (rc)
4646                 fprintf(stderr, "%s error: %s\n", argv[0],
4647                         strerror(-rc));
4648
4649         if (rc)
4650                 errno = -rc;
4651
4652         return rc;
4653 }
4654
4655 static int lfs_fid2path(int argc, char **argv)
4656 {
4657         struct option long_opts[] = {
4658                 { .val = 'c',   .name = "cur",  .has_arg = no_argument },
4659                 { .val = 'l',   .name = "link", .has_arg = required_argument },
4660                 { .val = 'r',   .name = "rec",  .has_arg = required_argument },
4661                 { .name = NULL } };
4662         char  short_opts[] = "cl:r:";
4663         char *device, *fid, *path;
4664         long long recno = -1;
4665         int linkno = -1;
4666         int lnktmp;
4667         int printcur = 0;
4668         int rc = 0;
4669
4670         while ((rc = getopt_long(argc, argv, short_opts,
4671                 long_opts, NULL)) != -1) {
4672                 switch (rc) {
4673                 case 'c':
4674                         printcur++;
4675                         break;
4676                 case 'l':
4677                         linkno = strtol(optarg, NULL, 10);
4678                         break;
4679                 case 'r':
4680                         recno = strtoll(optarg, NULL, 10);
4681                         break;
4682                 case '?':
4683                         return CMD_HELP;
4684                 default:
4685                         fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4686                                 argv[0], argv[optind - 1]);
4687                         return CMD_HELP;
4688                 }
4689         }
4690
4691         if (argc < 3)
4692                 return CMD_HELP;
4693
4694         device = argv[optind++];
4695         path = calloc(1, PATH_MAX);
4696         if (path == NULL) {
4697                 fprintf(stderr, "error: Not enough memory\n");
4698                 return -errno;
4699         }
4700
4701         rc = 0;
4702         while (optind < argc) {
4703                 fid = argv[optind++];
4704
4705                 lnktmp = (linkno >= 0) ? linkno : 0;
4706                 while (1) {
4707                         int oldtmp = lnktmp;
4708                         long long rectmp = recno;
4709                         int rc2;
4710                         rc2 = llapi_fid2path(device, fid, path, PATH_MAX,
4711                                              &rectmp, &lnktmp);
4712                         if (rc2 < 0) {
4713                                 fprintf(stderr, "%s: error on FID %s: %s\n",
4714                                         argv[0], fid, strerror(errno = -rc2));
4715                                 if (rc == 0)
4716                                         rc = rc2;
4717                                 break;
4718                         }
4719
4720                         if (printcur)
4721                                 fprintf(stdout, "%lld ", rectmp);
4722                         if (device[0] == '/') {
4723                                 fprintf(stdout, "%s", device);
4724                                 if (device[strlen(device) - 1] != '/')
4725                                         fprintf(stdout, "/");
4726                         } else if (path[0] == '\0') {
4727                                 fprintf(stdout, "/");
4728                         }
4729                         fprintf(stdout, "%s\n", path);
4730
4731                         if (linkno >= 0)
4732                                 /* specified linkno */
4733                                 break;
4734                         if (oldtmp == lnktmp)
4735                                 /* no more links */
4736                                 break;
4737                 }
4738         }
4739
4740         free(path);
4741         return rc;
4742 }
4743
4744 static int lfs_path2fid(int argc, char **argv)
4745 {
4746         struct option     long_opts[] = {
4747                 {"parents", no_argument, 0, 'p'},
4748                 {0, 0, 0, 0}
4749         };
4750         char            **path;
4751         const char        short_opts[] = "p";
4752         const char       *sep = "";
4753         lustre_fid        fid;
4754         int               rc = 0;
4755         bool              show_parents = false;
4756
4757         while ((rc = getopt_long(argc, argv, short_opts,
4758                                  long_opts, NULL)) != -1) {
4759                 switch (rc) {
4760                 case 'p':
4761                         show_parents = true;
4762                         break;
4763                 default:
4764                         fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4765                                 argv[0], argv[optind - 1]);
4766                         return CMD_HELP;
4767                 }
4768         }
4769
4770         if (optind > argc - 1)
4771                 return CMD_HELP;
4772         else if (optind < argc - 1)
4773                 sep = ": ";
4774
4775         rc = 0;
4776         for (path = argv + optind; *path != NULL; path++) {
4777                 int err = 0;
4778                 if (!show_parents) {
4779                         err = llapi_path2fid(*path, &fid);
4780                         if (!err)
4781                                 printf("%s%s"DFID"\n",
4782                                        *sep != '\0' ? *path : "", sep,
4783                                        PFID(&fid));
4784                 } else {
4785                         char            name[NAME_MAX + 1];
4786                         unsigned int    linkno = 0;
4787
4788                         while ((err = llapi_path2parent(*path, linkno, &fid,
4789                                                 name, sizeof(name))) == 0) {
4790                                 if (*sep != '\0' && linkno == 0)
4791                                         printf("%s%s", *path, sep);
4792
4793                                 printf("%s"DFID"/%s", linkno != 0 ? "\t" : "",
4794                                        PFID(&fid), name);
4795                                 linkno++;
4796                         }
4797
4798                         /* err == -ENODATA is end-of-loop */
4799                         if (linkno > 0 && err == -ENODATA) {
4800                                 printf("\n");
4801                                 err = 0;
4802                         }
4803                 }
4804
4805                 if (err) {
4806                         fprintf(stderr, "%s: can't get %sfid for %s: %s\n",
4807                                 argv[0], show_parents ? "parent " : "", *path,
4808                                 strerror(-err));
4809                         if (rc == 0) {
4810                                 rc = err;
4811                                 errno = -err;
4812                         }
4813                 }
4814         }
4815
4816         return rc;
4817 }
4818
4819 static int lfs_data_version(int argc, char **argv)
4820 {
4821         char *path;
4822         __u64 data_version;
4823         int fd;
4824         int rc;
4825         int c;
4826         int data_version_flags = LL_DV_RD_FLUSH; /* Read by default */
4827
4828         if (argc < 2)
4829                 return CMD_HELP;
4830
4831         while ((c = getopt(argc, argv, "nrw")) != -1) {
4832                 switch (c) {
4833                 case 'n':
4834                         data_version_flags = 0;
4835                         break;
4836                 case 'r':
4837                         data_version_flags |= LL_DV_RD_FLUSH;
4838                         break;
4839                 case 'w':
4840                         data_version_flags |= LL_DV_WR_FLUSH;
4841                         break;
4842                 default:
4843                         return CMD_HELP;
4844                 }
4845         }
4846         if (optind == argc)
4847                 return CMD_HELP;
4848
4849         path = argv[optind];
4850         fd = open(path, O_RDONLY);
4851         if (fd < 0)
4852                 err(errno, "cannot open file %s", path);
4853
4854         rc = llapi_get_data_version(fd, &data_version, data_version_flags);
4855         if (rc < 0)
4856                 err(errno, "cannot get version for %s", path);
4857         else
4858                 printf("%ju" "\n", (uintmax_t)data_version);
4859
4860         close(fd);
4861         return rc;
4862 }
4863
4864 static int lfs_hsm_state(int argc, char **argv)
4865 {
4866         int rc;
4867         int i = 1;
4868         char *path;
4869         struct hsm_user_state hus;
4870
4871         if (argc < 2)
4872                 return CMD_HELP;
4873
4874         do {
4875                 path = argv[i];
4876
4877                 rc = llapi_hsm_state_get(path, &hus);
4878                 if (rc) {
4879                         fprintf(stderr, "can't get hsm state for %s: %s\n",
4880                                 path, strerror(errno = -rc));
4881                         return rc;
4882                 }
4883
4884                 /* Display path name and status flags */
4885                 printf("%s: (0x%08x)", path, hus.hus_states);
4886
4887                 if (hus.hus_states & HS_RELEASED)
4888                         printf(" released");
4889                 if (hus.hus_states & HS_EXISTS)
4890                         printf(" exists");
4891                 if (hus.hus_states & HS_DIRTY)
4892                         printf(" dirty");
4893                 if (hus.hus_states & HS_ARCHIVED)
4894                         printf(" archived");
4895                 /* Display user-settable flags */
4896                 if (hus.hus_states & HS_NORELEASE)
4897                         printf(" never_release");
4898                 if (hus.hus_states & HS_NOARCHIVE)
4899                         printf(" never_archive");
4900                 if (hus.hus_states & HS_LOST)
4901                         printf(" lost_from_hsm");
4902
4903                 if (hus.hus_archive_id != 0)
4904                         printf(", archive_id:%d", hus.hus_archive_id);
4905                 printf("\n");
4906
4907         } while (++i < argc);
4908
4909         return 0;
4910 }
4911
4912 #define LFS_HSM_SET   0
4913 #define LFS_HSM_CLEAR 1
4914
4915 /**
4916  * Generic function to set or clear HSM flags.
4917  * Used by hsm_set and hsm_clear.
4918  *
4919  * @mode  if LFS_HSM_SET, set the flags, if LFS_HSM_CLEAR, clear the flags.
4920  */
4921 static int lfs_hsm_change_flags(int argc, char **argv, int mode)
4922 {
4923         struct option long_opts[] = {
4924         { .val = 'A',   .name = "archived",     .has_arg = no_argument },
4925         { .val = 'a',   .name = "noarchive",    .has_arg = no_argument },
4926         { .val = 'd',   .name = "dirty",        .has_arg = no_argument },
4927         { .val = 'e',   .name = "exists",       .has_arg = no_argument },
4928         { .val = 'l',   .name = "lost",         .has_arg = no_argument },
4929         { .val = 'r',   .name = "norelease",    .has_arg = no_argument },
4930         { .val = 'i',   .name = "archive-id",   .has_arg = required_argument },
4931         { .name = NULL } };
4932         char short_opts[] = "lraAdei:";
4933         __u64 mask = 0;
4934         int c, rc;
4935         char *path;
4936         __u32 archive_id = 0;
4937         char *end = NULL;
4938
4939         if (argc < 3)
4940                 return CMD_HELP;
4941
4942         while ((c = getopt_long(argc, argv, short_opts,
4943                                 long_opts, NULL)) != -1) {
4944                 switch (c) {
4945                 case 'l':
4946                         mask |= HS_LOST;
4947                         break;
4948                 case 'a':
4949                         mask |= HS_NOARCHIVE;
4950                         break;
4951                 case 'A':
4952                         mask |= HS_ARCHIVED;
4953                         break;
4954                 case 'r':
4955                         mask |= HS_NORELEASE;
4956                         break;
4957                 case 'd':
4958                         mask |= HS_DIRTY;
4959                         break;
4960                 case 'e':
4961                         mask |= HS_EXISTS;
4962                         break;
4963                 case 'i':
4964                         archive_id = strtol(optarg, &end, 10);
4965                         if (*end != '\0') {
4966                                 fprintf(stderr, "invalid archive_id: '%s'\n",
4967                                         end);
4968                                 return CMD_HELP;
4969                         }
4970                         break;
4971                 case '?':
4972                         return CMD_HELP;
4973                 default:
4974                         fprintf(stderr, "error: %s: option '%s' unrecognized\n",
4975                                 argv[0], argv[optind - 1]);
4976                         return CMD_HELP;
4977                 }
4978         }
4979
4980         /* User should have specified a flag */
4981         if (mask == 0)
4982                 return CMD_HELP;
4983
4984         while (optind < argc) {
4985
4986                 path = argv[optind];
4987
4988                 /* If mode == 0, this means we apply the mask. */
4989                 if (mode == LFS_HSM_SET)
4990                         rc = llapi_hsm_state_set(path, mask, 0, archive_id);
4991                 else
4992                         rc = llapi_hsm_state_set(path, 0, mask, 0);
4993
4994                 if (rc != 0) {
4995                         fprintf(stderr, "Can't change hsm flags for %s: %s\n",
4996                                 path, strerror(errno = -rc));
4997                         return rc;
4998                 }
4999                 optind++;
5000         }
5001
5002         return 0;
5003 }
5004
5005 static int lfs_hsm_action(int argc, char **argv)
5006 {
5007         int                              rc;
5008         int                              i = 1;
5009         char                            *path;
5010         struct hsm_current_action        hca;
5011         struct hsm_extent                he;
5012         enum hsm_user_action             hua;
5013         enum hsm_progress_states         hps;
5014
5015         if (argc < 2)
5016                 return CMD_HELP;
5017
5018         do {
5019                 path = argv[i];
5020
5021                 rc = llapi_hsm_current_action(path, &hca);
5022                 if (rc) {
5023                         fprintf(stderr, "can't get hsm action for %s: %s\n",
5024                                 path, strerror(errno = -rc));
5025                         return rc;
5026                 }
5027                 he = hca.hca_location;
5028                 hua = hca.hca_action;
5029                 hps = hca.hca_state;
5030
5031                 printf("%s: %s", path, hsm_user_action2name(hua));
5032
5033                 /* Skip file without action */
5034                 if (hca.hca_action == HUA_NONE) {
5035                         printf("\n");
5036                         continue;
5037                 }
5038
5039                 printf(" %s ", hsm_progress_state2name(hps));
5040
5041                 if ((hps == HPS_RUNNING) &&
5042                     (hua == HUA_ARCHIVE || hua == HUA_RESTORE))
5043                         printf("(%llu bytes moved)\n",
5044                                (unsigned long long)he.length);
5045                 else if ((he.offset + he.length) == LUSTRE_EOF)
5046                         printf("(from %llu to EOF)\n",
5047                                (unsigned long long)he.offset);
5048                 else
5049                         printf("(from %llu to %llu)\n",
5050                                (unsigned long long)he.offset,
5051                                (unsigned long long)(he.offset + he.length));
5052
5053         } while (++i < argc);
5054
5055         return 0;
5056 }
5057
5058 static int lfs_hsm_set(int argc, char **argv)
5059 {
5060         return lfs_hsm_change_flags(argc, argv, LFS_HSM_SET);
5061 }
5062
5063 static int lfs_hsm_clear(int argc, char **argv)
5064 {
5065         return lfs_hsm_change_flags(argc, argv, LFS_HSM_CLEAR);
5066 }
5067
5068 /**
5069  * Check file state and return its fid, to be used by lfs_hsm_request().
5070  *
5071  * \param[in]     file      Path to file to check
5072  * \param[in,out] fid       Pointer to allocated lu_fid struct.
5073  * \param[in,out] last_dev  Pointer to last device id used.
5074  *
5075  * \return 0 on success.
5076  */
5077 static int lfs_hsm_prepare_file(const char *file, struct lu_fid *fid,
5078                                 dev_t *last_dev)
5079 {
5080         struct stat     st;
5081         int             rc;
5082
5083         rc = lstat(file, &st);
5084         if (rc) {
5085                 fprintf(stderr, "Cannot stat %s: %s\n", file, strerror(errno));
5086                 return -errno;
5087         }
5088         /* Checking for regular file as archiving as posix copytool
5089          * rejects archiving files other than regular files
5090          */
5091         if (!S_ISREG(st.st_mode)) {
5092                 fprintf(stderr, "error: \"%s\" is not a regular file\n", file);
5093                 return CMD_HELP;
5094         }
5095         /* A request should be ... */
5096         if (*last_dev != st.st_dev && *last_dev != 0) {
5097                 fprintf(stderr, "All files should be "
5098                         "on the same filesystem: %s\n", file);
5099                 return -EINVAL;
5100         }
5101         *last_dev = st.st_dev;
5102
5103         rc = llapi_path2fid(file, fid);
5104         if (rc) {
5105                 fprintf(stderr, "Cannot read FID of %s: %s\n",
5106                         file, strerror(-rc));
5107                 return rc;
5108         }
5109         return 0;
5110 }
5111
5112 /* Fill an HSM HUR item with a given file name.
5113  *
5114  * If mntpath is set, then the filename is actually a FID, and no
5115  * lookup on the filesystem will be performed.
5116  *
5117  * \param[in]  hur         the user request to fill
5118  * \param[in]  idx         index of the item inside the HUR to fill
5119  * \param[in]  mntpath     mountpoint of Lustre
5120  * \param[in]  fname       filename (if mtnpath is NULL)
5121  *                         or FID (if mntpath is set)
5122  * \param[in]  last_dev    pointer to last device id used
5123  *
5124  * \retval 0 on success
5125  * \retval CMD_HELP or a negative errno on error
5126  */
5127 static int fill_hur_item(struct hsm_user_request *hur, unsigned int idx,
5128                          const char *mntpath, const char *fname,
5129                          dev_t *last_dev)
5130 {
5131         struct hsm_user_item *hui = &hur->hur_user_item[idx];
5132         int rc;
5133
5134         hui->hui_extent.length = -1;
5135
5136         if (mntpath != NULL) {
5137                 if (*fname == '[')
5138                         fname++;
5139                 rc = sscanf(fname, SFID, RFID(&hui->hui_fid));
5140                 if (rc == 3) {
5141                         rc = 0;
5142                 } else {
5143                         fprintf(stderr, "hsm: '%s' is not a valid FID\n",
5144                                 fname);
5145                         rc = -EINVAL;
5146                 }
5147         } else {
5148                 rc = lfs_hsm_prepare_file(fname, &hui->hui_fid, last_dev);
5149         }
5150
5151         if (rc == 0)
5152                 hur->hur_request.hr_itemcount++;
5153
5154         return rc;
5155 }
5156
5157 static int lfs_hsm_request(int argc, char **argv, int action)
5158 {
5159         struct option            long_opts[] = {
5160                 {"filelist", 1, 0, 'l'},
5161                 {"data", 1, 0, 'D'},
5162                 {"archive", 1, 0, 'a'},
5163                 {"mntpath", 1, 0, 'm'},
5164                 {0, 0, 0, 0}
5165         };
5166         dev_t                    last_dev = 0;
5167         char                     short_opts[] = "l:D:a:m:";
5168         struct hsm_user_request *hur, *oldhur;
5169         int                      c, i;
5170         size_t                   len;
5171         int                      nbfile;
5172         char                    *line = NULL;
5173         char                    *filelist = NULL;
5174         char                     fullpath[PATH_MAX];
5175         char                    *opaque = NULL;
5176         int                      opaque_len = 0;
5177         int                      archive_id = 0;
5178         FILE                    *fp;
5179         int                      nbfile_alloc = 0;
5180         char                    *some_file = NULL;
5181         char                    *mntpath = NULL;
5182         int                      rc;
5183
5184         if (argc < 2)
5185                 return CMD_HELP;
5186
5187         while ((c = getopt_long(argc, argv, short_opts,
5188                                 long_opts, NULL)) != -1) {
5189                 switch (c) {
5190                 case 'l':
5191                         filelist = optarg;
5192                         break;
5193                 case 'D':
5194                         opaque = optarg;
5195                         break;
5196                 case 'a':
5197                         if (action != HUA_ARCHIVE &&
5198                             action != HUA_REMOVE) {
5199                                 fprintf(stderr,
5200                                         "error: -a is supported only "
5201                                         "when archiving or removing\n");
5202                                 return CMD_HELP;
5203                         }
5204                         archive_id = atoi(optarg);
5205                         break;
5206                 case 'm':
5207                         if (some_file == NULL) {
5208                                 mntpath = optarg;
5209                                 some_file = strdup(optarg);
5210                         }
5211                         break;
5212                 case '?':
5213                         return CMD_HELP;
5214                 default:
5215                         fprintf(stderr, "error: %s: option '%s' unrecognized\n",
5216                                 argv[0], argv[optind - 1]);
5217                         return CMD_HELP;
5218                 }
5219         }
5220
5221         /* All remaining args are files, so we have at least nbfile */
5222         nbfile = argc - optind;
5223
5224         if ((nbfile == 0) && (filelist == NULL))
5225                 return CMD_HELP;
5226
5227         if (opaque != NULL)
5228                 opaque_len = strlen(opaque);
5229
5230         /* Alloc the request structure with enough place to store all files
5231          * from command line. */
5232         hur = llapi_hsm_user_request_alloc(nbfile, opaque_len);
5233         if (hur == NULL) {
5234                 fprintf(stderr, "Cannot create the request: %s\n",
5235                         strerror(errno));
5236                 return errno;
5237         }
5238         nbfile_alloc = nbfile;
5239
5240         hur->hur_request.hr_action = action;
5241         hur->hur_request.hr_archive_id = archive_id;
5242         hur->hur_request.hr_flags = 0;
5243
5244         /* All remaining args are files, add them */
5245         if (nbfile != 0 && some_file == NULL)
5246                 some_file = strdup(argv[optind]);
5247
5248         for (i = 0; i < nbfile; i++) {
5249                 rc = fill_hur_item(hur, i, mntpath, argv[optind + i],
5250                                    &last_dev);
5251                 if (rc)
5252                         goto out_free;
5253         }
5254
5255         /* from here stop using nb_file, use hur->hur_request.hr_itemcount */
5256
5257         /* If a filelist was specified, read the filelist from it. */
5258         if (filelist != NULL) {
5259                 fp = fopen(filelist, "r");
5260                 if (fp == NULL) {
5261                         fprintf(stderr, "Cannot read the file list %s: %s\n",
5262                                 filelist, strerror(errno));
5263                         rc = -errno;
5264                         goto out_free;
5265                 }
5266
5267                 while ((rc = getline(&line, &len, fp)) != -1) {
5268                         /* If allocated buffer was too small, get something
5269                          * larger */
5270                         if (nbfile_alloc <= hur->hur_request.hr_itemcount) {
5271                                 ssize_t size;
5272
5273                                 nbfile_alloc = nbfile_alloc * 2 + 1;
5274                                 oldhur = hur;
5275                                 hur = llapi_hsm_user_request_alloc(nbfile_alloc,
5276                                                                    opaque_len);
5277                                 if (hur == NULL) {
5278                                         fprintf(stderr, "hsm: cannot allocate "
5279                                                 "the request: %s\n",
5280                                                 strerror(errno));
5281                                         hur = oldhur;
5282                                         rc = -errno;
5283                                         fclose(fp);
5284                                         goto out_free;
5285                                 }
5286                                 size = hur_len(oldhur);
5287                                 if (size < 0) {
5288                                         fprintf(stderr, "hsm: cannot allocate "
5289                                                 "%u files + %u bytes data\n",
5290                                             oldhur->hur_request.hr_itemcount,
5291                                             oldhur->hur_request.hr_data_len);
5292                                         free(hur);
5293                                         hur = oldhur;
5294                                         rc = -E2BIG;
5295                                         fclose(fp);
5296                                         goto out_free;
5297                                 }
5298                                 memcpy(hur, oldhur, size);
5299                                 free(oldhur);
5300                         }
5301
5302                         /* Chop CR */
5303                         if (line[strlen(line) - 1] == '\n')
5304                                 line[strlen(line) - 1] = '\0';
5305
5306                         rc = fill_hur_item(hur, hur->hur_request.hr_itemcount,
5307                                            mntpath, line, &last_dev);
5308                         if (rc) {
5309                                 fclose(fp);
5310                                 goto out_free;
5311                         }
5312
5313                         if (some_file == NULL) {
5314                                 some_file = line;
5315                                 line = NULL;
5316                         }
5317                 }
5318
5319                 rc = fclose(fp);
5320                 free(line);
5321         }
5322
5323         /* If a --data was used, add it to the request */
5324         hur->hur_request.hr_data_len = opaque_len;
5325         if (opaque != NULL)
5326                 memcpy(hur_data(hur), opaque, opaque_len);
5327
5328         /* Send the HSM request */
5329         if (realpath(some_file, fullpath) == NULL) {
5330                 fprintf(stderr, "Could not find path '%s': %s\n",
5331                         some_file, strerror(errno));
5332         }
5333         rc = llapi_hsm_request(fullpath, hur);
5334         if (rc) {
5335                 fprintf(stderr, "Cannot send HSM request (use of %s): %s\n",
5336                         some_file, strerror(-rc));
5337                 goto out_free;
5338         }
5339
5340 out_free:
5341         free(some_file);
5342         free(hur);
5343         return rc;
5344 }
5345
5346 static int lfs_hsm_archive(int argc, char **argv)
5347 {
5348         return lfs_hsm_request(argc, argv, HUA_ARCHIVE);
5349 }
5350
5351 static int lfs_hsm_restore(int argc, char **argv)
5352 {
5353         return lfs_hsm_request(argc, argv, HUA_RESTORE);
5354 }
5355
5356 static int lfs_hsm_release(int argc, char **argv)
5357 {
5358         return lfs_hsm_request(argc, argv, HUA_RELEASE);
5359 }
5360
5361 static int lfs_hsm_remove(int argc, char **argv)
5362 {
5363         return lfs_hsm_request(argc, argv, HUA_REMOVE);
5364 }
5365
5366 static int lfs_hsm_cancel(int argc, char **argv)
5367 {
5368         return lfs_hsm_request(argc, argv, HUA_CANCEL);
5369 }
5370
5371 static int lfs_swap_layouts(int argc, char **argv)
5372 {
5373         if (argc != 3)
5374                 return CMD_HELP;
5375
5376         return llapi_swap_layouts(argv[1], argv[2], 0, 0,
5377                                   SWAP_LAYOUTS_KEEP_MTIME |
5378                                   SWAP_LAYOUTS_KEEP_ATIME);
5379 }
5380
5381 static const char *const ladvise_names[] = LU_LADVISE_NAMES;
5382
5383 static enum lu_ladvise_type lfs_get_ladvice(const char *string)
5384 {
5385         enum lu_ladvise_type advice;
5386
5387         for (advice = 0;
5388              advice < ARRAY_SIZE(ladvise_names); advice++) {
5389                 if (ladvise_names[advice] == NULL)
5390                         continue;
5391                 if (strcmp(string, ladvise_names[advice]) == 0)
5392                         return advice;
5393         }
5394
5395         return LU_LADVISE_INVALID;
5396 }
5397
5398 static int lfs_ladvise(int argc, char **argv)
5399 {
5400         struct option            long_opts[] = {
5401                 {"advice",      required_argument,      0, 'a'},
5402                 {"background",  no_argument,            0, 'b'},
5403                 {"end",         required_argument,      0, 'e'},
5404                 {"start",       required_argument,      0, 's'},
5405                 {"length",      required_argument,      0, 'l'},
5406                 {0, 0, 0, 0}
5407         };
5408         char                     short_opts[] = "a:be:l:s:";
5409         int                      c;
5410         int                      rc = 0;
5411         const char              *path;
5412         int                      fd;
5413         struct llapi_lu_ladvise  advice;
5414         enum lu_ladvise_type     advice_type = LU_LADVISE_INVALID;
5415         unsigned long long       start = 0;
5416         unsigned long long       end = LUSTRE_EOF;
5417         unsigned long long       length = 0;
5418         unsigned long long       size_units;
5419         unsigned long long       flags = 0;
5420
5421         optind = 0;
5422         while ((c = getopt_long(argc, argv, short_opts,
5423                                 long_opts, NULL)) != -1) {
5424                 switch (c) {
5425                 case 'a':
5426                         advice_type = lfs_get_ladvice(optarg);
5427                         if (advice_type == LU_LADVISE_INVALID) {
5428                                 fprintf(stderr, "%s: invalid advice type "
5429                                         "'%s'\n", argv[0], optarg);
5430                                 fprintf(stderr, "Valid types:");
5431
5432                                 for (advice_type = 0;
5433                                      advice_type < ARRAY_SIZE(ladvise_names);
5434                                      advice_type++) {
5435                                         if (ladvise_names[advice_type] == NULL)
5436                                                 continue;
5437                                         fprintf(stderr, " %s",
5438                                                 ladvise_names[advice_type]);
5439                                 }
5440                                 fprintf(stderr, "\n");
5441
5442                                 return CMD_HELP;
5443                         }
5444                         break;
5445                 case 'b':
5446                         flags |= LF_ASYNC;
5447                         break;
5448                 case 'e':
5449                         size_units = 1;
5450                         rc = llapi_parse_size(optarg, &end,
5451                                               &size_units, 0);
5452                         if (rc) {
5453                                 fprintf(stderr, "%s: bad end offset '%s'\n",
5454                                         argv[0], optarg);
5455                                 return CMD_HELP;
5456                         }
5457                         break;
5458                 case 's':
5459                         size_units = 1;
5460                         rc = llapi_parse_size(optarg, &start,
5461                                               &size_units, 0);
5462                         if (rc) {
5463                                 fprintf(stderr, "%s: bad start offset "
5464                                         "'%s'\n", argv[0], optarg);
5465                                 return CMD_HELP;
5466                         }
5467                         break;
5468                 case 'l':
5469                         size_units = 1;
5470                         rc = llapi_parse_size(optarg, &length,
5471                                               &size_units, 0);
5472                         if (rc) {
5473                                 fprintf(stderr, "%s: bad length '%s'\n",
5474                                         argv[0], optarg);
5475                                 return CMD_HELP;
5476                         }
5477                         break;
5478                 case '?':
5479                         return CMD_HELP;
5480                 default:
5481                         fprintf(stderr, "%s: option '%s' unrecognized\n",
5482                                 argv[0], argv[optind - 1]);
5483                         return CMD_HELP;
5484                 }
5485         }
5486
5487         if (advice_type == LU_LADVISE_INVALID) {
5488                 fprintf(stderr, "%s: please give an advice type\n", argv[0]);
5489                 fprintf(stderr, "Valid types:");
5490                 for (advice_type = 0; advice_type < ARRAY_SIZE(ladvise_names);
5491                      advice_type++) {
5492                         if (ladvise_names[advice_type] == NULL)
5493                                 continue;
5494                         fprintf(stderr, " %s", ladvise_names[advice_type]);
5495                 }
5496                 fprintf(stderr, "\n");
5497                 return CMD_HELP;
5498         }
5499
5500         if (argc <= optind) {
5501                 fprintf(stderr, "%s: please give one or more file names\n",
5502                         argv[0]);
5503                 return CMD_HELP;
5504         }
5505
5506         if (end != LUSTRE_EOF && length != 0 && end != start + length) {
5507                 fprintf(stderr, "%s: conflicting arguments of -l and -e\n",
5508                         argv[0]);
5509                 return CMD_HELP;
5510         }
5511
5512         if (end == LUSTRE_EOF && length != 0)
5513                 end = start + length;
5514
5515         if (end <= start) {
5516                 fprintf(stderr, "%s: range [%llu, %llu] is invalid\n",
5517                         argv[0], start, end);
5518                 return CMD_HELP;
5519         }
5520
5521         while (optind < argc) {
5522                 int rc2;
5523
5524                 path = argv[optind++];
5525
5526                 fd = open(path, O_RDONLY);
5527                 if (fd < 0) {
5528                         fprintf(stderr, "%s: cannot open file '%s': %s\n",
5529                                 argv[0], path, strerror(errno));
5530                         rc2 = -errno;
5531                         goto next;
5532                 }
5533
5534                 advice.lla_start = start;
5535                 advice.lla_end = end;
5536                 advice.lla_advice = advice_type;
5537                 advice.lla_value1 = 0;
5538                 advice.lla_value2 = 0;
5539                 advice.lla_value3 = 0;
5540                 advice.lla_value4 = 0;
5541                 rc2 = llapi_ladvise(fd, flags, 1, &advice);
5542                 close(fd);
5543                 if (rc2 < 0) {
5544                         fprintf(stderr, "%s: cannot give advice '%s' to file "
5545                                 "'%s': %s\n", argv[0],
5546                                 ladvise_names[advice_type],
5547                                 path, strerror(errno));
5548                 }
5549 next:
5550                 if (rc == 0 && rc2 < 0)
5551                         rc = rc2;
5552         }
5553         return rc;
5554 }
5555
5556 static int lfs_list_commands(int argc, char **argv)
5557 {
5558         char buffer[81] = ""; /* 80 printable chars + terminating NUL */
5559
5560         Parser_list_commands(cmdlist, buffer, sizeof(buffer), NULL, 0, 4);
5561
5562         return 0;
5563 }
5564
5565 int main(int argc, char **argv)
5566 {
5567         int rc;
5568
5569         /* Ensure that liblustreapi constructor has run */
5570         if (!liblustreapi_initialized)
5571                 fprintf(stderr, "liblustreapi was not properly initialized\n");
5572
5573         setlinebuf(stdout);
5574
5575         Parser_init("lfs > ", cmdlist);
5576
5577         progname = argv[0]; /* Used in error messages */
5578         if (argc > 1) {
5579                 rc = Parser_execarg(argc - 1, argv + 1, cmdlist);
5580         } else {
5581                 rc = Parser_commands();
5582         }
5583
5584         return rc < 0 ? -rc : rc;
5585 }
5586
5587 #ifdef _LUSTRE_IDL_H_
5588 /* Everything we need here should be included by lustreapi.h. */
5589 # error "lfs should not depend on lustre_idl.h"
5590 #endif /* _LUSTRE_IDL_H_ */