Whamcloud - gitweb
LU-19098 hsm: don't print progname twice with lhsmtool
[fs/lustre-release.git] / lustre / utils / liblustreapi.c
1 // SPDX-License-Identifier: LGPL-2.1+
2 /*
3  * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
4  * Use is subject to license terms.
5  *
6  * Copyright (c) 2011, 2017, Intel Corporation.
7  */
8 /*
9  * This file is part of Lustre, http://www.lustre.org/
10  *
11  * Author: Peter J. Braam <braam@clusterfs.com>
12  * Author: Phil Schwan <phil@clusterfs.com>
13  * Author: Robert Read <rread@clusterfs.com>
14  */
15
16 /* for O_DIRECTORY */
17 #ifndef _GNU_SOURCE
18 #define _GNU_SOURCE
19 #endif
20
21 #include <ctype.h>
22 #include <dirent.h>
23 #include <errno.h>
24 #include <fcntl.h>
25 #include <grp.h>
26 #include <mntent.h>
27 #include <pwd.h>
28 #include <stdlib.h>
29 #include <stdio.h>
30 #include <string.h>
31 #include <stddef.h>
32 #include <sys/ioctl.h>
33 #include <unistd.h>
34 #include <stdarg.h>
35 #include <sys/stat.h>
36 #include <sys/statfs.h>
37 #include <sys/syscall.h>
38 #include <sys/time.h>
39 #include <sys/types.h>
40 #include <sys/xattr.h>
41 #include <sys/sysmacros.h>
42 #include <time.h>
43 #include <fnmatch.h>
44 #include <libgen.h> /* for dirname() */
45 #include <linux/limits.h>
46 #ifdef HAVE_LINUX_UNISTD_H
47 #include <linux/unistd.h>
48 #else
49 #include <unistd.h>
50 #endif
51 #include <poll.h>
52 #include <time.h>
53 #include <inttypes.h>
54 #include <pthread.h>
55
56 #include <libcfs/util/ioctl.h>
57 #include <libcfs/util/param.h>
58 #include <libcfs/util/string.h>
59 #include <linux/lnet/lnetctl.h>
60 #include <lustre/lustreapi.h>
61 #include <linux/lustre/lustre_ostid.h>
62 #include <linux/lustre/lustre_ioctl.h>
63 #include "lstddef.h"
64 #include "lustreapi_internal.h"
65
66 #define FORMATTED_BUF_LEN       1024
67
68 #ifndef DEFAULT_PROJID
69 #define DEFAULT_PROJID  0
70 #endif
71
72 static int llapi_msg_level = LLAPI_MSG_MAX;
73 const char *liblustreapi_cmd;
74
75 struct lustre_foreign_type lu_foreign_types[] = {
76         {.lft_type = LU_FOREIGN_TYPE_NONE,      .lft_name = "none"},
77         {.lft_type = LU_FOREIGN_TYPE_POSIX,     .lft_name = "posix"},
78         {.lft_type = LU_FOREIGN_TYPE_PCCRW,     .lft_name = "pccrw"},
79         {.lft_type = LU_FOREIGN_TYPE_PCCRO,     .lft_name = "pccro"},
80         {.lft_type = LU_FOREIGN_TYPE_S3,        .lft_name = "S3"},
81         {.lft_type = LU_FOREIGN_TYPE_SYMLINK,   .lft_name = "symlink"},
82         /* must be the last element */
83         {.lft_type = LU_FOREIGN_TYPE_UNKNOWN, .lft_name = NULL}
84         /* array max dimension must be <= UINT32_MAX */
85 };
86
87 void llapi_msg_set_level(int level)
88 {
89         /* ensure level is in the good range */
90         if (level < LLAPI_MSG_OFF)
91                 llapi_msg_level = LLAPI_MSG_OFF;
92         else if (level > LLAPI_MSG_MAX)
93                 llapi_msg_level = LLAPI_MSG_MAX;
94         else
95                 llapi_msg_level = level;
96 }
97
98 int llapi_msg_get_level(void)
99 {
100         return llapi_msg_level;
101 }
102
103 void llapi_set_command_name(const char *cmd)
104 {
105         liblustreapi_cmd = cmd;
106 }
107
108 void llapi_clear_command_name(void)
109 {
110         liblustreapi_cmd = NULL;
111 }
112
113 static void error_callback_default(enum llapi_message_level level, int err,
114                                    const char *fmt, va_list ap)
115 {
116         bool has_nl = strchr(fmt, '\n') != NULL;
117
118         if (liblustreapi_cmd != NULL)
119                 fprintf(stderr, "%s %s: ", program_invocation_short_name,
120                         liblustreapi_cmd);
121         else
122                 fprintf(stderr, "%s: ", program_invocation_short_name);
123
124
125         if (level & LLAPI_MSG_NO_ERRNO) {
126                 vfprintf(stderr, fmt, ap);
127                 if (!has_nl)
128                         fprintf(stderr, "\n");
129         } else {
130                 char *newfmt;
131
132                 /*
133                  * Remove trailing linefeed so error string can be appended.
134                  * @fmt is a const string, so we can't modify it directly.
135                  */
136                 if (has_nl && (newfmt = strdup(fmt)))
137                         *strrchr(newfmt, '\n') = '\0';
138                 else
139                         newfmt = (char *)fmt;
140
141                 vfprintf(stderr, newfmt, ap);
142                 if (newfmt != fmt)
143                         free(newfmt);
144                 fprintf(stderr, ": %s (%d)\n", strerror(err), err);
145         }
146 }
147
148 static void info_callback_default(enum llapi_message_level level, int err,
149                                   const char *fmt, va_list ap)
150 {
151         if (err != 0) {
152                 if (liblustreapi_cmd != NULL) {
153                         fprintf(stdout, "%s %s: ",
154                                 program_invocation_short_name,
155                                 liblustreapi_cmd);
156                 } else {
157                         fprintf(stdout, "%s: ", program_invocation_short_name);
158                 }
159         }
160         vfprintf(stdout, fmt, ap);
161 }
162
163 static llapi_log_callback_t llapi_error_callback = error_callback_default;
164 static llapi_log_callback_t llapi_info_callback = info_callback_default;
165
166
167 /* llapi_error will preserve errno */
168 void llapi_error(enum llapi_message_level level, int err, const char *fmt, ...)
169 {
170         va_list  args;
171         int      tmp_errno = errno;
172
173         if ((level & LLAPI_MSG_MASK) > llapi_msg_level)
174                 return;
175
176         va_start(args, fmt);
177         llapi_error_callback(level, abs(err), fmt, args);
178         va_end(args);
179         errno = tmp_errno;
180 }
181
182 /* llapi_printf will preserve errno */
183 void llapi_printf(enum llapi_message_level level, const char *fmt, ...)
184 {
185         va_list  args;
186         int      tmp_errno = errno;
187
188         if ((level & LLAPI_MSG_MASK) > llapi_msg_level)
189                 return;
190
191         va_start(args, fmt);
192         llapi_info_callback(level, 0, fmt, args);
193         va_end(args);
194         errno = tmp_errno;
195 }
196
197 /**
198  * Set a custom error logging function. Passing in NULL will reset the logging
199  * callback to its default value.
200  *
201  * This function returns the value of the old callback.
202  */
203 llapi_log_callback_t llapi_error_callback_set(llapi_log_callback_t cb)
204 {
205         llapi_log_callback_t    old = llapi_error_callback;
206
207         if (cb != NULL)
208                 llapi_error_callback = cb;
209         else
210                 llapi_error_callback = error_callback_default;
211
212         return old;
213 }
214
215 /**
216  * Set a custom info logging function. Passing in NULL will reset the logging
217  * callback to its default value.
218  *
219  * This function returns the value of the old callback.
220  */
221 llapi_log_callback_t llapi_info_callback_set(llapi_log_callback_t cb)
222 {
223         llapi_log_callback_t    old = llapi_info_callback;
224
225         if (cb != NULL)
226                 llapi_info_callback = cb;
227         else
228                 llapi_info_callback = info_callback_default;
229
230         return old;
231 }
232
233 /**
234  * Convert a size string (with optional suffix) into binary value.
235  *
236  * \param optarg [in]           string containing numeric value with optional
237  *                              KMGTPE suffix to specify the unit size.
238  *                              The \a string may be a decimal value.
239  * \param size [out]            pointer to integer numeric value to be returned
240  * \param size_units [in]       units of \a string if dimensionless.  Must be
241  *                              initialized by caller. If zero, units = bytes.
242  * \param bytes_spec [in]       if suffix 'b' means bytes or 512-byte sectors.
243  *
244  * \retval 0                    success
245  * \retval -EINVAL              negative or too large size, or unknown suffix
246  */
247 int llapi_parse_size(const char *optarg, unsigned long long *size,
248                      unsigned long long *size_units, int bytes_spec)
249 {
250         char *end;
251         char *argbuf = (char *)optarg;
252         unsigned long long frac = 0, frac_d = 1;
253
254         if (strncmp(optarg, "-", 1) == 0)
255                 return -EINVAL;
256
257         if (*size_units == 0)
258                 *size_units = 1;
259
260         *size = strtoull(argbuf, &end, 0);
261         if (end != NULL && *end == '.') {
262                 int i;
263
264                 argbuf = end + 1;
265                 frac = strtoull(argbuf, &end, 10);
266                 /* count decimal places */
267                 for (i = 0; i < (end - argbuf); i++)
268                         frac_d *= 10;
269         }
270
271         if (*end != '\0') {
272                 char next = tolower(*(end + 1));
273
274                 switch (tolower(*end)) {
275                 case 'b':
276                         if (bytes_spec) {
277                                 *size_units = 1;
278                         } else {
279                                 if (*size & (~0ULL << (64 - 9)))
280                                         return -EINVAL;
281                                 *size_units = 1 << 9;
282                         }
283                         break;
284                 case 'c':
285                         *size_units = 1;
286                         break;
287                 case 'k':
288                         if (*size & (~0ULL << (64 - 10)))
289                                 return -EINVAL;
290                         *size_units = 1 << 10;
291                         break;
292                 case 'm':
293                         if (*size & (~0ULL << (64 - 20)))
294                                 return -EINVAL;
295                         *size_units = 1 << 20;
296                         break;
297                 case 'g':
298                         if (*size & (~0ULL << (64 - 30)))
299                                 return -EINVAL;
300                         *size_units = 1 << 30;
301                         break;
302                 case 't':
303                         if (*size & (~0ULL << (64 - 40)))
304                                 return -EINVAL;
305                         *size_units = 1ULL << 40;
306                         break;
307                 case 'p':
308                         if (*size & (~0ULL << (64 - 50)))
309                                 return -EINVAL;
310                         *size_units = 1ULL << 50;
311                         break;
312                 case 'e':
313                         if (*size & (~0ULL << (64 - 60)))
314                                 return -EINVAL;
315                         *size_units = 1ULL << 60;
316                         break;
317                 default:
318                         return -EINVAL;
319                 }
320                 if (next != '\0' && next != 'i' && next != 'b')
321                         return -EINVAL;
322         }
323         *size = *size * *size_units + frac * *size_units / frac_d;
324
325         return 0;
326 }
327
328 /**
329  * Verify the setstripe parameters before using.
330  * This is a pair method for comp_args_to_layout()/llapi_layout_sanity_cb()
331  * when just 1 component or a non-PFL layout is given.
332  *
333  * \param[in] param             stripe parameters
334  * \param[in] pool_name         pool name
335  * \param[in] fsname            lustre FS name
336  *
337  * \retval                      0, success
338  *                              < 0, error code on failre
339  */
340 static int llapi_stripe_param_verify(const struct llapi_stripe_param *param,
341                                      const char **pool_name, char *fsname)
342 {
343         int count;
344         static int page_size;
345         int rc = 0;
346
347         if (page_size == 0) {
348                 /*
349                  * 64 KB is the largest common page size (on ia64/PPC/ARM),
350                  * but check the local page size just in case. The page_size
351                  * will not change for the lifetime of this process at least.
352                  */
353                 page_size = LOV_MIN_STRIPE_SIZE;
354                 if (getpagesize() > page_size) {
355                         page_size = getpagesize();
356                         llapi_err_noerrno(LLAPI_MSG_WARN,
357                                           "warning: page size (%u) larger than expected (%u)",
358                                           page_size, LOV_MIN_STRIPE_SIZE);
359                 }
360         }
361         if (!llapi_stripe_size_is_aligned(param->lsp_stripe_size)) {
362                 rc = -EINVAL;
363                 llapi_error(LLAPI_MSG_ERROR, rc,
364                             "error: bad stripe_size %llu, must be an even multiple of %d bytes",
365                             param->lsp_stripe_size, page_size);
366                 goto out;
367         }
368         if (!llapi_stripe_index_is_valid(param->lsp_stripe_offset)) {
369                 rc = -EINVAL;
370                 llapi_error(LLAPI_MSG_ERROR, rc, "error: bad stripe offset %d",
371                             param->lsp_stripe_offset);
372                 goto out;
373         }
374         if (llapi_stripe_size_is_too_big(param->lsp_stripe_size)) {
375                 rc = -EINVAL;
376                 llapi_error(LLAPI_MSG_ERROR, rc,
377                             "error: stripe size '%llu' over 4GB limit",
378                             param->lsp_stripe_size);
379                 goto out;
380         }
381
382         count = param->lsp_stripe_count;
383         if (param->lsp_stripe_pattern & LOV_PATTERN_MDT) {
384                 rc = -EINVAL;
385                 llapi_error(LLAPI_MSG_ERROR, rc,
386                             "Invalid pattern: '-L mdt', must be specified "
387                             "with -E\n");
388                 goto out;
389         } else {
390                 if (!llapi_stripe_count_is_valid(count)) {
391                         rc = -EINVAL;
392                         llapi_error(LLAPI_MSG_ERROR, rc,
393                                     "Invalid stripe count %d\n", count);
394                         goto out;
395                 }
396         }
397
398         /* Make sure we have a good pool */
399         if (*pool_name != NULL) {
400                 if (!llapi_pool_name_is_valid(pool_name)) {
401                         rc = -EINVAL;
402                         llapi_error(LLAPI_MSG_ERROR, rc,
403                                     "Invalid Poolname '%s'", *pool_name);
404                         goto out;
405                 }
406
407                 if (!lov_pool_is_ignored((const char *) *pool_name)) {
408                         /* Make sure the pool exists */
409                         rc = llapi_search_ost(fsname, *pool_name, NULL);
410                         if (rc < 0) {
411                                 llapi_error(LLAPI_MSG_ERROR, rc,
412                                             "pool '%s fsname %s' does not exist",
413                                             *pool_name, fsname);
414                                 rc = -EINVAL;
415                                 goto out;
416                         }
417                 }
418         }
419
420 out:
421         errno = -rc;
422         return rc;
423 }
424
425 static int dir_stripe_limit_check(int stripe_offset, int stripe_count,
426                                   int hash_type)
427 {
428         int rc;
429
430         if (!llapi_dir_stripe_index_is_valid(stripe_offset)) {
431                 rc = -EINVAL;
432                 llapi_error(LLAPI_MSG_ERROR, rc, "error: bad stripe offset %d",
433                                 stripe_offset);
434                 return rc;
435         }
436         if (!llapi_dir_stripe_count_is_valid(stripe_count)) {
437                 rc = -EINVAL;
438                 llapi_error(LLAPI_MSG_ERROR, rc, "error: bad stripe count %d",
439                                 stripe_count);
440                 return rc;
441         }
442
443         if (!llapi_dir_hash_type_is_valid(hash_type)) {
444                 rc = -EINVAL;
445                 llapi_error(LLAPI_MSG_ERROR, rc, "error: bad hash type %d",
446                                 hash_type);
447                 return rc;
448         }
449         return 0;
450 }
451
452 /*
453  * Trim a trailing newline from a string, if it exists.
454  */
455 int llapi_chomp_string(char *buf)
456 {
457         if (!buf || !*buf)
458                 return 0;
459
460         while (buf[1])
461                 buf++;
462
463         if (*buf != '\n')
464                 return 0;
465
466         *buf = '\0';
467         return '\n';
468 }
469
470 /*
471  * Wrapper to grab parameter settings for {lov,lmv}.*-clilov-*.* values
472  */
473 static int get_param_tgt(const char *path, enum tgt_type type,
474                          const char *param, char *buf, size_t buf_size)
475 {
476         const char *typestr = type == LOV_TYPE ? "lov" : "lmv";
477         struct obd_uuid uuid;
478         int rc;
479
480         rc = llapi_file_get_type_uuid(path, type, &uuid);
481         if (rc != 0)
482                 return rc;
483
484         rc = get_lustre_param_value(typestr, uuid.uuid, FILTER_BY_EXACT, param,
485                                     buf, buf_size);
486         return rc;
487 }
488
489 static int get_mds_md_size(const char *path)
490 {
491         int md_size = lov_user_md_size(LOV_MAX_STRIPE_COUNT, LOV_USER_MAGIC_V3);
492
493         /*
494          * Rather than open the file and do the ioctl to get the
495          * instance name and close the file and search for the param
496          * file and open the param file and read the param file and
497          * parse the value and close the param file, let's just return
498          * a large enough value. It's 2020, RAM is cheap and this is
499          * much faster.
500          */
501
502         if (md_size < XATTR_SIZE_MAX)
503                 md_size = XATTR_SIZE_MAX;
504
505         return md_size;
506 }
507
508 int llapi_get_agent_uuid(char *path, char *buf, size_t bufsize)
509 {
510         return get_param_tgt(path, LMV_TYPE, "uuid", buf, bufsize);
511 }
512
513 /**
514  * Open a Lustre file.
515  *
516  * \param name     the name of the file to be opened
517  * \param flags    access mode, see flags in open(2)
518  * \param mode     permission of the file if it is created, see mode in open(2)
519  * \param param    stripe pattern of the newly created file
520  *
521  * \retval         file descriptor of opened file
522  * \retval         negative errno on failure
523  */
524 int llapi_file_open_param(const char *name, int flags, mode_t mode,
525                           const struct llapi_stripe_param *param)
526 {
527         char fsname[MAX_OBD_NAME + 1] = { 0 };
528         struct lov_user_md *lum = NULL;
529         const char *pool_name = param->lsp_pool;
530         bool use_default_striping = false;
531         size_t lum_size;
532         int fd, rc = 0;
533
534         /* Make sure we are on a Lustre file system */
535         if (pool_name && !lov_pool_is_ignored(pool_name)) {
536                 rc = llapi_search_fsname(name, fsname);
537                 if (rc) {
538                         llapi_error(LLAPI_MSG_ERROR, rc,
539                                     "'%s' is not on a Lustre filesystem", name);
540                         return rc;
541                 }
542         }
543
544         /* Check if the stripe pattern is sane. */
545         rc = llapi_stripe_param_verify(param, &pool_name, fsname);
546         if (rc < 0)
547                 return rc;
548
549         if (param->lsp_is_specific)
550                 lum_size = lov_user_md_size(param->lsp_stripe_count,
551                                             LOV_USER_MAGIC_SPECIFIC);
552         else if (pool_name)
553                 lum_size = sizeof(struct lov_user_md_v3);
554         else
555                 lum_size = sizeof(*lum);
556
557         lum = calloc(1, lum_size);
558         if (lum == NULL)
559                 return -ENOMEM;
560
561 retry_open:
562         if (!use_default_striping)
563                 fd = open(name, flags | O_LOV_DELAY_CREATE, mode);
564         else
565                 fd = open(name, flags, mode);
566         if (fd < 0) {
567                 if (errno == EISDIR && !(flags & O_DIRECTORY)) {
568                         flags = O_DIRECTORY | O_RDONLY;
569                         goto retry_open;
570                 }
571         }
572
573         if (fd < 0) {
574                 rc = -errno;
575                 llapi_error(LLAPI_MSG_ERROR, rc, "unable to open '%s'", name);
576                 free(lum);
577                 return rc;
578         }
579
580         /*  Initialize IOCTL striping pattern structure */
581         lum->lmm_magic = LOV_USER_MAGIC_V1;
582         lum->lmm_pattern = param->lsp_stripe_pattern;
583         lum->lmm_stripe_size = param->lsp_stripe_size;
584         lum->lmm_stripe_count = param->lsp_stripe_count;
585         lum->lmm_stripe_offset = param->lsp_stripe_offset;
586         if (pool_name != NULL) {
587                 struct lov_user_md_v3 *lumv3 = (void *)lum;
588
589                 lumv3->lmm_magic = LOV_USER_MAGIC_V3;
590                 snprintf(lumv3->lmm_pool_name, sizeof(lumv3->lmm_pool_name),
591                          "%s", pool_name);
592         }
593         if (param->lsp_is_specific) {
594                 struct lov_user_md_v3 *lumv3 = (void *)lum;
595                 int i;
596
597                 lumv3->lmm_magic = LOV_USER_MAGIC_SPECIFIC;
598                 if (pool_name == NULL) {
599                         /*
600                          * LOV_USER_MAGIC_SPECIFIC uses v3 format plus specified
601                          * OST list, therefore if pool is not specified we have
602                          * to pack a null pool name for placeholder.
603                          */
604                         memset(lumv3->lmm_pool_name, 0,
605                                sizeof(lumv3->lmm_pool_name));
606                 }
607
608                 for (i = 0; i < param->lsp_stripe_count; i++)
609                         lumv3->lmm_objects[i].l_ost_idx = param->lsp_osts[i];
610         }
611
612         if (!use_default_striping && ioctl(fd, LL_IOC_LOV_SETSTRIPE, lum) != 0) {
613                 char errbuf[512] = "stripe already set";
614                 char *errmsg = errbuf;
615
616                 rc = -errno;
617                 if (rc != -EEXIST && rc != -EALREADY)
618                         strncpy(errbuf, strerror(errno), sizeof(errbuf) - 1);
619                 if (rc == -EREMOTEIO)
620                         snprintf(errbuf, sizeof(errbuf),
621                                  "inactive OST among your specified %d OST(s)",
622                                  param->lsp_stripe_count);
623                 close(fd);
624                 /* the only reason we get EACESS on the ioctl is if setstripe
625                  * has been explicitly restricted, normal permission errors
626                  * happen earlier on open() and we never call ioctl()
627                  */
628                 if (rc == -EACCES) {
629                         errmsg = "Setstripe is restricted by your administrator, default striping applied";
630                         llapi_err_noerrno(LLAPI_MSG_WARN,
631                                           "setstripe warning for '%s': %s",
632                                           name, errmsg);
633                         rc = remove(name);
634                         if (rc) {
635                                 llapi_err_noerrno(LLAPI_MSG_ERROR,
636                                                   "setstripe error for '%s': %s",
637                                                   name, strerror(errno));
638                                 goto out;
639                         }
640                         use_default_striping = true;
641                         goto retry_open;
642                 } else {
643                         llapi_err_noerrno(LLAPI_MSG_ERROR,
644                                           "setstripe error for '%s': %s", name,
645                                           errmsg);
646                 }
647                 fd = rc;
648         }
649
650 out:
651         free(lum);
652
653         return fd;
654 }
655
656 int llapi_file_is_encrypted(int fd)
657 {
658         unsigned long flags;
659         int rc;
660
661         rc = ioctl(fd, FS_IOC_GETFLAGS, &flags);
662         if (rc == -1)
663                 return -errno;
664
665         return !!(flags & LUSTRE_ENCRYPT_FL);
666 }
667
668 int llapi_file_open_pool(const char *name, int flags, int mode,
669                          unsigned long long stripe_size, int stripe_offset,
670                          int stripe_count, enum lov_pattern stripe_pattern,
671                          char *pool_name)
672 {
673         const struct llapi_stripe_param param = {
674                 .lsp_stripe_size = stripe_size,
675                 .lsp_stripe_count = stripe_count,
676                 .lsp_stripe_pattern = stripe_pattern,
677                 .lsp_stripe_offset = stripe_offset,
678                 .lsp_pool = pool_name
679         };
680         return llapi_file_open_param(name, flags, mode, &param);
681 }
682
683 int llapi_file_open(const char *name, int flags, int mode,
684                     unsigned long long stripe_size, int stripe_offset,
685                     int stripe_count, enum lov_pattern stripe_pattern)
686 {
687         return llapi_file_open_pool(name, flags, mode, stripe_size,
688                                     stripe_offset, stripe_count,
689                                     stripe_pattern, NULL);
690 }
691
692 int llapi_file_create_foreign(const char *name, mode_t mode, __u32 type,
693                               __u32 flags, char *foreign_lov)
694 {
695         size_t len;
696         struct lov_foreign_md *lfm;
697         bool use_default_striping = false;
698         int fd, rc;
699
700         if (foreign_lov == NULL) {
701                 rc = -EINVAL;
702                 llapi_error(LLAPI_MSG_ERROR, rc,
703                             "foreign LOV EA content must be provided");
704                 goto out_err;
705         }
706
707         len = strlen(foreign_lov);
708         if (len > XATTR_SIZE_MAX - offsetof(struct lov_foreign_md, lfm_value) ||
709             len <= 0) {
710                 rc = -EINVAL;
711                 llapi_error(LLAPI_MSG_ERROR, rc,
712                             "foreign LOV EA size %zu (must be 0 < len < %zu)",
713                             len, XATTR_SIZE_MAX -
714                             offsetof(struct lov_foreign_md, lfm_value));
715                 goto out_err;
716         }
717
718         lfm = malloc(len + offsetof(struct lov_foreign_md, lfm_value));
719         if (lfm == NULL) {
720                 rc = -ENOMEM;
721                 llapi_error(LLAPI_MSG_ERROR, rc,
722                             "failed to allocate lov_foreign_md");
723                 goto out_err;
724         }
725
726 retry_open:
727         if (!use_default_striping)
728                 fd = open(name, O_WRONLY|O_CREAT|O_LOV_DELAY_CREATE, mode);
729         else
730                 fd = open(name, O_WRONLY|O_CREAT, mode);
731         if (fd == -1) {
732                 fd = -errno;
733                 llapi_error(LLAPI_MSG_ERROR, fd, "open '%s' failed", name);
734                 goto out_free;
735         }
736
737         lfm->lfm_magic = LOV_USER_MAGIC_FOREIGN;
738         lfm->lfm_length = len;
739         lfm->lfm_type = type;
740         lfm->lfm_flags = flags;
741         memcpy(lfm->lfm_value, foreign_lov, len);
742
743         if (!use_default_striping && ioctl(fd, LL_IOC_LOV_SETSTRIPE, lfm) != 0) {
744                 char *errmsg;
745
746                 rc = -errno;
747                 if (errno == ENOTTY)
748                         errmsg = "not on a Lustre filesystem";
749                 else if (errno == EEXIST || errno == EALREADY)
750                         errmsg = "stripe already set";
751                 else if (errno == EACCES)
752                         errmsg = "Setstripe is restricted by your administrator, default striping applied";
753                 else
754                         errmsg = strerror(errno);
755
756                 close(fd);
757                 /* the only reason we get ENOPERM on the ioctl is if setstripe
758                  * has been explicitly restricted, normal permission errors
759                  * happen earlier on open() and we never call ioctl()
760                  */
761                 if (rc == -EACCES) {
762                         llapi_err_noerrno(LLAPI_MSG_WARN,
763                                           "setstripe warning for '%s': %s",
764                                           name, errmsg);
765                         rc = remove(name);
766                         if (rc) {
767                                 llapi_err_noerrno(LLAPI_MSG_ERROR,
768                                                   "setstripe error for '%s': %s",
769                                                   name, strerror(errno));
770                                 goto out_free;
771                         }
772                         use_default_striping = true;
773                         goto retry_open;
774                 } else {
775                         llapi_err_noerrno(LLAPI_MSG_ERROR,
776                                           "setstripe error for '%s': %s", name,
777                                           errmsg);
778                 }
779
780                 fd = rc;
781         }
782
783 out_free:
784         free(lfm);
785
786         return fd;
787
788 out_err:
789         errno = -rc;
790         return rc;
791 }
792
793 int llapi_file_create(const char *name, unsigned long long stripe_size,
794                       int stripe_offset, int stripe_count,
795                       enum lov_pattern stripe_pattern)
796 {
797         int fd;
798
799         fd = llapi_file_open_pool(name, O_CREAT | O_WRONLY, 0644, stripe_size,
800                                   stripe_offset, stripe_count, stripe_pattern,
801                                   NULL);
802         if (fd < 0)
803                 return fd;
804
805         close(fd);
806         return 0;
807 }
808
809 int llapi_file_create_pool(const char *name, unsigned long long stripe_size,
810                            int stripe_offset, int stripe_count,
811                            enum lov_pattern stripe_pattern, char *pool_name)
812 {
813         int fd;
814
815         fd = llapi_file_open_pool(name, O_CREAT | O_WRONLY, 0644, stripe_size,
816                                   stripe_offset, stripe_count, stripe_pattern,
817                                   pool_name);
818         if (fd < 0)
819                 return fd;
820
821         close(fd);
822         return 0;
823 }
824
825 static int verify_dir_param(const char *name,
826                             const struct llapi_stripe_param *param)
827 {
828         char fsname[MAX_OBD_NAME + 1] = { 0 };
829         char *pool_name = param->lsp_pool;
830         int rc;
831
832         /* Make sure we are on a Lustre file system */
833         rc = llapi_search_fsname(name, fsname);
834         if (rc) {
835                 llapi_error(LLAPI_MSG_ERROR, rc,
836                             "'%s' is not on a Lustre filesystem",
837                             name);
838                 return rc;
839         }
840
841         /* Check if the stripe pattern is sane. */
842         rc = dir_stripe_limit_check(param->lsp_stripe_offset,
843                                     param->lsp_stripe_count,
844                                     param->lsp_stripe_pattern);
845         if (rc != 0)
846                 return rc;
847
848         /* Make sure we have a good pool */
849         if (pool_name != NULL) {
850                 /*
851                  * in case user gives the full pool name <fsname>.<poolname>,
852                  * strip the fsname
853                  */
854                 char *ptr = strchr(pool_name, '.');
855
856                 if (ptr != NULL) {
857                         *ptr = '\0';
858                         if (strcmp(pool_name, fsname) != 0) {
859                                 *ptr = '.';
860                                 llapi_err_noerrno(LLAPI_MSG_ERROR,
861                                         "Pool '%s' is not on filesystem '%s'",
862                                         pool_name, fsname);
863                                 return -EINVAL;
864                         }
865                         pool_name = ptr + 1;
866                 }
867
868                 /* Make sure the pool exists and is non-empty */
869                 rc = llapi_search_tgt(fsname, pool_name, NULL, true);
870                 if (rc < 1) {
871                         char *err = rc == 0 ? "has no OSTs" : "does not exist";
872
873                         llapi_err_noerrno(LLAPI_MSG_ERROR, "pool '%s.%s' %s",
874                                           fsname, pool_name, err);
875                         return -EINVAL;
876                 }
877         }
878
879         /* sanity check of target list */
880         if (param->lsp_is_specific) {
881                 char mdtname[MAX_OBD_NAME + 64];
882                 bool found = false;
883                 int i;
884
885                 for (i = 0; i < param->lsp_stripe_count; i++) {
886                         snprintf(mdtname, sizeof(mdtname), "%s-MDT%04x_UUID",
887                                  fsname, param->lsp_tgts[i]);
888                         rc = llapi_search_tgt(fsname, pool_name, mdtname, true);
889                         if (rc <= 0) {
890                                 if (rc == 0)
891                                         rc = -ENODEV;
892
893                                 llapi_error(LLAPI_MSG_ERROR, rc,
894                                             "%s: cannot find MDT %s in %s",
895                                             __func__, mdtname,
896                                             pool_name != NULL ?
897                                             "pool" : "system");
898                                 return rc;
899                         }
900
901                         /* Make sure stripe offset is in MDT list. */
902                         if (param->lsp_tgts[i] == param->lsp_stripe_offset)
903                                 found = true;
904                 }
905                 if (!found) {
906                         llapi_error(LLAPI_MSG_ERROR, -EINVAL,
907                                     "%s: stripe offset '%d' is not in the target list",
908                                     __func__, param->lsp_stripe_offset);
909                         return -EINVAL;
910                 }
911         }
912
913         return 0;
914 }
915
916 static inline void param2lmu(struct lmv_user_md *lmu,
917                              const struct llapi_stripe_param *param)
918 {
919         lmu->lum_magic = param->lsp_is_specific ? LMV_USER_MAGIC_SPECIFIC :
920                                                   LMV_USER_MAGIC;
921         lmu->lum_stripe_count = param->lsp_stripe_count;
922         lmu->lum_stripe_offset = param->lsp_stripe_offset;
923         lmu->lum_hash_type = param->lsp_stripe_pattern;
924         lmu->lum_max_inherit = param->lsp_max_inherit;
925         lmu->lum_max_inherit_rr = param->lsp_max_inherit_rr;
926         if (param->lsp_is_specific) {
927                 int i;
928
929                 for (i = 0; i < param->lsp_stripe_count; i++)
930                         lmu->lum_objects[i].lum_mds = param->lsp_tgts[i];
931         }
932         if (param->lsp_pool)
933                 snprintf(lmu->lum_pool_name, sizeof(lmu->lum_pool_name), "%s",
934                          param->lsp_pool);
935 }
936
937 int llapi_dir_set_default_lmv(const char *name,
938                               const struct llapi_stripe_param *param)
939 {
940         struct lmv_user_md lmu = { 0 };
941         int fd;
942         int rc = 0;
943
944         rc = verify_dir_param(name, param);
945         if (rc)
946                 return rc;
947
948         /* TODO: default lmv doesn't support specific targets yet */
949         if (param->lsp_is_specific)
950                 return -EINVAL;
951
952         param2lmu(&lmu, param);
953
954         fd = open(name, O_DIRECTORY | O_RDONLY);
955         if (fd < 0) {
956                 rc = -errno;
957                 llapi_error(LLAPI_MSG_ERROR, rc, "unable to open '%s'", name);
958                 return rc;
959         }
960
961         rc = ioctl(fd, LL_IOC_LMV_SET_DEFAULT_STRIPE, &lmu);
962         if (rc < 0) {
963                 char *errmsg = "stripe already set";
964
965                 rc = -errno;
966                 if (errno != EEXIST && errno != EALREADY)
967                         errmsg = strerror(errno);
968
969                 llapi_err_noerrno(LLAPI_MSG_ERROR,
970                                   "default dirstripe error on '%s': %s",
971                                   name, errmsg);
972         }
973         close(fd);
974         return rc;
975 }
976
977 int llapi_dir_set_default_lmv_stripe(const char *name, int stripe_offset,
978                                      int stripe_count, int stripe_pattern,
979                                      const char *pool_name)
980 {
981         const struct llapi_stripe_param param = {
982                 .lsp_stripe_count = stripe_count,
983                 .lsp_stripe_offset = stripe_offset,
984                 .lsp_stripe_pattern = stripe_pattern,
985                 .lsp_pool = (char *)pool_name
986         };
987
988         return llapi_dir_set_default_lmv(name, &param);
989 }
990
991 /**
992  * Create a Lustre directory.
993  *
994  * \param name     the name of the directory to be created
995  * \param mode     permission of the file if it is created, see mode in open(2)
996  * \param param    stripe pattern of the newly created directory
997  *
998  * \retval         0 on success
999  * \retval         negative errno on failure
1000  */
1001 int llapi_dir_create(const char *name, mode_t mode,
1002                      const struct llapi_stripe_param *param)
1003 {
1004         struct lmv_user_md *lmu = NULL;
1005         size_t lmu_size;
1006         struct obd_ioctl_data data = { 0 };
1007         char rawbuf[8192];
1008         char *buf = rawbuf;
1009         char *dirpath = NULL;
1010         char *namepath = NULL;
1011         char *dir;
1012         char *filename;
1013         int fd, rc;
1014
1015         rc = verify_dir_param(name, param);
1016         if (rc)
1017                 return rc;
1018
1019         lmu_size = lmv_user_md_size(param->lsp_stripe_count,
1020                                     param->lsp_is_specific ?
1021                                          LMV_USER_MAGIC_SPECIFIC :
1022                                          LMV_USER_MAGIC);
1023
1024         lmu = calloc(1, lmu_size);
1025         if (lmu == NULL)
1026                 return -ENOMEM;
1027
1028         dirpath = strdup(name);
1029         if (!dirpath) {
1030                 free(lmu);
1031                 return -ENOMEM;
1032         }
1033
1034         namepath = strdup(name);
1035         if (!namepath) {
1036                 free(dirpath);
1037                 free(lmu);
1038                 return -ENOMEM;
1039         }
1040
1041         param2lmu(lmu, param);
1042
1043         filename = basename(namepath);
1044         dir = dirname(dirpath);
1045
1046         data.ioc_inlbuf1 = (char *)filename;
1047         data.ioc_inllen1 = strlen(filename) + 1;
1048         data.ioc_inlbuf2 = (char *)lmu;
1049         data.ioc_inllen2 = lmu_size;
1050         data.ioc_type = mode;
1051         if (param->lsp_is_create)
1052                 /* borrow obdo1.o_flags to store this flag */
1053                 data.ioc_obdo1.o_flags = OBD_FL_OBDMDEXISTS;
1054         rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf));
1055         if (rc) {
1056                 llapi_error(LLAPI_MSG_ERROR, rc,
1057                             "error: LL_IOC_LMV_SETSTRIPE pack failed '%s'.",
1058                             name);
1059                 goto out;
1060         }
1061
1062         fd = open(dir, O_DIRECTORY | O_RDONLY);
1063         if (fd < 0) {
1064                 rc = -errno;
1065                 llapi_error(LLAPI_MSG_ERROR, rc, "unable to open '%s'", name);
1066                 goto out;
1067         }
1068
1069         if (ioctl(fd, LL_IOC_LMV_SETSTRIPE, buf)) {
1070                 char *errmsg = "stripe already set";
1071
1072                 rc = -errno;
1073                 if (errno != EEXIST && errno != EALREADY)
1074                         errmsg = strerror(errno);
1075
1076                 llapi_err_noerrno(LLAPI_MSG_ERROR,
1077                                   "dirstripe error on '%s': %s", name, errmsg);
1078         }
1079         close(fd);
1080 out:
1081         free(namepath);
1082         free(dirpath);
1083         free(lmu);
1084         return rc;
1085 }
1086
1087 /**
1088  * Create a foreign directory.
1089  *
1090  * \param name     the name of the directory to be created
1091  * \param mode     permission of the file if it is created, see mode in open(2)
1092  * \param type     foreign type to be set in LMV EA
1093  * \param flags    foreign flags to be set in LMV EA
1094  * \param value    foreign pattern to be set in LMV EA
1095  *
1096  * \retval         0 on success
1097  * \retval         negative errno on failure
1098  */
1099 int llapi_dir_create_foreign(const char *name, mode_t mode, __u32 type,
1100                              __u32 flags, const char *value)
1101 {
1102         struct lmv_foreign_md *lfm = NULL;
1103         size_t lfm_size, len;
1104         struct obd_ioctl_data data = { 0 };
1105         char rawbuf[8192];
1106         char *buf = rawbuf;
1107         char *dirpath = NULL;
1108         char *namepath = NULL;
1109         char *dir;
1110         char *filename;
1111         int fd, rc;
1112
1113         len = strlen(value);
1114         if (len > XATTR_SIZE_MAX - offsetof(struct lmv_foreign_md, lfm_value) ||
1115             len <= 0) {
1116                 rc = -EINVAL;
1117                 llapi_error(LLAPI_MSG_ERROR, rc,
1118                             "invalid LOV EA length %zu (must be 0 < len < %zu)",
1119                             len, XATTR_SIZE_MAX -
1120                             offsetof(struct lmv_foreign_md, lfm_value));
1121                 return rc;
1122         }
1123         lfm_size = len + offsetof(struct lmv_foreign_md, lfm_value);
1124         lfm = calloc(1, lfm_size);
1125         if (lfm == NULL)
1126                 return -ENOMEM;
1127
1128         dirpath = strdup(name);
1129         if (!dirpath) {
1130                 free(lfm);
1131                 return -ENOMEM;
1132         }
1133
1134         namepath = strdup(name);
1135         if (!namepath) {
1136                 free(dirpath);
1137                 free(lfm);
1138                 return -ENOMEM;
1139         }
1140
1141         lfm->lfm_magic = LMV_MAGIC_FOREIGN;
1142         lfm->lfm_length = len;
1143         lfm->lfm_type = type;
1144         lfm->lfm_flags = flags;
1145         memcpy(lfm->lfm_value, value, len);
1146
1147         filename = basename(namepath);
1148         dir = dirname(dirpath);
1149
1150         data.ioc_inlbuf1 = (char *)filename;
1151         data.ioc_inllen1 = strlen(filename) + 1;
1152         data.ioc_inlbuf2 = (char *)lfm;
1153         data.ioc_inllen2 = lfm_size;
1154         data.ioc_type = mode;
1155         rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf));
1156         if (rc) {
1157                 llapi_error(LLAPI_MSG_ERROR, rc,
1158                             "error: LL_IOC_LMV_SETSTRIPE pack failed '%s'.",
1159                             name);
1160                 goto out;
1161         }
1162
1163         fd = open(dir, O_DIRECTORY | O_RDONLY);
1164         if (fd < 0) {
1165                 rc = -errno;
1166                 llapi_error(LLAPI_MSG_ERROR, rc, "unable to open '%s'", name);
1167                 goto out;
1168         }
1169
1170         if (ioctl(fd, LL_IOC_LMV_SETSTRIPE, buf)) {
1171                 char *errmsg = "stripe already set";
1172
1173                 rc = -errno;
1174                 if (errno != EEXIST && errno != EALREADY)
1175                         errmsg = strerror(errno);
1176
1177                 llapi_err_noerrno(LLAPI_MSG_ERROR,
1178                                   "dirstripe error on '%s': %s", name, errmsg);
1179         }
1180         close(fd);
1181 out:
1182         free(namepath);
1183         free(dirpath);
1184         free(lfm);
1185         return rc;
1186 }
1187
1188 int llapi_dir_create_pool(const char *name, int mode, int stripe_offset,
1189                           int stripe_count, enum lov_pattern stripe_pattern,
1190                           const char *pool_name)
1191 {
1192         const struct llapi_stripe_param param = {
1193                 .lsp_stripe_count = stripe_count,
1194                 .lsp_stripe_offset = stripe_offset,
1195                 .lsp_stripe_pattern = stripe_pattern,
1196                 .lsp_pool = (char *)pool_name
1197         };
1198
1199         return llapi_dir_create(name, mode, &param);
1200 }
1201
1202 /**
1203  * Get the list of pool members.
1204  * \param poolname    string of format \<fsname\>.\<poolname\>
1205  * \param members     caller-allocated array of char*
1206  * \param list_size   size of the members array
1207  * \param buffer      caller-allocated buffer for storing OST names
1208  * \param buffer_size size of the buffer
1209  *
1210  * \return number of members retrieved for this pool
1211  * \retval -error failure
1212  */
1213 int llapi_get_poolmembers(const char *poolname, char **members,
1214                           int list_size, char *buffer, int buffer_size)
1215 {
1216         char fsname[PATH_MAX];
1217         char *pool, *tmp;
1218         glob_t pathname;
1219         char buf[PATH_MAX];
1220         FILE *fd;
1221         int rc = 0;
1222         int nb_entries = 0;
1223         int used = 0;
1224
1225         /* name is FSNAME.POOLNAME */
1226         if (strlen(poolname) >= sizeof(fsname))
1227                 return -EOVERFLOW;
1228
1229         snprintf(fsname, sizeof(fsname), "%s", poolname);
1230         pool = strchr(fsname, '.');
1231         if (pool == NULL)
1232                 return -EINVAL;
1233
1234         *pool = '\0';
1235         pool++;
1236
1237         rc = poolpath(&pathname, fsname, NULL);
1238         if (rc != 0) {
1239                 llapi_error(LLAPI_MSG_ERROR, rc,
1240                             "Lustre filesystem '%s' not found",
1241                             fsname);
1242                 return rc;
1243         }
1244
1245         llapi_printf(LLAPI_MSG_NORMAL, "Pool: %s.%s\n", fsname, pool);
1246         rc = snprintf(buf, sizeof(buf), "%s/%s", pathname.gl_pathv[0], pool);
1247         cfs_free_param_data(&pathname);
1248         if (rc >= sizeof(buf))
1249                 return -EOVERFLOW;
1250         fd = fopen(buf, "r");
1251         if (fd == NULL) {
1252                 rc = -errno;
1253                 llapi_error(LLAPI_MSG_ERROR, rc, "cannot open %s", buf);
1254                 return rc;
1255         }
1256
1257         rc = 0;
1258         while (fgets(buf, sizeof(buf), fd) != NULL) {
1259                 if (nb_entries >= list_size) {
1260                         rc = -EOVERFLOW;
1261                         break;
1262                 }
1263                 buf[sizeof(buf) - 1] = '\0';
1264                 /* remove '\n' */
1265                 tmp = strchr(buf, '\n');
1266                 if (tmp != NULL)
1267                         *tmp = '\0';
1268                 if (used + strlen(buf) + 1 > buffer_size) {
1269                         rc = -EOVERFLOW;
1270                         break;
1271                 }
1272
1273                 strcpy(buffer + used, buf);
1274                 members[nb_entries] = buffer + used;
1275                 used += strlen(buf) + 1;
1276                 nb_entries++;
1277                 rc = nb_entries;
1278         }
1279
1280         fclose(fd);
1281         return rc;
1282 }
1283
1284 /**
1285  * Get the list of pools in a filesystem.
1286  * \param name        filesystem name or path
1287  * \param poollist    caller-allocated array of char*
1288  * \param list_size   size of the poollist array
1289  * \param buffer      caller-allocated buffer for storing pool names
1290  * \param buffer_size size of the buffer
1291  *
1292  * \return number of pools retrieved for this filesystem
1293  * \retval -error failure
1294  */
1295 int llapi_get_poollist(const char *name, char **poollist, int list_size,
1296                        char *buffer, int buffer_size)
1297 {
1298         glob_t pathname;
1299         char *fsname;
1300         char *ptr;
1301         DIR *dir;
1302         struct dirent *pool;
1303         int rc = 0;
1304         unsigned int nb_entries = 0;
1305         unsigned int used = 0;
1306         unsigned int i;
1307
1308         /* initialize output array */
1309         for (i = 0; i < list_size; i++)
1310                 poollist[i] = NULL;
1311
1312         /* is name a pathname ? */
1313         ptr = strchr(name, '/');
1314         if (ptr != NULL) {
1315                 char fsname_buf[MAXNAMLEN];
1316
1317                 /* We will need fsname for printing later */
1318                 rc = llapi_getname(name, fsname_buf, sizeof(fsname_buf));
1319                 if (rc)
1320                         return rc;
1321
1322                 ptr = strrchr(fsname_buf, '-');
1323                 if (ptr)
1324                         *ptr = '\0';
1325
1326                 fsname = strdup(fsname_buf);
1327                 if (!fsname)
1328                         return -ENOMEM;
1329         } else {
1330                 /* name is FSNAME */
1331                 fsname = strdup(name);
1332                 if (!fsname)
1333                         return -ENOMEM;
1334         }
1335
1336         rc = poolpath(&pathname, fsname, NULL);
1337         if (rc != 0) {
1338                 llapi_error(LLAPI_MSG_ERROR, rc,
1339                             "Lustre filesystem '%s' not found", name);
1340                 goto free_path;
1341         }
1342
1343         dir = opendir(pathname.gl_pathv[0]);
1344         if (dir == NULL) {
1345                 rc = -errno;
1346                 llapi_error(LLAPI_MSG_ERROR, rc,
1347                             "Could not open pool list for '%s'",
1348                             name);
1349                 goto free_path;
1350         }
1351
1352         do {
1353                 errno = 0;
1354                 pool = readdir(dir);
1355                 if (pool == NULL) {
1356                         rc = -errno;
1357                         goto free_dir;
1358                 }
1359
1360                 /* ignore . and .. */
1361                 if (!strcmp(pool->d_name, ".") || !strcmp(pool->d_name, ".."))
1362                         continue;
1363
1364                 /* check output bounds */
1365                 if (nb_entries >= list_size) {
1366                         rc = -EOVERFLOW;
1367                         goto free_dir_no_msg;
1368                 }
1369
1370                 /* +2 for '.' and final '\0' */
1371                 if (used + strlen(pool->d_name) + strlen(fsname) + 2
1372                     > buffer_size) {
1373                         rc = -EOVERFLOW;
1374                         goto free_dir_no_msg;
1375                 }
1376
1377                 sprintf(buffer + used, "%s.%s", fsname, pool->d_name);
1378                 poollist[nb_entries] = buffer + used;
1379                 used += strlen(pool->d_name) + strlen(fsname) + 2;
1380                 nb_entries++;
1381         } while (1);
1382
1383 free_dir:
1384         if (rc)
1385                 llapi_error(LLAPI_MSG_ERROR, rc,
1386                             "Error reading pool list for '%s'", name);
1387         else
1388                 llapi_printf(LLAPI_MSG_NORMAL, "Pools from %s:\n", fsname);
1389
1390 free_dir_no_msg:
1391         closedir(dir);
1392 free_path:
1393         cfs_free_param_data(&pathname);
1394         if (fsname)
1395                 free(fsname);
1396         return rc != 0 ? rc : nb_entries;
1397 }
1398
1399 /* wrapper for lfs.c and obd.c */
1400 int llapi_poollist(const char *name)
1401 {
1402         int poolcount, rc, i;
1403         char *buf, **pools;
1404
1405         rc = llapi_get_poolbuf(name, &buf, &pools, &poolcount);
1406         if (rc)
1407                 return rc;
1408
1409         for (i = 0; i < poolcount; i++)
1410                 llapi_printf(LLAPI_MSG_NORMAL, "%s\n", pools[i]);
1411         free(buf);
1412
1413         return 0;
1414 }
1415
1416 /**
1417  * Get buffer that holds uuids and the list of pools in a filesystem.
1418  *
1419  * \param name          filesystem name or path
1420  * \param buf           bufffer that has to be freed if function returns 0
1421  * \param pools         pointer to the list of pools in buffer
1422  * \param poolcount     number of pools
1423  *
1424  * \return 0 when found at least 1 pool, i.e. poolcount  > 0
1425  * \retval -error failure
1426  */
1427 int llapi_get_poolbuf(const char *name, char **buf,
1428                       char ***pools, int *poolcount)
1429 {
1430         /*
1431          * list of pool names (assume that pool count is smaller
1432          * than OST count)
1433          */
1434         char **list, *buffer = NULL, *fsname = (char *)name;
1435         char *poolname = NULL, *tmp = NULL, data[16];
1436         enum param_filter type = FILTER_BY_PATH;
1437         int obdcount, bufsize, rc, nb;
1438
1439         if (name == NULL)
1440                 return -EINVAL;
1441
1442         if (name[0] != '/') {
1443                 fsname = strdup(name);
1444                 if (fsname == NULL)
1445                         return -ENOMEM;
1446
1447                 poolname = strchr(fsname, '.');
1448                 if (poolname)
1449                         *poolname = '\0';
1450                 type = FILTER_BY_FS_NAME;
1451         }
1452
1453         rc = get_lustre_param_value("lov", fsname, type, "numobd",
1454                                     data, sizeof(data));
1455         if (rc < 0)
1456                 goto err;
1457         obdcount = atoi(data);
1458
1459         /*
1460          * Allocate space for each fsname-OST0000_UUID, 1 per OST,
1461          * and also an array to store the pointers for all that
1462          * allocated space.
1463          */
1464 retry_get_pools:
1465         bufsize = sizeof(struct obd_uuid) * obdcount;
1466         buffer = realloc(tmp, bufsize + sizeof(*list) * obdcount);
1467         if (buffer == NULL) {
1468                 rc = -ENOMEM;
1469                 goto err;
1470         }
1471         list = (char **) (buffer + bufsize);
1472
1473         if (!poolname) {
1474                 /* name is a path or fsname */
1475                 nb = llapi_get_poollist(name, list, obdcount,
1476                                         buffer, bufsize);
1477         } else {
1478                 /* name is a pool name (<fsname>.<poolname>) */
1479                 nb = llapi_get_poolmembers(name, list, obdcount,
1480                                            buffer, bufsize);
1481         }
1482
1483         if (nb == -EOVERFLOW) {
1484                 obdcount *= 2;
1485                 tmp = buffer;
1486                 goto retry_get_pools;
1487         }
1488
1489         rc = (nb < 0 ? nb : 0);
1490         if (!rc) {
1491                 *buf = buffer;
1492                 *pools = list;
1493                 *poolcount = nb;
1494         }
1495 err:
1496         /* Don't free buffer, it will be used later */
1497         if (rc && buffer)
1498                 free(buffer);
1499         if (fsname != NULL && type == FILTER_BY_FS_NAME)
1500                 free(fsname);
1501         return rc;
1502 }
1503
1504 #define OBD_NOT_FOUND           (-1)
1505
1506 static bool lmv_is_foreign(__u32 magic)
1507 {
1508         return magic == LMV_MAGIC_FOREIGN;
1509 }
1510
1511 void find_param_fini(struct find_param *param)
1512 {
1513         if (param->fp_migrate)
1514                 return;
1515
1516         if (param->fp_obd_indexes) {
1517                 free(param->fp_obd_indexes);
1518                 param->fp_obd_indexes = NULL;
1519         }
1520
1521         if (param->fp_lmd) {
1522                 free(param->fp_lmd);
1523                 param->fp_lmd = NULL;
1524         }
1525
1526         if (param->fp_lmv_md) {
1527                 free(param->fp_lmv_md);
1528                 param->fp_lmv_md = NULL;
1529         }
1530 }
1531
1532 int common_param_init(struct find_param *param, char *path)
1533 {
1534         int lum_size = get_mds_md_size(path);
1535
1536         if (lum_size < 0)
1537                 return lum_size;
1538
1539         /* migrate has fp_lmv_md initialized outside */
1540         if (param->fp_migrate)
1541                 return 0;
1542
1543         if (lum_size < PATH_MAX + 1)
1544                 lum_size = PATH_MAX + 1;
1545
1546         param->fp_lum_size = lum_size;
1547         param->fp_lmd = calloc(1, offsetof(typeof(*param->fp_lmd), lmd_lmm) +
1548                                lum_size);
1549         if (param->fp_lmd == NULL) {
1550                 llapi_error(LLAPI_MSG_ERROR, -ENOMEM,
1551                             "error: allocate %zu bytes for layout failed",
1552                             sizeof(lstat_t) + param->fp_lum_size);
1553                 return -ENOMEM;
1554         }
1555
1556         param->fp_lmv_stripe_count = 256;
1557         param->fp_lmv_md = calloc(1,
1558                                   lmv_user_md_size(param->fp_lmv_stripe_count,
1559                                                    LMV_USER_MAGIC_SPECIFIC));
1560         if (param->fp_lmv_md == NULL) {
1561                 llapi_error(LLAPI_MSG_ERROR, -ENOMEM,
1562                             "error: allocation of %d bytes for ioctl",
1563                             lmv_user_md_size(param->fp_lmv_stripe_count,
1564                                              LMV_USER_MAGIC_SPECIFIC));
1565                 find_param_fini(param);
1566                 return -ENOMEM;
1567         }
1568
1569         param->fp_got_uuids = 0;
1570         param->fp_obd_indexes = NULL;
1571         param->fp_obd_index = OBD_NOT_FOUND;
1572         param->fp_mdt_index = OBD_NOT_FOUND;
1573         return 0;
1574 }
1575
1576 int cb_common_fini(char *path, int p, int *dp, void *data,
1577                    struct dirent64 *de)
1578 {
1579         struct find_param *param = data;
1580
1581         param->fp_depth--;
1582         return 0;
1583 }
1584
1585 /* set errno upon failure */
1586 int open_parent(const char *path)
1587 {
1588         char *path_copy;
1589         char *parent_path;
1590         int parent;
1591
1592         path_copy = strdup(path);
1593         if (path_copy == NULL)
1594                 return -1;
1595
1596         parent_path = dirname(path_copy);
1597         parent = open(parent_path, O_RDONLY|O_NDELAY|O_DIRECTORY);
1598         free(path_copy);
1599
1600         return parent;
1601 }
1602
1603 static int cb_get_dirstripe(char *path, int *d, struct find_param *param)
1604 {
1605         int ret;
1606         bool did_nofollow = false;
1607
1608         if (!d || *d < 0)
1609                 return -ENOTDIR;
1610 again:
1611         param->fp_lmv_md->lum_stripe_count = param->fp_lmv_stripe_count;
1612         if (param->fp_get_default_lmv) {
1613 #ifdef HAVE_STATX
1614                 struct statx stx;
1615
1616                 /* open() may not fetch LOOKUP lock, statx() to ensure dir depth
1617                  * is set.
1618                  */
1619                 statx(*d, "", AT_EMPTY_PATH, STATX_MODE, &stx);
1620 #else
1621                 struct stat st;
1622
1623                 fstat(*d, &st);
1624 #endif
1625                 param->fp_lmv_md->lum_magic = LMV_USER_MAGIC;
1626         } else {
1627                 param->fp_lmv_md->lum_magic = LMV_MAGIC_V1;
1628         }
1629         if (param->fp_raw)
1630                 param->fp_lmv_md->lum_type = LMV_TYPE_RAW;
1631
1632         ret = ioctl(*d, LL_IOC_LMV_GETSTRIPE, param->fp_lmv_md);
1633
1634         /* if ENOTTY likely to be a fake symlink, so try again after
1635          * new open() with O_NOFOLLOW, but only once to prevent any
1636          * loop like for the path of a file/dir not on Lustre !!
1637          */
1638         if (ret < 0 && errno == ENOTTY && !did_nofollow) {
1639                 int fd, ret2;
1640                 struct stat st;
1641
1642                 did_nofollow = true;
1643                 fd = open(path, O_RDONLY | O_NOFOLLOW | O_NONBLOCK);
1644                 if (fd < 0) {
1645                         /* restore original errno */
1646                         errno = ENOTTY;
1647                         return ret;
1648                 }
1649                 if (fstat(fd, &st) != 0) {
1650                         errno = ENOTTY;
1651                         close(fd);
1652                         return ret;
1653                 }
1654                 if (!S_ISFIFO(st.st_mode))
1655                         fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) & ~O_NONBLOCK);
1656                 /* close original fd and set new */
1657                 close(*d);
1658                 *d = fd;
1659                 ret2 = ioctl(fd, LL_IOC_LMV_GETSTRIPE, param->fp_lmv_md);
1660                 if (ret2 < 0 && errno != E2BIG) {
1661                         /* restore original errno */
1662                         errno = ENOTTY;
1663                         return ret;
1664                 }
1665                 /* LMV is ok or need to handle E2BIG case now */
1666                 ret = ret2;
1667         }
1668
1669         if (errno == E2BIG && ret != 0) {
1670                 int stripe_count;
1671                 int lmv_size;
1672
1673                 /* if foreign LMV case, fake stripes number */
1674                 if (lmv_is_foreign(param->fp_lmv_md->lum_magic)) {
1675                         struct lmv_foreign_md *lfm;
1676
1677                         lfm = (struct lmv_foreign_md *)param->fp_lmv_md;
1678                         if (lfm->lfm_length < XATTR_SIZE_MAX -
1679                             offsetof(typeof(*lfm), lfm_value)) {
1680                                 uint32_t size = lfm->lfm_length +
1681                                              offsetof(typeof(*lfm), lfm_value);
1682
1683                                 stripe_count = lmv_foreign_to_md_stripes(size);
1684                         } else {
1685                                 llapi_error(LLAPI_MSG_ERROR, -EINVAL,
1686                                             "error: invalid %d foreign size returned from ioctl",
1687                                             lfm->lfm_length);
1688                                 return -EINVAL;
1689                         }
1690                 } else {
1691                         stripe_count = param->fp_lmv_md->lum_stripe_count;
1692                 }
1693                 if (stripe_count <= param->fp_lmv_stripe_count)
1694                         return ret;
1695
1696                 free(param->fp_lmv_md);
1697                 param->fp_lmv_stripe_count = stripe_count;
1698                 lmv_size = lmv_user_md_size(stripe_count,
1699                                             LMV_USER_MAGIC_SPECIFIC);
1700                 param->fp_lmv_md = malloc(lmv_size);
1701                 if (param->fp_lmv_md == NULL) {
1702                         llapi_error(LLAPI_MSG_ERROR, -ENOMEM,
1703                                     "error: allocation of %d bytes for ioctl",
1704                                     lmv_user_md_size(param->fp_lmv_stripe_count,
1705                                                      LMV_USER_MAGIC_SPECIFIC));
1706                         return -ENOMEM;
1707                 }
1708                 goto again;
1709         }
1710
1711         return ret;
1712 }
1713
1714 static void convert_lmd_statx(struct lov_user_mds_data *lmd_v2, lstat_t *st,
1715                               bool strict)
1716 {
1717         lmd_v2->lmd_stx.stx_blksize = st->st_blksize;
1718         lmd_v2->lmd_stx.stx_nlink = st->st_nlink;
1719         lmd_v2->lmd_stx.stx_uid = st->st_uid;
1720         lmd_v2->lmd_stx.stx_gid = st->st_gid;
1721         lmd_v2->lmd_stx.stx_mode = st->st_mode;
1722         lmd_v2->lmd_stx.stx_ino = st->st_ino;
1723         lmd_v2->lmd_stx.stx_size = st->st_size;
1724         lmd_v2->lmd_stx.stx_blocks = st->st_blocks;
1725         lmd_v2->lmd_stx.stx_atime.tv_sec = st->st_atime;
1726         lmd_v2->lmd_stx.stx_ctime.tv_sec = st->st_ctime;
1727         lmd_v2->lmd_stx.stx_mtime.tv_sec = st->st_mtime;
1728         lmd_v2->lmd_stx.stx_rdev_major = major(st->st_rdev);
1729         lmd_v2->lmd_stx.stx_rdev_minor = minor(st->st_rdev);
1730         lmd_v2->lmd_stx.stx_dev_major = major(st->st_dev);
1731         lmd_v2->lmd_stx.stx_dev_minor = minor(st->st_dev);
1732         lmd_v2->lmd_stx.stx_mask |= STATX_BASIC_STATS;
1733
1734         lmd_v2->lmd_flags = 0;
1735         if (strict) {
1736                 lmd_v2->lmd_flags |= OBD_MD_FLSIZE | OBD_MD_FLBLOCKS;
1737         } else {
1738                 lmd_v2->lmd_stx.stx_mask &= ~(STATX_SIZE | STATX_BLOCKS);
1739                 if (lmd_v2->lmd_stx.stx_size)
1740                         lmd_v2->lmd_flags |= OBD_MD_FLLAZYSIZE;
1741                 if (lmd_v2->lmd_stx.stx_blocks)
1742                         lmd_v2->lmd_flags |= OBD_MD_FLLAZYBLOCKS;
1743         }
1744         lmd_v2->lmd_flags |= OBD_MD_FLATIME | OBD_MD_FLMTIME | OBD_MD_FLCTIME |
1745                              OBD_MD_FLBLKSZ | OBD_MD_FLMODE | OBD_MD_FLTYPE |
1746                              OBD_MD_FLUID | OBD_MD_FLGID | OBD_MD_FLNLINK |
1747                              OBD_MD_FLRDEV;
1748
1749 }
1750
1751 static int convert_lmdbuf_v1v2(void *lmdbuf, int lmdlen)
1752 {
1753         struct lov_user_mds_data_v1 *lmd_v1 = lmdbuf;
1754         struct lov_user_mds_data *lmd_v2 = lmdbuf;
1755         lstat_t st;
1756         int size;
1757
1758         size = lov_comp_md_size((struct lov_comp_md_v1 *)&lmd_v1->lmd_lmm);
1759         if (size < 0)
1760                 return size;
1761
1762         if (lmdlen < sizeof(lmd_v1->lmd_st) + size)
1763                 return -EOVERFLOW;
1764
1765         st = lmd_v1->lmd_st;
1766         memmove(&lmd_v2->lmd_lmm, &lmd_v1->lmd_lmm,
1767                 lmdlen - (&lmd_v2->lmd_lmm - &lmd_v1->lmd_lmm));
1768         convert_lmd_statx(lmd_v2, &st, false);
1769         lmd_v2->lmd_lmmsize = 0;
1770         lmd_v2->lmd_padding = 0;
1771
1772         return 0;
1773 }
1774
1775 int get_lmd_info_fd(const char *path, int parent_fd, int dir_fd,
1776                     void *lmdbuf, int lmdlen, enum get_lmd_info_type type)
1777 {
1778         struct lov_user_mds_data *lmd = lmdbuf;
1779         static bool use_old_ioctl;
1780         unsigned long cmd;
1781         int ret = 0;
1782
1783         if (parent_fd < 0 && dir_fd < 0)
1784                 return -EINVAL;
1785         if (type != GET_LMD_INFO && type != GET_LMD_STRIPE)
1786                 return -EINVAL;
1787
1788         if (dir_fd >= 0) {
1789                 /*
1790                  * LL_IOC_MDC_GETINFO operates on the current directory inode
1791                  * and returns struct lov_user_mds_data, while
1792                  * LL_IOC_LOV_GETSTRIPE returns only struct lov_user_md.
1793                  */
1794                 if (type == GET_LMD_INFO)
1795                         cmd = use_old_ioctl ? LL_IOC_MDC_GETINFO_V1 :
1796                                               LL_IOC_MDC_GETINFO_V2;
1797                 else
1798                         cmd = LL_IOC_LOV_GETSTRIPE;
1799
1800 retry_getinfo:
1801                 ret = ioctl(dir_fd, cmd, lmdbuf);
1802                 if (ret < 0 && errno == ENOTTY &&
1803                     cmd == LL_IOC_MDC_GETINFO_V2) {
1804                         cmd = LL_IOC_MDC_GETINFO_V1;
1805                         use_old_ioctl = true;
1806                         goto retry_getinfo;
1807                 }
1808
1809                 if (cmd == LL_IOC_MDC_GETINFO_V1 && !ret)
1810                         ret = convert_lmdbuf_v1v2(lmdbuf, lmdlen);
1811
1812                 if (ret < 0 && errno == ENOTTY && type == GET_LMD_STRIPE) {
1813                         int dir_fd2;
1814
1815                         /* retry ioctl() after new open() with O_NOFOLLOW
1816                          * just in case it could be a fake symlink
1817                          * need using a new open() as dir_fd is being closed
1818                          * by caller
1819                          */
1820
1821                         dir_fd2 = open(path, O_RDONLY | O_NDELAY | O_NOFOLLOW);
1822                         if (dir_fd2 < 0) {
1823                                 /* return original error */
1824                                 errno = ENOTTY;
1825                         } else {
1826                                 ret = ioctl(dir_fd2, cmd, lmdbuf);
1827                                 /* pass new errno or success back to caller */
1828
1829                                 close(dir_fd2);
1830                         }
1831                 }
1832
1833         } else if (parent_fd >= 0) {
1834                 const char *fname = strrchr(path, '/');
1835
1836                 /*
1837                  * IOC_MDC_GETFILEINFO takes as input the filename (relative to
1838                  * the parent directory) and returns struct lov_user_mds_data,
1839                  * while IOC_MDC_GETFILESTRIPE returns only struct lov_user_md.
1840                  *
1841                  * This avoids opening, locking, and closing each file on the
1842                  * client if that is not needed. Multiple of these ioctl() can
1843                  * be done on the parent dir with a single open for all
1844                  * files in that directory, and it also doesn't pollute the
1845                  * client dcache with millions of dentries when traversing
1846                  * a large filesystem.
1847                  */
1848                 fname = (fname == NULL ? path : fname + 1);
1849
1850                 ret = snprintf(lmdbuf, lmdlen, "%s", fname);
1851                 if (ret < 0)
1852                         errno = -ret;
1853                 else if (ret >= lmdlen || ret++ == 0)
1854                         errno = EINVAL;
1855                 else {
1856                         if (type == GET_LMD_INFO)
1857                                 cmd = use_old_ioctl ? IOC_MDC_GETFILEINFO_V1 :
1858                                                       IOC_MDC_GETFILEINFO_V2;
1859                         else
1860                                 cmd = IOC_MDC_GETFILESTRIPE;
1861
1862 retry_getfileinfo:
1863                         ret = ioctl(parent_fd, cmd, lmdbuf);
1864                         if (ret < 0 && errno == ENOTTY &&
1865                             cmd == IOC_MDC_GETFILEINFO_V2) {
1866                                 cmd = IOC_MDC_GETFILEINFO_V1;
1867                                 use_old_ioctl = true;
1868                                 goto retry_getfileinfo;
1869                         }
1870
1871                         if (cmd == IOC_MDC_GETFILEINFO_V1 && !ret)
1872                                 ret = convert_lmdbuf_v1v2(lmdbuf, lmdlen);
1873                 }
1874         }
1875
1876         if (ret && type == GET_LMD_INFO) {
1877                 if (errno == ENOTTY) {
1878                         lstat_t st;
1879
1880                         /*
1881                          * ioctl is not supported, it is not a lustre fs.
1882                          * Do the regular lstat(2) instead.
1883                          */
1884                         ret = lstat_f(path, &st);
1885                         if (ret) {
1886                                 ret = -errno;
1887                                 llapi_error(LLAPI_MSG_ERROR, ret,
1888                                             "error: %s: lstat failed for %s",
1889                                             __func__, path);
1890                         }
1891
1892                         convert_lmd_statx(lmd, &st, true);
1893                         /*
1894                          * It may be wrong to set use_old_ioctl with true as
1895                          * the file is not a lustre fs. So reset it with false
1896                          * directly here.
1897                          */
1898                         use_old_ioctl = false;
1899                 } else if (errno == ENOENT) {
1900                         ret = -errno;
1901                         llapi_error(LLAPI_MSG_WARN, ret,
1902                                     "warning: %s does not exist", path);
1903                 } else if (errno != EISDIR && errno != ENODATA) {
1904                         ret = -errno;
1905                         llapi_error(LLAPI_MSG_ERROR, ret,
1906                                     "%s ioctl failed for %s.",
1907                                     dir_fd >= 0 ? "LL_IOC_MDC_GETINFO" :
1908                                     "IOC_MDC_GETFILEINFO", path);
1909                 }
1910         }
1911
1912         return ret;
1913 }
1914
1915 /**
1916  * Get the mirror layout info from a file.
1917  *
1918  * \param path [in]             a string containing the file path
1919  * \param lmmbuf [out]          pointer to an lov_user_md_v1 buffer
1920  *                              that will be set with the mirror layout info
1921  *                              from the file specified by \a path.
1922  *
1923  * \retval 0                    success
1924  * \retval -errno               on error
1925  */
1926 int llapi_get_lmm_from_path(const char *path, struct lov_user_md_v1 **lmmbuf)
1927 {
1928         ssize_t lmmlen;
1929         int p = -1;
1930         int rc = 0;
1931
1932         lmmlen = get_mds_md_size(path);
1933         if (lmmlen < 0)
1934                 return -EINVAL;
1935
1936         p = open_parent(path);
1937         if (p < 0)
1938                 return -errno;
1939
1940         *lmmbuf = calloc(1, lmmlen);
1941         if (*lmmbuf == NULL) {
1942                 rc = -errno;
1943                 goto out_close;
1944         }
1945
1946         rc = get_lmd_info_fd(path, p, 0, *lmmbuf, lmmlen, GET_LMD_STRIPE);
1947         if (rc < 0) {
1948                 free(*lmmbuf);
1949                 *lmmbuf = NULL;
1950         }
1951 out_close:
1952         close(p);
1953
1954         return rc;
1955 }
1956
1957 int llapi_semantic_traverse(char *path, int size, int parent,
1958                             semantic_func_t sem_init,
1959                             semantic_func_t sem_fini, void *data,
1960                             struct dirent64 *de)
1961 {
1962         struct find_param *param = (struct find_param *)data;
1963         struct dirent64 *dent;
1964         int len, ret, d, p = -1;
1965         DIR *dir = NULL;
1966
1967         ret = 0;
1968         len = strlen(path);
1969
1970         d = open(path, O_RDONLY|O_NDELAY|O_DIRECTORY);
1971         /* if an invalid fake dir symlink, opendir() will return EINVAL
1972          * instead of ENOTDIR. If a valid but dangling faked or real file/dir
1973          * symlink ENOENT will be returned. For a valid/resolved fake or real
1974          * file symlink ENOTDIR will be returned as for a regular file.
1975          * opendir() will be successful for a  valid and resolved fake or real
1976          * dir simlink or a regular dir.
1977          */
1978         if (d == -1 && errno != ENOTDIR && errno != EINVAL && errno != ENOENT) {
1979                 ret = -errno;
1980                 llapi_error(LLAPI_MSG_ERROR, ret, "%s: Failed to open '%s'",
1981                             __func__, path);
1982                 return ret;
1983         } else if (d == -1) {
1984                 if (errno == ENOENT || errno == EINVAL) {
1985                         int old_errno = errno;
1986
1987                         /* try to open with O_NOFOLLOW this will help
1988                          * differentiate fake vs real symlinks
1989                          * it is ok to not use O_DIRECTORY with O_RDONLY
1990                          * and it will prevent the need to deal with ENOTDIR
1991                          * error, instead of ELOOP, being returned by recent
1992                          * kernels for real symlinks
1993                          */
1994                         d = open(path, O_RDONLY|O_NDELAY|O_NOFOLLOW);
1995                         /* if a dangling real symlink should return ELOOP, or
1996                          * again ENOENT if really non-existing path, or E...??
1997                          * So return original error. If success or ENOTDIR, path
1998                          * is likely to be a fake dir/file symlink, so continue
1999                          */
2000                         if (d == -1) {
2001                                 ret =  -old_errno;
2002                                 goto out;
2003                         }
2004
2005                 }
2006
2007                 /* ENOTDIR */
2008                 if (parent == -1 && d == -1) {
2009                         /* Open the parent dir. */
2010                         p = open_parent(path);
2011                         if (p == -1) {
2012                                 ret = -errno;
2013                                 goto out;
2014                         }
2015                 }
2016         } else { /* d != -1 */
2017                 int d2;
2018
2019                 /* try to reopen dir with O_NOFOLLOW just in case of a foreign
2020                  * symlink dir
2021                  */
2022                 d2 = open(path, O_RDONLY|O_NDELAY|O_NOFOLLOW);
2023                 if (d2 != -1) {
2024                         close(d);
2025                         d = d2;
2026                 } else {
2027                         /* continue with d */
2028                         errno = 0;
2029                 }
2030         }
2031
2032         if (sem_init) {
2033                 ret = sem_init(path, (parent != -1) ? parent : p, &d, data, de);
2034                 if (ret)
2035                         goto err;
2036         }
2037
2038         if (d == -1)
2039                 goto out;
2040
2041         dir = fdopendir(d);
2042         if (dir == NULL) {
2043                 /* ENOTDIR if fake symlink, do not consider it as an error */
2044                 if (errno != ENOTDIR)
2045                         llapi_error(LLAPI_MSG_ERROR, errno,
2046                                     "fdopendir() failed");
2047                 else
2048                         errno = 0;
2049
2050                 goto out;
2051         }
2052
2053         while ((dent = readdir64(dir)) != NULL) {
2054                 int rc = 0;
2055
2056                 if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
2057                         continue;
2058
2059                 path[len] = 0;
2060                 if ((len + dent->d_reclen + 2) > size) {
2061                         llapi_err_noerrno(LLAPI_MSG_ERROR,
2062                                           "error: %s: string buffer too small for %s",
2063                                           __func__, path);
2064                         break;
2065                 }
2066                 strcat(path, "/");
2067                 strcat(path, dent->d_name);
2068
2069                 if (dent->d_type == DT_UNKNOWN) {
2070                         struct lov_user_mds_data *lmd = param->fp_lmd;
2071
2072                         rc = get_lmd_info_fd(path, d, -1, param->fp_lmd,
2073                                              param->fp_lum_size, GET_LMD_INFO);
2074                         if (rc == 0)
2075                                 dent->d_type = IFTODT(lmd->lmd_stx.stx_mode);
2076                         else if (ret == 0)
2077                                 ret = rc;
2078
2079                         if (rc == -ENOENT)
2080                                 continue;
2081                 }
2082
2083                 switch (dent->d_type) {
2084                 case DT_UNKNOWN:
2085                         llapi_err_noerrno(LLAPI_MSG_ERROR,
2086                                           "error: %s: '%s' is UNKNOWN type %d",
2087                                           __func__, dent->d_name, dent->d_type);
2088                         break;
2089                 case DT_DIR:
2090                         /* recursion down into a new subdirectory here */
2091                         if (param->fp_thread_count) {
2092                                 rc = work_unit_create_and_add(path, param,
2093                                                               dent);
2094                         } else {
2095                                 rc = llapi_semantic_traverse(path, size, d,
2096                                                              sem_init, sem_fini,
2097                                                              data, dent);
2098                         }
2099                         if (rc != 0 && ret == 0)
2100                                 ret = rc;
2101                         if (rc < 0 && rc != -EALREADY &&
2102                             param->fp_stop_on_error)
2103                                 goto out;
2104                         break;
2105                 default:
2106                         rc = 0;
2107                         if (sem_init) {
2108                                 rc = sem_init(path, d, NULL, data, dent);
2109                                 if (rc < 0 && ret == 0) {
2110                                         ret = rc;
2111                                         if (rc && rc != -EALREADY &&
2112                                             param->fp_stop_on_error)
2113                                                 goto out;
2114                                         break;
2115                                 }
2116                         }
2117                         if (sem_fini && rc == 0)
2118                                 sem_fini(path, d, NULL, data, dent);
2119                 }
2120         }
2121
2122 out:
2123         path[len] = 0;
2124
2125         if (sem_fini)
2126                 sem_fini(path, parent, &d, data, de);
2127 err:
2128         if (d != -1) {
2129                 if (dir)
2130                         closedir(dir);
2131                 else
2132                         close(d);
2133         }
2134         if (p != -1)
2135                 close(p);
2136         return ret;
2137 }
2138
2139 int param_callback(char *path, semantic_func_t sem_init,
2140                    semantic_func_t sem_fini, struct find_param *param)
2141 {
2142         int ret, len = strlen(path);
2143         char *buf;
2144
2145         if (len > PATH_MAX) {
2146                 ret = -EINVAL;
2147                 llapi_error(LLAPI_MSG_ERROR, ret,
2148                             "Path name '%s' is too long", path);
2149                 return ret;
2150         }
2151
2152         buf = (char *)malloc(2 * PATH_MAX);
2153         if (!buf)
2154                 return -ENOMEM;
2155
2156         ret = snprintf(buf, PATH_MAX + 1, "%s", path);
2157         if (ret < 0 || ret >= PATH_MAX + 1) {
2158                 ret = -ENAMETOOLONG;
2159                 goto out;
2160         }
2161         ret = common_param_init(param, buf);
2162         if (ret)
2163                 goto out;
2164
2165         param->fp_depth = 0;
2166
2167         ret = llapi_semantic_traverse(buf, 2 * PATH_MAX + 1, -1, sem_init,
2168                                       sem_fini, param, NULL);
2169 out:
2170         find_param_fini(param);
2171         free(buf);
2172         return ret < 0 ? ret : 0;
2173 }
2174
2175 int llapi_file_fget_lov_uuid(int fd, struct obd_uuid *lov_name)
2176 {
2177         int rc;
2178
2179         rc = llapi_ioctl(fd, OBD_IOC_GETDTNAME, lov_name);
2180         if (rc) {
2181                 rc = -errno;
2182                 llapi_error(LLAPI_MSG_ERROR, rc, "cannot get lov name");
2183         }
2184
2185         return rc;
2186 }
2187
2188 int llapi_file_fget_lmv_uuid(int fd, struct obd_uuid *lov_name)
2189 {
2190         int rc;
2191
2192         rc = llapi_ioctl(fd, OBD_IOC_GETMDNAME, lov_name);
2193         if (rc) {
2194                 rc = -errno;
2195                 llapi_error(LLAPI_MSG_ERROR, rc, "error: can't get lmv name.");
2196         }
2197
2198         return rc;
2199 }
2200
2201 int llapi_file_get_lov_uuid(const char *path, struct obd_uuid *lov_uuid)
2202 {
2203         int fd, rc;
2204
2205         /* do not follow faked symlinks */
2206         fd = open(path, O_RDONLY | O_NONBLOCK | O_NOFOLLOW);
2207         if (fd < 0) {
2208                 /* real symlink should have failed with ELOOP so retry without
2209                  * O_NOFOLLOW just in case
2210                  */
2211                 fd = open(path, O_RDONLY | O_NONBLOCK);
2212                 if (fd < 0) {
2213                         rc = -errno;
2214                         llapi_error(LLAPI_MSG_ERROR, rc, "cannot open '%s'",
2215                                     path);
2216                         return rc;
2217                 }
2218         }
2219
2220         rc = llapi_file_fget_lov_uuid(fd, lov_uuid);
2221
2222         close(fd);
2223         return rc;
2224 }
2225
2226 int llapi_file_get_lmv_uuid(const char *path, struct obd_uuid *lov_uuid)
2227 {
2228         int fd, rc;
2229
2230         fd = open(path, O_RDONLY | O_NONBLOCK);
2231         if (fd < 0) {
2232                 rc = -errno;
2233                 llapi_error(LLAPI_MSG_ERROR, rc, "error opening %s", path);
2234                 return rc;
2235         }
2236
2237         rc = llapi_file_fget_lmv_uuid(fd, lov_uuid);
2238
2239         close(fd);
2240         return rc;
2241 }
2242
2243 int llapi_file_fget_type_uuid(int fd, enum tgt_type type, struct obd_uuid *uuid)
2244 {
2245         unsigned int cmd = 0;
2246         int rc;
2247
2248         if (type == LOV_TYPE)
2249                 cmd = OBD_IOC_GETDTNAME;
2250         else if (type == LMV_TYPE)
2251                 cmd = OBD_IOC_GETMDNAME;
2252         else if (type == CLI_TYPE)
2253                 cmd = OBD_IOC_GETUUID;
2254
2255         rc = llapi_ioctl(fd, cmd, uuid);
2256         if (rc) {
2257                 rc = -errno;
2258                 llapi_error(LLAPI_MSG_ERROR, rc, "cannot get uuid");
2259         }
2260
2261         return rc;
2262 }
2263
2264 int llapi_file_get_type_uuid(const char *path, enum tgt_type type,
2265                         struct obd_uuid *uuid)
2266 {
2267         int fd, rc;
2268
2269         /* do not follow faked symlinks */
2270         fd = open(path, O_RDONLY | O_NONBLOCK | O_NOFOLLOW);
2271         if (fd < 0) {
2272                 /* real symlink should have failed with ELOOP so retry without
2273                  * O_NOFOLLOW just in case
2274                  */
2275                 fd = open(path, O_RDONLY | O_NONBLOCK);
2276                 if (fd < 0) {
2277                         rc = -errno;
2278                         llapi_error(LLAPI_MSG_ERROR, rc, "cannot open '%s'",
2279                                     path);
2280                         return rc;
2281                 }
2282         }
2283
2284         rc = llapi_file_fget_type_uuid(fd, type, uuid);
2285
2286         close(fd);
2287         return rc;
2288 }
2289
2290 /*
2291  * If uuidp is NULL, return the number of available obd uuids.
2292  * If uuidp is non-NULL, then it will return the uuids of the obds. If
2293  * there are more OSTs than allocated to uuidp, then an error is returned with
2294  * the ost_count set to number of available obd uuids.
2295  */
2296 static int llapi_get_target_uuids(int fd, struct obd_uuid *uuidp, int *indices,
2297                                   int *ost_count, enum tgt_type type)
2298 {
2299         char buf[PATH_MAX], format[32];
2300         int i, rc = 0;
2301         struct obd_uuid name;
2302         glob_t param;
2303         FILE *fp;
2304
2305         /* Get the lov name */
2306         rc = llapi_file_fget_type_uuid(fd, type, &name);
2307         if (rc != 0)
2308                 return rc;
2309
2310         /* Now get the ost uuids */
2311         rc = get_lustre_param_path(type == LOV_TYPE ? "lov" : "lmv", name.uuid,
2312                                    FILTER_BY_EXACT, "target_obd", &param);
2313         if (rc != 0)
2314                 return -ENOENT;
2315
2316         fp = fopen(param.gl_pathv[0], "r");
2317         if (fp == NULL) {
2318                 rc = -errno;
2319                 llapi_error(LLAPI_MSG_ERROR, rc, "error: opening '%s'",
2320                             param.gl_pathv[0]);
2321                 goto free_param;
2322         }
2323
2324         snprintf(format, sizeof(format),
2325                  "%%d: %%%zus", sizeof(uuidp[0].uuid) - 1);
2326         for (i = 0; fgets(buf, sizeof(buf), fp); i++) {
2327                 int index;
2328
2329                 if (sscanf(buf, format, &index, name.uuid) < 2)
2330                         break;
2331
2332                 if (i < *ost_count) {
2333                         if (uuidp != NULL)
2334                                 uuidp[i] = name;
2335                         if (indices != NULL)
2336                                 indices[i] = index;
2337                 }
2338         }
2339         fclose(fp);
2340
2341         if (uuidp && (i > *ost_count))
2342                 rc = -EOVERFLOW;
2343
2344         *ost_count = i;
2345 free_param:
2346         cfs_free_param_data(&param);
2347         return rc;
2348 }
2349
2350 int llapi_lmv_get_uuids(int fd, struct obd_uuid *uuidp, int *mdt_count)
2351 {
2352         return llapi_get_target_uuids(fd, uuidp, NULL, mdt_count, LMV_TYPE);
2353 }
2354
2355 int llapi_lov_get_uuids(int fd, struct obd_uuid *uuidp, int *ost_count)
2356 {
2357         return llapi_get_target_uuids(fd, uuidp, NULL, ost_count, LOV_TYPE);
2358 }
2359
2360 int llapi_get_obd_count(char *mnt, int *count, int is_mdt)
2361 {
2362         int root;
2363         int rc;
2364
2365         root = open(mnt, O_RDONLY | O_DIRECTORY);
2366         if (root < 0) {
2367                 rc = -errno;
2368                 llapi_error(LLAPI_MSG_ERROR, rc, "open %s failed", mnt);
2369                 return rc;
2370         }
2371
2372         *count = is_mdt;
2373         rc = ioctl(root, LL_IOC_GETOBDCOUNT, count);
2374         if (rc < 0)
2375                 rc = -errno;
2376
2377         close(root);
2378         return rc;
2379 }
2380
2381 /*
2382  * Check if user specified value matches a real uuid.  Ignore _UUID,
2383  * -osc-4ba41334, other trailing gunk in comparison.
2384  * @param real_uuid ends in "_UUID"
2385  * @param search_uuid may or may not end in "_UUID"
2386  */
2387 int llapi_uuid_match(char *real_uuid, char *search_uuid)
2388 {
2389         int cmplen = strlen(real_uuid);
2390         int searchlen = strlen(search_uuid);
2391
2392         if (cmplen > 5 && strcmp(real_uuid + cmplen - 5, "_UUID") == 0)
2393                 cmplen -= 5;
2394         if (searchlen > 5 && strcmp(search_uuid + searchlen - 5, "_UUID") == 0)
2395                 searchlen -= 5;
2396
2397         /*
2398          * The UUIDs may legitimately be different lengths, if
2399          * the system was upgraded from an older version.
2400          */
2401         if (cmplen != searchlen)
2402                 return 0;
2403
2404         return (strncmp(search_uuid, real_uuid, cmplen) == 0);
2405 }
2406
2407 /*
2408  * Here, param->fp_obd_uuid points to a single obduuid, the index of which is
2409  * returned in param->fp_obd_index
2410  */
2411 static int setup_obd_uuid(int fd, char *dname, struct find_param *param)
2412 {
2413         struct obd_uuid obd_uuid;
2414         char buf[PATH_MAX];
2415         glob_t param_data;
2416         char format[32];
2417         int rc = 0;
2418         FILE *fp;
2419         enum tgt_type type = param->fp_get_lmv ? LMV_TYPE : LOV_TYPE;
2420
2421         if (param->fp_got_uuids)
2422                 return rc;
2423
2424         /* Get the lov/lmv name */
2425         rc = llapi_file_fget_type_uuid(fd, type, &obd_uuid);
2426         if (rc) {
2427                 if (rc != -ENOTTY) {
2428                         llapi_error(LLAPI_MSG_ERROR, rc,
2429                                     "error: can't get %s name: %s",
2430                                     param->fp_get_lmv ? "lmv" : "lov",
2431                                     dname);
2432                 } else {
2433                         rc = 0;
2434                 }
2435                 return rc;
2436         }
2437
2438         param->fp_got_uuids = 1;
2439
2440         /* Now get the ost uuids */
2441         rc = get_lustre_param_path(param->fp_get_lmv ? "lmv" : "lov",
2442                                    obd_uuid.uuid, FILTER_BY_EXACT,
2443                                    "target_obd", &param_data);
2444         if (rc != 0)
2445                 return -ENOENT;
2446
2447         fp = fopen(param_data.gl_pathv[0], "r");
2448         if (fp == NULL) {
2449                 rc = -errno;
2450                 llapi_error(LLAPI_MSG_ERROR, rc, "error: opening '%s'",
2451                             param_data.gl_pathv[0]);
2452                 goto free_param;
2453         }
2454
2455         if (!param->fp_obd_uuid && !param->fp_quiet && !param->fp_obds_printed)
2456                 llapi_printf(LLAPI_MSG_NORMAL, "%s:\n",
2457                              param->fp_get_lmv ? "MDTS" : "OBDS");
2458
2459         snprintf(format, sizeof(format),
2460                  "%%d: %%%zus", sizeof(obd_uuid.uuid) - 1);
2461         while (fgets(buf, sizeof(buf), fp) != NULL) {
2462                 int index;
2463
2464                 if (sscanf(buf, format, &index, obd_uuid.uuid) < 2)
2465                         break;
2466
2467                 if (param->fp_obd_uuid) {
2468                         if (llapi_uuid_match(obd_uuid.uuid,
2469                                              param->fp_obd_uuid->uuid)) {
2470                                 param->fp_obd_index = index;
2471                                 break;
2472                         }
2473                 } else if (!param->fp_quiet && !param->fp_obds_printed) {
2474                         /* Print everything */
2475                         llapi_printf(LLAPI_MSG_NORMAL, "%s", buf);
2476                 }
2477         }
2478         param->fp_obds_printed = 1;
2479
2480         fclose(fp);
2481
2482         if (param->fp_obd_uuid && (param->fp_obd_index == OBD_NOT_FOUND)) {
2483                 llapi_err_noerrno(LLAPI_MSG_ERROR,
2484                                   "error: %s: unknown obduuid: %s",
2485                                   __func__, param->fp_obd_uuid->uuid);
2486                 rc = -EINVAL;
2487         }
2488 free_param:
2489         cfs_free_param_data(&param_data);
2490         return rc;
2491 }
2492
2493 /*
2494  * In this case, param->fp_obd_uuid will be an array of obduuids and
2495  * obd index for all these obduuids will be returned in
2496  * param->fp_obd_indexes
2497  */
2498 static int setup_indexes(int d, char *path, struct obd_uuid *obduuids,
2499                          int num_obds, int **obdindexes, int *obdindex,
2500                          enum tgt_type type)
2501 {
2502         int ret, obdcount, obd_valid = 0, obdnum;
2503         int *indices = NULL;
2504         struct obd_uuid *uuids = NULL;
2505         int *indexes;
2506         char buf[16];
2507         long i;
2508
2509         ret = get_param_tgt(path, type, "numobd", buf, sizeof(buf));
2510         if (ret != 0)
2511                 return ret;
2512
2513         obdcount = atoi(buf);
2514         uuids = malloc(obdcount * sizeof(struct obd_uuid));
2515         if (uuids == NULL)
2516                 return -ENOMEM;
2517         indices = malloc(obdcount * sizeof(int));
2518         if (indices == NULL) {
2519                 ret = -ENOMEM;
2520                 goto out_uuids;
2521         }
2522
2523 retry_get_uuids:
2524         ret = llapi_get_target_uuids(d, uuids, indices, &obdcount, type);
2525         if (ret) {
2526                 if (ret == -EOVERFLOW) {
2527                         struct obd_uuid *uuids_temp;
2528                         int *indices_temp = NULL;
2529
2530                         uuids_temp = realloc(uuids, obdcount *
2531                                              sizeof(struct obd_uuid));
2532                         if (uuids_temp)
2533                                 uuids = uuids_temp;
2534                         indices_temp = realloc(indices, obdcount * sizeof(int));
2535                         if (indices_temp)
2536                                 indices = indices_temp;
2537                         if (uuids_temp && indices_temp)
2538                                 goto retry_get_uuids;
2539                         ret = -ENOMEM;
2540                 }
2541
2542                 llapi_error(LLAPI_MSG_ERROR, ret, "cannot fetch %u OST UUIDs",
2543                             obdcount);
2544                 goto out_free;
2545         }
2546
2547         indexes = malloc(num_obds * sizeof(*obdindex));
2548         if (indexes == NULL) {
2549                 ret = -ENOMEM;
2550                 goto out_free;
2551         }
2552
2553         for (obdnum = 0; obdnum < num_obds; obdnum++) {
2554                 int maxidx = LOV_V1_INSANE_STRIPE_COUNT;
2555                 char *end = NULL;
2556
2557                 /* The user may have specified a simple index */
2558                 i = strtol(obduuids[obdnum].uuid, &end, 0);
2559                 if (end && *end == '\0' && i < LOV_V1_INSANE_STRIPE_COUNT) {
2560                         indexes[obdnum] = i;
2561                         obd_valid++;
2562                 } else {
2563                         maxidx = obdcount;
2564                         for (i = 0; i < obdcount; i++) {
2565                                 if (llapi_uuid_match(uuids[i].uuid,
2566                                                      obduuids[obdnum].uuid)) {
2567                                         indexes[obdnum] = indices[i];
2568                                         obd_valid++;
2569                                         break;
2570                                 }
2571                         }
2572                 }
2573
2574                 if (i >= maxidx) {
2575                         indexes[obdnum] = OBD_NOT_FOUND;
2576                         llapi_err_noerrno(LLAPI_MSG_ERROR,
2577                                           "invalid obduuid '%s'",
2578                                           obduuids[obdnum].uuid);
2579                         ret = -EINVAL;
2580                 }
2581         }
2582
2583         if (obd_valid == 0)
2584                 *obdindex = OBD_NOT_FOUND;
2585         else
2586                 *obdindex = obd_valid;
2587
2588         *obdindexes = indexes;
2589 out_free:
2590         if (indices)
2591                 free(indices);
2592 out_uuids:
2593         if (uuids)
2594                 free(uuids);
2595
2596         return ret;
2597 }
2598
2599 static int setup_target_indexes(int d, char *path, struct find_param *param)
2600 {
2601         int ret = 0;
2602
2603         if (param->fp_mdt_uuid) {
2604                 ret = setup_indexes(d, path, param->fp_mdt_uuid,
2605                                     param->fp_num_mdts,
2606                                     &param->fp_mdt_indexes,
2607                                     &param->fp_mdt_index, LMV_TYPE);
2608                 if (ret)
2609                         return ret;
2610         }
2611
2612         if (param->fp_obd_uuid) {
2613                 ret = setup_indexes(d, path, param->fp_obd_uuid,
2614                                     param->fp_num_obds,
2615                                     &param->fp_obd_indexes,
2616                                     &param->fp_obd_index, LOV_TYPE);
2617                 if (ret)
2618                         return ret;
2619         }
2620
2621         param->fp_got_uuids = 1;
2622
2623         return ret;
2624 }
2625
2626 int llapi_ostlist(char *path, struct find_param *param)
2627 {
2628         int fd;
2629         int ret;
2630
2631         fd = open(path, O_RDONLY | O_DIRECTORY);
2632         if (fd < 0)
2633                 return -errno;
2634
2635         ret = setup_obd_uuid(fd, path, param);
2636         close(fd);
2637
2638         return ret;
2639 }
2640
2641 /*
2642  * Tries to determine the default stripe attributes for a given filesystem. The
2643  * filesystem to check should be specified by fsname, or will be determined
2644  * using pathname.
2645  */
2646 static int sattr_get_defaults(const char *const fsname,
2647                               unsigned int *scount,
2648                               unsigned int *ssize,
2649                               unsigned int *soffset)
2650 {
2651         char val[PATH_MAX];
2652         int rc;
2653
2654         if (scount) {
2655                 rc = get_lustre_param_value("lov", fsname, FILTER_BY_FS_NAME,
2656                                             "stripecount", val, sizeof(val));
2657                 if (rc != 0)
2658                         return rc;
2659                 *scount = atoi(val);
2660         }
2661
2662         if (ssize) {
2663                 rc = get_lustre_param_value("lov", fsname, FILTER_BY_FS_NAME,
2664                                             "stripesize", val, sizeof(val));
2665                 if (rc != 0)
2666                         return rc;
2667                 *ssize = atoi(val);
2668         }
2669
2670         if (soffset) {
2671                 rc = get_lustre_param_value("lov", fsname, FILTER_BY_FS_NAME,
2672                                             "stripeoffset", val, sizeof(val));
2673                 if (rc != 0)
2674                         return rc;
2675                 *soffset = atoi(val);
2676         }
2677
2678         return 0;
2679 }
2680
2681 /*
2682  * Tries to gather the default stripe attributes for a given filesystem. If
2683  * the attributes can be determined, they are cached for easy retreival the
2684  * next time they are needed. Only a single filesystem's attributes are
2685  * cached at a time.
2686  */
2687 int sattr_cache_get_defaults(const char *const fsname,
2688                              const char *const pathname, unsigned int *scount,
2689                              unsigned int *ssize, unsigned int *soffset)
2690 {
2691         static struct {
2692                 char fsname[PATH_MAX + 1];
2693                 unsigned int stripecount;
2694                 unsigned int stripesize;
2695                 unsigned int stripeoffset;
2696         } cache = {
2697                 .fsname = {'\0'}
2698         };
2699
2700         int rc;
2701         char fsname_buf[PATH_MAX + 1];
2702         unsigned int tmp[3];
2703
2704         if (fsname == NULL) {
2705                 rc = llapi_search_fsname(pathname, fsname_buf);
2706                 if (rc)
2707                         return rc;
2708         } else {
2709                 snprintf(fsname_buf, sizeof(fsname_buf), "%s", fsname);
2710         }
2711
2712         if (strncmp(fsname_buf, cache.fsname, sizeof(fsname_buf) - 1) != 0) {
2713                 /*
2714                  * Ensure all 3 sattrs (count, size, and offset) are
2715                  * successfully retrieved and stored in tmp before writing to
2716                  * cache.
2717                  */
2718                 rc = sattr_get_defaults(fsname_buf, &tmp[0], &tmp[1], &tmp[2]);
2719                 if (rc != 0)
2720                         return rc;
2721
2722                 cache.stripecount = tmp[0];
2723                 cache.stripesize = tmp[1];
2724                 cache.stripeoffset = tmp[2];
2725                 snprintf(cache.fsname, sizeof(cache.fsname), "%s", fsname_buf);
2726         }
2727
2728         if (scount)
2729                 *scount = cache.stripecount;
2730         if (ssize)
2731                 *ssize = cache.stripesize;
2732         if (soffset)
2733                 *soffset = cache.stripeoffset;
2734
2735         return 0;
2736 }
2737
2738 enum lov_dump_flags {
2739         LDF_IS_DIR      = 0x0001,
2740         LDF_IS_RAW      = 0x0002,
2741         LDF_INDENT      = 0x0004,
2742         LDF_SKIP_OBJS   = 0x0008,
2743         LDF_YAML        = 0x0010,
2744         LDF_EXTENSION   = 0x0020,
2745         LDF_HEX_IDX     = 0x0040,
2746 };
2747
2748 static void lov_dump_user_lmm_header(struct lov_user_md *lum, char *path,
2749                                      struct lov_user_ost_data_v1 *objects,
2750                                      enum llapi_layout_verbose verbose,
2751                                      int depth, char *pool_name,
2752                                      enum lov_dump_flags flags)
2753 {
2754         bool is_dir = flags & LDF_IS_DIR;
2755         bool is_raw = flags & LDF_IS_RAW;
2756         bool indent = flags & LDF_INDENT;
2757         bool yaml = flags & LDF_YAML;
2758         bool skip_objs = flags & LDF_SKIP_OBJS;
2759         bool extension = flags & LDF_EXTENSION;
2760         char *prefix = is_dir ? "" : "lmm_";
2761         char *separator = "";
2762         char *space = indent ? "      " : "";
2763         char *fmt_idx = flags & LDF_HEX_IDX ? "%#x" : "%d";
2764         int rc;
2765
2766         if (is_dir && lmm_oi_seq(&lum->lmm_oi) == FID_SEQ_LOV_DEFAULT) {
2767                 lmm_oi_set_seq(&lum->lmm_oi, 0);
2768                 if (!indent && (verbose & VERBOSE_DETAIL))
2769                         llapi_printf(LLAPI_MSG_NORMAL, "%s(Default) ", space);
2770         }
2771
2772         if (!yaml && !indent && depth && path &&
2773             ((verbose != VERBOSE_OBJID) || !is_dir))
2774                 llapi_printf(LLAPI_MSG_NORMAL, "%s\n", path);
2775
2776         if ((verbose & VERBOSE_DETAIL) && !is_dir) {
2777                 llapi_printf(LLAPI_MSG_NORMAL, "%s%smagic:         0x%08X\n",
2778                              space, prefix, lum->lmm_magic);
2779                 llapi_printf(LLAPI_MSG_NORMAL, "%s%sseq:           %#jx\n",
2780                              space, prefix,
2781                              (uintmax_t)lmm_oi_seq(&lum->lmm_oi));
2782                 llapi_printf(LLAPI_MSG_NORMAL, "%s%sobject_id:     %#jx\n",
2783                              space, prefix,
2784                              (uintmax_t)lmm_oi_id(&lum->lmm_oi));
2785         }
2786
2787         if (verbose & (VERBOSE_DETAIL | VERBOSE_DFID)) {
2788                 __u64 seq;
2789                 __u32 oid;
2790                 __u32 ver;
2791
2792                 if (verbose & ~VERBOSE_DFID)
2793                         llapi_printf(LLAPI_MSG_NORMAL, "%slmm_fid:           ",
2794                                      space);
2795
2796                 if (is_dir) {
2797                         struct lu_fid dir_fid;
2798
2799                         rc = llapi_path2fid(path, &dir_fid);
2800                         if (rc)
2801                                 llapi_error(LLAPI_MSG_ERROR, rc,
2802                                             "Cannot determine directory fid.");
2803
2804                         seq = dir_fid.f_seq;
2805                         oid = dir_fid.f_oid;
2806                         ver = dir_fid.f_ver;
2807                 } else {
2808                         /*
2809                          * This needs a bit of hand-holding since old 1.x
2810                          * lmm_oi have { oi.oi_id = mds_inum, oi.oi_seq = 0 }
2811                          * and 2.x lmm_oi have { oi.oi_id = mds_oid,
2812                          * oi.oi_seq = mds_seq } instead of a real FID.
2813                          * Ideally the 2.x code would have stored this like a
2814                          * FID with { oi_id = mds_seq, oi_seq = mds_oid } so
2815                          * the ostid union lu_fid { f_seq = mds_seq,
2816                          * f_oid = mds_oid } worked properly (especially since
2817                          * IGIF FIDs use mds_inum as the FID SEQ), but
2818                          * unfortunately that didn't happen.
2819                          *
2820                          * Print it to look like an IGIF FID, even though the
2821                          * fields are reversed on disk, so that it makes sense
2822                          * to userspace.
2823                          *
2824                          * Don't use ostid_id() and ostid_seq(), since they
2825                          * assume the oi_fid fields are in the right order.
2826                          * This is why there are separate lmm_oi_seq() and
2827                          * lmm_oi_id() routines for this.
2828                          *
2829                          * For newer layout types hopefully this will be a
2830                          * real FID.
2831                          */
2832                         seq = lmm_oi_seq(&lum->lmm_oi) == 0 ?
2833                                 lmm_oi_id(&lum->lmm_oi) :
2834                                 lmm_oi_seq(&lum->lmm_oi);
2835                         oid = lmm_oi_seq(&lum->lmm_oi) == 0 ?
2836                             0 : (__u32)lmm_oi_id(&lum->lmm_oi);
2837                         ver = (__u32)(lmm_oi_id(&lum->lmm_oi) >> 32);
2838                 }
2839
2840                 if (yaml)
2841                         llapi_printf(LLAPI_MSG_NORMAL, DFID_NOBRACE"\n",
2842                                      (unsigned long long)seq, oid, ver);
2843                 else
2844                         llapi_printf(LLAPI_MSG_NORMAL, DFID"\n",
2845                                      (unsigned long long)seq, oid, ver);
2846         }
2847
2848         if (verbose & VERBOSE_STRIPE_COUNT) {
2849                 if (verbose & ~VERBOSE_STRIPE_COUNT)
2850                         llapi_printf(LLAPI_MSG_NORMAL, "%s%sstripe_count:  ",
2851                                      space, prefix);
2852                 if (is_dir) {
2853                         if (!is_raw && lum->lmm_stripe_count == 0 &&
2854                             !(lov_pattern(lum->lmm_pattern) & LOV_PATTERN_MDT)){
2855                                 unsigned int scount;
2856
2857                                 rc = sattr_cache_get_defaults(NULL, path,
2858                                                               &scount, NULL,
2859                                                               NULL);
2860                                 if (rc == 0)
2861                                         llapi_printf(LLAPI_MSG_NORMAL, "%d",
2862                                                      scount);
2863                                 else
2864                                         llapi_error(LLAPI_MSG_ERROR, rc,
2865                                                     "Cannot determine default stripe count.");
2866                         } else {
2867                                 llapi_printf(LLAPI_MSG_NORMAL, "%d",
2868                                              extension ? 0 :
2869                                              (__s16)lum->lmm_stripe_count);
2870                         }
2871                 } else {
2872                         llapi_printf(LLAPI_MSG_NORMAL, "%i",
2873                                      extension ? 0 :
2874                                      (__s16)lum->lmm_stripe_count);
2875                 }
2876                 if (!yaml && is_dir)
2877                         separator = " ";
2878                 else
2879                         separator = "\n";
2880         }
2881
2882         if (((verbose & VERBOSE_STRIPE_SIZE) && !extension) ||
2883             ((verbose & VERBOSE_EXT_SIZE) && extension)) {
2884                 llapi_printf(LLAPI_MSG_NORMAL, "%s", separator);
2885                 if (verbose & ~VERBOSE_EXT_SIZE && extension)
2886                         llapi_printf(LLAPI_MSG_NORMAL, "%s%sextension_size: ",
2887                                      space, prefix);
2888                 if (verbose & ~VERBOSE_STRIPE_SIZE && !extension)
2889                         llapi_printf(LLAPI_MSG_NORMAL, "%s%sstripe_size:   ",
2890                                      space, prefix);
2891                 if (is_dir && !is_raw && lum->lmm_stripe_size == 0) {
2892                         unsigned int ssize;
2893
2894                         rc = sattr_cache_get_defaults(NULL, path, NULL, &ssize,
2895                                                       NULL);
2896                         if (rc == 0)
2897                                 llapi_printf(LLAPI_MSG_NORMAL, "%u", ssize);
2898                         else
2899                                 llapi_error(LLAPI_MSG_ERROR, rc,
2900                                             "Cannot determine default stripe size.");
2901                 } else {
2902                         /* Extension size is in KiB */
2903                         llapi_printf(LLAPI_MSG_NORMAL, "%llu",
2904                                      extension ?
2905                                      (unsigned long long)(lum->lmm_stripe_size * SEL_UNIT_SIZE) :
2906                                      (unsigned long long)lum->lmm_stripe_size);
2907                 }
2908                 if (!yaml && is_dir)
2909                         separator = " ";
2910                 else
2911                         separator = "\n";
2912         }
2913
2914         if ((verbose & VERBOSE_PATTERN)) {
2915                 char buf[128];
2916
2917                 llapi_printf(LLAPI_MSG_NORMAL, "%s", separator);
2918                 if (verbose & ~VERBOSE_PATTERN)
2919                         llapi_printf(LLAPI_MSG_NORMAL, "%s%spattern:       ",
2920                                      space, prefix);
2921                 if (lov_pattern_supported(lum->lmm_pattern))
2922                         llapi_printf(LLAPI_MSG_NORMAL, "%s",
2923                                      llapi_lov_pattern_string(lum->lmm_pattern,
2924                                                         buf, sizeof(buf)) ?:
2925                                                         "overflow");
2926                 else
2927                         llapi_printf(LLAPI_MSG_NORMAL, "%x", lum->lmm_pattern);
2928                 separator = (!yaml && is_dir) ? " " : "\n";
2929         }
2930
2931         if ((verbose & VERBOSE_GENERATION) && !is_dir) {
2932                 llapi_printf(LLAPI_MSG_NORMAL, "%s", separator);
2933                 if (verbose & ~VERBOSE_GENERATION)
2934                         llapi_printf(LLAPI_MSG_NORMAL, "%s%slayout_gen:    ",
2935                                      space, prefix);
2936                 llapi_printf(LLAPI_MSG_NORMAL, "%u",
2937                              skip_objs ? 0 : (int)lum->lmm_layout_gen);
2938                 separator = "\n";
2939         }
2940
2941         if (verbose & VERBOSE_STRIPE_OFFSET) {
2942                 llapi_printf(LLAPI_MSG_NORMAL, "%s", separator);
2943                 if (verbose & ~VERBOSE_STRIPE_OFFSET)
2944                         llapi_printf(LLAPI_MSG_NORMAL, "%s%sstripe_offset: ",
2945                                      space, prefix);
2946                 if (is_dir || skip_objs)
2947                         if (lum->lmm_stripe_offset ==
2948                             (typeof(lum->lmm_stripe_offset))(-1))
2949                                 llapi_printf(LLAPI_MSG_NORMAL, "-1");
2950                         else
2951                                 llapi_printf(LLAPI_MSG_NORMAL, fmt_idx,
2952                                              lum->lmm_stripe_offset);
2953                 else if (lov_pattern(lum->lmm_pattern) & LOV_PATTERN_MDT)
2954                         llapi_printf(LLAPI_MSG_NORMAL, "0");
2955                 else
2956                         llapi_printf(LLAPI_MSG_NORMAL, fmt_idx,
2957                                      objects[0].l_ost_idx);
2958                 if (!yaml && is_dir)
2959                         separator = " ";
2960                 else
2961                         separator = "\n";
2962         }
2963
2964         if ((verbose & VERBOSE_POOL) && pool_name && (pool_name[0] != '\0') &&
2965             (!lov_pool_is_ignored(pool_name) || is_raw)) {
2966                 llapi_printf(LLAPI_MSG_NORMAL, "%s", separator);
2967                 if (verbose & ~VERBOSE_POOL)
2968                         llapi_printf(LLAPI_MSG_NORMAL, "%s%spool:          ",
2969                                      space, prefix);
2970                 llapi_printf(LLAPI_MSG_NORMAL, "%s", pool_name);
2971                 if (!yaml && is_dir)
2972                         separator = " ";
2973                 else
2974                         separator = "\n";
2975         }
2976
2977         if (strlen(separator) != 0)
2978                 llapi_printf(LLAPI_MSG_NORMAL, "\n");
2979 }
2980
2981 static void lov_dump_user_lmm_v1v3(struct lov_user_md *lum, char *pool_name,
2982                                    struct lov_user_ost_data_v1 *objects,
2983                                    char *path, int obdindex, int depth,
2984                                    enum llapi_layout_verbose verbose,
2985                                    enum lov_dump_flags flags)
2986 {
2987         bool is_dir = flags & LDF_IS_DIR;
2988         bool indent = flags & LDF_INDENT;
2989         bool skip_objs = flags & LDF_SKIP_OBJS;
2990         bool yaml = flags & LDF_YAML;
2991         bool hex = flags & LDF_HEX_IDX;
2992         bool obdstripe = obdindex == OBD_NOT_FOUND;
2993         int i;
2994
2995         if (!obdstripe && !skip_objs) {
2996                 for (i = 0; !is_dir && i < lum->lmm_stripe_count; i++) {
2997                         if (obdindex == objects[i].l_ost_idx) {
2998                                 obdstripe = true;
2999                                 break;
3000                         }
3001                 }
3002         }
3003
3004         if (!obdstripe)
3005                 return;
3006
3007         lov_dump_user_lmm_header(lum, path, objects, verbose, depth, pool_name,
3008                                  flags);
3009
3010         if (!skip_objs && (verbose & VERBOSE_OBJID) &&
3011             ((!is_dir && !(lum->lmm_pattern & LOV_PATTERN_F_RELEASED ||
3012                            lov_pattern(lum->lmm_pattern) & LOV_PATTERN_MDT)) ||
3013              (is_dir && (lum->lmm_magic == LOV_USER_MAGIC_SPECIFIC)))) {
3014                 char *space = "      - ";
3015
3016                 if (indent)
3017                         llapi_printf(LLAPI_MSG_NORMAL,
3018                                      "%6slmm_objects:\n", " ");
3019                 else if (yaml)
3020                         llapi_printf(LLAPI_MSG_NORMAL, "lmm_objects:\n");
3021                 else
3022                         llapi_printf(LLAPI_MSG_NORMAL,
3023                                 "\tobdidx\t\t objid\t\t objid\t\t group\n");
3024
3025                 for (i = 0; i < lum->lmm_stripe_count; i++) {
3026                         int idx = objects[i].l_ost_idx;
3027                         long long oid = ostid_id(&objects[i].l_ost_oi);
3028                         long long gr = ostid_seq(&objects[i].l_ost_oi);
3029
3030                         if (obdindex != OBD_NOT_FOUND && obdindex != idx)
3031                                 continue;
3032
3033                         if (yaml) {
3034                                 struct lu_fid fid = { 0 };
3035                                 ostid_to_fid(&fid, &objects[i].l_ost_oi, idx);
3036                                 llapi_printf(LLAPI_MSG_NORMAL,
3037                                              hex ? "%sl_ost_idx: %#x\n"
3038                                                  : "%sl_ost_idx: %d\n",
3039                                              space, idx);
3040                                 llapi_printf(LLAPI_MSG_NORMAL,
3041                                     "%8sl_fid:     "DFID_NOBRACE"\n",
3042                                     " ", PFID(&fid));
3043                         } else if (indent) {
3044                                 struct lu_fid fid = { 0 };
3045
3046                                 ostid_to_fid(&fid, &objects[i].l_ost_oi, idx);
3047                                 llapi_printf(LLAPI_MSG_NORMAL, hex ?
3048                                     "%s%3d: { l_ost_idx: %#5x, l_fid: "DFID" }\n" :
3049                                     "%s%3d: { l_ost_idx: %3d, l_fid: "DFID" }\n",
3050                                     space, i, idx, PFID(&fid));
3051                         } else if (is_dir) {
3052                                 llapi_printf(LLAPI_MSG_NORMAL,
3053                                              "\t%6u\t%14s\t%13s\t%14s\n", idx, "N/A",
3054                                              "N/A", "N/A");
3055                         } else {
3056                                 char fmt[48] = { 0 };
3057
3058                                 sprintf(fmt, "%s%s%s\n",
3059                                         hex ? "\t%#6x\t%14llu\t%#13llx\t"
3060                                             : "\t%6u\t%14llu\t%#13llx\t",
3061                                         (fid_seq_is_rsvd(gr) ||
3062                                          fid_seq_is_mdt0(gr)) ?
3063                                          "%14llu" : "%#14llx", "%s");
3064                                 llapi_printf(LLAPI_MSG_NORMAL, fmt, idx, oid,
3065                                              oid, gr,
3066                                              obdindex == idx ? " *" : "");
3067                         }
3068                 }
3069         }
3070         if (!yaml)
3071                 llapi_printf(LLAPI_MSG_NORMAL, "\n");
3072 }
3073
3074 static void hsm_flags2str(__u32 hsm_flags)
3075 {
3076         bool found = false;
3077         int i = 0;
3078
3079         if (!hsm_flags) {
3080                 llapi_printf(LLAPI_MSG_NORMAL, "0");
3081                 return;
3082         }
3083         for (i = 0; i < ARRAY_SIZE(hsm_flags_table); i++) {
3084                 if (hsm_flags & hsm_flags_table[i].hfn_flag) {
3085                         if (found)
3086                                 llapi_printf(LLAPI_MSG_NORMAL, ",");
3087                         llapi_printf(LLAPI_MSG_NORMAL, "%s",
3088                                      hsm_flags_table[i].hfn_name);
3089                         found = true;
3090                 }
3091         }
3092         if (hsm_flags) {
3093                 if (found)
3094                         llapi_printf(LLAPI_MSG_NORMAL, ",");
3095                 llapi_printf(LLAPI_MSG_NORMAL, "%#x", hsm_flags);
3096         }
3097 }
3098
3099 static uint32_t check_foreign_type(uint32_t foreign_type)
3100 {
3101         uint32_t i;
3102
3103         for (i = 0; i < LU_FOREIGN_TYPE_UNKNOWN; i++) {
3104                 if (lu_foreign_types[i].lft_name == NULL)
3105                         break;
3106                 if (foreign_type == lu_foreign_types[i].lft_type)
3107                         return i;
3108         }
3109
3110         return LU_FOREIGN_TYPE_UNKNOWN;
3111 }
3112
3113 void lov_dump_hsm_lmm(void *lum, char *path, int depth,
3114                       enum llapi_layout_verbose verbose,
3115                       enum lov_dump_flags flags)
3116 {
3117         struct lov_hsm_md *lhm = lum;
3118         bool indent = flags & LDF_INDENT;
3119         bool is_dir = flags & LDF_IS_DIR;
3120         char *space = indent ? "      " : "";
3121
3122         if (!is_dir) {
3123                 uint32_t type = check_foreign_type(lhm->lhm_type);
3124
3125                 llapi_printf(LLAPI_MSG_NORMAL, "%slhm_magic:         0x%08X\n",
3126                              space, lhm->lhm_magic);
3127                 llapi_printf(LLAPI_MSG_NORMAL, "%slhm_pattern:       hsm\n",
3128                              space);
3129                 llapi_printf(LLAPI_MSG_NORMAL, "%slhm_length:        %u\n",
3130                              space, lhm->lhm_length);
3131                 llapi_printf(LLAPI_MSG_NORMAL, "%slhm_type:          0x%08X",
3132                              space, lhm->lhm_type);
3133                 if (type < LU_FOREIGN_TYPE_UNKNOWN)
3134                         llapi_printf(LLAPI_MSG_NORMAL, " (%s)\n",
3135                                      lu_foreign_types[type].lft_name);
3136                 else
3137                         llapi_printf(LLAPI_MSG_NORMAL, " (unknown)\n");
3138
3139                 llapi_printf(LLAPI_MSG_NORMAL, "%slhm_flags:         ", space);
3140                 hsm_flags2str(lhm->lhm_flags);
3141                 llapi_printf(LLAPI_MSG_NORMAL, "\n");
3142
3143                 if (!lov_hsm_type_supported(lhm->lhm_type))
3144                         return;
3145
3146                 llapi_printf(LLAPI_MSG_NORMAL, "%slhm_archive_id:    %llu\n",
3147                              space, (unsigned long long)lhm->lhm_archive_id);
3148                 llapi_printf(LLAPI_MSG_NORMAL, "%slhm_archive_ver:   %llu\n",
3149                              space, (unsigned long long)lhm->lhm_archive_ver);
3150                 llapi_printf(LLAPI_MSG_NORMAL, "%slhm_archive_uuid:  '%.*s'\n",
3151                              space, UUID_MAX, lhm->lhm_archive_uuid);
3152         }
3153 }
3154
3155 static void lmv_dump_user_lmm(struct lmv_user_md *lum, char *pool_name,
3156                               char *path, int obdindex, int depth,
3157                               enum llapi_layout_verbose verbose,
3158                               enum lov_dump_flags flags)
3159 {
3160         struct lmv_user_mds_data *objects = lum->lum_objects;
3161         char *prefix = lum->lum_magic == LMV_USER_MAGIC ? "(Default)" : "";
3162         char *separator = "";
3163         bool yaml = flags & LDF_YAML;
3164         bool hex = flags & LDF_HEX_IDX;
3165         bool obdstripe = false;
3166         struct lu_fid dir_fid;
3167         int rc;
3168         int i;
3169
3170         if (obdindex != OBD_NOT_FOUND) {
3171                 if (lum->lum_stripe_count == 0) {
3172                         if (obdindex == lum->lum_stripe_offset)
3173                                 obdstripe = true;
3174                 } else {
3175                         for (i = 0; i < lum->lum_stripe_count; i++) {
3176                                 if (obdindex == objects[i].lum_mds) {
3177                                         llapi_printf(LLAPI_MSG_NORMAL,
3178                                                      "%s%s\n", prefix,
3179                                                      path);
3180                                         obdstripe = true;
3181                                         break;
3182                                 }
3183                         }
3184                 }
3185         } else {
3186                 obdstripe = true;
3187         }
3188
3189         if (!obdstripe)
3190                 return;
3191
3192         /* show all information default */
3193         if (!verbose) {
3194                 if (lum->lum_magic == LMV_USER_MAGIC)
3195                         verbose = VERBOSE_POOL | VERBOSE_STRIPE_COUNT |
3196                                   VERBOSE_STRIPE_OFFSET | VERBOSE_HASH_TYPE;
3197                 else
3198                         verbose = VERBOSE_OBJID;
3199         }
3200
3201         if (verbose & (VERBOSE_DETAIL | VERBOSE_DFID) ||
3202             (verbose & VERBOSE_OBJID && lum->lum_stripe_count >= 0)) {
3203                 rc = llapi_path2fid(path, &dir_fid);
3204                 if (rc)
3205                         llapi_error(LLAPI_MSG_ERROR, rc,
3206                                     "Cannot determine directory FID: %s", path);
3207         }
3208
3209         if (depth && path && (verbose != VERBOSE_OBJID))
3210                 llapi_printf(LLAPI_MSG_NORMAL, "%s%s\n", prefix, path);
3211
3212         if (verbose & (VERBOSE_DETAIL | VERBOSE_DFID)) {
3213                 if (verbose & ~VERBOSE_DFID)
3214                         llapi_printf(LLAPI_MSG_NORMAL,
3215                                      "lmv_fid: %s", yaml ? "          " : "");
3216                 llapi_printf(LLAPI_MSG_NORMAL, DFID_NOBRACE, PFID(&dir_fid));
3217
3218                 separator = yaml ? "\n" : " ";
3219         }
3220
3221         if (verbose & VERBOSE_DETAIL) {
3222                 llapi_printf(LLAPI_MSG_NORMAL, "%s", separator);
3223                 llapi_printf(LLAPI_MSG_NORMAL, "lmv_magic: %s%#x",
3224                              yaml ? "        " : "", (int)lum->lum_magic);
3225                 separator = yaml ? "\n" : " ";
3226         }
3227
3228         if (verbose & VERBOSE_STRIPE_COUNT) {
3229                 llapi_printf(LLAPI_MSG_NORMAL, "%s", separator);
3230                 if (verbose & ~VERBOSE_STRIPE_COUNT)
3231                         llapi_printf(LLAPI_MSG_NORMAL, "lmv_stripe_count: %s",
3232                                      yaml ? " " : "");
3233                 llapi_printf(LLAPI_MSG_NORMAL, "%d",
3234                              (int)lum->lum_stripe_count);
3235                 separator = yaml ? "\n" : " ";
3236         }
3237
3238         if (verbose & VERBOSE_STRIPE_OFFSET) {
3239                 llapi_printf(LLAPI_MSG_NORMAL, "%s", separator);
3240                 if (verbose & ~VERBOSE_STRIPE_OFFSET)
3241                         llapi_printf(LLAPI_MSG_NORMAL, "lmv_stripe_offset: ");
3242                 llapi_printf(LLAPI_MSG_NORMAL, hex ? "%#x" : "%d",
3243                              (int)lum->lum_stripe_offset);
3244                 separator = yaml ? "\n" : " ";
3245         }
3246
3247         if (verbose & VERBOSE_HASH_TYPE) {
3248                 unsigned int type = lum->lum_hash_type & LMV_HASH_TYPE_MASK;
3249                 unsigned int flags = lum->lum_hash_type & ~LMV_HASH_TYPE_MASK;
3250
3251                 llapi_printf(LLAPI_MSG_NORMAL, "%s", separator);
3252                 if (verbose & ~VERBOSE_HASH_TYPE)
3253                         llapi_printf(LLAPI_MSG_NORMAL, "lmv_hash_type: %s",
3254                                      yaml ? "    " : "");
3255                 if (type < LMV_HASH_TYPE_MAX)
3256                         llapi_printf(LLAPI_MSG_NORMAL, "%s",
3257                                      mdt_hash_name[type]);
3258                 else
3259                         llapi_printf(LLAPI_MSG_NORMAL, "%#x", type);
3260
3261                 if (flags & LMV_HASH_FLAG_OVERSTRIPED)
3262                         llapi_printf(LLAPI_MSG_NORMAL, ",overstriped");
3263                 if (flags & LMV_HASH_FLAG_MIGRATION)
3264                         llapi_printf(LLAPI_MSG_NORMAL, ",migrating");
3265                 if (flags & LMV_HASH_FLAG_BAD_TYPE)
3266                         llapi_printf(LLAPI_MSG_NORMAL, ",bad_type");
3267                 if (flags & LMV_HASH_FLAG_LOST_LMV)
3268                         llapi_printf(LLAPI_MSG_NORMAL, ",lost_lmv");
3269                 if (flags & LMV_HASH_FLAG_FIXED)
3270                         llapi_printf(LLAPI_MSG_NORMAL, ",fixed");
3271                 if (flags & ~LMV_HASH_FLAG_KNOWN)
3272                         llapi_printf(LLAPI_MSG_NORMAL, ",unknown_%04x",
3273                                      flags & ~LMV_HASH_FLAG_KNOWN);
3274                 separator = yaml ? "\n" : " ";
3275         }
3276
3277         if ((verbose & VERBOSE_INHERIT) && lum->lum_magic == LMV_USER_MAGIC) {
3278                 llapi_printf(LLAPI_MSG_NORMAL, "%s", separator);
3279                 if (verbose & ~VERBOSE_INHERIT)
3280                         llapi_printf(LLAPI_MSG_NORMAL, "lmv_max_inherit: %s",
3281                                      yaml ? "  " : "");
3282                 if (lum->lum_max_inherit == LMV_INHERIT_UNLIMITED)
3283                         llapi_printf(LLAPI_MSG_NORMAL, "-1");
3284                 else if (lum->lum_max_inherit == LMV_INHERIT_NONE)
3285                         llapi_printf(LLAPI_MSG_NORMAL, "0");
3286                 else
3287                         llapi_printf(LLAPI_MSG_NORMAL, "%hhu",
3288                                      lum->lum_max_inherit);
3289                 separator = yaml ? "\n" : " ";
3290         }
3291
3292         if ((verbose & VERBOSE_INHERIT_RR) &&
3293             lum->lum_magic == LMV_USER_MAGIC) {
3294                 llapi_printf(LLAPI_MSG_NORMAL, "%s", separator);
3295                 if (verbose & ~VERBOSE_INHERIT_RR)
3296                         llapi_printf(LLAPI_MSG_NORMAL, "lmv_max_inherit_rr: ");
3297                 if (lum->lum_max_inherit_rr == LMV_INHERIT_RR_UNLIMITED)
3298                         llapi_printf(LLAPI_MSG_NORMAL, "-1");
3299                 else if (lum->lum_max_inherit_rr == LMV_INHERIT_RR_NONE)
3300                         llapi_printf(LLAPI_MSG_NORMAL, "0");
3301                 else
3302                         llapi_printf(LLAPI_MSG_NORMAL, "%hhu",
3303                                      lum->lum_max_inherit_rr);
3304                 separator = yaml ? "\n" : " ";
3305         }
3306
3307         if ((verbose & VERBOSE_POOL) && pool_name != NULL &&
3308             pool_name[0] != '\0') {
3309                 llapi_printf(LLAPI_MSG_NORMAL, "%s", separator);
3310                 if (verbose & ~VERBOSE_POOL)
3311                         llapi_printf(LLAPI_MSG_NORMAL, "%slmv_pool: %s",
3312                                      prefix, yaml ? "          " : "");
3313                 llapi_printf(LLAPI_MSG_NORMAL, "%s%c ", pool_name, ' ');
3314         }
3315
3316         separator = "\n";
3317
3318         if ((verbose & VERBOSE_OBJID) && lum->lum_magic != LMV_USER_MAGIC) {
3319                 char fmt[64];
3320
3321                 llapi_printf(LLAPI_MSG_NORMAL, "%s", separator);
3322                 if (yaml)
3323                         llapi_printf(LLAPI_MSG_NORMAL,
3324                                      "lmv_objects:\n");
3325                 else if (lum->lum_stripe_count >= 0)
3326                         llapi_printf(LLAPI_MSG_NORMAL,
3327                                      "mdtidx\t\t FID[seq:oid:ver]\n");
3328
3329                 if (yaml)
3330                         snprintf(fmt, sizeof(fmt),
3331                                  "      - l_mdt_idx: %s\n%s\n",
3332                                  hex ? "%#x" : "%d",
3333                                  "        l_fid:     "DFID_NOBRACE);
3334                 else
3335                         snprintf(fmt, sizeof(fmt), "%s%s", hex ? "%#6x" : "%6u",
3336                                 "\t\t "DFID"\t\t%s\n");
3337                 if (lum->lum_stripe_count == 0 && yaml) {
3338                         llapi_printf(LLAPI_MSG_NORMAL, fmt,
3339                                      lum->lum_stripe_offset,
3340                                      PFID(&dir_fid), "");
3341                 }
3342                 for (i = 0; i < lum->lum_stripe_count; i++) {
3343                         int idx = objects[i].lum_mds;
3344                         struct lu_fid *fid = &objects[i].lum_fid;
3345
3346                         if ((obdindex == OBD_NOT_FOUND) || (obdindex == idx))
3347                                 llapi_printf(LLAPI_MSG_NORMAL, fmt, idx,
3348                                              PFID(fid),
3349                                              obdindex == idx ? " *":"");
3350                 }
3351         }
3352
3353         if (!(verbose & VERBOSE_OBJID) || lum->lum_magic == LMV_USER_MAGIC)
3354                 llapi_printf(LLAPI_MSG_NORMAL, "\n");
3355 }
3356
3357 static void lov_dump_comp_v1_header(struct find_param *param, char *path,
3358                                     enum lov_dump_flags flags)
3359 {
3360         struct lov_comp_md_v1 *comp_v1 = (void *)&param->fp_lmd->lmd_lmm;
3361         int depth = param->fp_max_depth;
3362         enum llapi_layout_verbose verbose = param->fp_verbose;
3363         bool yaml = flags & LDF_YAML;
3364
3365         if (depth && path && ((verbose != VERBOSE_OBJID) ||
3366                               !(flags & LDF_IS_DIR)) && !yaml)
3367                 llapi_printf(LLAPI_MSG_NORMAL, "%s\n", path);
3368
3369         if (verbose & VERBOSE_DETAIL) {
3370                 llapi_printf(LLAPI_MSG_NORMAL, "composite_header:\n");
3371                 llapi_printf(LLAPI_MSG_NORMAL, "%2slcm_magic:         0x%08X\n",
3372                              " ", comp_v1->lcm_magic);
3373                 llapi_printf(LLAPI_MSG_NORMAL, "%2slcm_size:          %u\n",
3374                              " ", comp_v1->lcm_size);
3375                 if (flags & LDF_IS_DIR)
3376                         llapi_printf(LLAPI_MSG_NORMAL,
3377                                      "%2slcm_flags:         %s\n", " ",
3378                                      comp_v1->lcm_mirror_count > 0 ?
3379                                                         "mirrored" : "");
3380                 else
3381                         llapi_printf(LLAPI_MSG_NORMAL,
3382                                      "%2slcm_flags:         %s\n", " ",
3383                                 llapi_layout_flags_string(comp_v1->lcm_flags));
3384         }
3385
3386         if (verbose & VERBOSE_GENERATION) {
3387                 if (verbose & ~VERBOSE_GENERATION)
3388                         llapi_printf(LLAPI_MSG_NORMAL, "%slcm_layout_gen:    ",
3389                                      yaml ? "" : "  ");
3390                 llapi_printf(LLAPI_MSG_NORMAL, "%u\n", comp_v1->lcm_layout_gen);
3391         }
3392
3393         if (verbose & VERBOSE_MIRROR_COUNT) {
3394                 if (verbose & ~VERBOSE_MIRROR_COUNT)
3395                         llapi_printf(LLAPI_MSG_NORMAL, "%slcm_mirror_count:  ",
3396                                      yaml ? "" : "  ");
3397                 llapi_printf(LLAPI_MSG_NORMAL, "%u\n",
3398                              comp_v1->lcm_magic == LOV_USER_MAGIC_COMP_V1 ?
3399                              comp_v1->lcm_mirror_count + 1 : 1);
3400         }
3401
3402         if (verbose & VERBOSE_COMP_COUNT) {
3403                 if (verbose & ~VERBOSE_COMP_COUNT)
3404                         llapi_printf(LLAPI_MSG_NORMAL, "%slcm_entry_count:   ",
3405                                      yaml ? "" : "  ");
3406                 llapi_printf(LLAPI_MSG_NORMAL, "%u\n",
3407                              comp_v1->lcm_magic == LOV_USER_MAGIC_COMP_V1 ?
3408                              comp_v1->lcm_entry_count : 0);
3409         }
3410
3411         if (verbose & VERBOSE_DETAIL || yaml)
3412                 llapi_printf(LLAPI_MSG_NORMAL, "components:\n");
3413 }
3414
3415 static void lcme_flags2str(__u32 comp_flags)
3416 {
3417         bool found = false;
3418         int i = 0;
3419
3420         if (!comp_flags) {
3421                 llapi_printf(LLAPI_MSG_NORMAL, "0");
3422                 return;
3423         }
3424         for (i = 0; i < ARRAY_SIZE(comp_flags_table); i++) {
3425                 const char *cfn_name = comp_flags_table[i].cfn_name;
3426                 __u32 cfn_flag = comp_flags_table[i].cfn_flag;
3427
3428                 if ((comp_flags & cfn_flag) == cfn_flag) {
3429                         if (found)
3430                                 llapi_printf(LLAPI_MSG_NORMAL, ",");
3431                         llapi_printf(LLAPI_MSG_NORMAL, "%s", cfn_name);
3432                         comp_flags &= ~comp_flags_table[i].cfn_flag;
3433                         found = true;
3434                 }
3435         }
3436         if (comp_flags) {
3437                 if (found)
3438                         llapi_printf(LLAPI_MSG_NORMAL, ",");
3439                 llapi_printf(LLAPI_MSG_NORMAL, "%#x", comp_flags);
3440         }
3441 }
3442
3443 static void lov_dump_comp_v1_entry(struct find_param *param,
3444                                    enum lov_dump_flags flags, int index)
3445 {
3446         struct lov_comp_md_v1 *comp_v1 = (void *)&param->fp_lmd->lmd_lmm;
3447         struct lov_comp_md_entry_v1 *entry;
3448         char *separator = "";
3449         enum llapi_layout_verbose verbose = param->fp_verbose;
3450         bool yaml = flags & LDF_YAML;
3451
3452         entry = &comp_v1->lcm_entries[index];
3453
3454         if (verbose & VERBOSE_COMP_ID || yaml) {
3455                 if (verbose & VERBOSE_DETAIL || yaml)
3456                         llapi_printf(LLAPI_MSG_NORMAL,
3457                                      "%slcme_id:             ", "  - ");
3458                 else if (verbose & ~VERBOSE_COMP_ID)
3459                         llapi_printf(LLAPI_MSG_NORMAL,
3460                                      "%4slcme_id:             ", " ");
3461                 if (entry->lcme_id != LCME_ID_INVAL)
3462                         llapi_printf(LLAPI_MSG_NORMAL, "%u", entry->lcme_id);
3463                 else
3464                         llapi_printf(LLAPI_MSG_NORMAL, "N/A");
3465                 separator = "\n";
3466         }
3467
3468         if (verbose & VERBOSE_MIRROR_ID) {
3469                 llapi_printf(LLAPI_MSG_NORMAL, "%s", separator);
3470                 if (verbose & ~VERBOSE_MIRROR_ID)
3471                         llapi_printf(LLAPI_MSG_NORMAL,
3472                                      "%4slcme_mirror_id:      ", " ");
3473                 if (entry->lcme_id != LCME_ID_INVAL)
3474                         llapi_printf(LLAPI_MSG_NORMAL, "%u",
3475                                      mirror_id_of(entry->lcme_id));
3476                 else
3477                         llapi_printf(LLAPI_MSG_NORMAL, "N/A");
3478                 separator = "\n";
3479         }
3480
3481         if (verbose & VERBOSE_COMP_FLAGS) {
3482                 llapi_printf(LLAPI_MSG_NORMAL, "%s", separator);
3483                 if (verbose & ~VERBOSE_COMP_FLAGS)
3484                         llapi_printf(LLAPI_MSG_NORMAL,
3485                                      "%4slcme_flags:          ", " ");
3486                 lcme_flags2str(entry->lcme_flags);
3487                 separator = "\n";
3488         }
3489         /* print snapshot timestamp if its a nosync comp */
3490         if ((verbose & VERBOSE_COMP_FLAGS) &&
3491             (entry->lcme_flags & LCME_FL_NOSYNC)) {
3492                 llapi_printf(LLAPI_MSG_NORMAL, "%s", separator);
3493                 if (verbose & ~VERBOSE_COMP_FLAGS)
3494                         llapi_printf(LLAPI_MSG_NORMAL,
3495                                      "%4slcme_timestamp:      ", " ");
3496                 if (yaml) {
3497                         llapi_printf(LLAPI_MSG_NORMAL, "%llu",
3498                                      (unsigned long long)entry->lcme_timestamp);
3499                 } else {
3500                         time_t stamp = entry->lcme_timestamp;
3501                         char *date_str = asctime(localtime(&stamp));
3502
3503                         date_str[strlen(date_str) - 1] = '\0';
3504                         llapi_printf(LLAPI_MSG_NORMAL, "'%s'", date_str);
3505                 }
3506
3507                 separator = "\n";
3508         }
3509
3510         if (verbose & VERBOSE_COMP_START) {
3511                 llapi_printf(LLAPI_MSG_NORMAL, "%s", separator);
3512                 if (verbose & ~VERBOSE_COMP_START)
3513                         llapi_printf(LLAPI_MSG_NORMAL,
3514                                      "%4slcme_extent.e_start: ", " ");
3515                 llapi_printf(LLAPI_MSG_NORMAL, "%llu",
3516                              (unsigned long long)entry->lcme_extent.e_start);
3517                 separator = "\n";
3518         }
3519
3520         if (verbose & VERBOSE_COMP_END) {
3521                 llapi_printf(LLAPI_MSG_NORMAL, "%s", separator);
3522                 if (verbose & ~VERBOSE_COMP_END)
3523                         llapi_printf(LLAPI_MSG_NORMAL,
3524                                      "%4slcme_extent.e_end:   ", " ");
3525                 if (entry->lcme_extent.e_end == LUSTRE_EOF)
3526                         llapi_printf(LLAPI_MSG_NORMAL, "%s", "EOF");
3527                 else
3528                         llapi_printf(LLAPI_MSG_NORMAL, "%llu",
3529                                      (unsigned long long)entry->lcme_extent.e_end);
3530                 separator = "\n";
3531         }
3532
3533         if (yaml) {
3534                 llapi_printf(LLAPI_MSG_NORMAL, "%s", separator);
3535                 llapi_printf(LLAPI_MSG_NORMAL, "%4ssub_layout:\n", " ");
3536         } else if (verbose & VERBOSE_DETAIL) {
3537                 llapi_printf(LLAPI_MSG_NORMAL, "%s", separator);
3538                 llapi_printf(LLAPI_MSG_NORMAL, "%4slcme_offset:         %u\n",
3539                              " ", entry->lcme_offset);
3540                 llapi_printf(LLAPI_MSG_NORMAL, "%4slcme_size:           %u\n",
3541                              " ", entry->lcme_size);
3542                 llapi_printf(LLAPI_MSG_NORMAL, "%4ssub_layout:\n", " ");
3543         } else {
3544                 llapi_printf(LLAPI_MSG_NORMAL, "%s", separator);
3545         }
3546 }
3547
3548 /*
3549  * Check if the value matches 1 of the given criteria (e.g. --atime +/-N).
3550  * @mds indicates if this is MDS timestamps and there are attributes on OSTs.
3551  *
3552  * The result is -1 if it does not match, 0 if not yet clear, 1 if matches.
3553  * The table below gives the answers for the specified parameters (value and
3554  * sign), 1st column is the answer for the MDS value, the 2nd is for the OST:
3555  * --------------------------------------
3556  * 1 | file > limit; sign > 0 | -1 / -1 |
3557  * 2 | file = limit; sign > 0 | -1 / -1 |
3558  * 3 | file < limit; sign > 0 |  ? /  1 |
3559  * 4 | file > limit; sign = 0 | -1 / -1 |
3560  * 5 | file = limit; sign = 0 |  ? /  1 |  <- (see the Note below)
3561  * 6 | file < limit; sign = 0 |  ? / -1 |
3562  * 7 | file > limit; sign < 0 |  1 /  1 |
3563  * 8 | file = limit; sign < 0 |  ? / -1 |
3564  * 9 | file < limit; sign < 0 |  ? / -1 |
3565  * --------------------------------------
3566  * Note: 5th actually means that the value is within the interval
3567  * (limit - margin, limit].
3568  */
3569 static int find_value_cmp(unsigned long long file, unsigned long long limit,
3570                           int sign, int negopt, unsigned long long margin,
3571                           bool mds)
3572 {
3573         int ret = -1;
3574
3575         if (sign > 0) {
3576                 /* Drop the fraction of margin (of days or size). */
3577                 if (file + margin <= limit)
3578                         ret = mds ? 0 : 1;
3579         } else if (sign == 0) {
3580                 if (file <= limit && file + margin > limit)
3581                         ret = mds ? 0 : 1;
3582                 else if (file + margin <= limit)
3583                         ret = mds ? 0 : -1;
3584         } else if (sign < 0) {
3585                 if (file > limit)
3586                         ret = 1;
3587                 else if (mds)
3588                         ret = 0;
3589         }
3590
3591         return negopt ? ~ret + 1 : ret;
3592 }
3593
3594 static inline struct lov_user_md *
3595 lov_comp_entry(struct lov_comp_md_v1 *comp_v1, int ent_idx)
3596 {
3597         return (struct lov_user_md *)((char *)comp_v1 +
3598                         comp_v1->lcm_entries[ent_idx].lcme_offset);
3599 }
3600
3601 static inline struct lov_user_ost_data_v1 *
3602 lov_v1v3_objects(struct lov_user_md *v1)
3603 {
3604         if (v1->lmm_magic == LOV_USER_MAGIC_V3)
3605                 return ((struct lov_user_md_v3 *)v1)->lmm_objects;
3606         else
3607                 return v1->lmm_objects;
3608 }
3609
3610 static inline void
3611 lov_v1v3_pool_name(struct lov_user_md *v1, char *pool_name)
3612 {
3613         if (v1->lmm_magic == LOV_USER_MAGIC_V3)
3614                 snprintf(pool_name, LOV_MAXPOOLNAME + 1, "%s",
3615                          ((struct lov_user_md_v3 *)v1)->lmm_pool_name);
3616         else
3617                 pool_name[0] = '\0';
3618 }
3619
3620 static inline bool
3621 print_last_init_comp(struct find_param *param)
3622 {
3623         /* print all component info */
3624         if ((param->fp_verbose & VERBOSE_DEFAULT) == VERBOSE_DEFAULT)
3625                 return false;
3626
3627         /* print specific component info */
3628         if (param->fp_check_comp_id || param->fp_check_comp_flags ||
3629             param->fp_check_comp_start || param->fp_check_comp_end ||
3630             param->fp_check_mirror_id || param->fp_check_mirror_index)
3631                 return false;
3632
3633         return true;
3634 }
3635
3636 static int find_comp_end_cmp(unsigned long long end, struct find_param *param)
3637 {
3638         int match;
3639
3640         if (param->fp_comp_end == LUSTRE_EOF) {
3641                 if (param->fp_comp_end_sign == 0) /* equal to EOF */
3642                         match = end == LUSTRE_EOF ? 1 : -1;
3643                 else if (param->fp_comp_end_sign > 0) /* at most EOF */
3644                         match = end == LUSTRE_EOF ? -1 : 1;
3645                 else /* at least EOF */
3646                         match = -1;
3647                 if (param->fp_exclude_comp_end)
3648                         match = ~match + 1;
3649         } else {
3650                 unsigned long long margin;
3651
3652                 margin = end == LUSTRE_EOF ? 0 : param->fp_comp_end_units;
3653                 match = find_value_cmp(end, param->fp_comp_end,
3654                                        param->fp_comp_end_sign,
3655                                        param->fp_exclude_comp_end, margin, 0);
3656         }
3657
3658         return match;
3659 }
3660
3661 /**
3662  * An example of "getstripe -v" for a two components PFL file:
3663  *
3664  * composite_header:
3665  * lcm_magic:       0x0BD60BD0
3666  * lcm_size:        264
3667  * lcm_flags:       0
3668  * lcm_layout_gen:  2
3669  * lcm_entry_count: 2
3670  * components:
3671  * - lcme_id:             1
3672  *   lcme_flags:          0x10
3673  *   lcme_extent.e_start: 0
3674  *   lcme_extent.e_end:   1048576
3675  *   lcme_offset:         128
3676  *   lcme_size:           56
3677  *   sub_layout:
3678  *     lmm_magic:         0x0BD10BD0
3679  *     lmm_seq:           0x200000401
3680  *     lmm_object_id:     0x1
3681  *     lmm_fid:           [0x200000401:0x1:0x0]
3682  *     lmm_stripe_count:  1
3683  *     lmm_stripe_size:   1048576
3684  *     lmm_pattern:       raid0
3685  *     lmm_layout_gen:    0
3686  *     lmm_stripe_offset: 0
3687  *     lmm_objects:
3688  *     - 0: { l_ost_idx: 0, l_fid: [0x100000000:0x2:0x0] }
3689  *
3690  * - lcme_id:             2
3691  *   lcme_flags:          0x10
3692  *   lcme_extent.e_start: 1048576
3693  *   lcme_extent.e_end:   EOF
3694  *   lcme_offset:         184
3695  *   lcme_size:           80
3696  *     sub_layout:
3697  *     lmm_magic:         0x0BD10BD0
3698  *     lmm_seq:           0x200000401
3699  *     lmm_object_id:     0x1
3700  *     lmm_fid:           [0x200000401:0x1:0x0]
3701  *     lmm_stripe_count:  2
3702  *     lmm_stripe_size:   1048576
3703  *     lmm_pattern:       raid0
3704  *     lmm_layout_gen:    0
3705  *     lmm_stripe_offset: 1
3706  *     lmm_objects:
3707  *     - 0: { l_ost_idx: 1, l_fid: [0x100010000:0x2:0x0] }
3708  *     - 1: { l_ost_idx: 0, l_fid: [0x100000000:0x3:0x0] }
3709  */
3710 static void lov_dump_comp_v1(struct find_param *param, char *path,
3711                              enum lov_dump_flags flags)
3712 {
3713         struct lov_comp_md_entry_v1 *entry;
3714         struct lov_user_ost_data_v1 *objects;
3715         struct lov_comp_md_v1 *comp_v1 = (void *)&param->fp_lmd->lmd_lmm;
3716         struct lov_user_md_v1 *v1;
3717         char pool_name[LOV_MAXPOOLNAME + 1];
3718         int obdindex = param->fp_obd_index;
3719         int i, j, match, ext;
3720         bool obdstripe = false;
3721         __u16 mirror_index = 0;
3722         __u16 mirror_id = 0;
3723
3724         if (obdindex != OBD_NOT_FOUND) {
3725                 for (i = 0; !(flags & LDF_IS_DIR) && !obdstripe &&
3726                             i < comp_v1->lcm_entry_count; i++) {
3727                         if (!(comp_v1->lcm_entries[i].lcme_flags &
3728                               LCME_FL_INIT))
3729                                 continue;
3730
3731                         v1 = lov_comp_entry(comp_v1, i);
3732                         if (v1->lmm_magic == LOV_MAGIC_FOREIGN)
3733                                 continue;
3734
3735                         objects = lov_v1v3_objects(v1);
3736
3737                         for (j = 0; j < v1->lmm_stripe_count; j++) {
3738                                 if (obdindex == objects[j].l_ost_idx) {
3739                                         obdstripe = true;
3740                                         break;
3741                                 }
3742                         }
3743                 }
3744         } else {
3745                 obdstripe = true;
3746         }
3747
3748         if (!obdstripe)
3749                 return;
3750
3751         lov_dump_comp_v1_header(param, path, flags);
3752
3753         flags |= LDF_INDENT;
3754
3755         for (i = 0; i < comp_v1->lcm_entry_count; i++) {
3756                 entry = &comp_v1->lcm_entries[i];
3757
3758                 if (param->fp_check_comp_flags) {
3759                         if (((param->fp_comp_flags & entry->lcme_flags) !=
3760                              param->fp_comp_flags) ||
3761                             (param->fp_comp_neg_flags & entry->lcme_flags))
3762                                 continue;
3763                 }
3764
3765                 if (param->fp_check_comp_id &&
3766                     param->fp_comp_id != entry->lcme_id)
3767                         continue;
3768
3769                 if (param->fp_check_comp_start) {
3770                         match = find_value_cmp(entry->lcme_extent.e_start,
3771                                                param->fp_comp_start,
3772                                                param->fp_comp_start_sign,
3773                                                0,
3774                                                param->fp_comp_start_units, 0);
3775                         if (match == -1)
3776                                 continue;
3777                 }
3778
3779                 if (param->fp_check_comp_end) {
3780                         match = find_comp_end_cmp(entry->lcme_extent.e_end,
3781                                                   param);
3782                         if (match == -1)
3783                                 continue;
3784                 }
3785
3786                 if (param->fp_check_mirror_index) {
3787                         if (mirror_id != mirror_id_of(entry->lcme_id)) {
3788                                 mirror_index++;
3789                                 mirror_id = mirror_id_of(entry->lcme_id);
3790                         }
3791
3792                         match = find_value_cmp(mirror_index,
3793                                                param->fp_mirror_index,
3794                                                param->fp_mirror_index_sign,
3795                                                param->fp_exclude_mirror_index,
3796                                                1, 0);
3797                         if (match == -1)
3798                                 continue;
3799                 } else if (param->fp_check_mirror_id) {
3800                         if (mirror_id != mirror_id_of(entry->lcme_id))
3801                                 mirror_id = mirror_id_of(entry->lcme_id);
3802
3803                         match = find_value_cmp(mirror_id,
3804                                                param->fp_mirror_id,
3805                                                param->fp_mirror_id_sign,
3806                                                param->fp_exclude_mirror_id,
3807                                                1, 0);
3808                         if (match == -1)
3809                                 continue;
3810                 }
3811
3812                 if (print_last_init_comp(param)) {
3813                         /**
3814                          * if part of stripe info is needed, we'd print only
3815                          * the last instantiated component info.
3816                          */
3817                         if (entry->lcme_flags & LCME_FL_INIT)
3818                                 continue;
3819
3820                         if (param->fp_verbose & VERBOSE_EXT_SIZE) {
3821                                 if (entry->lcme_flags & LCME_FL_EXTENSION)
3822                                         /* moved back below */
3823                                         i++;
3824                                 else
3825                                         continue;
3826                         }
3827                         break;
3828                 }
3829
3830                 if (entry->lcme_flags & LCME_FL_INIT) {
3831                         if (obdindex != OBD_NOT_FOUND) {
3832                                 flags |= LDF_SKIP_OBJS;
3833                                 v1 = lov_comp_entry(comp_v1, i);
3834                                 if (v1->lmm_magic == LOV_MAGIC_FOREIGN)
3835                                         continue;
3836
3837                                 objects = lov_v1v3_objects(v1);
3838
3839                                 for (j = 0; j < v1->lmm_stripe_count; j++) {
3840                                         if (obdindex == objects[j].l_ost_idx) {
3841                                                 flags &= ~LDF_SKIP_OBJS;
3842                                                 break;
3843                                         }
3844                                 }
3845                         } else {
3846                                 flags &= ~LDF_SKIP_OBJS;
3847                         }
3848                 } else {
3849                         flags |= LDF_SKIP_OBJS;
3850                 }
3851
3852                 if (obdindex != OBD_NOT_FOUND && (flags & LDF_SKIP_OBJS))
3853                         continue;
3854                 lov_dump_comp_v1_entry(param, flags, i);
3855
3856                 v1 = lov_comp_entry(comp_v1, i);
3857                 if (v1->lmm_magic == LOV_MAGIC_FOREIGN) {
3858                         lov_dump_hsm_lmm(v1, path, param->fp_max_depth,
3859                                          param->fp_verbose, flags);
3860                 } else {
3861                         objects = lov_v1v3_objects(v1);
3862                         lov_v1v3_pool_name(v1, pool_name);
3863
3864                         ext = entry->lcme_flags & LCME_FL_EXTENSION ?
3865                               LDF_EXTENSION : 0;
3866                         lov_dump_user_lmm_v1v3(v1, pool_name, objects, path,
3867                                                obdindex, param->fp_max_depth,
3868                                                param->fp_verbose, flags | ext);
3869                 }
3870         }
3871         if (print_last_init_comp(param)) {
3872                 /**
3873                  * directory layout contains only layout template, print the
3874                  * last component.
3875                  */
3876                 if (i == 0)
3877                         i = comp_v1->lcm_entry_count - 1;
3878                 else
3879                         i--;
3880                 flags &= ~LDF_SKIP_OBJS;
3881
3882                 lov_dump_comp_v1_entry(param, flags, i);
3883
3884                 v1 = lov_comp_entry(comp_v1, i);
3885                 if (v1->lmm_magic == LOV_MAGIC_FOREIGN) {
3886                         lov_dump_hsm_lmm(v1, path, param->fp_max_depth,
3887                                          param->fp_verbose, flags);
3888                 } else {
3889                         objects = lov_v1v3_objects(v1);
3890                         lov_v1v3_pool_name(v1, pool_name);
3891
3892                         entry = &comp_v1->lcm_entries[i];
3893                         ext = entry->lcme_flags & LCME_FL_EXTENSION ?
3894                               LDF_EXTENSION : 0;
3895                         lov_dump_user_lmm_v1v3(v1, pool_name, objects, path,
3896                                                obdindex, param->fp_max_depth,
3897                                                param->fp_verbose, flags | ext);
3898                 }
3899         }
3900 }
3901
3902 #define VERBOSE_COMP_OPTS       (VERBOSE_COMP_COUNT | VERBOSE_COMP_ID | \
3903                                  VERBOSE_COMP_START | VERBOSE_COMP_END | \
3904                                  VERBOSE_COMP_FLAGS)
3905
3906 static inline bool has_any_comp_options(struct find_param *param)
3907 {
3908         enum llapi_layout_verbose verbose = param->fp_verbose;
3909
3910         if (param->fp_check_comp_id || param->fp_check_comp_count ||
3911             param->fp_check_comp_start || param->fp_check_comp_end ||
3912             param->fp_check_comp_flags)
3913                 return true;
3914
3915         /* show full layout information, not component specific */
3916         if ((verbose & ~VERBOSE_DETAIL) == VERBOSE_DEFAULT)
3917                 return false;
3918
3919         return verbose & VERBOSE_COMP_OPTS;
3920 }
3921
3922 static struct lov_user_mds_data *
3923 lov_forge_comp_v1(struct lov_user_mds_data *orig, bool is_dir)
3924 {
3925         struct lov_user_md *lum = &orig->lmd_lmm;
3926         struct lov_user_mds_data *new;
3927         struct lov_comp_md_v1 *comp_v1;
3928         struct lov_comp_md_entry_v1 *ent;
3929         int lumd_hdr = offsetof(typeof(*new), lmd_lmm);
3930         int lum_off = sizeof(*comp_v1) + sizeof(*ent);
3931         int lum_size = lov_user_md_size(is_dir ? 0 : lum->lmm_stripe_count,
3932                                         lum->lmm_magic);
3933
3934         new = malloc(sizeof(*new) + sizeof(*ent) + lum_size);
3935         if (new == NULL) {
3936                 llapi_printf(LLAPI_MSG_NORMAL, "out of memory\n");
3937                 return new;
3938         }
3939         /* struct lov_user_mds_data header */
3940         memcpy(new, orig, lumd_hdr);
3941         /* fill comp_v1 */
3942         comp_v1 = (struct lov_comp_md_v1 *)&new->lmd_lmm;
3943         comp_v1->lcm_magic = lum->lmm_magic;
3944         comp_v1->lcm_size = lum_off + lum_size;
3945         comp_v1->lcm_layout_gen = is_dir ? 0 : lum->lmm_layout_gen;
3946         comp_v1->lcm_flags = 0;
3947         comp_v1->lcm_entry_count = 1;
3948         /* fill entry */
3949         ent = &comp_v1->lcm_entries[0];
3950         ent->lcme_id = 0;
3951         ent->lcme_flags = is_dir ? 0 : LCME_FL_INIT;
3952         ent->lcme_extent.e_start = 0;
3953         ent->lcme_extent.e_end = LUSTRE_EOF;
3954         ent->lcme_offset = lum_off;
3955         ent->lcme_size = lum_size;
3956         /* fill blob at end of entry */
3957         memcpy((char *)&comp_v1->lcm_entries[1], lum, lum_size);
3958
3959         return new;
3960 }
3961
3962 static void lov_dump_plain_user_lmm(struct find_param *param, char *path,
3963                                     enum lov_dump_flags flags)
3964 {
3965         __u32 magic = *(__u32 *)&param->fp_lmd->lmd_lmm;
3966
3967         if (has_any_comp_options(param)) {
3968                 struct lov_user_mds_data *new_lmd, *orig_lmd;
3969
3970                 orig_lmd = param->fp_lmd;
3971                 new_lmd = lov_forge_comp_v1(orig_lmd, flags & LDF_IS_DIR);
3972                 if (new_lmd != NULL) {
3973                         param->fp_lmd = new_lmd;
3974                         lov_dump_comp_v1(param, path, flags);
3975                         param->fp_lmd = orig_lmd;
3976                         free(new_lmd);
3977                 }
3978                 return;
3979         }
3980
3981         if (magic == LOV_USER_MAGIC_V1) {
3982                 lov_dump_user_lmm_v1v3(&param->fp_lmd->lmd_lmm, NULL,
3983                                        param->fp_lmd->lmd_lmm.lmm_objects,
3984                                        path, param->fp_obd_index,
3985                                        param->fp_max_depth, param->fp_verbose,
3986                                        flags);
3987         } else {
3988                 char pool_name[LOV_MAXPOOLNAME + 1];
3989                 struct lov_user_ost_data_v1 *objects;
3990                 struct lov_user_md_v3 *lmmv3 = (void *)&param->fp_lmd->lmd_lmm;
3991
3992                 snprintf(pool_name, sizeof(pool_name), "%s",
3993                          lmmv3->lmm_pool_name);
3994                 objects = lmmv3->lmm_objects;
3995                 lov_dump_user_lmm_v1v3(&param->fp_lmd->lmd_lmm, pool_name,
3996                                        objects, path, param->fp_obd_index,
3997                                        param->fp_max_depth, param->fp_verbose,
3998                                        flags);
3999         }
4000 }
4001
4002 static void lov_dump_foreign_lmm(struct find_param *param, char *path,
4003                                  enum lov_dump_flags flags)
4004 {
4005         struct lov_foreign_md *lfm = (void *)&param->fp_lmd->lmd_lmm;
4006         bool yaml = flags & LDF_YAML;
4007
4008         if (!yaml && param->fp_depth && path)
4009                 llapi_printf(LLAPI_MSG_NORMAL, "%s\n", path);
4010
4011         if (param->fp_verbose & VERBOSE_DETAIL) {
4012                 uint32_t type = check_foreign_type(lfm->lfm_type);
4013
4014                 llapi_printf(LLAPI_MSG_NORMAL, "lfm_magic:         0x%08X\n",
4015                              lfm->lfm_magic);
4016                 llapi_printf(LLAPI_MSG_NORMAL, "lfm_length:          %u\n",
4017                              lfm->lfm_length);
4018                 llapi_printf(LLAPI_MSG_NORMAL, "lfm_type:          0x%08X",
4019                              lfm->lfm_type);
4020                 if (type < LU_FOREIGN_TYPE_UNKNOWN)
4021                         llapi_printf(LLAPI_MSG_NORMAL, " (%s)\n",
4022                                      lu_foreign_types[type].lft_name);
4023                 else
4024                         llapi_printf(LLAPI_MSG_NORMAL, " (unknown)\n");
4025
4026                 llapi_printf(LLAPI_MSG_NORMAL, "lfm_flags:          0x%08X\n",
4027                              lfm->lfm_flags);
4028         }
4029         llapi_printf(LLAPI_MSG_NORMAL, "lfm_value:     '%.*s'\n",
4030                      lfm->lfm_length, lfm->lfm_value);
4031         llapi_printf(LLAPI_MSG_NORMAL, "\n");
4032 }
4033
4034 static void lmv_dump_foreign_lmm(struct find_param *param, char *path,
4035                                     enum lov_dump_flags flags)
4036 {
4037         struct lmv_foreign_md *lfm = (struct lmv_foreign_md *)param->fp_lmv_md;
4038         bool yaml = flags & LDF_YAML;
4039
4040         if (!yaml && param->fp_depth && path)
4041                 llapi_printf(LLAPI_MSG_NORMAL, "%s\n", path);
4042
4043         if (param->fp_verbose & VERBOSE_DETAIL) {
4044                 uint32_t type = check_foreign_type(lfm->lfm_type);
4045
4046                 llapi_printf(LLAPI_MSG_NORMAL, "lfm_magic:         0x%08X\n",
4047                              lfm->lfm_magic);
4048                 llapi_printf(LLAPI_MSG_NORMAL, "lfm_length:          %u\n",
4049                              lfm->lfm_length);
4050                 llapi_printf(LLAPI_MSG_NORMAL, "lfm_type:          0x%08X",
4051                              lfm->lfm_type);
4052                 if (type < LU_FOREIGN_TYPE_UNKNOWN)
4053                         llapi_printf(LLAPI_MSG_NORMAL, " (%s)\n",
4054                                      lu_foreign_types[type].lft_name);
4055                 else
4056                         llapi_printf(LLAPI_MSG_NORMAL, " (unknown)\n");
4057
4058                 llapi_printf(LLAPI_MSG_NORMAL, "lfm_flags:          0x%08X\n",
4059                              lfm->lfm_flags);
4060         }
4061         llapi_printf(LLAPI_MSG_NORMAL, "lfm_value:     '%.*s'\n",
4062                      lfm->lfm_length, lfm->lfm_value);
4063         llapi_printf(LLAPI_MSG_NORMAL, "\n");
4064 }
4065
4066 static void llapi_lov_dump_user_lmm(struct find_param *param, char *path,
4067                                     enum lov_dump_flags flags)
4068 {
4069         __u32 magic;
4070
4071         if (param->fp_get_lmv || param->fp_get_default_lmv)
4072                 magic = (__u32)param->fp_lmv_md->lum_magic;
4073         else
4074                 magic = *(__u32 *)&param->fp_lmd->lmd_lmm; /* lum->lmm_magic */
4075
4076         if (param->fp_raw)
4077                 flags |= LDF_IS_RAW;
4078         if (param->fp_yaml)
4079                 flags |= LDF_YAML;
4080         if (param->fp_hex_idx)
4081                 flags |= LDF_HEX_IDX;
4082
4083         switch (magic) {
4084         case LOV_USER_MAGIC_V1:
4085         case LOV_USER_MAGIC_V3:
4086         case LOV_USER_MAGIC_SPECIFIC:
4087                 lov_dump_plain_user_lmm(param, path, flags);
4088                 break;
4089         case LOV_USER_MAGIC_FOREIGN:
4090                 lov_dump_foreign_lmm(param, path, flags);
4091                 break;
4092         case LMV_MAGIC_V1:
4093         case LMV_USER_MAGIC: {
4094                 char pool_name[LOV_MAXPOOLNAME + 1];
4095                 struct lmv_user_md *lum;
4096
4097                 lum = (struct lmv_user_md *)param->fp_lmv_md;
4098                 snprintf(pool_name, sizeof(pool_name), "%s",
4099                          lum->lum_pool_name);
4100                 lmv_dump_user_lmm(lum, pool_name, path, param->fp_obd_index,
4101                                   param->fp_max_depth, param->fp_verbose,
4102                                   flags);
4103                 break;
4104         }
4105         case LOV_USER_MAGIC_COMP_V1:
4106                 lov_dump_comp_v1(param, path, flags);
4107                 break;
4108         case LMV_MAGIC_FOREIGN:
4109                 lmv_dump_foreign_lmm(param, path, flags);
4110                 break;
4111         default:
4112                 llapi_printf(LLAPI_MSG_NORMAL,
4113                              "unknown lmm_magic:  %#x (expecting one of %#x %#x %#x %#x)\n",
4114                              *(__u32 *)&param->fp_lmd->lmd_lmm,
4115                              LOV_USER_MAGIC_V1, LOV_USER_MAGIC_V3,
4116                              LMV_USER_MAGIC, LMV_MAGIC_V1);
4117                 return;
4118         }
4119 }
4120
4121 static int llapi_file_get_stripe1(const char *path, struct lov_user_md *lum)
4122 {
4123         const char *fname;
4124         char *dname;
4125         int fd, rc = 0;
4126
4127         fname = strrchr(path, '/');
4128
4129         /* It should be a file (or other non-directory) */
4130         if (fname == NULL) {
4131                 dname = (char *)malloc(2);
4132                 if (dname == NULL)
4133                         return -ENOMEM;
4134                 strcpy(dname, ".");
4135                 fname = (char *)path;
4136         } else {
4137                 dname = (char *)malloc(fname - path + 1);
4138                 if (dname == NULL)
4139                         return -ENOMEM;
4140                 strncpy(dname, path, fname - path);
4141                 dname[fname - path] = '\0';
4142                 fname++;
4143         }
4144
4145         fd = open(dname, O_RDONLY | O_NONBLOCK);
4146         if (fd == -1) {
4147                 rc = -errno;
4148                 goto out_free;
4149         }
4150
4151         strcpy((char *)lum, fname);
4152         if (ioctl(fd, IOC_MDC_GETFILESTRIPE, (void *)lum) == -1)
4153                 rc = -errno;
4154
4155         if (close(fd) == -1 && rc == 0)
4156                 rc = -errno;
4157
4158 out_free:
4159         free(dname);
4160         return rc;
4161 }
4162
4163 int llapi_file_get_stripe(const char *path, struct lov_user_md *lum)
4164 {
4165         char *canon_path = NULL;
4166         int rc, rc2;
4167
4168         rc = llapi_file_get_stripe1(path, lum);
4169         if (!(rc == -ENOTTY || rc == -ENODATA))
4170                 goto out;
4171
4172         /* Handle failure due to symlinks by dereferencing path manually. */
4173         canon_path = canonicalize_file_name(path);
4174         if (canon_path == NULL)
4175                 goto out; /* Keep original rc. */
4176
4177         rc2 = llapi_file_get_stripe1(canon_path, lum);
4178         if (rc2 < 0)
4179                 goto out; /* Keep original rc. */
4180
4181         rc = 0;
4182 out:
4183         free(canon_path);
4184
4185         return rc;
4186 }
4187
4188 int llapi_file_lookup(int dirfd, const char *name)
4189 {
4190         struct obd_ioctl_data data = { 0 };
4191         char rawbuf[8192];
4192         char *buf = rawbuf;
4193         int rc;
4194
4195         if (dirfd < 0 || name == NULL)
4196                 return -EINVAL;
4197
4198         data.ioc_version = OBD_IOCTL_VERSION;
4199         data.ioc_len = sizeof(data);
4200         data.ioc_inlbuf1 = (char *)name;
4201         data.ioc_inllen1 = strlen(name) + 1;
4202
4203         rc = llapi_ioctl_pack(&data, &buf, sizeof(rawbuf));
4204         if (rc) {
4205                 llapi_error(LLAPI_MSG_ERROR, rc,
4206                             "error: IOC_MDC_LOOKUP pack failed for '%s': rc %d",
4207                             name, rc);
4208                 return rc;
4209         }
4210
4211         rc = ioctl(dirfd, IOC_MDC_LOOKUP, buf);
4212         if (rc < 0)
4213                 rc = -errno;
4214         return rc;
4215 }
4216
4217 /*
4218  * Check if the file time matches all the given criteria (e.g. --atime +/-N).
4219  * Return -1 or 1 if file timestamp does not or does match the given criteria
4220  * correspondingly. Return 0 if the MDS time is being checked and there are
4221  * attributes on OSTs and it is not yet clear if the timespamp matches.
4222  *
4223  * If 0 is returned, we need to do another RPC to the OSTs to obtain the
4224  * updated timestamps.
4225  */
4226 static int find_time_check(struct find_param *param, int mds)
4227 {
4228         struct lov_user_mds_data *lmd = param->fp_lmd;
4229         int rc = 1;
4230         int rc2;
4231
4232         /* Check if file is accepted. */
4233         if (param->fp_atime) {
4234                 rc2 = find_value_cmp(lmd->lmd_stx.stx_atime.tv_sec,
4235                                      param->fp_atime, param->fp_asign,
4236                                      param->fp_exclude_atime,
4237                                      param->fp_time_margin, mds);
4238                 if (rc2 < 0)
4239                         return rc2;
4240                 rc = rc2;
4241         }
4242
4243         if (param->fp_mtime) {
4244                 rc2 = find_value_cmp(lmd->lmd_stx.stx_mtime.tv_sec,
4245                                      param->fp_mtime, param->fp_msign,
4246                                      param->fp_exclude_mtime,
4247                                      param->fp_time_margin, mds);
4248                 if (rc2 < 0)
4249                         return rc2;
4250
4251                 /*
4252                  * If the previous check matches, but this one is not yet clear,
4253                  * we should return 0 to do an RPC on OSTs.
4254                  */
4255                 if (rc == 1)
4256                         rc = rc2;
4257         }
4258
4259         if (param->fp_ctime) {
4260                 rc2 = find_value_cmp(lmd->lmd_stx.stx_ctime.tv_sec,
4261                                      param->fp_ctime, param->fp_csign,
4262                                      param->fp_exclude_ctime,
4263                                      param->fp_time_margin, mds);
4264                 if (rc2 < 0)
4265                         return rc2;
4266
4267                 /*
4268                  * If the previous check matches, but this one is not yet clear,
4269                  * we should return 0 to do an RPC on OSTs.
4270                  */
4271                 if (rc == 1)
4272                         rc = rc2;
4273         }
4274
4275         return rc;
4276 }
4277
4278 static int find_newerxy_check(struct find_param *param, int mds, bool from_mdt)
4279 {
4280         struct lov_user_mds_data *lmd = param->fp_lmd;
4281         int i;
4282         int rc = 1;
4283         int rc2;
4284
4285         for (i = 0; i < 2; i++) {
4286                 /* Check if file is accepted. */
4287                 if (param->fp_newery[NEWERXY_ATIME][i]) {
4288                         rc2 = find_value_cmp(lmd->lmd_stx.stx_atime.tv_sec,
4289                                              param->fp_newery[NEWERXY_ATIME][i],
4290                                              -1, i, 0, mds);
4291                         if (rc2 < 0)
4292                                 return rc2;
4293                         rc = rc2;
4294                 }
4295
4296                 if (param->fp_newery[NEWERXY_MTIME][i]) {
4297                         rc2 = find_value_cmp(lmd->lmd_stx.stx_mtime.tv_sec,
4298                                              param->fp_newery[NEWERXY_MTIME][i],
4299                                              -1, i, 0, mds);
4300                         if (rc2 < 0)
4301                                 return rc2;
4302
4303                         /*
4304                          * If the previous check matches, but this one is not
4305                          * yet clear, we should return 0 to do an RPC on OSTs.
4306                          */
4307                         if (rc == 1)
4308                                 rc = rc2;
4309                 }
4310
4311                 if (param->fp_newery[NEWERXY_CTIME][i]) {
4312                         rc2 = find_value_cmp(lmd->lmd_stx.stx_ctime.tv_sec,
4313                                              param->fp_newery[NEWERXY_CTIME][i],
4314                                              -1, i, 0, mds);
4315                         if (rc2 < 0)
4316                                 return rc2;
4317
4318                         /*
4319                          * If the previous check matches, but this one is not
4320                          * yet clear, we should return 0 to do an RPC on OSTs.
4321                          */
4322                         if (rc == 1)
4323                                 rc = rc2;
4324                 }
4325
4326                 /*
4327                  * File birth time (btime) can get from MDT directly.
4328                  * if @from_mdt is true, it means the input file attributs are
4329                  * obtained directly from MDT.
4330                  * Thus, if @from_mdt is false, we should skip the following
4331                  * btime check.
4332                  */
4333                 if (!from_mdt)
4334                         continue;
4335
4336                 if (param->fp_newery[NEWERXY_BTIME][i]) {
4337                         if (!(lmd->lmd_stx.stx_mask & STATX_BTIME))
4338                                 return -EOPNOTSUPP;
4339
4340                         rc2 = find_value_cmp(lmd->lmd_stx.stx_btime.tv_sec,
4341                                              param->fp_newery[NEWERXY_BTIME][i],
4342                                              -1, i, 0, 0);
4343                         if (rc2 < 0)
4344                                 return rc2;
4345                 }
4346         }
4347
4348         return rc;
4349 }
4350
4351 /**
4352  * Check whether the stripes matches the indexes user provided
4353  *       1   : matched
4354  *       0   : Unmatched
4355  */
4356 static int check_obd_match(struct find_param *param)
4357 {
4358         struct lov_user_ost_data_v1 *objects;
4359         struct lov_comp_md_v1 *comp_v1 = NULL;
4360         struct lov_user_mds_data *lmd = param->fp_lmd;
4361         struct lov_user_md_v1 *v1 = &lmd->lmd_lmm;
4362         int i, j, k, count = 1;
4363
4364         if (param->fp_obd_uuid && param->fp_obd_index == OBD_NOT_FOUND)
4365                 return 0;
4366
4367         if (!S_ISREG(lmd->lmd_stx.stx_mode))
4368                 return 0;
4369
4370         /* exclude foreign */
4371         if (v1->lmm_magic == LOV_USER_MAGIC_FOREIGN)
4372                 return param->fp_exclude_obd;
4373
4374         /*
4375          * Only those files should be accepted, which have a
4376          * stripe on the specified OST.
4377          */
4378         if (v1->lmm_magic == LOV_USER_MAGIC_COMP_V1) {
4379                 comp_v1 = (struct lov_comp_md_v1 *)v1;
4380                 count = comp_v1->lcm_entry_count;
4381         }
4382
4383         for (i = 0; i < count; i++) {
4384                 if (comp_v1)
4385                         v1 = lov_comp_entry(comp_v1, i);
4386
4387                 objects = lov_v1v3_objects(v1);
4388
4389                 for (j = 0; j < v1->lmm_stripe_count; j++) {
4390                         if (comp_v1 && !(comp_v1->lcm_entries[i].lcme_flags &
4391                                          LCME_FL_INIT))
4392                                 continue;
4393                         for (k = 0; k < param->fp_num_obds; k++) {
4394                                 if (param->fp_obd_indexes[k] ==
4395                                     objects[j].l_ost_idx)
4396                                         return !param->fp_exclude_obd;
4397                         }
4398                 }
4399         }
4400
4401         return param->fp_exclude_obd;
4402 }
4403
4404 static int check_mdt_match(struct find_param *param)
4405 {
4406         int i;
4407
4408         if (param->fp_mdt_uuid && param->fp_mdt_index == OBD_NOT_FOUND)
4409                 return 0;
4410
4411         /* FIXME: For striped dir, we should get stripe information and check */
4412         for (i = 0; i < param->fp_num_mdts; i++) {
4413                 if (param->fp_mdt_indexes[i] == param->fp_file_mdt_index)
4414                         return !param->fp_exclude_mdt;
4415         }
4416
4417         if (param->fp_exclude_mdt)
4418                 return 1;
4419
4420         return 0;
4421 }
4422
4423 /**
4424  * Check whether the obd is active or not, if it is
4425  * not active, just print the object affected by this
4426  * failed target
4427  **/
4428 static void print_failed_tgt(struct find_param *param, char *path, int type)
4429 {
4430         struct obd_statfs stat_buf;
4431         struct obd_uuid uuid_buf;
4432         int tgt_nr, i, *indexes;
4433         int ret = 0;
4434
4435         if (type != LL_STATFS_LOV && type != LL_STATFS_LMV) {
4436                 llapi_error(LLAPI_MSG_NORMAL, ret, "%s: wrong statfs type(%d)",
4437                             __func__, type);
4438                 return;
4439         }
4440
4441         tgt_nr = (type == LL_STATFS_LOV) ? param->fp_obd_index :
4442                  param->fp_mdt_index;
4443         indexes = (type == LL_STATFS_LOV) ? param->fp_obd_indexes :
4444                   param->fp_mdt_indexes;
4445
4446         for (i = 0; i < tgt_nr; i++) {
4447                 memset(&stat_buf, 0, sizeof(struct obd_statfs));
4448                 memset(&uuid_buf, 0, sizeof(struct obd_uuid));
4449
4450                 ret = llapi_obd_statfs(path, type, indexes[i], &stat_buf,
4451                                        &uuid_buf);
4452                 if (ret)
4453                         llapi_error(LLAPI_MSG_NORMAL, ret,
4454                                     "%s: obd_uuid: %s failed",
4455                                     __func__, param->fp_obd_uuid->uuid);
4456         }
4457 }
4458
4459 static int find_check_stripe_size(struct find_param *param)
4460 {
4461         struct lov_comp_md_v1 *comp_v1 = NULL;
4462         struct lov_user_md_v1 *v1 = &param->fp_lmd->lmd_lmm;
4463         __u32 stripe_size = 0;
4464         int ret, i, count = 1;
4465
4466         if (v1->lmm_magic == LOV_USER_MAGIC_FOREIGN)
4467                 return param->fp_exclude_stripe_size ? 1 : -1;
4468
4469         ret = param->fp_exclude_stripe_size ? 1 : -1;
4470         if (v1->lmm_magic == LOV_USER_MAGIC_COMP_V1) {
4471                 comp_v1 = (struct lov_comp_md_v1 *)v1;
4472                 count = comp_v1->lcm_entry_count;
4473         }
4474
4475         for (i = 0; i < count; i++) {
4476                 struct lov_comp_md_entry_v1 *ent;
4477
4478                 if (comp_v1) {
4479                         v1 = lov_comp_entry(comp_v1, i);
4480
4481                         ent = &comp_v1->lcm_entries[i];
4482                         if (ent->lcme_flags & LCME_FL_EXTENSION)
4483                                 continue;
4484                         if (!(ent->lcme_flags & LCME_FL_INIT))
4485                                 continue;
4486                 }
4487                 stripe_size = v1->lmm_stripe_size;
4488         }
4489
4490         ret = find_value_cmp(stripe_size, param->fp_stripe_size,
4491                              param->fp_stripe_size_sign,
4492                              param->fp_exclude_stripe_size,
4493                              param->fp_stripe_size_units, 0);
4494
4495         return ret;
4496 }
4497
4498 static int find_check_ext_size(struct find_param *param)
4499 {
4500         struct lov_comp_md_v1 *comp_v1;
4501         struct lov_user_md_v1 *v1;
4502         int ret, i;
4503
4504         ret = param->fp_exclude_ext_size ? 1 : -1;
4505         comp_v1 = (struct lov_comp_md_v1 *)&param->fp_lmd->lmd_lmm;
4506         if (comp_v1->lcm_magic != LOV_USER_MAGIC_COMP_V1)
4507                 return ret;
4508
4509         for (i = 0; i < comp_v1->lcm_entry_count; i++) {
4510                 struct lov_comp_md_entry_v1 *ent;
4511
4512                 v1 = lov_comp_entry(comp_v1, i);
4513
4514                 ent = &comp_v1->lcm_entries[i];
4515                 if (!(ent->lcme_flags & LCME_FL_EXTENSION))
4516                         continue;
4517
4518                 ret = find_value_cmp(v1->lmm_stripe_size, param->fp_ext_size,
4519                                      param->fp_ext_size_sign,
4520                                      param->fp_exclude_ext_size,
4521                                      param->fp_ext_size_units, 0);
4522                 /* If any ext_size matches */
4523                 if (ret != -1)
4524                         break;
4525         }
4526
4527         return ret;
4528 }
4529
4530 static __u32 find_get_stripe_count(struct find_param *param)
4531 {
4532         struct lov_comp_md_v1 *comp_v1 = NULL;
4533         struct lov_user_md_v1 *v1 = &param->fp_lmd->lmd_lmm;
4534         int i, count = 1;
4535         __u32 stripe_count = 0;
4536
4537         if (v1->lmm_magic == LOV_USER_MAGIC_FOREIGN)
4538                 return 0;
4539
4540         if (v1->lmm_magic == LOV_USER_MAGIC_COMP_V1) {
4541                 comp_v1 = (struct lov_comp_md_v1 *)v1;
4542                 count = comp_v1->lcm_entry_count;
4543         }
4544
4545         for (i = 0; i < count; i++) {
4546                 if (comp_v1) {
4547                         struct lov_comp_md_entry_v1 *ent;
4548
4549                         v1 = lov_comp_entry(comp_v1, i);
4550
4551                         ent = &comp_v1->lcm_entries[i];
4552                         if (!(ent->lcme_flags & LCME_FL_INIT))
4553                                 continue;
4554
4555                         if (ent->lcme_flags & LCME_FL_EXTENSION)
4556                                 continue;
4557                 }
4558                 stripe_count = v1->lmm_stripe_count;
4559         }
4560
4561         return stripe_count;
4562 }
4563
4564 #define LOV_PATTERN_INVALID     0xFFFFFFFF
4565
4566 static int find_check_layout(struct find_param *param)
4567 {
4568         struct lov_comp_md_v1 *comp_v1 = NULL;
4569         struct lov_user_md_v1 *v1 = &param->fp_lmd->lmd_lmm;
4570         int i, count = 1;
4571         bool found = false, valid = false;
4572
4573         if (v1->lmm_magic == LOV_USER_MAGIC_COMP_V1) {
4574                 comp_v1 = (struct lov_comp_md_v1 *)v1;
4575                 count = comp_v1->lcm_entry_count;
4576         }
4577
4578         for (i = 0; i < count; i++) {
4579                 if (comp_v1)
4580                         v1 = lov_comp_entry(comp_v1, i);
4581
4582                 /* foreign file have a special magic but no pattern field */
4583                 if (v1->lmm_magic == LOV_USER_MAGIC_FOREIGN)
4584                         continue;
4585
4586                 if (v1->lmm_pattern == LOV_PATTERN_INVALID)
4587                         continue;
4588
4589                 valid = true;
4590                 if (v1->lmm_pattern & param->fp_layout) {
4591                         found = true;
4592                         break;
4593                 }
4594         }
4595
4596         if (!valid)
4597                 return -1;
4598
4599         if ((found && !param->fp_exclude_layout) ||
4600             (!found && param->fp_exclude_layout))
4601                 return 1;
4602
4603         return -1;
4604 }
4605
4606 /*
4607  * if no type specified, check/exclude all foreign
4608  * if type specified, check all foreign&type and exclude !foreign + foreign&type
4609  */
4610 static int find_check_foreign(struct find_param *param)
4611 {
4612         if (S_ISREG(param->fp_lmd->lmd_stx.stx_mode)) {
4613                 struct lov_foreign_md *lfm;
4614
4615                 lfm = (void *)&param->fp_lmd->lmd_lmm;
4616                 if (lfm->lfm_magic != LOV_USER_MAGIC_FOREIGN) {
4617                         if (param->fp_foreign_type == LU_FOREIGN_TYPE_UNKNOWN)
4618                                 return param->fp_exclude_foreign ? 1 : -1;
4619                         return -1;
4620                 }
4621
4622                 if (param->fp_foreign_type == LU_FOREIGN_TYPE_UNKNOWN ||
4623                     lfm->lfm_type == param->fp_foreign_type)
4624                         return param->fp_exclude_foreign ? -1 : 1;
4625                 return param->fp_exclude_foreign ? 1 : -1;
4626         }
4627
4628         if (S_ISDIR(param->fp_lmd->lmd_stx.stx_mode)) {
4629                 struct lmv_foreign_md *lfm;
4630
4631                 lfm = (void *)param->fp_lmv_md;
4632                 if (lmv_is_foreign(lfm->lfm_magic)) {
4633                         if (param->fp_foreign_type == LU_FOREIGN_TYPE_UNKNOWN)
4634                                 return param->fp_exclude_foreign ? 1 : -1;
4635                         return -1;
4636                 }
4637
4638                 if (param->fp_foreign_type == LU_FOREIGN_TYPE_UNKNOWN ||
4639                     lfm->lfm_type == param->fp_foreign_type)
4640                         return param->fp_exclude_foreign ? -1 : 1;
4641                 return param->fp_exclude_foreign ? 1 : -1;
4642         }
4643         return -1;
4644 }
4645
4646 static int find_check_pool(struct find_param *param)
4647 {
4648         struct lov_comp_md_v1 *comp_v1 = NULL;
4649         struct lov_user_md_v3 *v3 = (void *)&param->fp_lmd->lmd_lmm;
4650         int i, count = 1;
4651         bool found = false;
4652
4653         if (v3->lmm_magic == LOV_USER_MAGIC_COMP_V1) {
4654                 comp_v1 = (struct lov_comp_md_v1 *)v3;
4655                 count = comp_v1->lcm_entry_count;
4656                 /* empty requested pool is taken as no pool search */
4657                 if (count == 0 && param->fp_poolname[0] == '\0') {
4658                         found = true;
4659                         goto found;
4660                 }
4661         }
4662
4663         for (i = 0; i < count; i++) {
4664                 if (comp_v1 != NULL) {
4665                         if (!(comp_v1->lcm_entries[i].lcme_flags &
4666                               LCME_FL_INIT))
4667                                 continue;
4668
4669                         v3 = (void *)lov_comp_entry(comp_v1, i);
4670                 }
4671
4672                 if (v3->lmm_magic == LOV_USER_MAGIC_FOREIGN)
4673                         continue;
4674
4675                 if (((v3->lmm_magic == LOV_USER_MAGIC_V1) &&
4676                      (param->fp_poolname[0] == '\0')) ||
4677                     ((v3->lmm_magic == LOV_USER_MAGIC_V3) &&
4678                      (strncmp(v3->lmm_pool_name,
4679                               param->fp_poolname, LOV_MAXPOOLNAME) == 0)) ||
4680                     ((v3->lmm_magic == LOV_USER_MAGIC_V3) &&
4681                      (strcmp(param->fp_poolname, "*") == 0))) {
4682                         found = true;
4683                         break;
4684                 }
4685         }
4686
4687 found:
4688         if ((found && !param->fp_exclude_pool) ||
4689             (!found && param->fp_exclude_pool))
4690                 return 1;
4691
4692         return -1;
4693 }
4694
4695 static int find_check_comp_options(struct find_param *param)
4696 {
4697         struct lov_comp_md_v1 *comp_v1, *forged_v1 = NULL;
4698         struct lov_user_mds_data *lmd = param->fp_lmd;
4699         struct lov_user_md_v1 *v1 = &lmd->lmd_lmm;
4700         struct lov_comp_md_entry_v1 *entry;
4701         int i, ret = 0;
4702
4703         if (v1->lmm_magic == LOV_USER_MAGIC_FOREIGN)
4704                 return -1;
4705
4706         if (v1->lmm_magic == LOV_USER_MAGIC_COMP_V1) {
4707                 comp_v1 = (struct lov_comp_md_v1 *)v1;
4708         } else {
4709                 forged_v1 = malloc(sizeof(*forged_v1) + sizeof(*entry));
4710                 if (forged_v1 == NULL)
4711                         return -1;
4712                 comp_v1 = forged_v1;
4713                 comp_v1->lcm_entry_count = 1;
4714                 entry = &comp_v1->lcm_entries[0];
4715                 entry->lcme_flags = S_ISDIR(lmd->lmd_stx.stx_mode) ?
4716                                     0 : LCME_FL_INIT;
4717                 entry->lcme_extent.e_start = 0;
4718                 entry->lcme_extent.e_end = LUSTRE_EOF;
4719         }
4720
4721         /* invalid case, don't match for any kind of search. */
4722         if (comp_v1->lcm_entry_count == 0) {
4723                 ret = -1;
4724                 goto out;
4725         }
4726
4727         if (param->fp_check_comp_count) {
4728                 ret = find_value_cmp(forged_v1 ? 0 : comp_v1->lcm_entry_count,
4729                                      param->fp_comp_count,
4730                                      param->fp_comp_count_sign,
4731                                      param->fp_exclude_comp_count, 1, 0);
4732                 if (ret == -1)
4733                         goto out;
4734         }
4735
4736         ret = 1;
4737         for (i = 0; i < comp_v1->lcm_entry_count; i++) {
4738                 entry = &comp_v1->lcm_entries[i];
4739
4740                 if (param->fp_check_comp_flags) {
4741                         ret = 1;
4742                         if (((param->fp_comp_flags & entry->lcme_flags) !=
4743                              param->fp_comp_flags) ||
4744                             (param->fp_comp_neg_flags & entry->lcme_flags)) {
4745                                 ret = -1;
4746                                 continue;
4747                         }
4748                 }
4749
4750                 if (param->fp_check_comp_start) {
4751                         ret = find_value_cmp(entry->lcme_extent.e_start,
4752                                              param->fp_comp_start,
4753                                              param->fp_comp_start_sign,
4754                                              param->fp_exclude_comp_start,
4755                                              param->fp_comp_start_units, 0);
4756                         if (ret == -1)
4757                                 continue;
4758                 }
4759
4760                 if (param->fp_check_comp_end) {
4761                         ret = find_comp_end_cmp(entry->lcme_extent.e_end,
4762                                                 param);
4763                         if (ret == -1)
4764                                 continue;
4765                 }
4766
4767                 /* the component matches all criteria */
4768                 break;
4769         }
4770 out:
4771         if (forged_v1)
4772                 free(forged_v1);
4773         return ret;
4774 }
4775
4776 static int find_check_mirror_options(struct find_param *param)
4777 {
4778         struct lov_comp_md_v1 *comp_v1;
4779         struct lov_user_md_v1 *v1 = &param->fp_lmd->lmd_lmm;
4780         int ret = 0;
4781
4782         if (v1->lmm_magic != LOV_USER_MAGIC_COMP_V1)
4783                 return -1;
4784
4785         comp_v1 = (struct lov_comp_md_v1 *)v1;
4786
4787         if (param->fp_check_mirror_count) {
4788                 ret = find_value_cmp(comp_v1->lcm_mirror_count + 1,
4789                                      param->fp_mirror_count,
4790                                      param->fp_mirror_count_sign,
4791                                      param->fp_exclude_mirror_count, 1, 0);
4792                 if (ret == -1)
4793                         return ret;
4794         }
4795
4796         if (param->fp_check_mirror_state) {
4797                 ret = 1;
4798                 __u16 file_state = comp_v1->lcm_flags & LCM_FL_FLR_MASK;
4799
4800                 if ((param->fp_mirror_state != 0 &&
4801                     file_state != param->fp_mirror_state) ||
4802                     file_state == param->fp_mirror_neg_state)
4803                         return -1;
4804         }
4805
4806         return ret;
4807 }
4808
4809 static int find_check_attr_options(struct find_param *param)
4810 {
4811         bool found = true;
4812         __u64 attrs;
4813
4814         attrs = param->fp_lmd->lmd_stx.stx_attributes_mask &
4815                 param->fp_lmd->lmd_stx.stx_attributes;
4816
4817         /* This is a AND between all (negated) specified attributes */
4818         if ((param->fp_attrs && (param->fp_attrs & attrs) != param->fp_attrs) ||
4819             (param->fp_neg_attrs && (param->fp_neg_attrs & attrs)))
4820                 found = false;
4821
4822         if ((found && param->fp_exclude_attrs) ||
4823             (!found && !param->fp_exclude_attrs))
4824                 return -1;
4825
4826         return 1;
4827 }
4828
4829 /**
4830  * xattr_reg_match() - return true if the supplied string matches the pattern.
4831  *
4832  * This requires the regex to match the entire supplied string, not just a
4833  *     substring.
4834  *
4835  * str must be null-terminated. len should be passed in anyways to avoid an
4836  *     extra call to strlen(str) when the length is already known.
4837  */
4838 static bool xattr_reg_match(regex_t *pattern, const char *str, int len)
4839 {
4840         regmatch_t pmatch;
4841         int ret;
4842
4843         ret = regexec(pattern, str, 1, &pmatch, 0);
4844         if (ret == 0 && pmatch.rm_so == 0 && pmatch.rm_eo == len)
4845                 return true;
4846
4847         return false;
4848 }
4849
4850 /**
4851  * xattr_done_matching() - return true if all supplied patterns have been
4852  *     matched, allowing to skip checking any remaining xattrs on a file.
4853  *
4854  *     This is only allowed if there are no "exclude" patterns.
4855  */
4856 static int xattr_done_matching(struct xattr_match_info *xmi)
4857 {
4858         int i;
4859
4860         for (i = 0; i < xmi->xattr_regex_count; i++) {
4861                 /* if any pattern still undecided, need to keep going */
4862                 if (!xmi->xattr_regex_matched[i])
4863                         return false;
4864         }
4865
4866         return true;
4867 }
4868
4869 static int find_check_xattrs(char *path, struct xattr_match_info *xmi)
4870 {
4871         ssize_t list_len = 0;
4872         ssize_t val_len = 0;
4873         bool fetched_val;
4874         char *p;
4875         int i;
4876
4877         for (i = 0; i < xmi->xattr_regex_count; i++)
4878                 xmi->xattr_regex_matched[i] = false;
4879
4880         list_len = llistxattr(path, xmi->xattr_name_buf, XATTR_LIST_MAX);
4881         if (list_len < 0) {
4882                 llapi_error(LLAPI_MSG_ERROR, errno,
4883                             "error: listxattr: %s", path);
4884                 return -1;
4885         }
4886
4887         /* loop over all xattr names on the file */
4888         for (p = xmi->xattr_name_buf;
4889              p - xmi->xattr_name_buf < list_len;
4890              p = strchr(p, '\0'), p++) {
4891                 fetched_val = false;
4892                 /* loop over all regex patterns specified and check them */
4893                 for (i = 0; i < xmi->xattr_regex_count; i++) {
4894                         if (xmi->xattr_regex_matched[i])
4895                                 continue;
4896
4897                         if (!xattr_reg_match(xmi->xattr_regex_name[i],
4898                                              p, strlen(p)))
4899                                 continue;
4900
4901                         if (xmi->xattr_regex_value[i] == NULL)
4902                                 goto matched;
4903
4904                         /*
4905                          * even if multiple patterns match the same xattr name,
4906                          * don't call getxattr() more than once
4907                          */
4908                         if (!fetched_val) {
4909                                 val_len = lgetxattr(path, p,
4910                                                     xmi->xattr_value_buf,
4911                                                     XATTR_SIZE_MAX);
4912                                 fetched_val = true;
4913                                 if (val_len < 0) {
4914                                         llapi_error(LLAPI_MSG_ERROR, errno,
4915                                                     "error: getxattr: %s",
4916                                                     path);
4917                                         continue;
4918                                 }
4919
4920                                 /*
4921                                  * the value returned by getxattr might or
4922                                  * might not be null terminated.
4923                                  * if it is, then decrement val_len so it
4924                                  * matches what strlen() would return.
4925                                  * if it is not, then add a null terminator
4926                                  * since regexec() expects that.
4927                                  */
4928                                 if (val_len > 0 &&
4929                                     xmi->xattr_value_buf[val_len - 1] == '\0') {
4930                                         val_len--;
4931                                 } else {
4932                                         xmi->xattr_value_buf[val_len] = '\0';
4933                                 }
4934                         }
4935
4936                         if (!xattr_reg_match(xmi->xattr_regex_value[i],
4937                                              xmi->xattr_value_buf, val_len))
4938                                 continue;
4939
4940 matched:
4941                         /*
4942                          * if exclude this xattr, we can exit early
4943                          * with NO match
4944                          */
4945                         if (xmi->xattr_regex_exclude[i])
4946                                 return -1;
4947
4948                         xmi->xattr_regex_matched[i] = true;
4949
4950                         /*
4951                          * if all "include" patterns have matched, and there are
4952                          * no "exclude" patterns, we can exit early with match
4953                          */
4954                         if (xattr_done_matching(xmi) == 1)
4955                                 return 1;
4956                 }
4957         }
4958
4959         /*
4960          * finally, check that all supplied patterns either matched, or were
4961          * "exclude" patterns if they did not match.
4962          */
4963         for (i = 0; i < xmi->xattr_regex_count; i++) {
4964                 if (!xmi->xattr_regex_matched[i]) {
4965                         if (!xmi->xattr_regex_exclude[i]) {
4966                                 return -1;
4967                         }
4968                 }
4969         }
4970
4971         return 1;
4972 }
4973
4974 static bool find_skip_file(struct find_param *param)
4975 {
4976         if (param->fp_skip_count * 100 <
4977             param->fp_skip_percent * param->fp_skip_total++) {
4978                 param->fp_skip_count++;
4979                 return true;
4980         }
4981         return false;
4982 }
4983
4984 static bool find_check_lmm_info(struct find_param *param)
4985 {
4986         return param->fp_check_pool || param->fp_check_stripe_count ||
4987                param->fp_check_stripe_size || param->fp_check_layout ||
4988                param->fp_check_comp_count || param->fp_check_comp_end ||
4989                param->fp_check_comp_start || param->fp_check_comp_flags ||
4990                param->fp_check_mirror_count || param->fp_check_foreign ||
4991                param->fp_check_mirror_state || param->fp_check_ext_size ||
4992                param->fp_check_projid;
4993 }
4994
4995 /*
4996  * Interpret backslash escape sequences and write output into buffer.
4997  * Anything written to the buffer will be null terminated.
4998  *
4999  * @param[in]   seq     String being parsed for escape sequence. The leading
5000  *                      '\' character is not included in this string (only the
5001  *                      characters after it)
5002  * @param[out]  buffer  Location where interpreted escape sequence is written
5003  * @param[in]   size    Size of the available buffer. (Needs to be large enough
5004  *                      to handle escape sequence output plus null terminator.)
5005  * @param[out]  wrote   Number of bytes written to the buffer.
5006  * @return              Number of characters from input string processed
5007  *                      as part of the escape sequence (0 for an unrecognized
5008  *                      escape sequence)
5009  */
5010 static int printf_format_escape(char *seq, char *buffer, size_t size,
5011                                 int *wrote)
5012 {
5013         *wrote = 0;
5014         /* For now, only handle single char escape sequences: \n, \t, \\ */
5015         if (size < 2)
5016                 return 0;
5017
5018         switch (*seq) {
5019         case 'n':
5020                 *buffer = '\n';
5021                 break;
5022         case 't':
5023                 *buffer = '\t';
5024                 break;
5025         case '\\':
5026                 *buffer = '\\';
5027                 break;
5028         default:
5029                 return 0;
5030         }
5031
5032         *wrote = 1;
5033         return 1;
5034 }
5035
5036 /*
5037  * Interpret formats for timestamps (%a, %A@, etc)
5038  *
5039  * @param[in]   seq     String being parsed for timestamp format.  The leading
5040  *                      '%' character is not included in this string
5041  * @param[out]  buffer  Location where timestamp info is written
5042  * @param[in]   size    Size of the available buffer.
5043  * @param[out]  wrote   Number of bytes written to the buffer.
5044  * @return              Number of characters from input string processed
5045  *                      as part of the format (0 for an unknown format)
5046  */
5047 static int printf_format_timestamp(char *seq, char *buffer, size_t size,
5048                                    int *wrote, struct find_param *param)
5049 {
5050         struct statx_timestamp ts = { 0, 0 };
5051         struct tm *tm;
5052         time_t t;
5053         int rc = 0;
5054         char *fmt = "%c";  /* Print in ctime format by default */
5055         *wrote = 0;
5056
5057         switch (*seq) {
5058         case 'a':
5059                 ts = param->fp_lmd->lmd_stx.stx_atime;
5060                 rc = 1;
5061                 break;
5062         case 'A':
5063                 if (*(seq + 1) == '@') {
5064                         ts = param->fp_lmd->lmd_stx.stx_atime;
5065                         fmt = "%s";
5066                         rc = 2;
5067                 }
5068                 break;
5069         case 'c':
5070                 ts = param->fp_lmd->lmd_stx.stx_ctime;
5071                 rc = 1;
5072                 break;
5073         case 'C':
5074                 if (*(seq + 1) == '@') {
5075                         ts = param->fp_lmd->lmd_stx.stx_ctime;
5076                         fmt = "%s";
5077                         rc = 2;
5078                 }
5079                 break;
5080         case 't':
5081                 ts = param->fp_lmd->lmd_stx.stx_mtime;
5082                 rc = 1;
5083                 break;
5084         case 'T':
5085                 if (*(seq + 1) == '@') {
5086                         ts = param->fp_lmd->lmd_stx.stx_mtime;
5087                         fmt = "%s";
5088                         rc = 2;
5089                 }
5090                 break;
5091         case 'w':
5092                 ts = param->fp_lmd->lmd_stx.stx_btime;
5093                 rc = 1;
5094                 break;
5095         case 'W':
5096                 if (*(seq + 1) == '@') {
5097                         ts = param->fp_lmd->lmd_stx.stx_btime;
5098                         fmt = "%s";
5099                         rc = 2;
5100                 }
5101                 break;
5102         default:
5103                 rc = 0;
5104         }
5105
5106         if (rc) {
5107                 /* Found valid format, print to buffer */
5108                 t = ts.tv_sec;
5109                 tm = localtime(&t);
5110                 *wrote = strftime(buffer, size, fmt, tm);
5111         }
5112
5113         return rc;
5114 }
5115
5116 /*
5117  * Print all ost indices associated with a file layout using a commma separated
5118  * list.  For a file with mutliple components, the list of indices for each
5119  * component will be enclosed in brackets.
5120  *
5121  * @param[out]  buffer  Location where OST indices are written
5122  * @param[in]   size    Size of the available buffer.
5123  * @pararm[in]  layout  Pointer to layout structure for the file
5124  * @return              Number of bytes written to output buffer
5125  */
5126 static int printf_format_ost_indices(char *buffer, size_t size,
5127                                 struct llapi_layout *layout)
5128 {
5129         uint64_t count, idx, i;
5130         int err, bytes, wrote = 0;
5131
5132         /* Make sure to start at the first component */
5133         err = llapi_layout_comp_use(layout, LLAPI_LAYOUT_COMP_USE_FIRST);
5134         if (err) {
5135                 llapi_error(LLAPI_MSG_ERROR, err,
5136                             "error: layout component iteration failed\n");
5137                 goto format_done;
5138         }
5139         while (1) {
5140                 err = llapi_layout_stripe_count_get(layout, &count);
5141                 if (err) {
5142                         llapi_error(LLAPI_MSG_ERROR, err,
5143                                     "error: cannot get stripe_count\n");
5144                         goto format_done;
5145                 }
5146
5147                 bytes = snprintf(buffer, (size - wrote), "%s", "[");
5148                 wrote += bytes;
5149                 if (wrote >= size)
5150                         goto format_done;
5151                 buffer += bytes;
5152                 for (i = 0; i < count; i++) {
5153                         err = llapi_layout_ost_index_get(layout, i, &idx);
5154                         if (err) {
5155                                 llapi_error(LLAPI_MSG_ERROR, err,
5156                                             "error: cannot get OST index\n");
5157                                 bytes = snprintf(buffer, (size - wrote),
5158                                                  "%c,", '?');
5159                         } else {
5160                                 bytes = snprintf(buffer, (size - wrote),
5161                                                  "%"PRIu64",", idx);
5162                         }
5163                         wrote += bytes;
5164                         if (wrote >= size)
5165                                 goto format_done;
5166                         buffer += bytes;
5167                 }
5168                 /* Overwrite last comma with closing bracket */
5169                 *(buffer - 1) = ']';
5170
5171                 err = llapi_layout_comp_use(layout, LLAPI_LAYOUT_COMP_USE_NEXT);
5172                 if (err == 0)           /* next component is found */
5173                         continue;
5174                 if (err < 0)
5175                         llapi_error(LLAPI_MSG_ERROR, err,
5176                                     "error: layout component iteration failed\n");
5177                 /* At this point, either got error or reached last component */
5178                 break;
5179         }
5180
5181 format_done:
5182         if (wrote >= size)
5183                 wrote = (size - 1);
5184         return wrote;
5185 }
5186
5187 /*
5188  * Print file attributes as a comma-separated list of named attribute flags,
5189  * and hex value of any unknown attributes.
5190  *
5191  * @param[out]  buffer  Location where file attributes are written
5192  * @param[in]   size    Size of the available buffer.
5193  * @pararm[in]  lstx    Void pointer holding address of struct statx. Which is
5194  *                      containing attributes to be printed
5195  * @return              Number of bytes written to output buffer
5196  */
5197 static int printf_format_file_attributes(char *buffer, size_t size,
5198                                          void *lstx, bool longopt)
5199 {
5200         lstatx_t *stx = (lstatx_t *)lstx;
5201         uint64_t attrs = stx->stx_attributes_mask & stx->stx_attributes;
5202         int bytes = 0, wrote = 0, first = 1;
5203         uint64_t known_attrs = 0;
5204         struct attrs_name *ap;
5205
5206         /* before all, print '---' if no attributes, and exit */
5207         if (!attrs) {
5208                 bytes = snprintf(buffer, size - wrote, "---");
5209                 wrote += bytes;
5210                 goto format_done;
5211         }
5212
5213         /* first, browse list of known attributes */
5214         for (ap = (struct attrs_name *)attrs_array; ap->an_attr != 0; ap++) {
5215                 known_attrs |= ap->an_attr;
5216                 if (attrs & ap->an_attr) {
5217                         if (longopt)
5218                                 bytes = snprintf(buffer, size - wrote, "%s%s",
5219                                                  first ? "" : ",", ap->an_name);
5220                         else
5221                                 bytes = snprintf(buffer, size - wrote, "%c",
5222                                                  ap->an_shortname);
5223                         wrote += bytes;
5224                         first = 0;
5225                         if (wrote >= size)
5226                                 goto format_done;
5227                         buffer += bytes;
5228                 }
5229         }
5230
5231         /* second, print hex value for unknown attributes */
5232         attrs &= ~known_attrs;
5233         if (attrs) {
5234                 bytes = snprintf(buffer, size - wrote, "%s0x%lx",
5235                                  first ? "" : ",", attrs);
5236                 wrote += bytes;
5237         }
5238
5239 format_done:
5240         if (wrote >= size)
5241                 wrote = size - 1;
5242         return wrote;
5243 }
5244
5245 /*
5246  * Parse Lustre-specific format sequences of the form %L{x}.
5247  *
5248  * @param[in]   seq     String being parsed for format sequence.  The leading
5249  *                      '%' character is not included in this string
5250  * @param[out]  buffer  Location where interpreted format info is written
5251  * @param[in]   size    Size of the available buffer.
5252  * @param[out]  wrote   Number of bytes written to the buffer.
5253  * @param[in]   param   The find_param structure associated with the file/dir
5254  * @param[in]   path    Pathname of the current file/dir being handled
5255  * @param[in]   projid  Project ID associated with the current file/dir
5256  * @param[in]   d       File descriptor for the directory (or -1 for a
5257  *                      non-directory file)
5258  * @return              Number of characters from input string processed
5259  *                      as part of the format (0 for an unknown format)
5260  */
5261 static int printf_format_lustre(char *seq, char *buffer, size_t size,
5262                                 int *wrote, struct find_param *param,
5263                                 char *path, __u32 projid, int d)
5264 {
5265         struct lmv_user_md *lum;
5266         struct lmv_user_mds_data *objects;
5267         struct llapi_layout *layout = NULL;
5268         struct lu_fid fid;
5269         unsigned int hash_type;
5270         uint64_t str_cnt, str_size, idx;
5271         char pool_name[LOV_MAXPOOLNAME + 1] = { '\0' };
5272         int err, bytes, i;
5273         bool longopt = true;
5274         int rc = 2;     /* all current valid sequences are 2 chars */
5275         void *lstx;
5276         *wrote = 0;
5277
5278         /* Sanity check.  Formats always look like %L{X} */
5279         if (*seq++ != 'L') {
5280                 rc = 0;
5281                 goto format_done;
5282         }
5283
5284         /*
5285          * Some formats like %LF or %LP are handled the same for both files
5286          * and dirs, so handle all of those here.
5287          */
5288         switch (*seq) {
5289         case 'F':
5290                 err = llapi_path2fid(path, &fid);
5291                 if (err) {
5292                         llapi_error(LLAPI_MSG_ERROR, err,
5293                                     "error: cannot get fid\n");
5294                         goto format_done;
5295                 }
5296                 *wrote = snprintf(buffer, size, DFID_NOBRACE, PFID(&fid));
5297                 goto format_done;
5298         case 'P':
5299                 *wrote = snprintf(buffer, size, "%u", projid);
5300                 goto format_done;
5301         case 'a': /* file attributes */
5302                 longopt = false;
5303                 fallthrough;
5304         case 'A':
5305                 lstx = &param->fp_lmd->lmd_stx;
5306
5307                 *wrote = printf_format_file_attributes(buffer, size, lstx,
5308                                                        longopt);
5309                 goto format_done;
5310         }
5311
5312         /* Other formats for files/dirs need to be handled differently */
5313         if (d == -1) {          /* file */
5314                 //layout = llapi_layout_get_by_xattr(&param->fp_lmd->lmd_lmm,
5315                 //                                 param->fp_lum_size, 0);
5316                 layout = llapi_layout_get_by_path(path, 0);
5317                 if (layout == NULL) {
5318                         llapi_error(LLAPI_MSG_ERROR, errno,
5319                                     "error: cannot get file layout\n");
5320                         goto format_done;
5321                 }
5322
5323                 /*
5324                  * Set the layout pointer to the last init component
5325                  * since that is the component used for most of these
5326                  * formats. (This also works for non-composite files)
5327                  */
5328                 err = llapi_layout_get_last_init_comp(layout);
5329                 if (err) {
5330                         llapi_error(LLAPI_MSG_ERROR, err,
5331                                     "error: cannot get last initialized compomnent\n");
5332                         goto format_done;
5333                 }
5334
5335                 switch (*seq) {
5336                 case 'c':       /* stripe count */
5337                         err = llapi_layout_stripe_count_get(layout, &str_cnt);
5338                         if (err) {
5339                                 llapi_error(LLAPI_MSG_ERROR, err,
5340                                             "error: cannot get stripe_count\n");
5341                                 goto format_done;
5342                         }
5343                         *wrote = snprintf(buffer, size, "%"PRIu64, str_cnt);
5344                         break;
5345                 case 'h':       /* hash info */
5346                         /* Not applicable to files.  Skip it. */
5347                         break;
5348                 case 'i':       /* starting index */
5349                         err = llapi_layout_ost_index_get(layout, 0, &idx);
5350                         if (err) {
5351                                 llapi_error(LLAPI_MSG_ERROR, err,
5352                                             "error: cannot get OST index of last initialized component\n");
5353                                 goto format_done;
5354                         }
5355                         *wrote = snprintf(buffer, size, "%"PRIu64, idx);
5356                         break;
5357                 case 'o':       /* list of object indices */
5358                         *wrote = printf_format_ost_indices(buffer, size, layout);
5359                         break;
5360                 case 'p':       /* pool name */
5361                         err = llapi_layout_pool_name_get(layout, pool_name,
5362                                                          sizeof(pool_name));
5363                         if (err) {
5364                                 llapi_error(LLAPI_MSG_ERROR, rc,
5365                                             "error: cannot get pool name\n");
5366                                 goto format_done;
5367                         }
5368                         *wrote = snprintf(buffer, size, "%s", pool_name);
5369                         break;
5370                 case 'S':       /* stripe size */
5371                         err = llapi_layout_stripe_size_get(layout, &str_size);
5372                         if (err) {
5373                                 llapi_error(LLAPI_MSG_ERROR, rc,
5374                                             "error: cannot get stripe_size\n");
5375                                 goto format_done;
5376                         }
5377                         *wrote = snprintf(buffer, size, "%"PRIu64, str_size);
5378                         break;
5379                 default:
5380                         rc = 0;
5381                         break;
5382                 }
5383         } else {                /* directory */
5384                 lum = (struct lmv_user_md *)param->fp_lmv_md;
5385                 objects = lum->lum_objects;
5386
5387                 switch (*seq) {
5388                 case 'c':       /* stripe count */
5389                         *wrote = snprintf(buffer, size, "%d",
5390                                           (int)lum->lum_stripe_count);
5391                         break;
5392                 case 'h':       /* hash info */
5393                         hash_type = lum->lum_hash_type & LMV_HASH_TYPE_MASK;
5394                         if (hash_type < LMV_HASH_TYPE_MAX)
5395                                 *wrote = snprintf(buffer, size, "%s",
5396                                                   mdt_hash_name[hash_type]);
5397                         else
5398                                 *wrote = snprintf(buffer, size, "%#x",
5399                                                   hash_type);
5400                         break;
5401                 case 'i':       /* starting index */
5402                         *wrote = snprintf(buffer, size, "%d",
5403                                           lum->lum_stripe_offset);
5404                         break;
5405                 case 'o':       /* list of object indices */
5406                         str_cnt = (int) lum->lum_stripe_count;
5407                         *wrote = snprintf(buffer, size, "%s", "[");
5408                         if (*wrote >= size)
5409                                 goto format_done;
5410                         buffer += *wrote;
5411                         for (i = 0; i < str_cnt; i++) {
5412                                 bytes = snprintf(buffer, (size - *wrote),
5413                                                  "%d,", objects[i].lum_mds);
5414                                 *wrote += bytes;
5415                                 if (*wrote >= size)
5416                                         goto format_done;
5417                                 buffer += bytes;
5418                         }
5419                         if (str_cnt == 0) {
5420                                 /* Use lum_offset as the only list entry */
5421                                 bytes = snprintf(buffer, (size - *wrote),
5422                                                 "%d]", lum->lum_stripe_offset);
5423                                 *wrote += bytes;
5424                         } else {
5425                                 /* Overwrite last comma with closing bracket */
5426                                 *(buffer - 1) = ']';
5427                         }
5428                         break;
5429                 case 'p':       /* pool name */
5430                         *wrote = snprintf(buffer, size, "%s",
5431                                           lum->lum_pool_name);
5432                         break;
5433                 case 'S':       /* stripe size */
5434                         /* This has no meaning for directories.  Skip it. */
5435                         break;
5436                 default:
5437                         rc = 0;
5438                         break;
5439                 }
5440         }
5441
5442 format_done:
5443         if (layout != NULL)
5444                 llapi_layout_free(layout);
5445
5446         if (*wrote >= size)
5447                 /* output of snprintf was truncated */
5448                 *wrote = size - 1;
5449
5450         return rc;
5451 }
5452
5453 /*
5454  * Create a formated access mode string
5455  *
5456  * @param[in] param->fp_lmd->lmd_stx.stx_mode
5457  *
5458  */
5459
5460 static int snprintf_access_mode(char *buffer, size_t size, __u16 mode)
5461 {
5462         char access_string[16];
5463         char *p = access_string;
5464
5465         switch (mode & S_IFMT) {
5466         case S_IFREG:
5467                 *p++ = '-';
5468                 break;
5469         case S_IFDIR:
5470                 *p++ = 'd';
5471                 break;
5472         case S_IFLNK:
5473                 *p++ = 'l';
5474                 break;
5475         case S_IFIFO:
5476                 *p++ = 'p';
5477                 break;
5478         case S_IFSOCK:
5479                 *p++ = 's';
5480                 break;
5481         case S_IFBLK:
5482                 *p++ = 'b';
5483                 break;
5484         case S_IFCHR:
5485                 *p++ = 'c';
5486                 break;
5487         default:
5488                 *p++ = '?';
5489                 break;
5490         }
5491
5492         *p++ = (mode & S_IRUSR) ? 'r' : '-';
5493         *p++ = (mode & S_IWUSR) ? 'w' : '-';
5494         *p++ = (mode & S_IXUSR) ? ((mode & S_ISUID) ? 's' : 'x') :
5495                                   ((mode & S_ISUID) ? 'S' : '-');
5496         *p++ = (mode & S_IRGRP) ? 'r' : '-';
5497         *p++ = (mode & S_IWGRP) ? 'w' : '-';
5498         *p++ = (mode & S_IXGRP) ? ((mode & S_ISGID) ? 's' : 'x') :
5499                                   ((mode & S_ISGID) ? 'S' : '-');
5500         *p++ = (mode & S_IROTH) ? 'r' : '-';
5501         *p++ = (mode & S_IWOTH) ? 'w' : '-';
5502         *p++ = (mode & S_IXOTH) ? ((mode & S_ISVTX) ? 't' : 'x') :
5503                                   ((mode & S_ISVTX) ? 'T' : '-');
5504         *p = '\0';
5505
5506         return snprintf(buffer, size, "%s", access_string);
5507 }
5508
5509 static int parse_format_width(char **seq, size_t buf_size, int *width,
5510                               char *padding)
5511 {
5512         bool negative_width = false;
5513         char *end = NULL;
5514         int parsed = 0;
5515
5516         *padding = ' ';
5517         *width = 0;
5518
5519         /* GNU find supports formats such as "%----10s" */
5520         while (**seq == '-') {
5521                 (*seq)++;
5522                 parsed++;
5523                 negative_width = true;
5524         }
5525
5526         /* GNU find and printf only do 0 padding on the left (width > 0)
5527          * %-010m <=> %-10m.
5528          */
5529         if (**seq == '0' && !negative_width)
5530                 *padding = '0';
5531
5532         errno = 0;
5533         *width = strtol(*seq, &end, 10);
5534         if (errno != 0)
5535                 return -errno;
5536         if (*width >= buf_size)
5537                 *width = buf_size - 1;
5538
5539         /* increase the number of processed characters */
5540         parsed += end - *seq;
5541         *seq = end;
5542         if (negative_width)
5543                 *width = -*width;
5544
5545         /* GNU find only does 0 padding for %S, %d and %m. */
5546         switch (**seq) {
5547         case 'S':
5548         case 'd':
5549         case 'm':
5550                 break;
5551         default:
5552                 *padding = ' ';
5553                 break;
5554         }
5555
5556         return parsed;
5557 }
5558
5559 /*
5560  * Interpret format specifiers beginning with '%'.
5561  *
5562  * @param[in]   seq     String being parsed for format specifier.  The leading
5563  *                      '%' character is not included in this string
5564  * @param[out]  buffer  Location where formatted info is written
5565  * @param[in]   size    Size of the available buffer.
5566  * @param[out]  wrote   Number of bytes written to the buffer.
5567  * @param[in]   param   The find_param structure associated with the file/dir
5568  * @param[in]   path    Pathname of the current file/dir being handled
5569  * @param[in]   projid  Project ID associated with the current file/dir
5570  * @param[in]   d       File descriptor for the directory (or -1 for a
5571  *                      non-directory file)
5572  * @return              Number of characters from input string processed
5573  *                      as part of the format (0 for an unknown format)
5574  */
5575 static int printf_format_directive(char *seq, char *buffer, size_t size,
5576                                    int *wrote, struct find_param *param,
5577                                    char *path, __u32 projid, int d)
5578 {
5579         uint64_t blocks = param->fp_lmd->lmd_stx.stx_blocks;
5580         __u16 mode = param->fp_lmd->lmd_stx.stx_mode;
5581         char padding;
5582         int width_rc;
5583         int rc = 1;  /* most specifiers are single character */
5584         int width;
5585
5586         *wrote = 0;
5587
5588         width_rc = parse_format_width(&seq, size, &width, &padding);
5589         if (width_rc < 0)
5590                 return 0;
5591
5592         switch (*seq) {
5593         case 'a': case 'A':
5594         case 'c': case 'C':
5595         case 't': case 'T':
5596         case 'w': case 'W':     /* timestamps */
5597                 rc = printf_format_timestamp(seq, buffer, size, wrote, param);
5598                 break;
5599         case 'b':       /* file size (in 512B blocks) */
5600                 *wrote = snprintf(buffer, size, "%"PRIu64, blocks);
5601                 break;
5602         case 'g': { /* groupname of owner*/
5603                 static char save_gr_name[LOGIN_NAME_MAX + 1];
5604                 static gid_t save_gid = -1;
5605
5606                 if (save_gid != param->fp_lmd->lmd_stx.stx_gid) {
5607                         struct group *gr;
5608
5609                         gr = getgrgid(param->fp_lmd->lmd_stx.stx_gid);
5610                         if (gr) {
5611                                 save_gid = param->fp_lmd->lmd_stx.stx_gid;
5612                                 strncpy(save_gr_name, gr->gr_name,
5613                                         sizeof(save_gr_name) - 1);
5614                         }
5615                 }
5616                 if (save_gr_name[0]) {
5617                         *wrote = snprintf(buffer, size, "%s", save_gr_name);
5618                         break;
5619                 }
5620                 fallthrough;
5621         }
5622         case 'G':       /* GID of owner */
5623                 *wrote = snprintf(buffer, size, "%u",
5624                                   param->fp_lmd->lmd_stx.stx_gid);
5625                 break;
5626         case 'i':       /* inode number */
5627                 *wrote = snprintf(buffer, size, "%llu",
5628                                   param->fp_lmd->lmd_stx.stx_ino);
5629                 break;
5630         case 'k':       /* file size (in 1K blocks) */
5631                 *wrote = snprintf(buffer, size, "%"PRIu64, (blocks + 1)/2);
5632                 break;
5633         case 'L':       /* Lustre-specific formats */
5634                 rc = printf_format_lustre(seq, buffer, size, wrote, param,
5635                                           path, projid, d);
5636                 break;
5637         case 'm':       /* file mode in octal */
5638                 *wrote = snprintf(buffer, size, "%o", (mode & (~S_IFMT)));
5639                 break;
5640         case 'M':       /* file access mode */
5641                 *wrote = snprintf_access_mode(buffer, size, mode);
5642                 break;
5643         case 'n':       /* number of links */
5644                 *wrote = snprintf(buffer, size, "%u",
5645                                   param->fp_lmd->lmd_stx.stx_nlink);
5646                 break;
5647         case 'p':       /* Path name of file */
5648                 *wrote = snprintf(buffer, size, "%s", path);
5649                 break;
5650         case 's':       /* file size (in bytes) */
5651                 *wrote = snprintf(buffer, size, "%"PRIu64,
5652                                    (uint64_t) param->fp_lmd->lmd_stx.stx_size);
5653                 break;
5654         case 'u': {/* username of owner */
5655                 static char save_username[LOGIN_NAME_MAX + 1];
5656                 static uid_t save_uid = -1;
5657
5658                 if (save_uid != param->fp_lmd->lmd_stx.stx_uid) {
5659                         struct passwd *pw;
5660
5661                         pw = getpwuid(param->fp_lmd->lmd_stx.stx_uid);
5662                         if (pw) {
5663                                 save_uid = param->fp_lmd->lmd_stx.stx_uid;
5664                                 strncpy(save_username, pw->pw_name,
5665                                         sizeof(save_username) - 1);
5666                         }
5667                 }
5668                 if (save_username[0]) {
5669                         *wrote = snprintf(buffer, size, "%s", save_username);
5670                         break;
5671                 }
5672                 fallthrough;
5673         }
5674         case 'U':       /* UID of owner */
5675                 *wrote = snprintf(buffer, size, "%u",
5676                                    param->fp_lmd->lmd_stx.stx_uid);
5677                 break;
5678         case 'y':       /* file type */
5679                 if (S_ISREG(mode))
5680                         *buffer = 'f';
5681                 else if (S_ISDIR(mode))
5682                         *buffer = 'd';
5683                 else if (S_ISLNK(mode))
5684                         *buffer = 'l';
5685                 else if (S_ISBLK(mode))
5686                         *buffer = 'b';
5687                 else if (S_ISCHR(mode))
5688                         *buffer = 'c';
5689                 else if (S_ISFIFO(mode))
5690                         *buffer = 'p';
5691                 else if (S_ISSOCK(mode))
5692                         *buffer = 's';
5693                 else
5694                         *buffer = '?';
5695                 *wrote = 1;
5696                 break;
5697         case '%':
5698                 *buffer = '%';
5699                 *wrote = 1;
5700                 break;
5701         default:        /* invalid format specifier */
5702                 rc = 0;
5703                 break;
5704         }
5705
5706         if (rc == 0)
5707                 /* if parsing failed, return 0 to avoid skipping width_rc */
5708                 return 0;
5709
5710         if (width > 0 && width > *wrote) {
5711                 /* left padding */
5712                 int shift = width - *wrote;
5713
5714                 /* '\0' is added by caller if necessary */
5715                 memmove(buffer + shift, buffer, *wrote);
5716                 memset(buffer, padding, shift);
5717                 *wrote += shift;
5718         } else if (width < 0 && -width > *wrote) {
5719                 /* right padding */
5720                 int shift = -width - *wrote;
5721
5722                 memset(buffer + *wrote, padding, shift);
5723                 *wrote += shift;
5724         }
5725
5726         if (*wrote >= size)
5727                 /* output of snprintf was truncated */
5728                 *wrote = size - 1;
5729
5730         return width_rc + rc;
5731 }
5732
5733 /*
5734  * Parse user-supplied string for the -printf option and interpret any
5735  * '%' format specifiers or '\' escape sequences.
5736  *
5737  * @param[in]   param   The find_param struct containing the -printf string
5738  *                      as well as info about the current file/dir that mathced
5739  *                      the lfs find search criteria
5740  * @param[in]   path    Path name for current file/dir
5741  * @param[in]   projid  Project ID associated with current file/dir
5742  * @param[in]   d       File descriptor for current directory (or -1 for a
5743  *                      non-directory file)
5744  */
5745 static void printf_format_string(struct find_param *param, char *path,
5746                                  __u32 projid, int d)
5747 {
5748         char output[FORMATTED_BUF_LEN];
5749         char *fmt_char = param->fp_format_printf_str;
5750         char *buff = output;
5751         size_t buff_size;
5752         int rc, written;
5753
5754         buff = output;
5755         *buff = '\0';
5756         buff_size = FORMATTED_BUF_LEN;
5757
5758         /* Always leave one free byte in buffer for trailing NUL */
5759         while (*fmt_char && (buff_size > 1)) {
5760                 rc = 0;
5761                 written = 0;
5762                 if (*fmt_char == '%') {
5763                         rc = printf_format_directive(fmt_char + 1, buff,
5764                                                   buff_size, &written, param,
5765                                                   path, projid, d);
5766                 } else if (*fmt_char == '\\') {
5767                         rc = printf_format_escape(fmt_char + 1, buff,
5768                                                   buff_size, &written);
5769                 }
5770
5771                 if (rc > 0) {
5772                         /* Either a '\' escape or '%' format was processed.
5773                          * Increment pointers accordingly.
5774                          */
5775                         fmt_char += (rc + 1);
5776                         buff += written;
5777                         buff_size -= written;
5778                 } else if (rc < 0) {
5779                         return;
5780                 } else {
5781                         /* Regular char or invalid escape/format.
5782                          * Either way, copy current character.
5783                          */
5784                         *buff++ = *fmt_char++;
5785                         buff_size--;
5786                 }
5787         }
5788
5789         /* Terminate output buffer and print */
5790         *buff = '\0';
5791         llapi_printf(LLAPI_MSG_NORMAL, "%s", output);
5792 }
5793
5794 /*
5795  * Gets the project id of a file, directory, or special file,
5796  * and stores it at the projid memory address passed in.
5797  * Returns 0 on success, or -errno for failure.
5798  *
5799  * @param[in]   path    The full path of the file or directory we're trying
5800  *                      to retrieve the project id for.
5801  * @param[in]   fd      A reference to the file descriptor of either the file
5802  *                      or directory we're inspecting. The file/dir may or may
5803  *                      not have been already opened, but if not, we'll open
5804  *                      it here (for regular files/directories).
5805  * @param[in]   mode    The mode type of the file. This will tell us if the file
5806  *                      is a regular file/dir or if it's a special file type.
5807  * @param[out]  projid  A reference to where to store the projid of the file/dir
5808  */
5809 static int get_projid(const char *path, int *fd, mode_t mode, __u32 *projid)
5810 {
5811         struct fsxattr fsx = { 0 };
5812         struct lu_project lu_project = { 0 };
5813         int ret = 0;
5814
5815         /* Check the mode of the file */
5816         if (S_ISREG(mode) || S_ISDIR(mode)) {
5817                 /* This is a regular file type or directory */
5818                 if (*fd < 0) {
5819                         /* If we haven't yet opened the file,
5820                          * open it in read-only mode
5821                          */
5822                         *fd = open(path, O_RDONLY | O_NOCTTY | O_NDELAY);
5823                         if (*fd <= 0) {
5824                                 llapi_error(LLAPI_MSG_ERROR, -ENOENT,
5825                                             "warning: %s: unable to open file \"%s\"to get project id",
5826                                             __func__, path);
5827                                 return -ENOENT;
5828                         }
5829                 }
5830                 ret = ioctl(*fd, FS_IOC_FSGETXATTR, &fsx);
5831                 if (ret)
5832                         return -errno;
5833
5834                 *projid = fsx.fsx_projid;
5835         } else {
5836                 /* This is a special file type, like a symbolic link, block or
5837                  * character device file. We'll have to open its parent
5838                  * directory and get metadata about the file through that.
5839                  */
5840                 char dir_path[PATH_MAX + 1] = { 0 };
5841                 char base_path[PATH_MAX + 1] = { 0 };
5842
5843                 strncpy(dir_path, path, PATH_MAX);
5844                 strncpy(base_path, path, PATH_MAX);
5845                 char *dir_name = dirname(dir_path);
5846                 char *base_name = basename(base_path);
5847                 int dir_fd = open(dir_name, O_RDONLY | O_NOCTTY | O_NDELAY);
5848
5849                 if (dir_fd < 0) {
5850                         llapi_error(LLAPI_MSG_ERROR, -ENOENT,
5851                                     "warning: %s: unable to open dir \"%s\"to get project id",
5852                                     __func__, path);
5853                         return -errno;
5854                 }
5855                 lu_project.project_type = LU_PROJECT_GET;
5856                 if (base_name)
5857                         strncpy(lu_project.project_name, base_name, NAME_MAX);
5858
5859                 ret = ioctl(dir_fd, LL_IOC_PROJECT, &lu_project);
5860                 close(dir_fd);
5861                 if (ret) {
5862                         llapi_error(LLAPI_MSG_ERROR, -ENOENT,
5863                                     "warning: %s: failed to get xattr for '%s': %s",
5864                                     __func__, path, strerror(errno));
5865                         return -errno;
5866                 }
5867                 *projid = lu_project.project_id;
5868         }
5869
5870         return 0;
5871 }
5872
5873 /*
5874  * Check that the file's permissions in *st matches the one in find_param
5875  */
5876 static int check_file_permissions(const struct find_param *param,
5877                         mode_t mode)
5878 {
5879         int decision = 0;
5880
5881         mode &= 07777;
5882
5883         switch (param->fp_perm_sign) {
5884         case LFS_FIND_PERM_EXACT:
5885                 decision = (mode == param->fp_perm);
5886                 break;
5887         case LFS_FIND_PERM_ALL:
5888                 decision = ((mode & param->fp_perm) == param->fp_perm);
5889                 break;
5890         case LFS_FIND_PERM_ANY:
5891                 decision = ((mode & param->fp_perm) != 0);
5892                 break;
5893         }
5894
5895         if ((param->fp_exclude_perm && decision)
5896                 || (!param->fp_exclude_perm && !decision))
5897                 return -1;
5898         else
5899                 return 1;
5900 }
5901
5902 int cb_find_init(char *path, int p, int *dp,
5903                  void *data, struct dirent64 *de)
5904 {
5905         struct find_param *param = (struct find_param *)data;
5906         struct lov_user_mds_data *lmd = param->fp_lmd;
5907         int d = dp == NULL ? -1 : *dp;
5908         int decision = 1; /* 1 is accepted; -1 is rejected. */
5909         int lustre_fs = 1;
5910         int checked_type = 0;
5911         int ret = 0;
5912         __u32 stripe_count = 0;
5913         __u64 flags;
5914         int fd = -2;
5915         __u32 projid = DEFAULT_PROJID;
5916         bool gather_all = false;
5917
5918         if (p == -1 && d == -1)
5919                 return -EINVAL;
5920         /* if below minimum depth do not process further */
5921         if (param->fp_depth < param->fp_min_depth)
5922                 goto decided;
5923
5924         /* Reset this value between invocations */
5925         param->fp_get_lmv = 0;
5926
5927         /* Gather all file/dir info, not just what's needed for search params */
5928         if (param->fp_format_printf_str)
5929                 gather_all = true;
5930
5931         /* If a regular expression is presented, make the initial decision */
5932         if (param->fp_pattern != NULL) {
5933                 char *fname = strrchr(path, '/');
5934
5935                 fname = (fname == NULL ? path : fname + 1);
5936                 ret = fnmatch(param->fp_pattern, fname, 0);
5937                 if ((ret == FNM_NOMATCH && !param->fp_exclude_pattern) ||
5938                     (ret == 0 && param->fp_exclude_pattern))
5939                         goto decided;
5940         }
5941
5942         /* See if we can check the file type from the dirent. */
5943         if (de != NULL && de->d_type != DT_UNKNOWN) {
5944                 if (param->fp_type != 0) {
5945                         checked_type = 1;
5946
5947                         if (DTTOIF(de->d_type) == param->fp_type) {
5948                                 if (param->fp_exclude_type)
5949                                         goto decided;
5950                         } else {
5951                                 if (!param->fp_exclude_type)
5952                                         goto decided;
5953                         }
5954                 }
5955                 if ((param->fp_check_mdt_count || param->fp_hash_type ||
5956                      param->fp_check_hash_flag) && de->d_type != DT_DIR)
5957                         goto decided;
5958         }
5959
5960         ret = 0;
5961
5962         /*
5963          * Request MDS for the stat info if some of these parameters need
5964          * to be compared.
5965          */
5966         if (param->fp_obd_uuid || param->fp_mdt_uuid ||
5967             param->fp_check_uid || param->fp_check_gid ||
5968             param->fp_newerxy || param->fp_btime ||
5969             param->fp_atime || param->fp_mtime || param->fp_ctime ||
5970             param->fp_check_size || param->fp_check_blocks ||
5971             find_check_lmm_info(param) ||
5972             param->fp_check_mdt_count || param->fp_hash_type ||
5973             param->fp_check_hash_flag || param->fp_perm_sign ||
5974             param->fp_nlink || param->fp_attrs || param->fp_neg_attrs ||
5975             gather_all)
5976                 decision = 0;
5977
5978         if (param->fp_type != 0 && checked_type == 0)
5979                 decision = 0;
5980
5981         if (decision == 0) {
5982                 if (d != -1 &&
5983                     (param->fp_check_mdt_count || param->fp_hash_type ||
5984                      param->fp_check_hash_flag || param->fp_check_foreign ||
5985                      /*
5986                       * cb_get_dirstripe is needed when checking nlink because
5987                       * nlink is handled differently for multi-stripe directory
5988                       * vs. single-stripe directory
5989                       */
5990                      param->fp_nlink || gather_all)) {
5991                         param->fp_get_lmv = 1;
5992                         ret = cb_get_dirstripe(path, &d, param);
5993                         if (ret != 0) {
5994                                 if (errno == ENODATA) {
5995                                         /* Fill in struct for unstriped dir */
5996                                         ret = 0;
5997                                         param->fp_lmv_md->lum_magic = LMV_MAGIC_V1;
5998                                         /* Use 0 until we find actual offset */
5999                                         param->fp_lmv_md->lum_stripe_offset = 0;
6000                                         param->fp_lmv_md->lum_stripe_count = 0;
6001                                         param->fp_lmv_md->lum_hash_type = 0;
6002
6003                                         if (param->fp_check_foreign) {
6004                                                 if (param->fp_exclude_foreign)
6005                                                         goto print;
6006                                                 goto decided;
6007                                         }
6008                                 } else {
6009                                         return ret;
6010                                 }
6011                         }
6012
6013                         if (param->fp_check_mdt_count) {
6014                                 if (lmv_is_foreign(param->fp_lmv_md->lum_magic))
6015                                         goto decided;
6016
6017                                 decision = find_value_cmp(param->fp_lmv_md->lum_stripe_count,
6018                                                           param->fp_mdt_count,
6019                                                           param->fp_mdt_count_sign,
6020                                                           param->fp_exclude_mdt_count, 1, 0);
6021                                 if (decision == -1)
6022                                         goto decided;
6023                         }
6024
6025                         if (param->fp_hash_type) {
6026                                 __u32 found;
6027                                 __u32 type = param->fp_lmv_md->lum_hash_type &
6028                                         LMV_HASH_TYPE_MASK;
6029
6030                                 if (lmv_is_foreign(param->fp_lmv_md->lum_magic))
6031                                         goto decided;
6032
6033                                 found = (1 << type) & param->fp_hash_type;
6034                                 if ((found && param->fp_exclude_hash_type) ||
6035                                     (!found && !param->fp_exclude_hash_type))
6036                                         goto decided;
6037                         }
6038
6039                         if (param->fp_check_hash_flag) {
6040                                 __u32 flags = param->fp_lmv_md->lum_hash_type &
6041                                         ~LMV_HASH_TYPE_MASK;
6042
6043                                 if (lmv_is_foreign(param->fp_lmv_md->lum_magic))
6044                                         goto decided;
6045
6046                                 if (!(flags & param->fp_hash_inflags) ||
6047                                     (flags & param->fp_hash_exflags))
6048                                         goto decided;
6049                         }
6050                 }
6051
6052                 param->fp_lmd->lmd_lmm.lmm_magic = 0;
6053                 ret = get_lmd_info_fd(path, p, d, param->fp_lmd,
6054                                       param->fp_lum_size, GET_LMD_INFO);
6055                 if (ret == 0 && param->fp_lmd->lmd_lmm.lmm_magic == 0 &&
6056                     find_check_lmm_info(param)) {
6057                         struct lov_user_md *lmm = &param->fp_lmd->lmd_lmm;
6058
6059                         /*
6060                          * We need to "fake" the "use the default" values
6061                          * since the lmm struct is zeroed out at this point.
6062                          */
6063                         lmm->lmm_magic = LOV_USER_MAGIC_V1;
6064                         lmm->lmm_pattern = LOV_PATTERN_DEFAULT;
6065                         if (!param->fp_raw)
6066                                 ostid_set_seq(&lmm->lmm_oi,
6067                                               FID_SEQ_LOV_DEFAULT);
6068                         lmm->lmm_stripe_size = 0;
6069                         lmm->lmm_stripe_count = 0;
6070                         lmm->lmm_stripe_offset = -1;
6071                 }
6072                 if (ret == 0 && (param->fp_mdt_uuid != NULL || gather_all)) {
6073                         if (d != -1) {
6074                                 ret = llapi_file_fget_mdtidx(d,
6075                                                      &param->fp_file_mdt_index);
6076                                 /*
6077                                  *  Make sure lum_stripe_offset matches
6078                                  *  mdt_index even for unstriped directories.
6079                                  */
6080                                 if (ret == 0 && param->fp_get_lmv)
6081                                         param->fp_lmv_md->lum_stripe_offset =
6082                                                 param->fp_file_mdt_index;
6083                         } else if (S_ISREG(lmd->lmd_stx.stx_mode)) {
6084                                 /*
6085                                  * FIXME: we could get the MDT index from the
6086                                  * file's FID in lmd->lmd_lmm.lmm_oi without
6087                                  * opening the file, once we are sure that
6088                                  * LFSCK2 (2.6) has fixed up pre-2.0 LOV EAs.
6089                                  * That would still be an ioctl() to map the
6090                                  * FID to the MDT, but not an open RPC.
6091                                  */
6092                                 fd = open(path, O_RDONLY);
6093                                 if (fd > 0) {
6094                                         ret = llapi_file_fget_mdtidx(fd,
6095                                                      &param->fp_file_mdt_index);
6096                                 } else {
6097                                         ret = -errno;
6098                                 }
6099                         } else {
6100                                 /*
6101                                  * For a special file, we assume it resides on
6102                                  * the same MDT as the parent directory.
6103                                  */
6104                                 ret = llapi_file_fget_mdtidx(p,
6105                                                      &param->fp_file_mdt_index);
6106                         }
6107                 }
6108                 if (ret != 0) {
6109                         if (ret == -ENOTTY)
6110                                 lustre_fs = 0;
6111                         if (ret == -ENOENT)
6112                                 goto decided;
6113
6114                         goto out;
6115                 } else {
6116                         stripe_count = find_get_stripe_count(param);
6117                 }
6118         }
6119
6120         /* Check the file permissions from the stat info */
6121         if (param->fp_perm_sign) {
6122                 decision = check_file_permissions(param, lmd->lmd_stx.stx_mode);
6123                 if (decision == -1)
6124                         goto decided;
6125         }
6126
6127         if (param->fp_type && !checked_type) {
6128                 if ((param->fp_check_mdt_count || param->fp_check_hash_flag ||
6129                      param->fp_hash_type) && !S_ISDIR(lmd->lmd_stx.stx_mode))
6130                         goto decided;
6131
6132                 if ((lmd->lmd_stx.stx_mode & S_IFMT) == param->fp_type) {
6133                         if (param->fp_exclude_type)
6134                                 goto decided;
6135                 } else {
6136                         if (!param->fp_exclude_type)
6137                                 goto decided;
6138                 }
6139         }
6140
6141         /* Prepare odb. */
6142         if (param->fp_obd_uuid || param->fp_mdt_uuid) {
6143                 if (lustre_fs && param->fp_got_uuids &&
6144                     param->fp_dev != makedev(lmd->lmd_stx.stx_dev_major,
6145                                              lmd->lmd_stx.stx_dev_minor)) {
6146                         /* A lustre/lustre mount point is crossed. */
6147                         param->fp_got_uuids = 0;
6148                         param->fp_obds_printed = 0;
6149                         param->fp_mdt_index = OBD_NOT_FOUND;
6150                         param->fp_obd_index = OBD_NOT_FOUND;
6151                 }
6152
6153                 if (lustre_fs && !param->fp_got_uuids) {
6154                         ret = setup_target_indexes((d != -1) ? d : p, path,
6155                                                    param);
6156                         if (ret)
6157                                 goto out;
6158
6159                         param->fp_dev = makedev(lmd->lmd_stx.stx_dev_major,
6160                                                 lmd->lmd_stx.stx_dev_minor);
6161                 } else if (!lustre_fs && param->fp_got_uuids) {
6162                         /* A lustre/non-lustre mount point is crossed. */
6163                         param->fp_got_uuids = 0;
6164                         param->fp_mdt_index = OBD_NOT_FOUND;
6165                         param->fp_obd_index = OBD_NOT_FOUND;
6166                 }
6167         }
6168
6169         if (param->fp_check_foreign) {
6170                 decision = find_check_foreign(param);
6171                 if (decision == -1)
6172                         goto decided;
6173         }
6174
6175         if (param->fp_check_stripe_size) {
6176                 decision = find_check_stripe_size(param);
6177                 if (decision == -1)
6178                         goto decided;
6179         }
6180
6181         if (param->fp_check_ext_size) {
6182                 decision = find_check_ext_size(param);
6183                 if (decision == -1)
6184                         goto decided;
6185         }
6186
6187         if (param->fp_check_stripe_count) {
6188                 decision = find_value_cmp(stripe_count, param->fp_stripe_count,
6189                                           param->fp_stripe_count_sign,
6190                                           param->fp_exclude_stripe_count, 1, 0);
6191                 if (decision == -1)
6192                         goto decided;
6193         }
6194
6195         if (param->fp_check_layout) {
6196                 decision = find_check_layout(param);
6197                 if (decision == -1)
6198                         goto decided;
6199         }
6200
6201         /* If an OBD UUID is specified but none matches, skip this file. */
6202         if ((param->fp_obd_uuid && param->fp_obd_index == OBD_NOT_FOUND) ||
6203             (param->fp_mdt_uuid && param->fp_mdt_index == OBD_NOT_FOUND))
6204                 goto decided;
6205
6206         /*
6207          * If an OST or MDT UUID is given, and some OST matches,
6208          * check it here.
6209          */
6210         if (param->fp_obd_index != OBD_NOT_FOUND ||
6211             param->fp_mdt_index != OBD_NOT_FOUND) {
6212                 if (param->fp_obd_uuid) {
6213                         if (check_obd_match(param)) {
6214                                 /*
6215                                  * If no mdtuuid is given, we are done.
6216                                  * Otherwise, fall through to the mdtuuid
6217                                  * check below.
6218                                  */
6219                                 if (!param->fp_mdt_uuid)
6220                                         goto obd_matches;
6221                         } else {
6222                                 goto decided;
6223                         }
6224                 }
6225
6226                 if (param->fp_mdt_uuid) {
6227                         if (check_mdt_match(param))
6228                                 goto obd_matches;
6229                         goto decided;
6230                 }
6231         }
6232
6233 obd_matches:
6234         if (param->fp_check_uid) {
6235                 if (lmd->lmd_stx.stx_uid == param->fp_uid) {
6236                         if (param->fp_exclude_uid)
6237                                 goto decided;
6238                 } else {
6239                         if (!param->fp_exclude_uid)
6240                                 goto decided;
6241                 }
6242         }
6243
6244         if (param->fp_check_gid) {
6245                 if (lmd->lmd_stx.stx_gid == param->fp_gid) {
6246                         if (param->fp_exclude_gid)
6247                                 goto decided;
6248                 } else {
6249                         if (!param->fp_exclude_gid)
6250                                 goto decided;
6251                 }
6252         }
6253
6254         /* Retrieve project id from file/dir */
6255         if (param->fp_check_projid || gather_all) {
6256                 ret = get_projid(path, &fd, lmd->lmd_stx.stx_mode, &projid);
6257                 if (ret) {
6258                         llapi_error(LLAPI_MSG_ERROR, -ENOENT,
6259                                     "warning: %s: failed to get project id from file \"%s\"",
6260                                     __func__, path);
6261                         goto out;
6262                 }
6263                 if (param->fp_check_projid) {
6264                         /* Conditionally filter this result based on --projid
6265                          * param, and whether or not we're including or
6266                          * excluding matching results.
6267                          * fp_exclude_projid = 0 means only include exact match.
6268                          * fp_exclude_projid = 1 means exclude exact match.
6269                          */
6270                         bool matches = projid == param->fp_projid;
6271
6272                         if (matches == param->fp_exclude_projid)
6273                                 goto decided;
6274                 }
6275         }
6276
6277         if (param->fp_check_pool) {
6278                 decision = find_check_pool(param);
6279                 if (decision == -1)
6280                         goto decided;
6281         }
6282
6283         if (param->fp_check_comp_count || param->fp_check_comp_flags ||
6284             param->fp_check_comp_start || param->fp_check_comp_end) {
6285                 decision = find_check_comp_options(param);
6286                 if (decision == -1)
6287                         goto decided;
6288         }
6289
6290         if (param->fp_check_mirror_count || param->fp_check_mirror_state) {
6291                 decision = find_check_mirror_options(param);
6292                 if (decision == -1)
6293                         goto decided;
6294         }
6295
6296         /* Check the time on mds. */
6297         decision = 1;
6298         if (param->fp_atime || param->fp_mtime || param->fp_ctime) {
6299                 int for_mds;
6300
6301                 for_mds = lustre_fs ?
6302                           (S_ISREG(lmd->lmd_stx.stx_mode) && stripe_count) : 0;
6303                 decision = find_time_check(param, for_mds);
6304                 if (decision == -1)
6305                         goto decided;
6306         }
6307
6308         if (param->fp_btime) {
6309                 if (!(lmd->lmd_stx.stx_mask & STATX_BTIME)) {
6310                         ret = -EOPNOTSUPP;
6311                         goto out;
6312                 }
6313
6314                 decision = find_value_cmp(lmd->lmd_stx.stx_btime.tv_sec,
6315                                           param->fp_btime, param->fp_bsign,
6316                                           param->fp_exclude_btime,
6317                                           param->fp_time_margin, 0);
6318                 if (decision == -1)
6319                         goto decided;
6320         }
6321
6322         if (param->fp_newerxy) {
6323                 int for_mds;
6324
6325                 for_mds = lustre_fs ?
6326                           (S_ISREG(lmd->lmd_stx.stx_mode) && stripe_count) : 0;
6327                 decision = find_newerxy_check(param, for_mds, true);
6328                 if (decision == -1)
6329                         goto decided;
6330                 if (decision < 0) {
6331                         ret = decision;
6332                         goto out;
6333                 }
6334         }
6335
6336         if (param->fp_attrs || param->fp_neg_attrs) {
6337                 decision = find_check_attr_options(param);
6338                 if (decision == -1)
6339                         goto decided;
6340         }
6341
6342         flags = param->fp_lmd->lmd_flags;
6343         if (param->fp_check_size &&
6344             ((S_ISREG(lmd->lmd_stx.stx_mode) && stripe_count) ||
6345               S_ISDIR(lmd->lmd_stx.stx_mode)) &&
6346             !(flags & OBD_MD_FLSIZE ||
6347               (param->fp_lazy && flags & OBD_MD_FLLAZYSIZE)))
6348                 decision = 0;
6349
6350         if (param->fp_check_blocks &&
6351             ((S_ISREG(lmd->lmd_stx.stx_mode) && stripe_count) ||
6352               S_ISDIR(lmd->lmd_stx.stx_mode)) &&
6353             !(flags & OBD_MD_FLBLOCKS ||
6354               (param->fp_lazy && flags & OBD_MD_FLLAZYBLOCKS)))
6355                 decision = 0;
6356
6357         if (param->fp_xattr_match_info) {
6358                 decision = find_check_xattrs(path, param->fp_xattr_match_info);
6359                 if (decision == -1)
6360                         goto decided;
6361         }
6362
6363         /*
6364          * When checking nlink, stat(2) is needed for multi-striped directories
6365          * because the nlink value retrieved from the MDS above comes from
6366          * the number of stripes for the dir.
6367          * The posix stat call below fills in the correct number of links.
6368          * Single-stripe directories and regular files already have the
6369          * correct nlink value.
6370          */
6371         if (param->fp_nlink && S_ISDIR(lmd->lmd_stx.stx_mode) &&
6372             (param->fp_lmv_md->lum_stripe_count != 0))
6373                 decision = 0;
6374
6375         /*
6376          * If file still fits the request, ask ost for updated info.
6377          * The regular stat is almost of the same speed as some new
6378          * 'glimpse-size-ioctl'.
6379          */
6380         if (!decision || gather_all) {
6381                 lstat_t st;
6382
6383                 /*
6384                  * For regular files with the stripe the decision may have not
6385                  * been taken yet if *time or size is to be checked.
6386                  */
6387                 if (param->fp_obd_index != OBD_NOT_FOUND)
6388                         print_failed_tgt(param, path, LL_STATFS_LOV);
6389
6390                 if (param->fp_mdt_index != OBD_NOT_FOUND)
6391                         print_failed_tgt(param, path, LL_STATFS_LMV);
6392
6393                 if (d != -1)
6394                         ret = fstat_f(d, &st);
6395                 else if (de != NULL)
6396                         ret = fstatat_f(p, de->d_name, &st,
6397                                         AT_SYMLINK_NOFOLLOW);
6398                 else
6399                         ret = lstat_f(path, &st);
6400
6401                 if (ret) {
6402                         if (errno == ENOENT) {
6403                                 llapi_error(LLAPI_MSG_ERROR, -ENOENT,
6404                                             "warning: %s: %s does not exist",
6405                                             __func__, path);
6406                                 goto decided;
6407                         } else {
6408                                 ret = -errno;
6409                                 llapi_error(LLAPI_MSG_ERROR, ret,
6410                                             "%s: stat on %s failed",
6411                                             __func__, path);
6412                                 goto out;
6413                         }
6414                 }
6415
6416                 convert_lmd_statx(param->fp_lmd, &st, true);
6417                 /* Check the time on osc. */
6418                 decision = find_time_check(param, 0);
6419                 if (decision == -1)
6420                         goto decided;
6421
6422                 if (param->fp_newerxy) {
6423                         decision = find_newerxy_check(param, 0, false);
6424                         if (decision == -1)
6425                                 goto decided;
6426                         if (decision < 0) {
6427                                 ret = decision;
6428                                 goto out;
6429                         }
6430                 }
6431         }
6432
6433         if (param->fp_nlink) {
6434                 decision = find_value_cmp(lmd->lmd_stx.stx_nlink,
6435                                           param->fp_nlink, param->fp_nlink_sign,
6436                                           param->fp_exclude_nlink, 1, 0);
6437                 if (decision == -1)
6438                         goto decided;
6439         }
6440
6441         if (param->fp_check_size) {
6442                 decision = find_value_cmp(lmd->lmd_stx.stx_size,
6443                                           param->fp_size,
6444                                           param->fp_size_sign,
6445                                           param->fp_exclude_size,
6446                                           param->fp_size_units, 0);
6447                 if (decision == -1)
6448                         goto decided;
6449         }
6450
6451         if (param->fp_check_blocks) { /* convert st_blocks to bytes */
6452                 decision = find_value_cmp(lmd->lmd_stx.stx_blocks * 512,
6453                                           param->fp_blocks,
6454                                           param->fp_blocks_sign,
6455                                           param->fp_exclude_blocks,
6456                                           param->fp_blocks_units, 0);
6457                 if (decision == -1)
6458                         goto decided;
6459         }
6460
6461 print:
6462         if (param->fp_skip_percent && find_skip_file(param))
6463                 goto decided;
6464
6465         if (param->fp_format_printf_str)
6466                 printf_format_string(param, path, projid, d);
6467         else
6468                 llapi_printf(LLAPI_MSG_NORMAL, "%s%c", path,
6469                              param->fp_zero_end ? '\0' : '\n');
6470
6471
6472 decided:
6473         ret = 0;
6474         /* Do not get down anymore? */
6475         if (param->fp_depth == param->fp_max_depth) {
6476                 ret = 1;
6477                 goto out;
6478         }
6479         param->fp_depth++;
6480 out:
6481         if (fd > 0)
6482                 close(fd);
6483         return ret;
6484 }
6485
6486 static int cb_migrate_mdt_init(char *path, int p, int *dp,
6487                                void *param_data, struct dirent64 *de)
6488 {
6489         struct find_param *param = (struct find_param *)param_data;
6490         struct lmv_user_md *lmu = param->fp_lmv_md;
6491         int tmp_p = p;
6492         char raw[MAX_IOC_BUFLEN] = {'\0'};
6493         char *rawbuf = raw;
6494         struct obd_ioctl_data data = { 0 };
6495         int ret;
6496         char *path_copy;
6497         char *filename;
6498         bool retry = false;
6499
6500         if (p == -1 && dp == NULL)
6501                 return -EINVAL;
6502
6503         if (!lmu)
6504                 return -EINVAL;
6505
6506         if (dp != NULL && *dp != -1)
6507                 close(*dp);
6508
6509         if (p == -1) {
6510                 tmp_p = open_parent(path);
6511                 if (tmp_p == -1) {
6512                         *dp = -1;
6513                         ret = -errno;
6514                         llapi_error(LLAPI_MSG_ERROR, ret,
6515                                     "can not open %s", path);
6516                         return ret;
6517                 }
6518         }
6519
6520         path_copy = strdup(path);
6521         filename = basename(path_copy);
6522
6523         data.ioc_inlbuf1 = (char *)filename;
6524         data.ioc_inllen1 = strlen(filename) + 1;
6525         data.ioc_inlbuf2 = (char *)lmu;
6526         data.ioc_inllen2 = lmv_user_md_size(lmu->lum_stripe_count,
6527                                             lmu->lum_magic);
6528         /* reach bottom? */
6529         if (param->fp_depth == param->fp_max_depth)
6530                 data.ioc_type = MDS_MIGRATE_NSONLY;
6531         ret = llapi_ioctl_pack(&data, &rawbuf, sizeof(raw));
6532         if (ret != 0) {
6533                 llapi_error(LLAPI_MSG_ERROR, ret,
6534                             "%s: error packing ioctl data", __func__);
6535                 goto out;
6536         }
6537
6538 migrate:
6539         ret = ioctl(tmp_p, LL_IOC_MIGRATE, rawbuf);
6540         if (ret != 0) {
6541                 if (errno == EBUSY && !retry) {
6542                         /*
6543                          * because migrate may not be able to lock all involved
6544                          * objects in order, for some of them it try lock, while
6545                          * there may be conflicting COS locks and cause migrate
6546                          * fail with EBUSY, hope a sync() could cause
6547                          * transaction commit and release these COS locks.
6548                          */
6549                         sync();
6550                         retry = true;
6551                         goto migrate;
6552                 } else if (errno == EALREADY) {
6553                         if (param->fp_verbose & VERBOSE_DETAIL)
6554                                 llapi_printf(LLAPI_MSG_NORMAL,
6555                                              "%s migrated to MDT%d already\n",
6556                                              path, lmu->lum_stripe_offset);
6557                         ret = 0;
6558                 } else {
6559                         ret = -errno;
6560                         llapi_error(LLAPI_MSG_ERROR, ret, "%s migrate failed",
6561                                     path);
6562                         goto out;
6563                 }
6564         } else if (param->fp_verbose & VERBOSE_DETAIL) {
6565                 llapi_printf(LLAPI_MSG_NORMAL,
6566                              "migrate %s to MDT%d stripe count %d\n",
6567                              path, lmu->lum_stripe_offset,
6568                              lmu->lum_stripe_count);
6569         }
6570
6571 out:
6572         /* Do not get down anymore? */
6573         if (param->fp_depth == param->fp_max_depth)
6574                 ret = 1;
6575         else
6576                 param->fp_depth++;
6577
6578         if (dp != NULL) {
6579                 /*
6580                  * If the directory is being migration, we need
6581                  * close the directory after migration,
6582                  * so the old directory cache will be cleanup
6583                  * on the client side, and re-open to get the
6584                  * new directory handle
6585                  */
6586                 *dp = open(path, O_RDONLY|O_NDELAY|O_DIRECTORY);
6587                 if (*dp == -1) {
6588                         ret = -errno;
6589                         llapi_error(LLAPI_MSG_ERROR, ret,
6590                                     "%s: Failed to open '%s'", __func__, path);
6591                 }
6592         }
6593
6594         if (p == -1)
6595                 close(tmp_p);
6596
6597         free(path_copy);
6598
6599         return ret;
6600 }
6601
6602 /* dir migration finished, shrink its stripes */
6603 static int cb_migrate_mdt_fini(char *path, int p, int *dp, void *data,
6604                                struct dirent64 *de)
6605 {
6606         struct find_param *param = data;
6607         struct lmv_user_md *lmu = param->fp_lmv_md;
6608         int lmulen = lmv_user_md_size(lmu->lum_stripe_count, lmu->lum_magic);
6609         int ret = 0;
6610
6611         if (de && de->d_type != DT_DIR)
6612                 goto out;
6613
6614         if (*dp != -1) {
6615                 /*
6616                  * close it before setxattr because the latter may destroy the
6617                  * original object, and cause close fail.
6618                  */
6619                 ret = close(*dp);
6620                 *dp = -1;
6621                 if (ret)
6622                         goto out;
6623         }
6624
6625         ret = setxattr(path, XATTR_NAME_LMV, lmu, lmulen, 0);
6626         if (ret == -1) {
6627                 if (errno == EALREADY) {
6628                         ret = 0;
6629                 } else {
6630                         llapi_error(LLAPI_MSG_ERROR, errno,
6631                                     "%s: error completing migration of %s",
6632                                     __func__, path);
6633                         ret = -errno;
6634                 }
6635         }
6636
6637 out:
6638         cb_common_fini(path, p, dp, data, de);
6639         return ret;
6640 }
6641
6642 int llapi_migrate_mdt(char *path, struct find_param *param)
6643 {
6644         param->fp_stop_on_error = 1;
6645         return param_callback(path, cb_migrate_mdt_init, cb_migrate_mdt_fini,
6646                               param);
6647 }
6648
6649 int llapi_mv(char *path, struct find_param *param)
6650 {
6651 #if LUSTRE_VERSION_CODE > OBD_OCD_VERSION(2, 9, 59, 0)
6652         static bool printed;
6653
6654         if (!printed) {
6655                 llapi_error(LLAPI_MSG_ERROR, -ESTALE,
6656                           "%s() is deprecated, use llapi_migrate_mdt() instead",
6657                           __func__);
6658                 printed = true;
6659         }
6660 #endif
6661         return llapi_migrate_mdt(path, param);
6662 }
6663
6664 /*
6665  * Check string for escape sequences and print a message to stdout
6666  * if any invalid escapes are found.
6667  *
6668  * @param[in]   c       Pointer to character immediately following the
6669  *                      '\' character indicating the start of an escape
6670  *                      sequence.
6671  * @return              Number of characters examined in the escape sequence
6672  *                      (regardless of whether the sequence is valid or not).
6673  */
6674 static int validate_printf_esc(char *c)
6675 {
6676         char *valid_esc = "nt\\";
6677
6678         if (*c == '\0') {
6679                  /* backslash at end of string */
6680                 llapi_err_noerrno(LLAPI_MSG_WARN,
6681                         "warning: '\\' at end of -printf format string\n");
6682                 return 0;
6683         }
6684
6685         if (!strchr(valid_esc, *c))
6686                 /* Invalid escape character */
6687                 llapi_err_noerrno(LLAPI_MSG_WARN,
6688                         "warning: unrecognized escape: '\\%c'\n", *c);
6689
6690         return 1;
6691 }
6692
6693 /*
6694  * Check string for format directives and print a message to stdout
6695  * if any invalid directives are found.
6696  *
6697  * @param[in]   c       Pointer to character immediately following the
6698  *                      '%' character indicating the start of a format
6699  *                      directive.
6700  * @return              Number of characters examined in the format directive
6701  *                      (regardless of whether the directive is valid or not).
6702  */
6703 static int validate_printf_fmt(char *c)
6704 {
6705         char *valid_fmt_single = "abcigGkmMnpstuUwy%";
6706         char *valid_fmt_double = "ACTW";
6707         char *valid_fmt_lustre = "aAcFhioPpS";
6708         char curr = *c, next;
6709
6710         if (curr == '\0') {
6711                 llapi_err_noerrno(LLAPI_MSG_WARN,
6712                         "warning: '%%' at end of -printf format string\n");
6713                 return 0;
6714         }
6715
6716         /* GNU find supports formats such as "%----10s" */
6717         while (curr == '-')
6718                 curr = *(++c);
6719
6720         if (isdigit(curr)) {
6721                 /* skip width format specifier */
6722                 while (isdigit(*c))
6723                         c++;
6724         }
6725
6726         curr = *c;
6727         next = *(c + 1);
6728
6729         if ((next == '\0') || (next == '%') || (next == '\\'))
6730                 /* Treat as single char format directive */
6731                 goto check_single;
6732
6733         /* Check format directives with multiple characters */
6734         if (strchr(valid_fmt_double, curr)) {
6735                 /* For now, only valid formats are followed by '@' char */
6736                 if (next != '@')
6737                         llapi_err_noerrno(LLAPI_MSG_WARN,
6738                                 "warning: unrecognized format directive: '%%%c%c'\n",
6739                                 curr, next);
6740                 return 2;
6741         }
6742
6743         /* Lustre formats always start with 'L' */
6744         if (curr == 'L') {
6745                 if (!strchr(valid_fmt_lustre, next))
6746                         llapi_err_noerrno(LLAPI_MSG_WARN,
6747                                 "warning: unrecognized format directive: '%%%c%c'\n",
6748                                 curr, next);
6749                 return 2;
6750         }
6751
6752 check_single:
6753
6754         if (!strchr(valid_fmt_single, curr))
6755                 llapi_err_noerrno(LLAPI_MSG_WARN,
6756                         "warning: unrecognized format directive: '%%%c'\n", curr);
6757         return 1;
6758 }
6759
6760 /*
6761  * Validate the user-supplied string for the -printf option and report
6762  * any invalid backslash escape sequences or format directives.
6763  *
6764  * @param[in]   param   Structure containing info about invocation of lfs find
6765  * @return              None
6766  */
6767 void validate_printf_str(struct find_param *param)
6768 {
6769         char *c = param->fp_format_printf_str;
6770         int ret = 0;
6771
6772         while (*c) {
6773                 switch (*c) {
6774                 case '%':
6775                         ret = validate_printf_fmt(++c);
6776                         c += ret;
6777                         break;
6778                 case '\\':
6779                         ret = validate_printf_esc(++c);
6780                         c += ret;
6781                         break;
6782                 default:
6783                         c++;
6784                         break;
6785                 }
6786         }
6787 }
6788
6789 int llapi_find(char *path, struct find_param *param)
6790 {
6791         if (param->fp_format_printf_str)
6792                 validate_printf_str(param);
6793         if (param->fp_thread_count) {
6794                 return parallel_find(path, param);
6795         } else {
6796                 return param_callback(path, cb_find_init, cb_common_fini,
6797                                       param);
6798         }
6799 }
6800
6801 /*
6802  * Get MDT number that the file/directory inode referenced
6803  * by the open fd resides on.
6804  * Return 0 and mdtidx on success, or -ve errno.
6805  */
6806 int llapi_file_fget_mdtidx(int fd, int *mdtidx)
6807 {
6808         if (ioctl(fd, LL_IOC_GET_MDTIDX, mdtidx) < 0)
6809                 return -errno;
6810         return 0;
6811 }
6812
6813 static int cb_get_mdt_index(char *path, int p, int *dp, void *data,
6814                             struct dirent64 *de)
6815 {
6816         struct find_param *param = (struct find_param *)data;
6817         int d = dp == NULL ? -1 : *dp;
6818         int ret;
6819         int mdtidx;
6820         bool hex = param->fp_hex_idx;
6821
6822         if (p == -1 && d == -1)
6823                 return -EINVAL;
6824
6825         if (d != -1) {
6826                 ret = llapi_file_fget_mdtidx(d, &mdtidx);
6827         } else /* if (p != -1) */ {
6828                 int fd;
6829
6830                 fd = open(path, O_RDONLY | O_NOCTTY);
6831                 if (fd > 0) {
6832                         ret = llapi_file_fget_mdtidx(fd, &mdtidx);
6833                         close(fd);
6834                 } else {
6835                         ret = -errno;
6836                 }
6837         }
6838
6839         if (ret != 0) {
6840                 if (ret == -ENODATA) {
6841                         if (!param->fp_obd_uuid)
6842                                 llapi_printf(LLAPI_MSG_NORMAL,
6843                                              "'%s' has no stripe info\n", path);
6844                         goto out;
6845                 } else if (ret == -ENOENT) {
6846                         llapi_error(LLAPI_MSG_WARN, ret,
6847                                     "warning: %s: '%s' does not exist",
6848                                     __func__, path);
6849                         goto out;
6850                 } else if (ret == -ENOTTY) {
6851                         llapi_error(LLAPI_MSG_ERROR, ret,
6852                                     "%s: '%s' not on a Lustre fs",
6853                                     __func__, path);
6854                 } else {
6855                         llapi_error(LLAPI_MSG_ERROR, ret,
6856                                     "error: %s: '%s' failed get_mdtidx",
6857                                     __func__, path);
6858                 }
6859                 return ret;
6860         }
6861
6862         if (param->fp_quiet || !(param->fp_verbose & VERBOSE_DETAIL))
6863                 llapi_printf(LLAPI_MSG_NORMAL, hex ? "%#x\n" : "%d\n", mdtidx);
6864         else
6865                 llapi_printf(LLAPI_MSG_NORMAL, hex ? "%s\nmdt_index:\t%#x\n"
6866                                                    : "%s\nmdt_index:\t%d\n",
6867                              path, mdtidx);
6868
6869 out:
6870         /* Do not go down anymore? */
6871         if (param->fp_depth == param->fp_max_depth)
6872                 return 1;
6873
6874         param->fp_depth++;
6875
6876         return 0;
6877 }
6878
6879 static int cb_getstripe(char *path, int p, int *dp, void *data,
6880                         struct dirent64 *de)
6881 {
6882         struct find_param *param = (struct find_param *)data;
6883         int d = dp == NULL ? -1 : *dp, fd = -1;
6884         int ret = 0;
6885         struct stat st;
6886
6887         if (p == -1 && d == -1)
6888                 return -EINVAL;
6889
6890         if (param->fp_obd_uuid) {
6891                 param->fp_quiet = 1;
6892                 ret = setup_obd_uuid(d != -1 ? d : p, path, param);
6893                 if (ret)
6894                         return ret;
6895         }
6896
6897         if (!param->fp_no_follow && de && de->d_type == DT_LNK && d == -1)
6898                 d = fd = open(path, O_RDONLY | O_DIRECTORY);
6899
6900         if (d != -1 && (param->fp_get_lmv || param->fp_get_default_lmv))
6901                 ret = cb_get_dirstripe(path, &d, param);
6902         else if (d != -1)
6903                 ret = get_lmd_info_fd(path, p, d, &param->fp_lmd->lmd_lmm,
6904                                       param->fp_lum_size, GET_LMD_STRIPE);
6905         else if (d == -1 && (param->fp_get_lmv || param->fp_get_default_lmv)) {
6906                 /* in case of a dangling or valid faked symlink dir, opendir()
6907                  * should have return either EINVAL or ENOENT, so let's try
6908                  * to get LMV just in case, and by opening it as a file but
6909                  * with O_NOFOLLOW ...
6910                  */
6911                 int flag = O_RDONLY | O_NONBLOCK;
6912
6913                 if (param->fp_no_follow)
6914                         flag |= O_NOFOLLOW;
6915
6916                 fd = open(path, flag);
6917                 if (fd == -1)
6918                         return 0;
6919                 if (fstat(fd, &st) != 0) {
6920                         ret = -errno;
6921                         close(fd);
6922                         return ret;
6923                 }
6924                 /* clear O_NONBLOCK for non-PIPEs */
6925                 if (!S_ISFIFO(st.st_mode))
6926                         fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) & ~O_NONBLOCK);
6927                 ret = cb_get_dirstripe(path, &fd, param);
6928                 if (ret == 0)
6929                         llapi_lov_dump_user_lmm(param, path, LDF_IS_DIR);
6930                 close(fd);
6931                 return 0;
6932         } else if (d == -1) {
6933                 if (!param->fp_no_follow && de && de->d_type == DT_LNK) {
6934                         /* open the target of symlink as a file */
6935                         fd = open(path, O_RDONLY);
6936                         if (fd == -1)
6937                                 return 0;
6938                 }
6939                 ret = get_lmd_info_fd(path, p, fd, &param->fp_lmd->lmd_lmm,
6940                                       param->fp_lum_size, GET_LMD_STRIPE);
6941         } else
6942                 return 0;
6943
6944         if (fd >= 0)
6945                 close(fd);
6946
6947         if (ret) {
6948                 if (errno == ENODATA && d != -1) {
6949                         /*
6950                          * We need to "fake" the "use the default" values
6951                          * since the lmm struct is zeroed out at this point.
6952                          * The magic needs to be set in order to satisfy
6953                          * a check later on in the code path.
6954                          * The object_seq needs to be set for the "(Default)"
6955                          * prefix to be displayed.
6956                          */
6957                         if (param->fp_get_default_lmv) {
6958                                 struct lmv_user_md *lum = param->fp_lmv_md;
6959
6960                                 if (param->fp_raw)
6961                                         goto out;
6962                                 lum->lum_magic = LMV_USER_MAGIC;
6963                                 lum->lum_stripe_count = 0;
6964                                 lum->lum_stripe_offset = LMV_OFFSET_DEFAULT;
6965                                 goto dump;
6966                         } else if (param->fp_get_lmv) {
6967                                 struct lmv_user_md *lum = param->fp_lmv_md;
6968                                 int mdtidx;
6969
6970                                 ret = llapi_file_fget_mdtidx(d, &mdtidx);
6971                                 if (ret != 0)
6972                                         goto err_out;
6973                                 lum->lum_magic = LMV_MAGIC_V1;
6974                                 lum->lum_stripe_count = 0;
6975                                 lum->lum_stripe_offset = mdtidx;
6976                                 goto dump;
6977                         } else {
6978                                 struct lov_user_md *lmm =
6979                                         &param->fp_lmd->lmd_lmm;
6980
6981                                 lmm->lmm_magic = LOV_USER_MAGIC_V1;
6982                                 if (!param->fp_raw)
6983                                         ostid_set_seq(&lmm->lmm_oi,
6984                                                       FID_SEQ_LOV_DEFAULT);
6985                                 lmm->lmm_stripe_count = 0;
6986                                 lmm->lmm_stripe_size = 0;
6987                                 lmm->lmm_stripe_offset = -1;
6988                                 goto dump;
6989                         }
6990                 } else if (errno == ENODATA && p != -1) {
6991                         if (!param->fp_obd_uuid && !param->fp_mdt_uuid)
6992                                 llapi_printf(LLAPI_MSG_NORMAL,
6993                                              "%s has no stripe info\n", path);
6994                         goto out;
6995                 } else if (errno == ENOENT) {
6996                         llapi_error(LLAPI_MSG_WARN, -ENOENT,
6997                                     "warning: %s: %s does not exist",
6998                                     __func__, path);
6999                         goto out;
7000                 } else if (errno == ENOTTY) {
7001                         ret = -errno;
7002                         llapi_error(LLAPI_MSG_ERROR, ret,
7003                                     "%s: '%s' not on a Lustre fs?",
7004                                     __func__, path);
7005                 } else {
7006                         ret = -errno;
7007 err_out:
7008                         llapi_error(LLAPI_MSG_ERROR, ret,
7009                                     "error: %s: %s failed for %s",
7010                                      __func__, d != -1 ?
7011                                                "LL_IOC_LOV_GETSTRIPE" :
7012                                                "IOC_MDC_GETFILESTRIPE", path);
7013                 }
7014
7015                 return ret;
7016         }
7017
7018 dump:
7019         if (!(param->fp_verbose & VERBOSE_MDTINDEX))
7020                 llapi_lov_dump_user_lmm(param, path, d != -1 ? LDF_IS_DIR : 0);
7021
7022 out:
7023         /* Do not get down anymore? */
7024         if (param->fp_depth == param->fp_max_depth)
7025                 return 1;
7026
7027         param->fp_depth++;
7028
7029         return 0;
7030 }
7031
7032 int llapi_getstripe(char *path, struct find_param *param)
7033 {
7034         return param_callback(path, (param->fp_verbose & VERBOSE_MDTINDEX) ?
7035                               cb_get_mdt_index : cb_getstripe,
7036                               cb_common_fini, param);
7037 }
7038
7039 int llapi_obd_fstatfs(int fd, __u32 type, __u32 index,
7040                       struct obd_statfs *stat_buf, struct obd_uuid *uuid_buf)
7041 {
7042         char raw[MAX_IOC_BUFLEN] = {'\0'};
7043         char *rawbuf = raw;
7044         struct obd_ioctl_data data = { 0 };
7045         int rc = 0;
7046
7047         data.ioc_inlbuf1 = (char *)&type;
7048         data.ioc_inllen1 = sizeof(__u32);
7049         data.ioc_inlbuf2 = (char *)&index;
7050         data.ioc_inllen2 = sizeof(__u32);
7051         data.ioc_pbuf1 = (char *)stat_buf;
7052         data.ioc_plen1 = sizeof(struct obd_statfs);
7053         data.ioc_pbuf2 = (char *)uuid_buf;
7054         data.ioc_plen2 = sizeof(struct obd_uuid);
7055
7056         rc = llapi_ioctl_pack(&data, &rawbuf, sizeof(raw));
7057         if (rc != 0) {
7058                 llapi_error(LLAPI_MSG_ERROR, rc,
7059                             "%s: error packing ioctl data", __func__);
7060                 return rc;
7061         }
7062
7063         rc = ioctl(fd, IOC_OBD_STATFS, (void *)rawbuf);
7064
7065         return rc < 0 ? -errno : 0;
7066 }
7067
7068 int llapi_obd_statfs(char *path, __u32 type, __u32 index,
7069                      struct obd_statfs *stat_buf, struct obd_uuid *uuid_buf)
7070 {
7071         int fd;
7072         int rc;
7073
7074         fd = open(path, O_RDONLY);
7075         if (fd < 0) {
7076                 rc = -errno;
7077                 llapi_error(LLAPI_MSG_ERROR, rc, "error: %s: opening '%s'",
7078                             __func__, path);
7079                 /*
7080                  * If we can't even open a file on the filesystem (e.g. with
7081                  * -ESHUTDOWN), force caller to exit or it will loop forever.
7082                  */
7083                 return -ENODEV;
7084         }
7085
7086         rc = llapi_obd_fstatfs(fd, type, index, stat_buf, uuid_buf);
7087
7088         close(fd);
7089
7090         return rc;
7091 }
7092
7093 #define MAX_STRING_SIZE 128
7094
7095 int llapi_ping(char *obd_type, char *obd_name)
7096 {
7097         int flags = O_RDONLY;
7098         char buf[1] = { 0 };
7099         glob_t path;
7100         int rc, fd;
7101
7102         rc = cfs_get_param_paths(&path, "%s/%s/ping",
7103                                 obd_type, obd_name);
7104         if (rc != 0)
7105                 return -errno;
7106 retry_open:
7107         fd = open(path.gl_pathv[0], flags);
7108         if (fd < 0) {
7109                 if (errno == EACCES && flags == O_RDONLY) {
7110                         flags = O_WRONLY;
7111                         goto retry_open;
7112                 }
7113                 rc = -errno;
7114                 llapi_error(LLAPI_MSG_ERROR, rc, "error opening %s",
7115                             path.gl_pathv[0]);
7116                 goto failed;
7117         }
7118
7119         if (flags == O_RDONLY)
7120                 rc = read(fd, buf, sizeof(buf));
7121         else
7122                 rc = write(fd, buf, sizeof(buf));
7123         if (rc < 0)
7124                 rc = -errno;
7125         close(fd);
7126
7127         if (rc == 1)
7128                 rc = 0;
7129 failed:
7130         cfs_free_param_data(&path);
7131         return rc;
7132 }
7133
7134 int llapi_target_iterate(int type_num, char **obd_type,
7135                          void *args, llapi_cb_t cb)
7136 {
7137         int i, rc = 0;
7138         glob_t param;
7139         FILE *fp;
7140
7141         for (i = 0; i < type_num; i++) {
7142                 int j;
7143
7144                 rc = cfs_get_param_paths(&param, "%s/*/uuid", obd_type[i]);
7145                 if (rc != 0)
7146                         continue;
7147
7148                 for (j = 0; j < param.gl_pathc; j++) {
7149                         char obd_uuid[UUID_MAX + 1];
7150                         char *obd_name;
7151                         char *ptr;
7152
7153                         fp = fopen(param.gl_pathv[j], "r");
7154                         if (fp == NULL) {
7155                                 rc = -errno;
7156                                 llapi_error(LLAPI_MSG_ERROR, rc,
7157                                             "error: opening '%s'",
7158                                             param.gl_pathv[j]);
7159                                 goto free_path;
7160                         }
7161
7162                         if (fgets(obd_uuid, sizeof(obd_uuid), fp) == NULL) {
7163                                 rc = -errno;
7164                                 llapi_error(LLAPI_MSG_ERROR, rc,
7165                                             "error: reading '%s'",
7166                                             param.gl_pathv[j]);
7167                                 goto free_path;
7168                         }
7169
7170                         /* Extract the obd_name from the sysfs path.
7171                          * 'topsysfs'/fs/lustre/'obd_type'/'obd_name'.
7172                          */
7173                         obd_name = strstr(param.gl_pathv[j], "/fs/lustre/");
7174                         if (!obd_name) {
7175                                 rc = -EINVAL;
7176                                 goto free_path;
7177                         }
7178
7179                         /* skip /fs/lustre/'obd_type'/ */
7180                         obd_name += strlen(obd_type[i]) + 12;
7181                         /* chop off after obd_name */
7182                         ptr = strrchr(obd_name, '/');
7183                         if (ptr)
7184                                 *ptr = '\0';
7185
7186                         cb(obd_type[i], obd_name, obd_uuid, args);
7187
7188                         fclose(fp);
7189                         fp = NULL;
7190                 }
7191                 cfs_free_param_data(&param);
7192         }
7193 free_path:
7194         if (fp)
7195                 fclose(fp);
7196         cfs_free_param_data(&param);
7197         return rc;
7198 }
7199
7200 struct check_target_filter {
7201         char *nid;
7202         char *instance;
7203 };
7204
7205 static void do_target_check(char *obd_type_name, char *obd_name,
7206                             char *obd_uuid, void *args)
7207 {
7208         int rc;
7209         struct check_target_filter *filter = args;
7210
7211         if (filter != NULL) {
7212                 /* check NIDs if obd type is mgc */
7213                 if (strcmp(obd_type_name, "mgc") == 0) {
7214                         char *delimiter = filter->nid;
7215                         char *nidstr = filter->nid;
7216                         bool found = false;
7217
7218                         while (*nidstr && *delimiter) {
7219                                 delimiter = cfs_nidstr_find_delimiter(nidstr);
7220                                 if (!strncmp(obd_name + 3, nidstr,
7221                                              delimiter - nidstr)) {
7222                                         found = true;
7223                                         break;
7224                                 }
7225                                 nidstr = delimiter + 1;
7226                         }
7227                         if (!found)
7228                                 return;
7229                 }
7230                 /* check instance for other types of device (osc/mdc) */
7231                 else if (strstr(obd_name, filter->instance) == NULL)
7232                         return;
7233         }
7234
7235         rc = llapi_ping(obd_type_name, obd_name);
7236         if (rc == ENOTCONN)
7237                 llapi_printf(LLAPI_MSG_NORMAL, "%s inactive.\n", obd_name);
7238         else if (rc)
7239                 llapi_error(LLAPI_MSG_ERROR, rc, "error: check '%s'", obd_name);
7240         else
7241                 llapi_printf(LLAPI_MSG_NORMAL, "%s active.\n", obd_name);
7242 }
7243
7244 int llapi_target_check(int type_num, char **obd_type, char *dir)
7245 {
7246         char instance[MAX_INSTANCE_LEN];
7247         struct check_target_filter filter = {NULL, NULL};
7248         char *nid = NULL;
7249         int rc;
7250
7251         if (dir == NULL || dir[0] == '\0')
7252                 return llapi_target_iterate(type_num, obd_type, NULL,
7253                                             do_target_check);
7254
7255         rc = get_root_path(WANT_NID | WANT_ERROR, NULL, NULL, dir, -1, NULL,
7256                            &nid);
7257         if (rc) {
7258                 llapi_error(LLAPI_MSG_ERROR, rc,
7259                             "cannot get nid of path '%s'", dir);
7260                 return rc;
7261         }
7262         filter.nid = nid;
7263
7264         rc = llapi_get_instance(dir, instance, ARRAY_SIZE(instance));
7265         if (rc)
7266                 goto out;
7267
7268         filter.instance = instance;
7269
7270         rc = llapi_target_iterate(type_num, obd_type, &filter,
7271                                     do_target_check);
7272
7273 out:
7274         free(nid);
7275         return rc;
7276 }
7277
7278 #undef MAX_STRING_SIZE
7279
7280 /* Is this a lustre fs? */
7281 int llapi_is_lustre_mnttype(const char *type)
7282 {
7283         return strcmp(type, "lustre") == 0 || strcmp(type, "lustre_tgt") == 0;
7284 }
7285
7286 /* Is this a lustre client fs? */
7287 int llapi_is_lustre_mnt(struct mntent *mnt)
7288 {
7289         return (llapi_is_lustre_mnttype(mnt->mnt_type) &&
7290                 strstr(mnt->mnt_fsname, ":/") != NULL);
7291 }
7292
7293 int llapi_quotactl(char *mnt, struct if_quotactl *qctl)
7294 {
7295         char fsname[PATH_MAX + 1];
7296         int root;
7297         int rc;
7298
7299         rc = llapi_search_fsname(mnt, fsname);
7300         if (rc)
7301                 return rc;
7302
7303         root = open(mnt, O_RDONLY | O_DIRECTORY);
7304         if (root < 0) {
7305                 rc = -errno;
7306                 llapi_error(LLAPI_MSG_ERROR, rc, "cannot open '%s'", mnt);
7307                 return rc;
7308         }
7309
7310         rc = ioctl(root, OBD_IOC_QUOTACTL, qctl);
7311         if (rc < 0)
7312                 rc = -errno;
7313         if (rc == -ENOENT && LUSTRE_Q_CMD_IS_POOL(qctl->qc_cmd))
7314                 llapi_error(LLAPI_MSG_ERROR | LLAPI_MSG_NO_ERRNO, rc,
7315                             "Cannot find pool '%s'", qctl->qc_poolname);
7316
7317         close(root);
7318         return rc;
7319 }
7320
7321 int llapi_get_connect_flags(const char *mnt, __u64 *flags)
7322 {
7323         int root;
7324         int rc;
7325
7326         root = open(mnt, O_RDONLY | O_DIRECTORY);
7327         if (root < 0) {
7328                 rc = -errno;
7329                 llapi_error(LLAPI_MSG_ERROR, rc, "open %s failed", mnt);
7330                 return rc;
7331         }
7332
7333         rc = ioctl(root, LL_IOC_GET_CONNECT_FLAGS, flags);
7334         if (rc < 0) {
7335                 rc = -errno;
7336                 llapi_error(LLAPI_MSG_ERROR, rc,
7337                         "ioctl on %s for getting connect flags failed", mnt);
7338         }
7339         close(root);
7340         return rc;
7341 }
7342
7343 /**
7344  * Flush cached pages from all clients.
7345  *
7346  * \param fd    File descriptor
7347  * \retval 0    success
7348  * \retval < 0  error
7349  */
7350 int llapi_file_flush(int fd)
7351 {
7352         __u64 dv;
7353
7354         return llapi_get_data_version(fd, &dv, LL_DV_WR_FLUSH);
7355 }
7356
7357 /**
7358  * Flush dirty pages from all clients.
7359  *
7360  * OSTs will take LCK_PR to flush dirty pages from clients.
7361  *
7362  * \param[in]   fd      File descriptor
7363  *
7364  * \retval 0 on success.
7365  * \retval -errno on error.
7366  */
7367 int llapi_fsync(int fd)
7368 {
7369         __u64 dv;
7370
7371         return llapi_get_data_version(fd, &dv, LL_DV_RD_FLUSH);
7372 }