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