Whamcloud - gitweb
LU-4209 utils: fix O_TMPFILE/O_LOV_DELAY_CREATE conflict
[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.sun.com/software/products/lustre/docs/GPLv2.pdf
19  *
20  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
21  * CA 95054 USA or visit www.sun.com if you need additional information or
22  * have any questions.
23  *
24  * GPL HEADER END
25  */
26 /*
27  * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
28  * Use is subject to license terms.
29  *
30  * Copyright (c) 2011, 2013, Intel Corporation.
31  */
32 /*
33  * This file is part of Lustre, http://www.lustre.org/
34  * Lustre is a trademark of Sun Microsystems, Inc.
35  *
36  * lustre/utils/liblustreapi.c
37  *
38  * Author: Peter J. Braam <braam@clusterfs.com>
39  * Author: Phil Schwan <phil@clusterfs.com>
40  * Author: Robert Read <rread@clusterfs.com>
41  */
42
43 /* for O_DIRECTORY */
44 #ifndef _GNU_SOURCE
45 #define _GNU_SOURCE
46 #endif
47
48 #include <stdlib.h>
49 #include <stdio.h>
50 #include <string.h>
51 #include <stddef.h>
52 #include <sys/ioctl.h>
53 #include <unistd.h>
54 #include <fcntl.h>
55 #include <errno.h>
56 #include <dirent.h>
57 #include <stdarg.h>
58 #include <sys/stat.h>
59 #include <sys/types.h>
60 #include <sys/syscall.h>
61 #include <sys/xattr.h>
62 #include <fnmatch.h>
63 #include <glob.h>
64 #include <libgen.h> /* for dirname() */
65 #ifdef HAVE_LINUX_UNISTD_H
66 #include <linux/unistd.h>
67 #else
68 #include <unistd.h>
69 #endif
70 #include <poll.h>
71
72 #include <liblustre.h>
73 #include <lnet/lnetctl.h>
74 #include <obd.h>
75 #include <obd_lov.h>
76 #include <lustre/lustreapi.h>
77 #include "lustreapi_internal.h"
78
79 static unsigned llapi_dir_filetype_table[] = {
80         [DT_UNKNOWN]= 0,
81         [DT_FIFO]= S_IFIFO,
82         [DT_CHR] = S_IFCHR,
83         [DT_DIR] = S_IFDIR,
84         [DT_BLK] = S_IFBLK,
85         [DT_REG] = S_IFREG,
86         [DT_LNK] = S_IFLNK,
87         [DT_SOCK]= S_IFSOCK,
88 #if defined(DT_DOOR) && defined(S_IFDOOR)
89         [DT_DOOR]= S_IFDOOR,
90 #endif
91 };
92
93 #if defined(DT_DOOR) && defined(S_IFDOOR)
94 static const int DT_MAX = DT_DOOR;
95 #else
96 static const int DT_MAX = DT_SOCK;
97 #endif
98
99 static unsigned llapi_filetype_dir_table[] = {
100         [0]= DT_UNKNOWN,
101         [S_IFIFO]= DT_FIFO,
102         [S_IFCHR] = DT_CHR,
103         [S_IFDIR] = DT_DIR,
104         [S_IFBLK] = DT_BLK,
105         [S_IFREG] = DT_REG,
106         [S_IFLNK] = DT_LNK,
107         [S_IFSOCK]= DT_SOCK,
108 #if defined(DT_DOOR) && defined(S_IFDOOR)
109         [S_IFDOOR]= DT_DOOR,
110 #endif
111 };
112
113 #if defined(DT_DOOR) && defined(S_IFDOOR)
114 static const int S_IFMAX = DT_DOOR;
115 #else
116 static const int S_IFMAX = DT_SOCK;
117 #endif
118
119 /* liblustreapi message level */
120 static int llapi_msg_level = LLAPI_MSG_MAX;
121
122 void llapi_msg_set_level(int level)
123 {
124         /* ensure level is in the good range */
125         if (level < LLAPI_MSG_OFF)
126                 llapi_msg_level = LLAPI_MSG_OFF;
127         else if (level > LLAPI_MSG_MAX)
128                 llapi_msg_level = LLAPI_MSG_MAX;
129         else
130                 llapi_msg_level = level;
131 }
132
133 static void error_callback_default(enum llapi_message_level level, int err,
134                                    const char *fmt, va_list ap)
135 {
136         vfprintf(stderr, fmt, ap);
137         if (level & LLAPI_MSG_NO_ERRNO)
138                 fprintf(stderr, "\n");
139         else
140                 fprintf(stderr, ": %s (%d)\n", strerror(err), err);
141 }
142
143 static void info_callback_default(enum llapi_message_level level, int err,
144                                   const char *fmt, va_list ap)
145 {
146         vfprintf(stdout, fmt, ap);
147 }
148
149 static llapi_log_callback_t llapi_error_callback = error_callback_default;
150 static llapi_log_callback_t llapi_info_callback = info_callback_default;
151
152
153 /* llapi_error will preserve errno */
154 void llapi_error(enum llapi_message_level level, int err, const char *fmt, ...)
155 {
156         va_list  args;
157         int      tmp_errno = errno;
158
159         if ((level & LLAPI_MSG_MASK) > llapi_msg_level)
160                 return;
161
162         va_start(args, fmt);
163         llapi_error_callback(level, abs(err), fmt, args);
164         va_end(args);
165         errno = tmp_errno;
166 }
167
168 /* llapi_printf will preserve errno */
169 void llapi_printf(enum llapi_message_level level, const char *fmt, ...)
170 {
171         va_list  args;
172         int      tmp_errno = errno;
173
174         if ((level & LLAPI_MSG_MASK) > llapi_msg_level)
175                 return;
176
177         va_start(args, fmt);
178         llapi_info_callback(level, 0, fmt, args);
179         va_end(args);
180         errno = tmp_errno;
181 }
182
183 /**
184  * Set a custom error logging function. Passing in NULL will reset the logging
185  * callback to its default value.
186  *
187  * This function returns the value of the old callback.
188  */
189 llapi_log_callback_t llapi_error_callback_set(llapi_log_callback_t cb)
190 {
191         llapi_log_callback_t    old = llapi_error_callback;
192
193         if (cb != NULL)
194                 llapi_error_callback = cb;
195         else
196                 llapi_error_callback = error_callback_default;
197
198         return old;
199 }
200
201 /**
202  * Set a custom info logging function. Passing in NULL will reset the logging
203  * callback to its default value.
204  *
205  * This function returns the value of the old callback.
206  */
207 llapi_log_callback_t llapi_info_callback_set(llapi_log_callback_t cb)
208 {
209         llapi_log_callback_t    old = llapi_info_callback;
210
211         if (cb != NULL)
212                 llapi_info_callback = cb;
213         else
214                 llapi_info_callback = info_callback_default;
215
216         return old;
217 }
218
219 /**
220  * size_units is to be initialized (or zeroed) by caller.
221  */
222 int llapi_parse_size(const char *optarg, unsigned long long *size,
223                      unsigned long long *size_units, int bytes_spec)
224 {
225         char *end;
226
227         if (strncmp(optarg, "-", 1) == 0)
228                 return -1;
229
230         if (*size_units == 0)
231                 *size_units = 1;
232
233         *size = strtoull(optarg, &end, 0);
234
235         if (*end != '\0') {
236                 if ((*end == 'b') && *(end + 1) == '\0' &&
237                     (*size & (~0ULL << (64 - 9))) == 0 &&
238                     !bytes_spec) {
239                         *size_units = 1 << 9;
240                 } else if ((*end == 'b') &&
241                            *(end + 1) == '\0' &&
242                            bytes_spec) {
243                         *size_units = 1;
244                 } else if ((*end == 'k' || *end == 'K') &&
245                            *(end + 1) == '\0' &&
246                            (*size & (~0ULL << (64 - 10))) == 0) {
247                         *size_units = 1 << 10;
248                 } else if ((*end == 'm' || *end == 'M') &&
249                            *(end + 1) == '\0' &&
250                            (*size & (~0ULL << (64 - 20))) == 0) {
251                         *size_units = 1 << 20;
252                 } else if ((*end == 'g' || *end == 'G') &&
253                            *(end + 1) == '\0' &&
254                            (*size & (~0ULL << (64 - 30))) == 0) {
255                         *size_units = 1 << 30;
256                 } else if ((*end == 't' || *end == 'T') &&
257                            *(end + 1) == '\0' &&
258                            (*size & (~0ULL << (64 - 40))) == 0) {
259                         *size_units = 1ULL << 40;
260                 } else if ((*end == 'p' || *end == 'P') &&
261                            *(end + 1) == '\0' &&
262                            (*size & (~0ULL << (64 - 50))) == 0) {
263                         *size_units = 1ULL << 50;
264                 } else if ((*end == 'e' || *end == 'E') &&
265                            *(end + 1) == '\0' &&
266                            (*size & (~0ULL << (64 - 60))) == 0) {
267                         *size_units = 1ULL << 60;
268                 } else {
269                         return -1;
270                 }
271         }
272         *size *= *size_units;
273         return 0;
274 }
275
276 /* XXX: llapi_xxx() functions return negative values upon failure */
277
278 int llapi_stripe_limit_check(unsigned long long stripe_size, int stripe_offset,
279                                 int stripe_count, int stripe_pattern)
280 {
281         int page_size, rc;
282
283         /* 64 KB is the largest common page size I'm aware of (on ia64), but
284          * check the local page size just in case. */
285         page_size = LOV_MIN_STRIPE_SIZE;
286         if (getpagesize() > page_size) {
287                 page_size = getpagesize();
288                 llapi_err_noerrno(LLAPI_MSG_WARN,
289                                 "warning: your page size (%u) is "
290                                 "larger than expected (%u)", page_size,
291                                 LOV_MIN_STRIPE_SIZE);
292         }
293         if ((stripe_size & (LOV_MIN_STRIPE_SIZE - 1))) {
294                 rc = -EINVAL;
295                 llapi_error(LLAPI_MSG_ERROR, rc, "error: bad stripe_size %llu, "
296                                 "must be an even multiple of %d bytes",
297                                 stripe_size, page_size);
298                 return rc;
299         }
300         if (stripe_offset < -1 || stripe_offset > MAX_OBD_DEVICES) {
301                 rc = -EINVAL;
302                 llapi_error(LLAPI_MSG_ERROR, rc, "error: bad stripe offset %d",
303                                 stripe_offset);
304                 return rc;
305         }
306         if (stripe_count < -1 || stripe_count > LOV_MAX_STRIPE_COUNT) {
307                 rc = -EINVAL;
308                 llapi_error(LLAPI_MSG_ERROR, rc, "error: bad stripe count %d",
309                                 stripe_count);
310                 return rc;
311         }
312         if (stripe_size >= (1ULL << 32)) {
313                 rc = -EINVAL;
314                 llapi_error(LLAPI_MSG_ERROR, rc,
315                                 "warning: stripe size 4G or larger "
316                                 "is not currently supported and would wrap");
317                 return rc;
318         }
319         return 0;
320 }
321
322 /* return the first file matching this pattern */
323 static int first_match(char *pattern, char *buffer)
324 {
325         glob_t glob_info;
326
327         if (glob(pattern, GLOB_BRACE, NULL, &glob_info))
328                 return -ENOENT;
329
330         if (glob_info.gl_pathc < 1) {
331                 globfree(&glob_info);
332                 return -ENOENT;
333         }
334
335         strcpy(buffer, glob_info.gl_pathv[0]);
336
337         globfree(&glob_info);
338         return 0;
339 }
340
341 static int find_target_obdpath(char *fsname, char *path)
342 {
343         glob_t glob_info;
344         char pattern[PATH_MAX + 1];
345         int rc;
346
347         snprintf(pattern, PATH_MAX,
348                  "/proc/fs/lustre/lov/%s-*/target_obd",
349                  fsname);
350         rc = glob(pattern, GLOB_BRACE, NULL, &glob_info);
351         if (rc == GLOB_NOMATCH)
352                 return -ENODEV;
353         else if (rc)
354                 return -EINVAL;
355
356         strcpy(path, glob_info.gl_pathv[0]);
357         globfree(&glob_info);
358         return 0;
359 }
360
361 static int find_poolpath(char *fsname, char *poolname, char *poolpath)
362 {
363         glob_t glob_info;
364         char pattern[PATH_MAX + 1];
365         int rc;
366
367         snprintf(pattern, PATH_MAX,
368                  "/proc/fs/lustre/lov/%s-*/pools/%s",
369                  fsname, poolname);
370         rc = glob(pattern, GLOB_BRACE, NULL, &glob_info);
371         /* If no pools, make sure the lov is available */
372         if ((rc == GLOB_NOMATCH) &&
373             (find_target_obdpath(fsname, poolpath) == -ENODEV))
374                 return -ENODEV;
375         if (rc)
376                 return -EINVAL;
377
378         strcpy(poolpath, glob_info.gl_pathv[0]);
379         globfree(&glob_info);
380         return 0;
381 }
382
383 /**
384   * return a parameter string for a specific device type or mountpoint
385   *
386   * \param param_path the path to the file containing parameter data
387   * \param result buffer for parameter value string
388   * \param result_size size of buffer for return value
389   *
390   * The \param param_path is appended to /proc/{fs,sys}/{lnet,lustre} to
391   * complete the absolute path to the file containing the parameter data
392   * the user is requesting. If that file exist then the data is read from
393   * the file and placed into the \param result buffer that is passed by
394   * the user. Data is only copied up to the \param result_size to prevent
395   * overflow of the array.
396   *
397   * Return 0 for success, with a NUL-terminated string in \param result.
398   * Return -ve value for error.
399   */
400 int get_param(const char *param_path, char *result,
401                      unsigned int result_size)
402 {
403         char file[PATH_MAX + 1], pattern[PATH_MAX + 1], buf[result_size];
404         FILE *fp = NULL;
405         int rc = 0;
406
407         snprintf(pattern, PATH_MAX, "/proc/{fs,sys}/{lnet,lustre}/%s",
408                  param_path);
409         rc = first_match(pattern, file);
410         if (rc != 0 || result == NULL)
411                 return rc;
412
413         fp = fopen(file, "r");
414         if (fp != NULL) {
415                 while (fgets(buf, result_size, fp) != NULL)
416                         strcpy(result, buf);
417                 fclose(fp);
418         } else {
419                 rc = -errno;
420         }
421         return rc;
422 }
423
424 #define DEVICES_LIST "/proc/fs/lustre/devices"
425
426 /**
427   * return a parameter string for a specific device type or mountpoint
428   *
429   * \param fsname Lustre filesystem name (optional)
430   * \param file_path path to file in filesystem (optional, if fsname unset)
431   * \param obd_type Lustre OBD device type
432   * \param param_name parameter name to fetch
433   * \param value return buffer for parameter value string
434   * \param val_len size of buffer for return value
435   *
436   * If fsname is specified then the parameter will be from that filesystem
437   * (if it exists). If file_path is given and it is in a mounted Lustre
438   * filesystem, then the parameter will be otherwise the value may be
439   * from any mounted filesystem (if there is more than one).
440   *
441   * If "obd_type" matches a Lustre device then the first matching device
442   * (as with "lctl dl", constrained by \param fsname or \param mount_path)
443   * will be used to provide the return value, otherwise the first such
444   * device found will be used.
445   *
446   * Return 0 for success, with a NUL-terminated string in \param buffer.
447   * Return -ve value for error.
448   */
449 static int get_param_obdvar(const char *fsname, const char *file_path,
450                             const char *obd_type, const char *param_name,
451                             char *value, unsigned int val_len)
452 {
453         char devices[PATH_MAX + 1], dev[PATH_MAX + 1] = "*", fs[PATH_MAX + 1];
454         FILE *fp = fopen(DEVICES_LIST, "r");
455         int rc = 0;
456
457         if (!fsname && file_path) {
458                 rc = llapi_search_fsname(file_path, fs);
459                 if (rc) {
460                         llapi_error(LLAPI_MSG_ERROR, rc,
461                                     "'%s' is not on a Lustre filesystem",
462                                     file_path);
463                         if (fp != NULL)
464                                 fclose(fp);
465                         return rc;
466                 }
467         } else if (fsname) {
468                 if (strlen(fsname) > sizeof(fs)-1) {
469                         if (fp != NULL)
470                                 fclose(fp);
471                         return -E2BIG;
472                 }
473                 strncpy(fs, fsname, sizeof(fs));
474         }
475
476         if (fp == NULL) {
477                 rc = -errno;
478                 llapi_error(LLAPI_MSG_ERROR, rc, "error: opening "DEVICES_LIST);
479                 return rc;
480         }
481
482         while (fgets(devices, sizeof(devices), fp) != NULL) {
483                 char *bufp = devices, *tmp;
484
485                 while (bufp[0] == ' ')
486                         ++bufp;
487
488                 tmp = strstr(bufp, obd_type);
489                 if (tmp) {
490                         tmp += strlen(obd_type) + 1;
491                         if (strcmp(tmp, fs))
492                                 continue;
493                         if (strlen(tmp) > sizeof(dev)-1) {
494                                 fclose(fp);
495                                 return -E2BIG;
496                         }
497                         strncpy(dev, tmp, sizeof(dev));
498                         tmp = strchr(dev, ' ');
499                         if (tmp != NULL)
500                                 *tmp = '\0';
501                         break;
502                 }
503         }
504
505         if (dev[0] == '*' && strlen(fs))
506                 snprintf(dev, PATH_MAX, "%s-*", fs);
507         snprintf(devices, PATH_MAX, "%s/%s/%s", obd_type, dev, param_name);
508         fclose(fp);
509         return get_param(devices, value, val_len);
510 }
511
512 /*
513  * TYPE one of llite, lmv, lov.
514  * /proc/fs/lustre/TYPE/INST the directory of interest.
515  */
516 static int get_param_cli(const char *type, const char *inst,
517                          const char *param, char *buf, size_t buf_size)
518 {
519         char param_path[PATH_MAX + 1];
520         FILE *param_file = NULL;
521         int rc;
522
523         snprintf(param_path, sizeof(param_path),
524                  "/proc/fs/lustre/%s/%s/%s", type, inst, param);
525
526         param_file = fopen(param_path, "r");
527         if (param_file == NULL) {
528                 rc = -errno;
529                 goto out;
530         }
531
532         if (fgets(buf, buf_size, param_file) == NULL) {
533                 rc = -errno;
534                 goto out;
535         }
536
537         rc = 0;
538 out:
539         if (param_file != NULL)
540                 fclose(param_file);
541
542         return rc;
543 }
544
545 static int get_param_llite(const char *path,
546                            const char *param, char *buf, size_t buf_size)
547 {
548         char inst[80];
549         int rc;
550
551         rc = llapi_getname(path, inst, sizeof(inst));
552         if (rc != 0)
553                 return rc;
554
555         return get_param_cli("llite", inst, param, buf, buf_size);
556 }
557
558 static int get_param_lov(const char *path,
559                          const char *param, char *buf, size_t buf_size)
560 {
561         struct obd_uuid uuid;
562         int rc;
563
564         rc = llapi_file_get_lov_uuid(path, &uuid);
565         if (rc != 0)
566                 return rc;
567
568         return get_param_cli("lov", uuid.uuid, param, buf, buf_size);
569 }
570
571 static int get_param_lmv(const char *path,
572                          const char *param, char *buf, size_t buf_size)
573 {
574         struct obd_uuid uuid;
575         int rc;
576
577         rc = llapi_file_get_lmv_uuid(path, &uuid);
578         if (rc != 0)
579                 return rc;
580
581         return get_param_cli("lmv", uuid.uuid, param, buf, buf_size);
582 }
583
584 static int get_mds_md_size(const char *path)
585 {
586         int md_size = lov_user_md_size(LOV_MAX_STRIPE_COUNT, LOV_USER_MAGIC_V3);
587         char buf[80];
588         int rc;
589
590         /* Get the max ea size from llite proc. */
591         rc = get_param_llite(path, "max_easize", buf, sizeof(buf));
592         if (rc != 0)
593                 goto out;
594
595         rc = atoi(buf);
596         if (rc > 0)
597                 md_size = rc;
598
599 out:
600         return md_size;
601 }
602
603 /*
604  * if pool is NULL, search ostname in target_obd
605  * if pool is not NULL:
606  *  if pool not found returns errno < 0
607  *  if ostname is NULL, returns 1 if pool is not empty and 0 if pool empty
608  *  if ostname is not NULL, returns 1 if OST is in pool and 0 if not
609  */
610 int llapi_search_ost(char *fsname, char *poolname, char *ostname)
611 {
612         FILE *fd;
613         char buffer[PATH_MAX + 1];
614         int len = 0, rc;
615
616         if (ostname != NULL)
617                 len = strlen(ostname);
618
619         if (poolname == NULL) {
620                 if (len == 0)
621                         rc = -EINVAL;
622                 else
623                         rc = find_target_obdpath(fsname, buffer);
624         } else {
625                 rc = find_poolpath(fsname, poolname, buffer);
626         }
627         if (rc)
628                 return rc;
629
630         fd = fopen(buffer, "r");
631         if (fd == NULL)
632                 return -errno;
633
634         while (fgets(buffer, sizeof(buffer), fd) != NULL) {
635                 if (poolname == NULL) {
636                         char *ptr;
637                         /* Search for an ostname in the list of OSTs
638                          Line format is IDX: fsname-OSTxxxx_UUID STATUS */
639                         ptr = strchr(buffer, ' ');
640                         if ((ptr != NULL) &&
641                             (strncmp(ptr + 1, ostname, len) == 0)) {
642                                 fclose(fd);
643                                 return 1;
644                         }
645                 } else {
646                         /* Search for an ostname in a pool,
647                          (or an existing non-empty pool if no ostname) */
648                         if ((ostname == NULL) ||
649                             (strncmp(buffer, ostname, len) == 0)) {
650                                 fclose(fd);
651                                 return 1;
652                         }
653                 }
654         }
655         fclose(fd);
656         return 0;
657 }
658
659 int llapi_file_open_pool(const char *name, int flags, int mode,
660                          unsigned long long stripe_size, int stripe_offset,
661                          int stripe_count, int stripe_pattern, char *pool_name)
662 {
663         struct lov_user_md_v3 lum = { 0 };
664         int fd, rc = 0;
665
666         /* Make sure we have a good pool */
667         if (pool_name != NULL) {
668                 char fsname[MAX_OBD_NAME + 1], *ptr;
669
670                 rc = llapi_search_fsname(name, fsname);
671                 if (rc) {
672                         llapi_error(LLAPI_MSG_ERROR, rc,
673                                     "'%s' is not on a Lustre filesystem",
674                                     name);
675                         return rc;
676                 }
677
678                 /* in case user gives the full pool name <fsname>.<poolname>,
679                  * strip the fsname */
680                 ptr = strchr(pool_name, '.');
681                 if (ptr != NULL) {
682                         *ptr = '\0';
683                         if (strcmp(pool_name, fsname) != 0) {
684                                 *ptr = '.';
685                                 llapi_err_noerrno(LLAPI_MSG_ERROR,
686                                           "Pool '%s' is not on filesystem '%s'",
687                                           pool_name, fsname);
688                                 return -EINVAL;
689                         }
690                         pool_name = ptr + 1;
691                 }
692
693                 /* Make sure the pool exists and is non-empty */
694                 rc = llapi_search_ost(fsname, pool_name, NULL);
695                 if (rc < 1) {
696                         llapi_err_noerrno(LLAPI_MSG_ERROR,
697                                           "pool '%s.%s' %s", fsname, pool_name,
698                                           rc == 0 ? "has no OSTs" : "does not exist");
699                         return -EINVAL;
700                 }
701         }
702
703 retry_open:
704         fd = open(name, flags | O_LOV_DELAY_CREATE, mode);
705         if (fd < 0) {
706                 if (errno == EISDIR && !(flags & O_DIRECTORY)) {
707                         flags = O_DIRECTORY | O_RDONLY;
708                         goto retry_open;
709                 }
710         }
711
712         if (fd < 0) {
713                 rc = -errno;
714                 llapi_error(LLAPI_MSG_ERROR, rc, "unable to open '%s'", name);
715                 return rc;
716         }
717
718         rc = llapi_stripe_limit_check(stripe_size, stripe_offset, stripe_count,
719                                       stripe_pattern);
720         if (rc != 0)
721                 goto out;
722
723         /*  Initialize IOCTL striping pattern structure */
724         lum.lmm_magic = LOV_USER_MAGIC_V3;
725         lum.lmm_pattern = stripe_pattern;
726         lum.lmm_stripe_size = stripe_size;
727         lum.lmm_stripe_count = stripe_count;
728         lum.lmm_stripe_offset = stripe_offset;
729         if (pool_name != NULL) {
730                 strncpy(lum.lmm_pool_name, pool_name, LOV_MAXPOOLNAME);
731         } else {
732                 /* If no pool is specified at all, use V1 request */
733                 lum.lmm_magic = LOV_USER_MAGIC_V1;
734         }
735
736         if (ioctl(fd, LL_IOC_LOV_SETSTRIPE, &lum)) {
737                 char *errmsg = "stripe already set";
738                 rc = -errno;
739                 if (errno != EEXIST && errno != EALREADY)
740                         errmsg = strerror(errno);
741
742                 llapi_err_noerrno(LLAPI_MSG_ERROR,
743                                   "error on ioctl "LPX64" for '%s' (%d): %s",
744                                   (__u64)LL_IOC_LOV_SETSTRIPE, name, fd,errmsg);
745         }
746 out:
747         if (rc) {
748                 close(fd);
749                 fd = rc;
750         }
751
752         return fd;
753 }
754
755 int llapi_file_open(const char *name, int flags, int mode,
756                     unsigned long long stripe_size, int stripe_offset,
757                     int stripe_count, int stripe_pattern)
758 {
759         return llapi_file_open_pool(name, flags, mode, stripe_size,
760                                     stripe_offset, stripe_count,
761                                     stripe_pattern, NULL);
762 }
763
764 int llapi_file_create(const char *name, unsigned long long stripe_size,
765                       int stripe_offset, int stripe_count, int stripe_pattern)
766 {
767         int fd;
768
769         fd = llapi_file_open_pool(name, O_CREAT | O_WRONLY, 0644, stripe_size,
770                                   stripe_offset, stripe_count, stripe_pattern,
771                                   NULL);
772         if (fd < 0)
773                 return fd;
774
775         close(fd);
776         return 0;
777 }
778
779 int llapi_file_create_pool(const char *name, unsigned long long stripe_size,
780                            int stripe_offset, int stripe_count,
781                            int stripe_pattern, char *pool_name)
782 {
783         int fd;
784
785         fd = llapi_file_open_pool(name, O_CREAT | O_WRONLY, 0644, stripe_size,
786                                   stripe_offset, stripe_count, stripe_pattern,
787                                   pool_name);
788         if (fd < 0)
789                 return fd;
790
791         close(fd);
792         return 0;
793 }
794
795 /**
796  * In DNE phase I, only stripe_offset will be used in this function.
797  * stripe_count, stripe_pattern and pool_name will be supported later.
798  */
799 int llapi_dir_create_pool(const char *name, int flags, int stripe_offset,
800                           int stripe_count, int stripe_pattern, char *pool_name)
801 {
802         struct lmv_user_md lmu = { 0 };
803         struct obd_ioctl_data data = { 0 };
804         char rawbuf[8192];
805         char *buf = rawbuf;
806         char *dirpath = NULL;
807         char *namepath = NULL;
808         char *dir;
809         char *filename;
810         int fd = -1;
811         int rc;
812
813         dirpath = strdup(name);
814         namepath = strdup(name);
815         if (!dirpath || !namepath)
816                 return -ENOMEM;
817
818         lmu.lum_magic = LMV_USER_MAGIC;
819         lmu.lum_stripe_offset = stripe_offset;
820         lmu.lum_stripe_count = stripe_count;
821         lmu.lum_hash_type = stripe_pattern;
822         if (pool_name != NULL) {
823                 if (strlen(pool_name) >= LOV_MAXPOOLNAME) {
824                         llapi_err_noerrno(LLAPI_MSG_ERROR,
825                                   "error LL_IOC_LMV_SETSTRIPE '%s' : too large"
826                                   "pool name: %s", name, pool_name);
827                         rc = -E2BIG;
828                         goto out;
829                 }
830                 memcpy(lmu.lum_pool_name, pool_name, strlen(pool_name));
831         }
832
833         filename = basename(namepath);
834         lmu.lum_type = LMV_STRIPE_TYPE;
835         dir = dirname(dirpath);
836
837         data.ioc_inlbuf1 = (char *)filename;
838         data.ioc_inllen1 = strlen(filename) + 1;
839         data.ioc_inlbuf2 = (char *)&lmu;
840         data.ioc_inllen2 = sizeof(struct lmv_user_md);
841         rc = obd_ioctl_pack(&data, &buf, sizeof(rawbuf));
842         if (rc) {
843                 llapi_error(LLAPI_MSG_ERROR, rc,
844                             "error: LL_IOC_LMV_SETSTRIPE pack failed '%s'.",
845                             name);
846                 goto out;
847         }
848
849         fd = open(dir, O_DIRECTORY | O_RDONLY);
850         if (fd < 0) {
851                 rc = -errno;
852                 llapi_error(LLAPI_MSG_ERROR, rc, "unable to open '%s'", name);
853                 goto out;
854         }
855
856         if (ioctl(fd, LL_IOC_LMV_SETSTRIPE, buf)) {
857                 char *errmsg = "stripe already set";
858                 rc = -errno;
859                 if (errno != EEXIST && errno != EALREADY)
860                         errmsg = strerror(errno);
861
862                 llapi_err_noerrno(LLAPI_MSG_ERROR,
863                                   "error on LL_IOC_LMV_SETSTRIPE '%s' (%d): %s",
864                                   name, fd, errmsg);
865         }
866         close(fd);
867 out:
868         free(dirpath);
869         free(namepath);
870         return rc;
871 }
872
873 int llapi_direntry_remove(char *dname)
874 {
875         char *dirpath = NULL;
876         char *namepath = NULL;
877         char *dir;
878         char *filename;
879         int fd = -1;
880         int rc = 0;
881
882         dirpath = strdup(dname);
883         namepath = strdup(dname);
884         if (!dirpath || !namepath)
885                 return -ENOMEM;
886
887         filename = basename(namepath);
888
889         dir = dirname(dirpath);
890
891         fd = open(dir, O_DIRECTORY | O_RDONLY);
892         if (fd < 0) {
893                 rc = -errno;
894                 llapi_error(LLAPI_MSG_ERROR, rc, "unable to open '%s'",
895                             filename);
896                 goto out;
897         }
898
899         if (ioctl(fd, LL_IOC_REMOVE_ENTRY, filename)) {
900                 char *errmsg = strerror(errno);
901                 llapi_err_noerrno(LLAPI_MSG_ERROR,
902                                   "error on ioctl "LPX64" for '%s' (%d): %s",
903                                   (__u64)LL_IOC_LMV_SETSTRIPE, filename,
904                                   fd, errmsg);
905         }
906 out:
907         free(dirpath);
908         free(namepath);
909         if (fd != -1)
910                 close(fd);
911         return rc;
912 }
913
914 /*
915  * Find the fsname, the full path, and/or an open fd.
916  * Either the fsname or path must not be NULL
917  */
918 int get_root_path(int want, char *fsname, int *outfd, char *path, int index)
919 {
920         struct mntent mnt;
921         char buf[PATH_MAX], mntdir[PATH_MAX];
922         char *ptr;
923         FILE *fp;
924         int idx = 0, len = 0, mntlen, fd;
925         int rc = -ENODEV;
926
927         /* get the mount point */
928         fp = setmntent(MOUNTED, "r");
929         if (fp == NULL) {
930                 rc = -EIO;
931                 llapi_error(LLAPI_MSG_ERROR, rc,
932                             "setmntent(%s) failed", MOUNTED);
933                 return rc;
934         }
935         while (1) {
936                 if (getmntent_r(fp, &mnt, buf, sizeof(buf)) == NULL)
937                         break;
938
939                 if (!llapi_is_lustre_mnt(&mnt))
940                         continue;
941
942                 if ((want & WANT_INDEX) && (idx++ != index))
943                         continue;
944
945                 mntlen = strlen(mnt.mnt_dir);
946                 ptr = strrchr(mnt.mnt_fsname, '/');
947                 /* thanks to the call to llapi_is_lustre_mnt() above,
948                  * we are sure that mnt.mnt_fsname contains ":/",
949                  * so ptr should never be NULL */
950                 if (ptr == NULL)
951                         continue;
952                 ptr++;
953
954                 /* Check the fsname for a match, if given */
955                 if (!(want & WANT_FSNAME) && fsname != NULL &&
956                     (strlen(fsname) > 0) && (strcmp(ptr, fsname) != 0))
957                         continue;
958
959                 /* If the path isn't set return the first one we find */
960                 if (path == NULL || strlen(path) == 0) {
961                         strcpy(mntdir, mnt.mnt_dir);
962                         if ((want & WANT_FSNAME) && fsname != NULL)
963                                 strcpy(fsname, ptr);
964                         rc = 0;
965                         break;
966                 /* Otherwise find the longest matching path */
967                 } else if ((strlen(path) >= mntlen) && (mntlen >= len) &&
968                            (strncmp(mnt.mnt_dir, path, mntlen) == 0)) {
969                         strcpy(mntdir, mnt.mnt_dir);
970                         len = mntlen;
971                         if ((want & WANT_FSNAME) && fsname != NULL)
972                                 strcpy(fsname, ptr);
973                         rc = 0;
974                 }
975         }
976         endmntent(fp);
977
978         /* Found it */
979         if (rc == 0) {
980                 if ((want & WANT_PATH) && path != NULL)
981                         strcpy(path, mntdir);
982                 if (want & WANT_FD) {
983                         fd = open(mntdir, O_RDONLY | O_DIRECTORY | O_NONBLOCK);
984                         if (fd < 0) {
985                                 rc = -errno;
986                                 llapi_error(LLAPI_MSG_ERROR, rc,
987                                             "error opening '%s'", mntdir);
988
989                         } else {
990                                 *outfd = fd;
991                         }
992                 }
993         } else if (want & WANT_ERROR)
994                 llapi_err_noerrno(LLAPI_MSG_ERROR,
995                                   "can't find fs root for '%s': %d",
996                                   (want & WANT_PATH) ? fsname : path, rc);
997         return rc;
998 }
999
1000 /*
1001  * search lustre mounts
1002  *
1003  * Calling this function will return to the user the mount point, mntdir, and
1004  * the file system name, fsname, if the user passed a buffer to this routine.
1005  *
1006  * The user inputs are pathname and index. If the pathname is supplied then
1007  * the value of the index will be ignored. The pathname will return data if
1008  * the pathname is located on a lustre mount. Index is used to pick which
1009  * mount point you want in the case of multiple mounted lustre file systems.
1010  * See function lfs_osts in lfs.c for a example of the index use.
1011  */
1012 int llapi_search_mounts(const char *pathname, int index, char *mntdir,
1013                         char *fsname)
1014 {
1015         int want = WANT_PATH, idx = -1;
1016
1017         if (!pathname || pathname[0] == '\0') {
1018                 want |= WANT_INDEX;
1019                 idx = index;
1020         } else
1021                 strcpy(mntdir, pathname);
1022
1023         if (fsname)
1024                 want |= WANT_FSNAME;
1025         return get_root_path(want, fsname, NULL, mntdir, idx);
1026 }
1027
1028 /* Given a path, find the corresponding Lustre fsname */
1029 int llapi_search_fsname(const char *pathname, char *fsname)
1030 {
1031         char *path;
1032         int rc;
1033
1034         path = realpath(pathname, NULL);
1035         if (path == NULL) {
1036                 char buf[PATH_MAX + 1], *ptr;
1037
1038                 buf[0] = 0;
1039                 if (pathname[0] != '/') {
1040                         /* Need an absolute path, but realpath() only works for
1041                          * pathnames that actually exist.  We go through the
1042                          * extra hurdle of dirname(getcwd() + pathname) in
1043                          * case the relative pathname contains ".." in it. */
1044                         if (getcwd(buf, sizeof(buf) - 1) == NULL)
1045                                 return -errno;
1046                         strcat(buf, "/");
1047                 }
1048                 strncat(buf, pathname, sizeof(buf) - strlen(buf));
1049                 path = realpath(buf, NULL);
1050                 if (path == NULL) {
1051                         ptr = strrchr(buf, '/');
1052                         if (ptr == NULL)
1053                                 return -ENOENT;
1054                         *ptr = '\0';
1055                         path = realpath(buf, NULL);
1056                         if (path == NULL) {
1057                                 rc = -errno;
1058                                 llapi_error(LLAPI_MSG_ERROR, rc,
1059                                             "pathname '%s' cannot expand",
1060                                             pathname);
1061                                 return rc;
1062                         }
1063                 }
1064         }
1065         rc = get_root_path(WANT_FSNAME | WANT_ERROR, fsname, NULL, path, -1);
1066         free(path);
1067         return rc;
1068 }
1069
1070 int llapi_search_rootpath(char *pathname, const char *fsname)
1071 {
1072         return get_root_path(WANT_PATH, (char *)fsname, NULL, pathname, -1);
1073 }
1074
1075 int llapi_getname(const char *path, char *buf, size_t size)
1076 {
1077         struct obd_uuid uuid_buf;
1078         char *uuid = uuid_buf.uuid;
1079         int rc, nr;
1080
1081         memset(&uuid_buf, 0, sizeof(uuid_buf));
1082         rc = llapi_file_get_lov_uuid(path, &uuid_buf);
1083         if (rc)
1084                 return rc;
1085
1086         /* We want to turn lustre-clilov-ffff88002738bc00 into
1087          * lustre-ffff88002738bc00. */
1088
1089         nr = snprintf(buf, size, "%.*s-%s",
1090                       (int) (strlen(uuid) - 24), uuid,
1091                       uuid + strlen(uuid) - 16);
1092
1093         if (nr >= size)
1094                 rc = -ENAMETOOLONG;
1095
1096         return rc;
1097 }
1098
1099
1100 /*
1101  * find the pool directory path under /proc
1102  * (can be also used to test if a fsname is known)
1103  */
1104 static int poolpath(char *fsname, char *pathname, char *pool_pathname)
1105 {
1106         int rc = 0;
1107         char pattern[PATH_MAX + 1];
1108         char buffer[PATH_MAX];
1109
1110         if (fsname == NULL) {
1111                 rc = llapi_search_fsname(pathname, buffer);
1112                 if (rc != 0)
1113                         return rc;
1114                 fsname = buffer;
1115                 strcpy(pathname, fsname);
1116         }
1117
1118         snprintf(pattern, PATH_MAX, "/proc/fs/lustre/lov/%s-*/pools", fsname);
1119         rc = first_match(pattern, buffer);
1120         if (rc)
1121                 return rc;
1122
1123         /* in fsname test mode, pool_pathname is NULL */
1124         if (pool_pathname != NULL)
1125                 strcpy(pool_pathname, buffer);
1126
1127         return 0;
1128 }
1129
1130 /**
1131  * Get the list of pool members.
1132  * \param poolname    string of format \<fsname\>.\<poolname\>
1133  * \param members     caller-allocated array of char*
1134  * \param list_size   size of the members array
1135  * \param buffer      caller-allocated buffer for storing OST names
1136  * \param buffer_size size of the buffer
1137  *
1138  * \return number of members retrieved for this pool
1139  * \retval -error failure
1140  */
1141 int llapi_get_poolmembers(const char *poolname, char **members,
1142                           int list_size, char *buffer, int buffer_size)
1143 {
1144         char fsname[PATH_MAX + 1];
1145         char *pool, *tmp;
1146         char pathname[PATH_MAX + 1];
1147         char path[PATH_MAX + 1];
1148         char buf[1024];
1149         FILE *fd;
1150         int rc = 0;
1151         int nb_entries = 0;
1152         int used = 0;
1153
1154         /* name is FSNAME.POOLNAME */
1155         if (strlen(poolname) > PATH_MAX)
1156                 return -EOVERFLOW;
1157         strcpy(fsname, poolname);
1158         pool = strchr(fsname, '.');
1159         if (pool == NULL)
1160                 return -EINVAL;
1161
1162         *pool = '\0';
1163         pool++;
1164
1165         rc = poolpath(fsname, NULL, pathname);
1166         if (rc != 0) {
1167                 llapi_error(LLAPI_MSG_ERROR, rc,
1168                             "Lustre filesystem '%s' not found",
1169                             fsname);
1170                 return rc;
1171         }
1172
1173         llapi_printf(LLAPI_MSG_NORMAL, "Pool: %s.%s\n", fsname, pool);
1174         sprintf(path, "%s/%s", pathname, pool);
1175         fd = fopen(path, "r");
1176         if (fd == NULL) {
1177                 rc = -errno;
1178                 llapi_error(LLAPI_MSG_ERROR, rc, "Cannot open %s", path);
1179                 return rc;
1180         }
1181
1182         rc = 0;
1183         while (fgets(buf, sizeof(buf), fd) != NULL) {
1184                 if (nb_entries >= list_size) {
1185                         rc = -EOVERFLOW;
1186                         break;
1187                 }
1188                 /* remove '\n' */
1189                 tmp = strchr(buf, '\n');
1190                 if (tmp != NULL)
1191                         *tmp='\0';
1192                 if (used + strlen(buf) + 1 > buffer_size) {
1193                         rc = -EOVERFLOW;
1194                         break;
1195                 }
1196
1197                 strcpy(buffer + used, buf);
1198                 members[nb_entries] = buffer + used;
1199                 used += strlen(buf) + 1;
1200                 nb_entries++;
1201                 rc = nb_entries;
1202         }
1203
1204         fclose(fd);
1205         return rc;
1206 }
1207
1208 /**
1209  * Get the list of pools in a filesystem.
1210  * \param name        filesystem name or path
1211  * \param poollist    caller-allocated array of char*
1212  * \param list_size   size of the poollist array
1213  * \param buffer      caller-allocated buffer for storing pool names
1214  * \param buffer_size size of the buffer
1215  *
1216  * \return number of pools retrieved for this filesystem
1217  * \retval -error failure
1218  */
1219 int llapi_get_poollist(const char *name, char **poollist, int list_size,
1220                        char *buffer, int buffer_size)
1221 {
1222         char fsname[PATH_MAX + 1], rname[PATH_MAX + 1], pathname[PATH_MAX + 1];
1223         char *ptr;
1224         DIR *dir;
1225         struct dirent pool;
1226         struct dirent *cookie = NULL;
1227         int rc = 0;
1228         unsigned int nb_entries = 0;
1229         unsigned int used = 0;
1230         unsigned int i;
1231
1232         /* initilize output array */
1233         for (i = 0; i < list_size; i++)
1234                 poollist[i] = NULL;
1235
1236         /* is name a pathname ? */
1237         ptr = strchr(name, '/');
1238         if (ptr != NULL) {
1239                 /* only absolute pathname is supported */
1240                 if (*name != '/')
1241                         return -EINVAL;
1242
1243                 if (!realpath(name, rname)) {
1244                         rc = -errno;
1245                         llapi_error(LLAPI_MSG_ERROR, rc, "invalid path '%s'",
1246                                     name);
1247                         return rc;
1248                 }
1249
1250                 rc = poolpath(NULL, rname, pathname);
1251                 if (rc != 0) {
1252                         llapi_error(LLAPI_MSG_ERROR, rc, "'%s' is not"
1253                                     " a Lustre filesystem", name);
1254                         return rc;
1255                 }
1256                 if (strlen(rname) > sizeof(fsname)-1)
1257                         return -E2BIG;
1258                 strncpy(fsname, rname, sizeof(fsname));
1259         } else {
1260                 /* name is FSNAME */
1261                 if (strlen(name) > sizeof(fsname)-1)
1262                         return -E2BIG;
1263                 strncpy(fsname, name, sizeof(fsname));
1264                 rc = poolpath(fsname, NULL, pathname);
1265         }
1266         if (rc != 0) {
1267                 llapi_error(LLAPI_MSG_ERROR, rc,
1268                             "Lustre filesystem '%s' not found", name);
1269                 return rc;
1270         }
1271
1272         llapi_printf(LLAPI_MSG_NORMAL, "Pools from %s:\n", fsname);
1273         dir = opendir(pathname);
1274         if (dir == NULL) {
1275                 rc = -errno;
1276                 llapi_error(LLAPI_MSG_ERROR, rc,
1277                             "Could not open pool list for '%s'",
1278                             name);
1279                 return rc;
1280         }
1281
1282         while(1) {
1283                 rc = readdir_r(dir, &pool, &cookie);
1284
1285                 if (rc != 0) {
1286                         rc = -errno;
1287                         llapi_error(LLAPI_MSG_ERROR, rc,
1288                                     "Error reading pool list for '%s'", name);
1289                         goto out;
1290                 } else if ((rc == 0) && (cookie == NULL)) {
1291                         /* end of directory */
1292                         break;
1293                 }
1294
1295                 /* ignore . and .. */
1296                 if (!strcmp(pool.d_name, ".") || !strcmp(pool.d_name, ".."))
1297                         continue;
1298
1299                 /* check output bounds */
1300                 if (nb_entries >= list_size) {
1301                         rc = -EOVERFLOW;
1302                         goto out;
1303                 }
1304
1305                 /* +2 for '.' and final '\0' */
1306                 if (used + strlen(pool.d_name) + strlen(fsname) + 2
1307                     > buffer_size) {
1308                         rc = -EOVERFLOW;
1309                         goto out;
1310                 }
1311
1312                 sprintf(buffer + used, "%s.%s", fsname, pool.d_name);
1313                 poollist[nb_entries] = buffer + used;
1314                 used += strlen(pool.d_name) + strlen(fsname) + 2;
1315                 nb_entries++;
1316         }
1317
1318 out:
1319         closedir(dir);
1320         return ((rc != 0) ? rc : nb_entries);
1321 }
1322
1323 /* wrapper for lfs.c and obd.c */
1324 int llapi_poollist(const char *name)
1325 {
1326         /* list of pool names (assume that pool count is smaller
1327            than OST count) */
1328         char **list, *buffer = NULL, *path = NULL, *fsname = NULL;
1329         int obdcount, bufsize, rc, nb, i;
1330         char *poolname = NULL, *tmp = NULL, data[16];
1331
1332         if (name[0] != '/') {
1333                 fsname = strdup(name);
1334                 poolname = strchr(fsname, '.');
1335                 if (poolname)
1336                         *poolname = '\0';
1337         } else {
1338                 path = (char *) name;
1339         }
1340
1341         rc = get_param_obdvar(fsname, path, "lov", "numobd",
1342                               data, sizeof(data));
1343         if (rc < 0)
1344                 goto err;
1345         obdcount = atoi(data);
1346
1347         /* Allocate space for each fsname-OST0000_UUID, 1 per OST,
1348          * and also an array to store the pointers for all that
1349          * allocated space. */
1350 retry_get_pools:
1351         bufsize = sizeof(struct obd_uuid) * obdcount;
1352         buffer = realloc(tmp, bufsize + sizeof(*list) * obdcount);
1353         if (buffer == NULL) {
1354                 rc = -ENOMEM;
1355                 goto err;
1356         }
1357         list = (char **) (buffer + bufsize);
1358
1359         if (!poolname) {
1360                 /* name is a path or fsname */
1361                 nb = llapi_get_poollist(name, list, obdcount,
1362                                         buffer, bufsize);
1363         } else {
1364                 /* name is a pool name (<fsname>.<poolname>) */
1365                 nb = llapi_get_poolmembers(name, list, obdcount,
1366                                            buffer, bufsize);
1367         }
1368
1369         if (nb == -EOVERFLOW) {
1370                 obdcount *= 2;
1371                 tmp = buffer;
1372                 goto retry_get_pools;
1373         }
1374
1375         for (i = 0; i < nb; i++)
1376                 llapi_printf(LLAPI_MSG_NORMAL, "%s\n", list[i]);
1377         rc = (nb < 0 ? nb : 0);
1378 err:
1379         if (buffer)
1380                 free(buffer);
1381         if (fsname)
1382                 free(fsname);
1383         return rc;
1384 }
1385
1386 typedef int (semantic_func_t)(char *path, DIR *parent, DIR *d,
1387                               void *data, struct dirent64 *de);
1388
1389 #define OBD_NOT_FOUND           (-1)
1390
1391 static int common_param_init(struct find_param *param, char *path)
1392 {
1393         int lumlen = get_mds_md_size(path);
1394
1395         if (lumlen < PATH_MAX + 1)
1396                 lumlen = PATH_MAX + 1;
1397
1398         param->lumlen = lumlen;
1399         param->lmd = malloc(sizeof(lstat_t) + param->lumlen);
1400         if (param->lmd == NULL) {
1401                 llapi_error(LLAPI_MSG_ERROR, -ENOMEM,
1402                             "error: allocation of %zu bytes for ioctl",
1403                             sizeof(lstat_t) + param->lumlen);
1404                 return -ENOMEM;
1405         }
1406
1407         param->fp_lmv_count = 256;
1408         param->fp_lmv_md = malloc(lmv_user_md_size(256, LMV_MAGIC_V1));
1409         if (param->fp_lmv_md == NULL) {
1410                 llapi_error(LLAPI_MSG_ERROR, -ENOMEM,
1411                             "error: allocation of %d bytes for ioctl",
1412                             lmv_user_md_size(256, LMV_MAGIC_V1));
1413                 return -ENOMEM;
1414         }
1415
1416         param->got_uuids = 0;
1417         param->obdindexes = NULL;
1418         param->obdindex = OBD_NOT_FOUND;
1419         param->mdtindex = OBD_NOT_FOUND;
1420         return 0;
1421 }
1422
1423 static void find_param_fini(struct find_param *param)
1424 {
1425         if (param->obdindexes)
1426                 free(param->obdindexes);
1427
1428         if (param->lmd)
1429                 free(param->lmd);
1430
1431         if (param->fp_lmv_md)
1432                 free(param->fp_lmv_md);
1433 }
1434
1435 static int cb_common_fini(char *path, DIR *parent, DIR *d, void *data,
1436                           struct dirent64 *de)
1437 {
1438         struct find_param *param = (struct find_param *)data;
1439         param->depth--;
1440         return 0;
1441 }
1442
1443 /* set errno upon failure */
1444 static DIR *opendir_parent(char *path)
1445 {
1446         DIR *parent;
1447         char *fname;
1448         char c;
1449
1450         fname = strrchr(path, '/');
1451         if (fname == NULL)
1452                 return opendir(".");
1453
1454         c = fname[1];
1455         fname[1] = '\0';
1456         parent = opendir(path);
1457         fname[1] = c;
1458         return parent;
1459 }
1460
1461 static int cb_get_dirstripe(char *path, DIR *d, struct find_param *param)
1462 {
1463         struct lmv_user_md *lmv = (struct lmv_user_md *)param->fp_lmv_md;
1464         int ret = 0;
1465
1466         lmv->lum_stripe_count = param->fp_lmv_count;
1467         lmv->lum_magic = LMV_MAGIC_V1;
1468         ret = ioctl(dirfd(d), LL_IOC_LMV_GETSTRIPE, lmv);
1469         return ret;
1470 }
1471
1472 static int get_lmd_info(char *path, DIR *parent, DIR *dir,
1473                  struct lov_user_mds_data *lmd, int lumlen)
1474 {
1475         lstat_t *st = &lmd->lmd_st;
1476         int ret = 0;
1477
1478         if (parent == NULL && dir == NULL)
1479                 return -EINVAL;
1480
1481         if (dir) {
1482                 ret = ioctl(dirfd(dir), LL_IOC_MDC_GETINFO, (void *)lmd);
1483         } else if (parent) {
1484                 char *fname = strrchr(path, '/');
1485
1486                 fname = (fname == NULL ? path : fname + 1);
1487                 /* retrieve needed file info */
1488                 strncpy((char *)lmd, fname, lumlen);
1489                 ret = ioctl(dirfd(parent), IOC_MDC_GETFILEINFO, (void *)lmd);
1490         }
1491
1492         if (ret) {
1493                 if (errno == ENOTTY) {
1494                         /* ioctl is not supported, it is not a lustre fs.
1495                          * Do the regular lstat(2) instead. */
1496                         ret = lstat_f(path, st);
1497                         if (ret) {
1498                                 ret = -errno;
1499                                 llapi_error(LLAPI_MSG_ERROR, ret,
1500                                             "error: %s: lstat failed for %s",
1501                                             __func__, path);
1502                         }
1503                 } else if (errno == ENOENT) {
1504                         ret = -errno;
1505                         llapi_error(LLAPI_MSG_WARN, ret,
1506                                     "warning: %s: %s does not exist",
1507                                     __func__, path);
1508                 } else if (errno != EISDIR) {
1509                         ret = -errno;
1510                         llapi_error(LLAPI_MSG_ERROR, ret,
1511                                     "%s ioctl failed for %s.",
1512                                     dir ? "LL_IOC_MDC_GETINFO" :
1513                                     "IOC_MDC_GETFILEINFO", path);
1514                 } else {
1515                         ret = -errno;
1516                         llapi_error(LLAPI_MSG_ERROR, ret,
1517                                  "error: %s: IOC_MDC_GETFILEINFO failed for %s",
1518                                    __func__, path);
1519                 }
1520         }
1521         return ret;
1522 }
1523
1524 static int llapi_semantic_traverse(char *path, int size, DIR *parent,
1525                                    semantic_func_t sem_init,
1526                                    semantic_func_t sem_fini, void *data,
1527                                    struct dirent64 *de)
1528 {
1529         struct find_param *param = (struct find_param *)data;
1530         struct dirent64 *dent;
1531         int len, ret;
1532         DIR *d, *p = NULL;
1533
1534         ret = 0;
1535         len = strlen(path);
1536
1537         d = opendir(path);
1538         if (!d && errno != ENOTDIR) {
1539                 ret = -errno;
1540                 llapi_error(LLAPI_MSG_ERROR, ret, "%s: Failed to open '%s'",
1541                             __func__, path);
1542                 return ret;
1543         } else if (!d && !parent) {
1544                 /* ENOTDIR. Open the parent dir. */
1545                 p = opendir_parent(path);
1546                 if (!p) {
1547                         ret = -errno;
1548                         goto out;
1549                 }
1550         }
1551
1552         if (sem_init && (ret = sem_init(path, parent ?: p, d, data, de)))
1553                 goto err;
1554
1555         if (!d || (param->get_lmv && !param->recursive)) {
1556                 ret = 0;
1557                 goto out;
1558         }
1559
1560         while ((dent = readdir64(d)) != NULL) {
1561                 param->have_fileinfo = 0;
1562
1563                 if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
1564                         continue;
1565
1566                 /* Don't traverse .lustre directory */
1567                 if (!(strcmp(dent->d_name, dot_lustre_name)))
1568                         continue;
1569
1570                 path[len] = 0;
1571                 if ((len + dent->d_reclen + 2) > size) {
1572                         llapi_err_noerrno(LLAPI_MSG_ERROR,
1573                                           "error: %s: string buffer is too small",
1574                                           __func__);
1575                         break;
1576                 }
1577                 strcat(path, "/");
1578                 strcat(path, dent->d_name);
1579
1580                 if (dent->d_type == DT_UNKNOWN) {
1581                         lstat_t *st = &param->lmd->lmd_st;
1582
1583                         ret = get_lmd_info(path, d, NULL, param->lmd,
1584                                            param->lumlen);
1585                         if (ret == 0) {
1586                                 dent->d_type =
1587                                         llapi_filetype_dir_table[st->st_mode &
1588                                                                  S_IFMT];
1589                         }
1590                         if (ret == -ENOENT)
1591                                 continue;
1592                 }
1593                 switch (dent->d_type) {
1594                 case DT_UNKNOWN:
1595                         llapi_err_noerrno(LLAPI_MSG_ERROR,
1596                                           "error: %s: '%s' is UNKNOWN type %d",
1597                                           __func__, dent->d_name, dent->d_type);
1598                         break;
1599                 case DT_DIR:
1600                         ret = llapi_semantic_traverse(path, size, d, sem_init,
1601                                                       sem_fini, data, dent);
1602                         if (ret < 0)
1603                                 goto out;
1604                         break;
1605                 default:
1606                         ret = 0;
1607                         if (sem_init) {
1608                                 ret = sem_init(path, d, NULL, data, dent);
1609                                 if (ret < 0)
1610                                         goto out;
1611                         }
1612                         if (sem_fini && ret == 0)
1613                                 sem_fini(path, d, NULL, data, dent);
1614                 }
1615         }
1616
1617 out:
1618         path[len] = 0;
1619
1620         if (sem_fini)
1621                 sem_fini(path, parent, d, data, de);
1622 err:
1623         if (d)
1624                 closedir(d);
1625         if (p)
1626                 closedir(p);
1627         return ret;
1628 }
1629
1630 static int param_callback(char *path, semantic_func_t sem_init,
1631                           semantic_func_t sem_fini, struct find_param *param)
1632 {
1633         int ret, len = strlen(path);
1634         char *buf;
1635
1636         if (len > PATH_MAX) {
1637                 ret = -EINVAL;
1638                 llapi_error(LLAPI_MSG_ERROR, ret,
1639                             "Path name '%s' is too long", path);
1640                 return ret;
1641         }
1642
1643         buf = (char *)malloc(PATH_MAX + 1);
1644         if (!buf)
1645                 return -ENOMEM;
1646
1647         strncpy(buf, path, PATH_MAX + 1);
1648         ret = common_param_init(param, buf);
1649         if (ret)
1650                 goto out;
1651         param->depth = 0;
1652
1653         ret = llapi_semantic_traverse(buf, PATH_MAX + 1, NULL, sem_init,
1654                                       sem_fini, param, NULL);
1655 out:
1656         find_param_fini(param);
1657         free(buf);
1658         return ret < 0 ? ret : 0;
1659 }
1660
1661 int llapi_file_fget_lov_uuid(int fd, struct obd_uuid *lov_name)
1662 {
1663         int rc = ioctl(fd, OBD_IOC_GETNAME, lov_name);
1664         if (rc) {
1665                 rc = -errno;
1666                 llapi_error(LLAPI_MSG_ERROR, rc, "error: can't get lov name.");
1667         }
1668         return rc;
1669 }
1670
1671 int llapi_file_fget_lmv_uuid(int fd, struct obd_uuid *lov_name)
1672 {
1673         int rc = ioctl(fd, OBD_IOC_GETMDNAME, lov_name);
1674         if (rc) {
1675                 rc = -errno;
1676                 llapi_error(LLAPI_MSG_ERROR, rc, "error: can't get lmv name.");
1677         }
1678         return rc;
1679 }
1680
1681 int llapi_file_get_lov_uuid(const char *path, struct obd_uuid *lov_uuid)
1682 {
1683         int fd, rc;
1684
1685         fd = open(path, O_RDONLY);
1686         if (fd < 0) {
1687                 rc = -errno;
1688                 llapi_error(LLAPI_MSG_ERROR, rc, "error opening %s", path);
1689                 return rc;
1690         }
1691
1692         rc = llapi_file_fget_lov_uuid(fd, lov_uuid);
1693
1694         close(fd);
1695         return rc;
1696 }
1697
1698 int llapi_file_get_lmv_uuid(const char *path, struct obd_uuid *lov_uuid)
1699 {
1700         int fd, rc;
1701
1702         fd = open(path, O_RDONLY);
1703         if (fd < 0) {
1704                 rc = -errno;
1705                 llapi_error(LLAPI_MSG_ERROR, rc, "error opening %s", path);
1706                 return rc;
1707         }
1708
1709         rc = llapi_file_fget_lmv_uuid(fd, lov_uuid);
1710
1711         close(fd);
1712         return rc;
1713 }
1714
1715 enum tgt_type {
1716         LOV_TYPE = 1,
1717         LMV_TYPE
1718 };
1719 /*
1720  * If uuidp is NULL, return the number of available obd uuids.
1721  * If uuidp is non-NULL, then it will return the uuids of the obds. If
1722  * there are more OSTs then allocated to uuidp, then an error is returned with
1723  * the ost_count set to number of available obd uuids.
1724  */
1725 static int llapi_get_target_uuids(int fd, struct obd_uuid *uuidp,
1726                                   int *ost_count, enum tgt_type type)
1727 {
1728         struct obd_uuid name;
1729         char buf[1024];
1730         FILE *fp;
1731         int rc = 0, index = 0;
1732
1733         /* Get the lov name */
1734         if (type == LOV_TYPE) {
1735                 rc = llapi_file_fget_lov_uuid(fd, &name);
1736                 if (rc)
1737                         return rc;
1738         } else {
1739                 rc = llapi_file_fget_lmv_uuid(fd, &name);
1740                 if (rc)
1741                         return rc;
1742         }
1743
1744         /* Now get the ost uuids from /proc */
1745         snprintf(buf, sizeof(buf), "/proc/fs/lustre/%s/%s/target_obd",
1746                  type == LOV_TYPE ? "lov" : "lmv", name.uuid);
1747         fp = fopen(buf, "r");
1748         if (fp == NULL) {
1749                 rc = -errno;
1750                 llapi_error(LLAPI_MSG_ERROR, rc, "error: opening '%s'", buf);
1751                 return rc;
1752         }
1753
1754         while (fgets(buf, sizeof(buf), fp) != NULL) {
1755                 if (uuidp && (index < *ost_count)) {
1756                         if (sscanf(buf, "%d: %s", &index, uuidp[index].uuid) <2)
1757                                 break;
1758                 }
1759                 index++;
1760         }
1761
1762         fclose(fp);
1763
1764         if (uuidp && (index > *ost_count))
1765                 rc = -EOVERFLOW;
1766
1767         *ost_count = index;
1768         return rc;
1769 }
1770
1771 int llapi_lov_get_uuids(int fd, struct obd_uuid *uuidp, int *ost_count)
1772 {
1773         return llapi_get_target_uuids(fd, uuidp, ost_count, LOV_TYPE);
1774 }
1775
1776 int llapi_get_obd_count(char *mnt, int *count, int is_mdt)
1777 {
1778         DIR *root;
1779         int rc;
1780
1781         root = opendir(mnt);
1782         if (!root) {
1783                 rc = -errno;
1784                 llapi_error(LLAPI_MSG_ERROR, rc, "open %s failed", mnt);
1785                 return rc;
1786         }
1787
1788         *count = is_mdt;
1789         rc = ioctl(dirfd(root), LL_IOC_GETOBDCOUNT, count);
1790         if (rc < 0)
1791                 rc = -errno;
1792
1793         closedir(root);
1794         return rc;
1795 }
1796
1797 /* Check if user specified value matches a real uuid.  Ignore _UUID,
1798  * -osc-4ba41334, other trailing gunk in comparison.
1799  * @param real_uuid ends in "_UUID"
1800  * @param search_uuid may or may not end in "_UUID"
1801  */
1802 int llapi_uuid_match(char *real_uuid, char *search_uuid)
1803 {
1804         int cmplen = strlen(real_uuid);
1805         int searchlen = strlen(search_uuid);
1806
1807         if (cmplen > 5 && strcmp(real_uuid + cmplen - 5, "_UUID") == 0)
1808                 cmplen -= 5;
1809         if (searchlen > 5 && strcmp(search_uuid + searchlen - 5, "_UUID") == 0)
1810                 searchlen -= 5;
1811
1812         /* The UUIDs may legitimately be different lengths, if
1813          * the system was upgraded from an older version. */
1814         if (cmplen != searchlen)
1815                 return 0;
1816
1817         return (strncmp(search_uuid, real_uuid, cmplen) == 0);
1818 }
1819
1820 /* Here, param->obduuid points to a single obduuid, the index of which is
1821  * returned in param->obdindex */
1822 static int setup_obd_uuid(DIR *dir, char *dname, struct find_param *param)
1823 {
1824         struct obd_uuid obd_uuid;
1825         char uuid[sizeof(struct obd_uuid)];
1826         char buf[1024];
1827         FILE *fp;
1828         int rc = 0, index;
1829
1830         if (param->got_uuids)
1831                 return rc;
1832
1833         /* Get the lov/lmv name */
1834         if (param->get_lmv)
1835                 rc = llapi_file_fget_lmv_uuid(dirfd(dir), &obd_uuid);
1836         else
1837                 rc = llapi_file_fget_lov_uuid(dirfd(dir), &obd_uuid);
1838         if (rc) {
1839                 if (rc != -ENOTTY) {
1840                         llapi_error(LLAPI_MSG_ERROR, rc,
1841                                     "error: can't get lov name: %s", dname);
1842                 } else {
1843                         rc = 0;
1844                 }
1845                 return rc;
1846         }
1847
1848         param->got_uuids = 1;
1849
1850         /* Now get the ost uuids from /proc */
1851         snprintf(buf, sizeof(buf), "/proc/fs/lustre/%s/%s/target_obd",
1852                  param->get_lmv ? "lmv" : "lov", obd_uuid.uuid);
1853         fp = fopen(buf, "r");
1854         if (fp == NULL) {
1855                 rc = -errno;
1856                 llapi_error(LLAPI_MSG_ERROR, rc, "error: opening '%s'", buf);
1857                 return rc;
1858         }
1859
1860         if (!param->obduuid && !param->quiet && !param->obds_printed)
1861                 llapi_printf(LLAPI_MSG_NORMAL, "%s:\n",
1862                              param->get_lmv ? "MDTS" : "OBDS:");
1863
1864         while (fgets(buf, sizeof(buf), fp) != NULL) {
1865                 if (sscanf(buf, "%d: %s", &index, uuid) < 2)
1866                         break;
1867
1868                 if (param->obduuid) {
1869                         if (llapi_uuid_match(uuid, param->obduuid->uuid)) {
1870                                 param->obdindex = index;
1871                                 break;
1872                         }
1873                 } else if (!param->quiet && !param->obds_printed) {
1874                         /* Print everything */
1875                         llapi_printf(LLAPI_MSG_NORMAL, "%s", buf);
1876                 }
1877         }
1878         param->obds_printed = 1;
1879
1880         fclose(fp);
1881
1882         if (param->obduuid && (param->obdindex == OBD_NOT_FOUND)) {
1883                 llapi_err_noerrno(LLAPI_MSG_ERROR,
1884                                   "error: %s: unknown obduuid: %s",
1885                                   __func__, param->obduuid->uuid);
1886                 rc = -EINVAL;
1887         }
1888
1889         return (rc);
1890 }
1891
1892 /* In this case, param->obduuid will be an array of obduuids and
1893  * obd index for all these obduuids will be returned in
1894  * param->obdindexes */
1895 static int setup_indexes(DIR *dir, char *path, struct obd_uuid *obduuids,
1896                          int num_obds, int **obdindexes, int *obdindex,
1897                          enum tgt_type type)
1898 {
1899         int ret, obdcount, obd_valid = 0, obdnum;
1900         long i;
1901         struct obd_uuid *uuids = NULL;
1902         char buf[16];
1903         int *indexes;
1904
1905         if (type == LOV_TYPE)
1906                 ret = get_param_lov(path, "numobd", buf, sizeof(buf));
1907         else
1908                 ret = get_param_lmv(path, "numobd", buf, sizeof(buf));
1909         if (ret != 0)
1910                 return ret;
1911
1912         obdcount = atoi(buf);
1913         uuids = (struct obd_uuid *)malloc(obdcount *
1914                                           sizeof(struct obd_uuid));
1915         if (uuids == NULL)
1916                 return -ENOMEM;
1917
1918 retry_get_uuids:
1919         ret = llapi_get_target_uuids(dirfd(dir), uuids, &obdcount, type);
1920         if (ret) {
1921                 struct obd_uuid *uuids_temp;
1922
1923                 if (ret == -EOVERFLOW) {
1924                         uuids_temp = realloc(uuids, obdcount *
1925                                              sizeof(struct obd_uuid));
1926                         if (uuids_temp != NULL) {
1927                                 uuids = uuids_temp;
1928                                 goto retry_get_uuids;
1929                         }
1930                         else
1931                                 ret = -ENOMEM;
1932                 }
1933
1934                 llapi_error(LLAPI_MSG_ERROR, ret, "get ost uuid failed");
1935                 goto out_free;
1936         }
1937
1938         indexes = malloc(num_obds * sizeof(*obdindex));
1939         if (indexes == NULL) {
1940                 ret = -ENOMEM;
1941                 goto out_free;
1942         }
1943
1944         for (obdnum = 0; obdnum < num_obds; obdnum++) {
1945                 char *end = NULL;
1946
1947                 /* The user may have specified a simple index */
1948                 i = strtol(obduuids[obdnum].uuid, &end, 0);
1949                 if (end && *end == '\0' && i < obdcount) {
1950                         indexes[obdnum] = i;
1951                         obd_valid++;
1952                 } else {
1953                         for (i = 0; i < obdcount; i++) {
1954                                 if (llapi_uuid_match(uuids[i].uuid,
1955                                                      obduuids[obdnum].uuid)) {
1956                                         indexes[obdnum] = i;
1957                                         obd_valid++;
1958                                         break;
1959                                 }
1960                         }
1961                 }
1962                 if (i >= obdcount) {
1963                         indexes[obdnum] = OBD_NOT_FOUND;
1964                         llapi_err_noerrno(LLAPI_MSG_ERROR,
1965                                           "error: %s: unknown obduuid: %s",
1966                                           __func__, obduuids[obdnum].uuid);
1967                         ret = -EINVAL;
1968                 }
1969         }
1970
1971         if (obd_valid == 0)
1972                 *obdindex = OBD_NOT_FOUND;
1973         else
1974                 *obdindex = obd_valid;
1975
1976         *obdindexes = indexes;
1977 out_free:
1978         if (uuids)
1979                 free(uuids);
1980
1981         return ret;
1982 }
1983
1984 static int setup_target_indexes(DIR *dir, char *path, struct find_param *param)
1985 {
1986         int ret = 0;
1987
1988         if (param->mdtuuid) {
1989                 ret = setup_indexes(dir, path, param->mdtuuid, param->num_mdts,
1990                               &param->mdtindexes, &param->mdtindex, LMV_TYPE);
1991                 if (ret)
1992                         return ret;
1993         }
1994         if (param->obduuid) {
1995                 ret = setup_indexes(dir, path, param->obduuid, param->num_obds,
1996                               &param->obdindexes, &param->obdindex, LOV_TYPE);
1997                 if (ret)
1998                         return ret;
1999         }
2000         param->got_uuids = 1;
2001         return ret;
2002 }
2003
2004 int llapi_ostlist(char *path, struct find_param *param)
2005 {
2006         DIR *dir;
2007         int ret;
2008
2009         dir = opendir(path);
2010         if (dir == NULL)
2011                 return -errno;
2012
2013         ret = setup_obd_uuid(dir, path, param);
2014         closedir(dir);
2015
2016         return ret;
2017 }
2018
2019 /*
2020  * Given a filesystem name, or a pathname of a file on a lustre filesystem,
2021  * tries to determine the path to the filesystem's clilov directory under /proc
2022  *
2023  * fsname is limited to MTI_NAME_MAXLEN in lustre_idl.h
2024  * The NUL terminator is compensated by the additional "%s" bytes. */
2025 #define LOV_LEN (sizeof("/proc/fs/lustre/lov/%s-clilov-*") + MTI_NAME_MAXLEN)
2026 static int clilovpath(const char *fsname, const char *const pathname,
2027                       char *clilovpath)
2028 {
2029         int rc;
2030         char pattern[LOV_LEN];
2031         char buffer[PATH_MAX + 1];
2032
2033         if (fsname == NULL) {
2034                 rc = llapi_search_fsname(pathname, buffer);
2035                 if (rc != 0)
2036                         return rc;
2037                 fsname = buffer;
2038         }
2039
2040         snprintf(pattern, sizeof(pattern), "/proc/fs/lustre/lov/%s-clilov-*",
2041                  fsname);
2042
2043         rc = first_match(pattern, buffer);
2044         if (rc != 0)
2045                 return rc;
2046
2047         strncpy(clilovpath, buffer, sizeof(buffer));
2048
2049         return 0;
2050 }
2051
2052 /*
2053  * Given the path to a stripe attribute proc file, tries to open and
2054  * read the attribute and return the value using the attr parameter
2055  */
2056 static int sattr_read_attr(const char *const fpath,
2057                            unsigned int *attr)
2058 {
2059
2060         FILE *f;
2061         char line[PATH_MAX + 1];
2062         int rc = 0;
2063
2064         f = fopen(fpath, "r");
2065         if (f == NULL) {
2066                 rc = -errno;
2067                 llapi_error(LLAPI_MSG_ERROR, rc, "Cannot open '%s'", fpath);
2068                 return rc;
2069         }
2070
2071         if (fgets(line, sizeof(line), f) != NULL) {
2072                 *attr = atoi(line);
2073         } else {
2074                 llapi_error(LLAPI_MSG_ERROR, errno, "Cannot read from '%s'", fpath);
2075                 rc = 1;
2076         }
2077
2078         fclose(f);
2079         return rc;
2080 }
2081
2082 /*
2083  * Tries to determine the default stripe attributes for a given filesystem. The
2084  * filesystem to check should be specified by fsname, or will be determined
2085  * using pathname.
2086  */
2087 static int sattr_get_defaults(const char *const fsname,
2088                               const char *const pathname,
2089                               unsigned int *scount,
2090                               unsigned int *ssize,
2091                               unsigned int *soffset)
2092 {
2093         int rc;
2094         char dpath[PATH_MAX + 1];
2095         char fpath[PATH_MAX + 1];
2096
2097         rc = clilovpath(fsname, pathname, dpath);
2098         if (rc != 0)
2099                 return rc;
2100
2101         if (scount) {
2102                 snprintf(fpath, PATH_MAX, "%s/stripecount", dpath);
2103                 rc = sattr_read_attr(fpath, scount);
2104                 if (rc != 0)
2105                         return rc;
2106         }
2107
2108         if (ssize) {
2109                 snprintf(fpath, PATH_MAX, "%s/stripesize", dpath);
2110                 rc = sattr_read_attr(fpath, ssize);
2111                 if (rc != 0)
2112                         return rc;
2113         }
2114
2115         if (soffset) {
2116                 snprintf(fpath, PATH_MAX, "%s/stripeoffset", dpath);
2117                 rc = sattr_read_attr(fpath, soffset);
2118                 if (rc != 0)
2119                         return rc;
2120         }
2121
2122         return 0;
2123 }
2124
2125 /*
2126  * Tries to gather the default stripe attributes for a given filesystem. If
2127  * the attributes can be determined, they are cached for easy retreival the
2128  * next time they are needed. Only a single filesystem's attributes are
2129  * cached at a time.
2130  */
2131 static int sattr_cache_get_defaults(const char *const fsname,
2132                                     const char *const pathname,
2133                                     unsigned int *scount,
2134                                     unsigned int *ssize,
2135                                     unsigned int *soffset)
2136 {
2137         static struct {
2138                 char fsname[PATH_MAX + 1];
2139                 unsigned int stripecount;
2140                 unsigned int stripesize;
2141                 unsigned int stripeoffset;
2142         } cache = {
2143                 .fsname = {'\0'}
2144         };
2145
2146         int rc;
2147         char fsname_buf[PATH_MAX + 1];
2148         unsigned int tmp[3];
2149
2150         if (fsname == NULL) {
2151                 rc = llapi_search_fsname(pathname, fsname_buf);
2152                 if (rc)
2153                         return rc;
2154         } else {
2155                 strncpy(fsname_buf, fsname, PATH_MAX);
2156         }
2157
2158         if (strncmp(fsname_buf, cache.fsname, PATH_MAX) != 0) {
2159                 /*
2160                  * Ensure all 3 sattrs (count, size, and offset) are
2161                  * successfully retrieved and stored in tmp before writing to
2162                  * cache.
2163                  */
2164                 rc = sattr_get_defaults(fsname_buf, NULL, &tmp[0], &tmp[1],
2165                                         &tmp[2]);
2166                 if (rc != 0)
2167                         return rc;
2168
2169                 cache.stripecount = tmp[0];
2170                 cache.stripesize = tmp[1];
2171                 cache.stripeoffset = tmp[2];
2172                 strncpy(cache.fsname, fsname_buf, PATH_MAX);
2173         }
2174
2175         if (scount)
2176                 *scount = cache.stripecount;
2177         if (ssize)
2178                 *ssize = cache.stripesize;
2179         if (soffset)
2180                 *soffset = cache.stripeoffset;
2181
2182         return 0;
2183 }
2184
2185 static void lov_dump_user_lmm_header(struct lov_user_md *lum, char *path,
2186                                      struct lov_user_ost_data_v1 *objects,
2187                                      int is_dir, int verbose, int depth,
2188                                      int raw, char *pool_name)
2189 {
2190         char *prefix = is_dir ? "" : "lmm_";
2191         char *seperator = "";
2192         int rc;
2193
2194         if (is_dir && lmm_oi_seq(&lum->lmm_oi) == FID_SEQ_LOV_DEFAULT) {
2195                 lmm_oi_set_seq(&lum->lmm_oi, 0);
2196                 if (verbose & VERBOSE_DETAIL)
2197                         llapi_printf(LLAPI_MSG_NORMAL, "(Default) ");
2198         }
2199
2200         if (depth && path && ((verbose != VERBOSE_OBJID) || !is_dir))
2201                 llapi_printf(LLAPI_MSG_NORMAL, "%s\n", path);
2202
2203         if ((verbose & VERBOSE_DETAIL) && !is_dir) {
2204                 llapi_printf(LLAPI_MSG_NORMAL, "lmm_magic:          0x%08X\n",
2205                              lum->lmm_magic);
2206                 llapi_printf(LLAPI_MSG_NORMAL, "lmm_seq:            "LPX64"\n",
2207                              lmm_oi_seq(&lum->lmm_oi));
2208                 llapi_printf(LLAPI_MSG_NORMAL, "lmm_object_id:      "LPX64"\n",
2209                              lmm_oi_id(&lum->lmm_oi));
2210         }
2211
2212         if (verbose & VERBOSE_COUNT) {
2213                 if (verbose & ~VERBOSE_COUNT)
2214                         llapi_printf(LLAPI_MSG_NORMAL, "%sstripe_count:   ",
2215                                      prefix);
2216                 if (is_dir) {
2217                         if (!raw && lum->lmm_stripe_count == 0) {
2218                                 unsigned int scount;
2219                                 rc = sattr_cache_get_defaults(NULL, path,
2220                                                               &scount, NULL,
2221                                                               NULL);
2222                                 if (rc == 0)
2223                                         llapi_printf(LLAPI_MSG_NORMAL, "%d",
2224                                                      scount);
2225                                 else
2226                                         llapi_error(LLAPI_MSG_ERROR, rc,
2227                                                     "Cannot determine default"
2228                                                     " stripe count.");
2229                         } else {
2230                                 llapi_printf(LLAPI_MSG_NORMAL, "%d",
2231                                              lum->lmm_stripe_count ==
2232                                              (typeof(lum->lmm_stripe_count))(-1)
2233                                              ? -1 : lum->lmm_stripe_count);
2234                         }
2235                 } else {
2236                         llapi_printf(LLAPI_MSG_NORMAL, "%hd",
2237                                      (__s16)lum->lmm_stripe_count);
2238                 }
2239                 seperator = is_dir ? " " : "\n";
2240         }
2241
2242         if (verbose & VERBOSE_SIZE) {
2243                 llapi_printf(LLAPI_MSG_NORMAL, "%s", seperator);
2244                 if (verbose & ~VERBOSE_SIZE)
2245                         llapi_printf(LLAPI_MSG_NORMAL, "%sstripe_size:    ",
2246                                      prefix);
2247                 if (is_dir && !raw && lum->lmm_stripe_size == 0) {
2248                         unsigned int ssize;
2249                         rc = sattr_cache_get_defaults(NULL, path, NULL, &ssize,
2250                                                       NULL);
2251                         if (rc == 0)
2252                                 llapi_printf(LLAPI_MSG_NORMAL, "%u", ssize);
2253                         else
2254                                 llapi_error(LLAPI_MSG_ERROR, rc,
2255                                             "Cannot determine default"
2256                                             " stripe size.");
2257                 } else {
2258                         llapi_printf(LLAPI_MSG_NORMAL, "%u",
2259                                      lum->lmm_stripe_size);
2260                 }
2261                 seperator = is_dir ? " " : "\n";
2262         }
2263
2264         if ((verbose & VERBOSE_LAYOUT) && !is_dir) {
2265                 llapi_printf(LLAPI_MSG_NORMAL, "%s", seperator);
2266                 if (verbose & ~VERBOSE_LAYOUT)
2267                         llapi_printf(LLAPI_MSG_NORMAL, "%spattern:        ",
2268                                      prefix);
2269                 llapi_printf(LLAPI_MSG_NORMAL, "%.x", lum->lmm_pattern);
2270                 seperator = "\n";
2271         }
2272
2273         if ((verbose & VERBOSE_GENERATION) && !is_dir) {
2274                 llapi_printf(LLAPI_MSG_NORMAL, "%s", seperator);
2275                 if (verbose & ~VERBOSE_GENERATION)
2276                         llapi_printf(LLAPI_MSG_NORMAL, "%slayout_gen:     ",
2277                                      prefix);
2278                 llapi_printf(LLAPI_MSG_NORMAL, "%u",
2279                              (int)lum->lmm_layout_gen);
2280                 seperator = "\n";
2281         }
2282
2283         if (verbose & VERBOSE_OFFSET) {
2284                 llapi_printf(LLAPI_MSG_NORMAL, "%s", seperator);
2285                 if (verbose & ~VERBOSE_OFFSET)
2286                         llapi_printf(LLAPI_MSG_NORMAL, "%sstripe_offset:  ",
2287                                      prefix);
2288                 if (is_dir)
2289                         llapi_printf(LLAPI_MSG_NORMAL, "%d",
2290                                      lum->lmm_stripe_offset ==
2291                                      (typeof(lum->lmm_stripe_offset))(-1) ? -1 :
2292                                      lum->lmm_stripe_offset);
2293                 else
2294                         llapi_printf(LLAPI_MSG_NORMAL, "%u",
2295                                      objects[0].l_ost_idx);
2296                 seperator = is_dir ? " " : "\n";
2297         }
2298
2299         if ((verbose & VERBOSE_POOL) && (pool_name != NULL)) {
2300                 llapi_printf(LLAPI_MSG_NORMAL, "%s", seperator);
2301                 if (verbose & ~VERBOSE_POOL)
2302                         llapi_printf(LLAPI_MSG_NORMAL, "%spool:           ",
2303                                      prefix);
2304                 llapi_printf(LLAPI_MSG_NORMAL, "%s", pool_name);
2305         }
2306
2307         if (!is_dir || (is_dir && (verbose != VERBOSE_OBJID)))
2308                 llapi_printf(LLAPI_MSG_NORMAL, "\n");
2309 }
2310
2311 void lov_dump_user_lmm_v1v3(struct lov_user_md *lum, char *pool_name,
2312                             struct lov_user_ost_data_v1 *objects,
2313                             char *path, int is_dir, int obdindex,
2314                             int depth, int header, int raw)
2315 {
2316         int i, obdstripe = (obdindex != OBD_NOT_FOUND) ? 0 : 1;
2317
2318         if (!obdstripe) {
2319                 for (i = 0; !is_dir && i < lum->lmm_stripe_count; i++) {
2320                         if (obdindex == objects[i].l_ost_idx) {
2321                                 obdstripe = 1;
2322                                 break;
2323                         }
2324                 }
2325         }
2326
2327         if (obdstripe == 1)
2328                 lov_dump_user_lmm_header(lum, path, objects, is_dir, header,
2329                                          depth, raw, pool_name);
2330
2331         if (!is_dir && (header & VERBOSE_OBJID) &&
2332             !(lum->lmm_pattern & LOV_PATTERN_F_RELEASED)) {
2333                 if (obdstripe == 1)
2334                         llapi_printf(LLAPI_MSG_NORMAL,
2335                                    "\tobdidx\t\t objid\t\t objid\t\t group\n");
2336
2337                 for (i = 0; i < lum->lmm_stripe_count; i++) {
2338                         int idx = objects[i].l_ost_idx;
2339                         long long oid = ostid_id(&objects[i].l_ost_oi);
2340                         long long gr = ostid_seq(&objects[i].l_ost_oi);
2341                         if ((obdindex == OBD_NOT_FOUND) || (obdindex == idx)) {
2342                                 char fmt[48];
2343                                 sprintf(fmt, "%s%s%s\n",
2344                                         "\t%6u\t%14llu\t%#13llx\t",
2345                                         (fid_seq_is_rsvd(gr) ||
2346                                          fid_seq_is_mdt0(gr)) ?
2347                                          "%14llu" : "%#14llx", "%s");
2348                                 llapi_printf(LLAPI_MSG_NORMAL, fmt, idx, oid,
2349                                              oid, gr,
2350                                              obdindex == idx ? " *" : "");
2351                         }
2352
2353                 }
2354                 llapi_printf(LLAPI_MSG_NORMAL, "\n");
2355         }
2356 }
2357
2358 void lmv_dump_user_lmm(struct lmv_user_md *lum, char *pool_name,
2359                        char *path, int obdindex, int depth, int verbose)
2360 {
2361         struct lmv_user_mds_data *objects = lum->lum_objects;
2362         char *prefix = lum->lum_magic == LMV_USER_MAGIC ? "(Default)" : "";
2363         int i, obdstripe = 0;
2364
2365         if (obdindex != OBD_NOT_FOUND) {
2366                 for (i = 0; i < lum->lum_stripe_count; i++) {
2367                         if (obdindex == objects[i].lum_mds) {
2368                                 llapi_printf(LLAPI_MSG_NORMAL, "%s%s\n", prefix,
2369                                              path);
2370                                 obdstripe = 1;
2371                                 break;
2372                         }
2373                 }
2374         } else {
2375                 obdstripe = 1;
2376         }
2377
2378         /* show all information default */
2379         if (!verbose) {
2380                 if (lum->lum_magic == LMV_USER_MAGIC)
2381                         verbose = VERBOSE_POOL | VERBOSE_COUNT | VERBOSE_OFFSET;
2382                 else
2383                         verbose = VERBOSE_OBJID;
2384         }
2385
2386         if (lum->lum_magic == LMV_USER_MAGIC)
2387                 verbose &= ~VERBOSE_OBJID;
2388
2389         if (depth && path && ((verbose != VERBOSE_OBJID)))
2390                 llapi_printf(LLAPI_MSG_NORMAL, "%s\n", path);
2391
2392         if (verbose & VERBOSE_COUNT) {
2393                 if (verbose & ~VERBOSE_COUNT)
2394                         llapi_printf(LLAPI_MSG_NORMAL, "lmv_stripe_count: ");
2395                 llapi_printf(LLAPI_MSG_NORMAL, "%u\n",
2396                              (int)lum->lum_stripe_count);
2397         }
2398
2399         if (verbose & VERBOSE_OFFSET) {
2400                 if (verbose & ~VERBOSE_OFFSET)
2401                         llapi_printf(LLAPI_MSG_NORMAL, "lmv_stripe_offset: ");
2402                 llapi_printf(LLAPI_MSG_NORMAL, "%d\n",
2403                              (int)lum->lum_stripe_offset);
2404         }
2405
2406         if (verbose & VERBOSE_OBJID) {
2407                 if ((obdstripe == 1))
2408                         llapi_printf(LLAPI_MSG_NORMAL,
2409                                      "\tmdtidx\t\t FID[seq:oid:ver]\n");
2410                 for (i = 0; i < lum->lum_stripe_count; i++) {
2411                         int idx = objects[i].lum_mds;
2412                         struct lu_fid *fid = &objects[i].lum_fid;
2413                         if ((obdindex == OBD_NOT_FOUND) || (obdindex == idx))
2414                                 llapi_printf(LLAPI_MSG_NORMAL,
2415                                              "\t%6u\t\t "DFID"\t\t%s\n",
2416                                             idx, PFID(fid),
2417                                             obdindex == idx ? " *" : "");
2418                 }
2419
2420         }
2421
2422         if ((verbose & VERBOSE_POOL) && (pool_name[0] != '\0')) {
2423                 if (verbose & ~VERBOSE_POOL)
2424                         llapi_printf(LLAPI_MSG_NORMAL, "%slmv_pool:           ",
2425                                      prefix);
2426                 llapi_printf(LLAPI_MSG_NORMAL, "%s%c ", pool_name, ' ');
2427         }
2428         llapi_printf(LLAPI_MSG_NORMAL, "\n");
2429 }
2430
2431 void llapi_lov_dump_user_lmm(struct find_param *param, char *path, int is_dir)
2432 {
2433         __u32 magic;
2434
2435         if (param->get_lmv)
2436                 magic = (__u32)param->fp_lmv_md->lum_magic;
2437         else
2438                 magic = *(__u32 *)&param->lmd->lmd_lmm; /* lum->lmm_magic */
2439
2440         switch (magic) {
2441         case LOV_USER_MAGIC_V1:
2442                 lov_dump_user_lmm_v1v3(&param->lmd->lmd_lmm, NULL,
2443                                        param->lmd->lmd_lmm.lmm_objects,
2444                                        path, is_dir,
2445                                        param->obdindex, param->maxdepth,
2446                                        param->verbose, param->raw);
2447                 break;
2448         case LOV_USER_MAGIC_V3: {
2449                 char pool_name[LOV_MAXPOOLNAME + 1];
2450                 struct lov_user_ost_data_v1 *objects;
2451                 struct lov_user_md_v3 *lmmv3 = (void *)&param->lmd->lmd_lmm;
2452
2453                 strncpy(pool_name, lmmv3->lmm_pool_name, LOV_MAXPOOLNAME);
2454                 pool_name[LOV_MAXPOOLNAME] = '\0';
2455                 objects = lmmv3->lmm_objects;
2456                 lov_dump_user_lmm_v1v3(&param->lmd->lmd_lmm, pool_name,
2457                                        objects, path, is_dir,
2458                                        param->obdindex, param->maxdepth,
2459                                        param->verbose, param->raw);
2460                 break;
2461         }
2462         case LMV_MAGIC_V1:
2463         case LMV_USER_MAGIC: {
2464                 char pool_name[LOV_MAXPOOLNAME + 1];
2465                 struct lmv_user_md *lum;
2466
2467                 lum = (struct lmv_user_md *)param->fp_lmv_md;
2468                 strncpy(pool_name, lum->lum_pool_name, LOV_MAXPOOLNAME);
2469                 lmv_dump_user_lmm(lum, pool_name, path,
2470                                   param->obdindex, param->maxdepth,
2471                                   param->verbose);
2472                 break;
2473         }
2474         default:
2475                 llapi_printf(LLAPI_MSG_NORMAL, "unknown lmm_magic:  %#x "
2476                              "(expecting one of %#x %#x %#x %#x)\n",
2477                              *(__u32 *)&param->lmd->lmd_lmm,
2478                              LOV_USER_MAGIC_V1, LOV_USER_MAGIC_V3,
2479                              LMV_USER_MAGIC, LMV_MAGIC_V1);
2480                 return;
2481         }
2482 }
2483
2484 int llapi_file_get_stripe(const char *path, struct lov_user_md *lum)
2485 {
2486         const char *fname;
2487         char *dname;
2488         int fd, rc = 0;
2489
2490         fname = strrchr(path, '/');
2491
2492         /* It should be a file (or other non-directory) */
2493         if (fname == NULL) {
2494                 dname = (char *)malloc(2);
2495                 if (dname == NULL)
2496                         return -ENOMEM;
2497                 strcpy(dname, ".");
2498                 fname = (char *)path;
2499         } else {
2500                 dname = (char *)malloc(fname - path + 1);
2501                 if (dname == NULL)
2502                         return -ENOMEM;
2503                 strncpy(dname, path, fname - path);
2504                 dname[fname - path] = '\0';
2505                 fname++;
2506         }
2507
2508         fd = open(dname, O_RDONLY);
2509         if (fd == -1) {
2510                 rc = -errno;
2511                 free(dname);
2512                 return rc;
2513         }
2514
2515         strcpy((char *)lum, fname);
2516         if (ioctl(fd, IOC_MDC_GETFILESTRIPE, (void *)lum) == -1)
2517                 rc = -errno;
2518
2519         if (close(fd) == -1 && rc == 0)
2520                 rc = -errno;
2521
2522         free(dname);
2523         return rc;
2524 }
2525
2526 int llapi_file_lookup(int dirfd, const char *name)
2527 {
2528         struct obd_ioctl_data data = { 0 };
2529         char rawbuf[8192];
2530         char *buf = rawbuf;
2531         int rc;
2532
2533         if (dirfd < 0 || name == NULL)
2534                 return -EINVAL;
2535
2536         data.ioc_version = OBD_IOCTL_VERSION;
2537         data.ioc_len = sizeof(data);
2538         data.ioc_inlbuf1 = (char *)name;
2539         data.ioc_inllen1 = strlen(name) + 1;
2540
2541         rc = obd_ioctl_pack(&data, &buf, sizeof(rawbuf));
2542         if (rc) {
2543                 llapi_error(LLAPI_MSG_ERROR, rc,
2544                             "error: IOC_MDC_LOOKUP pack failed for '%s': rc %d",
2545                             name, rc);
2546                 return rc;
2547         }
2548
2549         rc = ioctl(dirfd, IOC_MDC_LOOKUP, buf);
2550         if (rc < 0)
2551                 rc = -errno;
2552         return rc;
2553 }
2554
2555 /* Check if the value matches 1 of the given criteria (e.g. --atime +/-N).
2556  * @mds indicates if this is MDS timestamps and there are attributes on OSTs.
2557  *
2558  * The result is -1 if it does not match, 0 if not yet clear, 1 if matches.
2559  * The table below gives the answers for the specified parameters (value and
2560  * sign), 1st column is the answer for the MDS value, the 2nd is for the OST:
2561  * --------------------------------------
2562  * 1 | file > limit; sign > 0 | -1 / -1 |
2563  * 2 | file = limit; sign > 0 | -1 / -1 |
2564  * 3 | file < limit; sign > 0 |  ? /  1 |
2565  * 4 | file > limit; sign = 0 | -1 / -1 |
2566  * 5 | file = limit; sign = 0 |  ? /  1 |  <- (see the Note below)
2567  * 6 | file < limit; sign = 0 |  ? / -1 |
2568  * 7 | file > limit; sign < 0 |  1 /  1 |
2569  * 8 | file = limit; sign < 0 |  ? / -1 |
2570  * 9 | file < limit; sign < 0 |  ? / -1 |
2571  * --------------------------------------
2572  * Note: 5th actually means that the value is within the interval
2573  * (limit - margin, limit]. */
2574 static int find_value_cmp(unsigned long long file, unsigned long long limit,
2575                           int sign, int negopt, unsigned long long margin,
2576                           int mds)
2577 {
2578         int ret = -1;
2579
2580         if (sign > 0) {
2581                 /* Drop the fraction of margin (of days). */
2582                 if (file + margin <= limit)
2583                         ret = mds ? 0 : 1;
2584         } else if (sign == 0) {
2585                 if (file <= limit && file + margin > limit)
2586                         ret = mds ? 0 : 1;
2587                 else if (file + margin <= limit)
2588                         ret = mds ? 0 : -1;
2589         } else if (sign < 0) {
2590                 if (file > limit)
2591                         ret = 1;
2592                 else if (mds)
2593                         ret = 0;
2594         }
2595
2596         return negopt ? ~ret + 1 : ret;
2597 }
2598
2599 /* Check if the file time matches all the given criteria (e.g. --atime +/-N).
2600  * Return -1 or 1 if file timestamp does not or does match the given criteria
2601  * correspondingly. Return 0 if the MDS time is being checked and there are
2602  * attributes on OSTs and it is not yet clear if the timespamp matches.
2603  *
2604  * If 0 is returned, we need to do another RPC to the OSTs to obtain the
2605  * updated timestamps. */
2606 static int find_time_check(lstat_t *st, struct find_param *param, int mds)
2607 {
2608         int ret;
2609         int rc = 1;
2610
2611         /* Check if file is accepted. */
2612         if (param->atime) {
2613                 ret = find_value_cmp(st->st_atime, param->atime,
2614                                      param->asign, param->exclude_atime,
2615                                      24 * 60 * 60, mds);
2616                 if (ret < 0)
2617                         return ret;
2618                 rc = ret;
2619         }
2620
2621         if (param->mtime) {
2622                 ret = find_value_cmp(st->st_mtime, param->mtime,
2623                                      param->msign, param->exclude_mtime,
2624                                      24 * 60 * 60, mds);
2625                 if (ret < 0)
2626                         return ret;
2627
2628                 /* If the previous check matches, but this one is not yet clear,
2629                  * we should return 0 to do an RPC on OSTs. */
2630                 if (rc == 1)
2631                         rc = ret;
2632         }
2633
2634         if (param->ctime) {
2635                 ret = find_value_cmp(st->st_ctime, param->ctime,
2636                                      param->csign, param->exclude_ctime,
2637                                      24 * 60 * 60, mds);
2638                 if (ret < 0)
2639                         return ret;
2640
2641                 /* If the previous check matches, but this one is not yet clear,
2642                  * we should return 0 to do an RPC on OSTs. */
2643                 if (rc == 1)
2644                         rc = ret;
2645         }
2646
2647         return rc;
2648 }
2649
2650 /**
2651  * Check whether the stripes matches the indexes user provided
2652  *       1   : matched
2653  *       0   : Unmatched
2654  */
2655 static int check_obd_match(struct find_param *param)
2656 {
2657         lstat_t *st = &param->lmd->lmd_st;
2658         struct lov_user_ost_data_v1 *lmm_objects;
2659         int i, j;
2660
2661         if (param->obduuid && param->obdindex == OBD_NOT_FOUND)
2662                 return 0;
2663
2664         if (!S_ISREG(st->st_mode))
2665                 return 0;
2666
2667         /* Only those files should be accepted, which have a
2668          * stripe on the specified OST. */
2669         if (!param->lmd->lmd_lmm.lmm_stripe_count)
2670                 return 0;
2671
2672         if (param->lmd->lmd_lmm.lmm_magic ==
2673             LOV_USER_MAGIC_V3) {
2674                 struct lov_user_md_v3 *lmmv3 = (void *)&param->lmd->lmd_lmm;
2675
2676                 lmm_objects = lmmv3->lmm_objects;
2677         } else if (param->lmd->lmd_lmm.lmm_magic ==  LOV_USER_MAGIC_V1) {
2678                 lmm_objects = param->lmd->lmd_lmm.lmm_objects;
2679         } else {
2680                 llapi_err_noerrno(LLAPI_MSG_ERROR, "%s:Unknown magic: 0x%08X\n",
2681                                   __func__, param->lmd->lmd_lmm.lmm_magic);
2682                 return -EINVAL;
2683         }
2684
2685         for (i = 0; i < param->lmd->lmd_lmm.lmm_stripe_count; i++) {
2686                 for (j = 0; j < param->num_obds; j++) {
2687                         if (param->obdindexes[j] ==
2688                             lmm_objects[i].l_ost_idx) {
2689                                 if (param->exclude_obd)
2690                                         return 0;
2691                                 return 1;
2692                         }
2693                 }
2694         }
2695
2696         if (param->exclude_obd)
2697                 return 1;
2698         return 0;
2699 }
2700
2701 static int check_mdt_match(struct find_param *param)
2702 {
2703         int i;
2704
2705         if (param->mdtuuid && param->mdtindex == OBD_NOT_FOUND)
2706                 return 0;
2707
2708         /* FIXME: For striped dir, we should get stripe information and check */
2709         for (i = 0; i < param->num_mdts; i++) {
2710                 if (param->mdtindexes[i] == param->file_mdtindex)
2711                         return !param->exclude_mdt;
2712         }
2713
2714         if (param->exclude_mdt)
2715                 return 1;
2716         return 0;
2717 }
2718
2719 /**
2720  * Check whether the obd is active or not, if it is
2721  * not active, just print the object affected by this
2722  * failed target
2723  **/
2724 static int print_failed_tgt(struct find_param *param, char *path, int type)
2725 {
2726         struct obd_statfs stat_buf;
2727         struct obd_uuid uuid_buf;
2728         int ret;
2729
2730         LASSERT(type == LL_STATFS_LOV || type == LL_STATFS_LMV);
2731
2732         memset(&stat_buf, 0, sizeof(struct obd_statfs));
2733         memset(&uuid_buf, 0, sizeof(struct obd_uuid));
2734         ret = llapi_obd_statfs(path, type,
2735                                param->obdindex, &stat_buf,
2736                                &uuid_buf);
2737         if (ret) {
2738                 llapi_printf(LLAPI_MSG_NORMAL,
2739                              "obd_uuid: %s failed %s ",
2740                              param->obduuid->uuid,
2741                              strerror(errno));
2742         }
2743         return ret;
2744 }
2745
2746 static int cb_find_init(char *path, DIR *parent, DIR *dir,
2747                         void *data, struct dirent64 *de)
2748 {
2749         struct find_param *param = (struct find_param *)data;
2750         int decision = 1; /* 1 is accepted; -1 is rejected. */
2751         lstat_t *st = &param->lmd->lmd_st;
2752         int lustre_fs = 1;
2753         int checked_type = 0;
2754         int ret = 0;
2755
2756         LASSERT(parent != NULL || dir != NULL);
2757
2758         if (param->have_fileinfo == 0)
2759                 param->lmd->lmd_lmm.lmm_stripe_count = 0;
2760
2761         /* If a regular expression is presented, make the initial decision */
2762         if (param->pattern != NULL) {
2763                 char *fname = strrchr(path, '/');
2764                 fname = (fname == NULL ? path : fname + 1);
2765                 ret = fnmatch(param->pattern, fname, 0);
2766                 if ((ret == FNM_NOMATCH && !param->exclude_pattern) ||
2767                     (ret == 0 && param->exclude_pattern))
2768                         goto decided;
2769         }
2770
2771         /* See if we can check the file type from the dirent. */
2772         if (param->type && de != NULL && de->d_type != DT_UNKNOWN &&
2773             de->d_type < DT_MAX) {
2774                 checked_type = 1;
2775                 if (llapi_dir_filetype_table[de->d_type] == param->type) {
2776                         if (param->exclude_type)
2777                                 goto decided;
2778                 } else {
2779                         if (!param->exclude_type)
2780                                 goto decided;
2781                 }
2782         }
2783
2784         ret = 0;
2785
2786         /* Request MDS for the stat info if some of these parameters need
2787          * to be compared. */
2788         if (param->obduuid   || param->mdtuuid || param->check_uid ||
2789             param->check_gid || param->check_pool || param->atime   ||
2790             param->ctime     || param->mtime || param->check_size ||
2791             param->check_stripecount || param->check_stripesize ||
2792             param->check_layout)
2793                 decision = 0;
2794
2795         if (param->type && checked_type == 0)
2796                 decision = 0;
2797
2798         if (param->have_fileinfo == 0 && decision == 0) {
2799                 ret = get_lmd_info(path, parent, dir, param->lmd,
2800                                    param->lumlen);
2801                 if (ret == 0) {
2802                         if (dir) {
2803                                 ret = llapi_file_fget_mdtidx(dirfd(dir),
2804                                                      &param->file_mdtindex);
2805                         } else {
2806                                 int fd;
2807                                 lstat_t tmp_st;
2808
2809                                 ret = lstat_f(path, &tmp_st);
2810                                 if (ret) {
2811                                         ret = -errno;
2812                                         llapi_error(LLAPI_MSG_ERROR, ret,
2813                                                     "error: %s: lstat failed"
2814                                                     "for %s", __func__, path);
2815                                         return ret;
2816                                 }
2817                                 if (S_ISREG(tmp_st.st_mode)) {
2818                                         fd = open(path, O_RDONLY);
2819                                         if (fd > 0) {
2820                                                 ret = llapi_file_fget_mdtidx(fd,
2821                                                          &param->file_mdtindex);
2822                                                 close(fd);
2823                                         } else {
2824                                                 ret = fd;
2825                                         }
2826                                 } else {
2827                                         /* For special inode, it assumes to
2828                                          * reside on the same MDT with the
2829                                          * parent */
2830                                         fd = dirfd(parent);
2831                                         ret = llapi_file_fget_mdtidx(fd,
2832                                                         &param->file_mdtindex);
2833                                 }
2834                         }
2835                 }
2836                 if (ret) {
2837                         if (ret == -ENOTTY)
2838                                 lustre_fs = 0;
2839                         if (ret == -ENOENT)
2840                                 goto decided;
2841                         return ret;
2842                 }
2843         }
2844
2845         if (param->type && !checked_type) {
2846                 if ((st->st_mode & S_IFMT) == param->type) {
2847                         if (param->exclude_type)
2848                                 goto decided;
2849                 } else {
2850                         if (!param->exclude_type)
2851                                 goto decided;
2852                 }
2853         }
2854
2855         /* Prepare odb. */
2856         if (param->obduuid || param->mdtuuid) {
2857                 if (lustre_fs && param->got_uuids &&
2858                     param->st_dev != st->st_dev) {
2859                         /* A lustre/lustre mount point is crossed. */
2860                         param->got_uuids = 0;
2861                         param->obds_printed = 0;
2862                         param->obdindex = param->mdtindex = OBD_NOT_FOUND;
2863                 }
2864
2865                 if (lustre_fs && !param->got_uuids) {
2866                         ret = setup_target_indexes(dir ? dir : parent, path,
2867                                                    param);
2868                         if (ret)
2869                                 return ret;
2870
2871                         param->st_dev = st->st_dev;
2872                 } else if (!lustre_fs && param->got_uuids) {
2873                         /* A lustre/non-lustre mount point is crossed. */
2874                         param->got_uuids = 0;
2875                         param->obdindex = param->mdtindex = OBD_NOT_FOUND;
2876                 }
2877         }
2878
2879         if (param->check_stripesize) {
2880                 decision = find_value_cmp(param->lmd->lmd_lmm.lmm_stripe_size,
2881                                           param->stripesize,
2882                                           param->stripesize_sign,
2883                                           param->exclude_stripesize,
2884                                           param->stripesize_units, 0);
2885                 if (decision == -1)
2886                         goto decided;
2887         }
2888
2889         if (param->check_stripecount) {
2890                 decision = find_value_cmp(param->lmd->lmd_lmm.lmm_stripe_count,
2891                                           param->stripecount,
2892                                           param->stripecount_sign,
2893                                           param->exclude_stripecount, 1, 0);
2894                 if (decision == -1)
2895                         goto decided;
2896         }
2897
2898         if (param->check_layout) {
2899                 __u32 found;
2900
2901                 found = (param->lmd->lmd_lmm.lmm_pattern & param->layout);
2902                 if ((param->lmd->lmd_lmm.lmm_pattern == 0xFFFFFFFF) ||
2903                     (found && param->exclude_layout) ||
2904                     (!found && !param->exclude_layout)) {
2905                         decision = -1;
2906                         goto decided;
2907                 }
2908         }
2909
2910         /* If an OBD UUID is specified but none matches, skip this file. */
2911         if ((param->obduuid && param->obdindex == OBD_NOT_FOUND) ||
2912             (param->mdtuuid && param->mdtindex == OBD_NOT_FOUND))
2913                 goto decided;
2914
2915         /* If a OST or MDT UUID is given, and some OST matches,
2916          * check it here. */
2917         if (param->obdindex != OBD_NOT_FOUND ||
2918             param->mdtindex != OBD_NOT_FOUND) {
2919                 if (param->obduuid) {
2920                         if (check_obd_match(param)) {
2921                                 /* If no mdtuuid is given, we are done.
2922                                  * Otherwise, fall through to the mdtuuid
2923                                  * check below. */
2924                                 if (!param->mdtuuid)
2925                                         goto obd_matches;
2926                         } else {
2927                                 goto decided;
2928                         }
2929                 }
2930                 if (param->mdtuuid) {
2931                         if (check_mdt_match(param))
2932                                 goto obd_matches;
2933                         goto decided;
2934                 }
2935         }
2936 obd_matches:
2937         if (param->check_uid) {
2938                 if (st->st_uid == param->uid) {
2939                         if (param->exclude_uid)
2940                                 goto decided;
2941                 } else {
2942                         if (!param->exclude_uid)
2943                                 goto decided;
2944                 }
2945         }
2946
2947         if (param->check_gid) {
2948                 if (st->st_gid == param->gid) {
2949                         if (param->exclude_gid)
2950                                 goto decided;
2951                 } else {
2952                         if (!param->exclude_gid)
2953                                 goto decided;
2954                 }
2955         }
2956
2957         if (param->check_pool) {
2958                 struct lov_user_md_v3 *lmmv3 = (void *)&param->lmd->lmd_lmm;
2959
2960                 /* empty requested pool is taken as no pool search => V1 */
2961                 if (((param->lmd->lmd_lmm.lmm_magic == LOV_USER_MAGIC_V1) &&
2962                      (param->poolname[0] == '\0')) ||
2963                     ((param->lmd->lmd_lmm.lmm_magic == LOV_USER_MAGIC_V3) &&
2964                      (strncmp(lmmv3->lmm_pool_name,
2965                               param->poolname, LOV_MAXPOOLNAME) == 0)) ||
2966                     ((param->lmd->lmd_lmm.lmm_magic == LOV_USER_MAGIC_V3) &&
2967                      (strcmp(param->poolname, "*") == 0))) {
2968                         if (param->exclude_pool)
2969                                 goto decided;
2970                 } else {
2971                         if (!param->exclude_pool)
2972                                 goto decided;
2973                 }
2974         }
2975
2976         /* Check the time on mds. */
2977         decision = 1;
2978         if (param->atime || param->ctime || param->mtime) {
2979                 int for_mds;
2980
2981                 for_mds = lustre_fs ? (S_ISREG(st->st_mode) &&
2982                                        param->lmd->lmd_lmm.lmm_stripe_count)
2983                                     : 0;
2984                 decision = find_time_check(st, param, for_mds);
2985                 if (decision == -1)
2986                         goto decided;
2987         }
2988
2989         /* If file still fits the request, ask ost for updated info.
2990            The regular stat is almost of the same speed as some new
2991            'glimpse-size-ioctl'. */
2992
2993         if (param->check_size && S_ISREG(st->st_mode) &&
2994             param->lmd->lmd_lmm.lmm_stripe_count)
2995                 decision = 0;
2996
2997         while (!decision) {
2998                 /* For regular files with the stripe the decision may have not
2999                  * been taken yet if *time or size is to be checked. */
3000                 LASSERT((S_ISREG(st->st_mode) &&
3001                         param->lmd->lmd_lmm.lmm_stripe_count) ||
3002                         param->mdtindex != OBD_NOT_FOUND);
3003
3004                 if (param->obdindex != OBD_NOT_FOUND)
3005                         print_failed_tgt(param, path, LL_STATFS_LOV);
3006
3007                 if (param->mdtindex != OBD_NOT_FOUND)
3008                         print_failed_tgt(param, path, LL_STATFS_LMV);
3009
3010                 if (dir) {
3011                         ret = ioctl(dirfd(dir), IOC_LOV_GETINFO,
3012                                     (void *)param->lmd);
3013                 } else if (parent) {
3014                         ret = ioctl(dirfd(parent), IOC_LOV_GETINFO,
3015                                     (void *)param->lmd);
3016                 }
3017
3018                 if (ret) {
3019                         if (errno == ENOENT) {
3020                                 llapi_error(LLAPI_MSG_ERROR, -ENOENT,
3021                                             "warning: %s: %s does not exist",
3022                                             __func__, path);
3023                                 goto decided;
3024                         } else {
3025                                 ret = -errno;
3026                                 llapi_error(LLAPI_MSG_ERROR, ret,
3027                                             "%s: IOC_LOV_GETINFO on %s failed",
3028                                             __func__, path);
3029                                 return ret;
3030                         }
3031                 }
3032
3033                 /* Check the time on osc. */
3034                 decision = find_time_check(st, param, 0);
3035                 if (decision == -1)
3036                         goto decided;
3037
3038                 break;
3039         }
3040
3041         if (param->check_size)
3042                 decision = find_value_cmp(st->st_size, param->size,
3043                                           param->size_sign, param->exclude_size,
3044                                           param->size_units, 0);
3045
3046         if (decision != -1) {
3047                 llapi_printf(LLAPI_MSG_NORMAL, "%s", path);
3048                 if (param->zeroend)
3049                         llapi_printf(LLAPI_MSG_NORMAL, "%c", '\0');
3050                 else
3051                         llapi_printf(LLAPI_MSG_NORMAL, "\n");
3052         }
3053
3054 decided:
3055         /* Do not get down anymore? */
3056         if (param->depth == param->maxdepth)
3057                 return 1;
3058
3059         param->depth++;
3060         return 0;
3061 }
3062
3063 int llapi_find(char *path, struct find_param *param)
3064 {
3065         return param_callback(path, cb_find_init, cb_common_fini, param);
3066 }
3067
3068 /*
3069  * Get MDT number that the file/directory inode referenced
3070  * by the open fd resides on.
3071  * Return 0 and mdtidx on success, or -ve errno.
3072  */
3073 int llapi_file_fget_mdtidx(int fd, int *mdtidx)
3074 {
3075         if (ioctl(fd, LL_IOC_GET_MDTIDX, mdtidx) < 0)
3076                 return -errno;
3077         return 0;
3078 }
3079
3080 static int cb_get_mdt_index(char *path, DIR *parent, DIR *d, void *data,
3081                             struct dirent64 *de)
3082 {
3083         struct find_param *param = (struct find_param *)data;
3084         int ret = 0;
3085         int mdtidx;
3086
3087         LASSERT(parent != NULL || d != NULL);
3088
3089         if (d) {
3090                 ret = llapi_file_fget_mdtidx(dirfd(d), &mdtidx);
3091         } else if (parent) {
3092                 int fd;
3093
3094                 fd = open(path, O_RDONLY);
3095                 if (fd > 0) {
3096                         ret = llapi_file_fget_mdtidx(fd, &mdtidx);
3097                         close(fd);
3098                 } else {
3099                         ret = -errno;
3100                 }
3101         }
3102
3103         if (ret) {
3104                 if (ret == -ENODATA) {
3105                         if (!param->obduuid)
3106                                 llapi_printf(LLAPI_MSG_NORMAL,
3107                                              "%s has no stripe info\n", path);
3108                         goto out;
3109                 } else if (ret == -ENOENT) {
3110                         llapi_error(LLAPI_MSG_WARN, ret,
3111                                     "warning: %s: %s does not exist",
3112                                     __func__, path);
3113                         goto out;
3114                 } else if (ret == -ENOTTY) {
3115                         llapi_error(LLAPI_MSG_ERROR, ret,
3116                                     "%s: '%s' not on a Lustre fs?",
3117                                     __func__, path);
3118                 } else {
3119                         llapi_error(LLAPI_MSG_ERROR, ret,
3120                                     "error: %s: LL_IOC_GET_MDTIDX failed for %s",
3121                                     __func__, path);
3122                 }
3123                 return ret;
3124         }
3125
3126         /* The 'LASSERT(parent != NULL || d != NULL);' guarantees
3127          * that either 'd' or 'parent' is not null.
3128          * So in all cases llapi_file_fget_mdtidx() is called,
3129          * thus initializing 'mdtidx'. */
3130         if (param->quiet || !(param->verbose & VERBOSE_DETAIL))
3131                 /* coverity[uninit_use_in_call] */
3132                 llapi_printf(LLAPI_MSG_NORMAL, "%d\n", mdtidx);
3133         else
3134                 /* coverity[uninit_use_in_call] */
3135                 llapi_printf(LLAPI_MSG_NORMAL, "%s\nmdt_index:\t%d\n",
3136                              path, mdtidx);
3137
3138 out:
3139         /* Do not get down anymore? */
3140         if (param->depth == param->maxdepth)
3141                 return 1;
3142
3143         param->depth++;
3144         return 0;
3145 }
3146
3147 static int cb_getstripe(char *path, DIR *parent, DIR *d, void *data,
3148                         struct dirent64 *de)
3149 {
3150         struct find_param *param = (struct find_param *)data;
3151         int ret = 0;
3152
3153         LASSERT(parent != NULL || d != NULL);
3154
3155         if (param->obduuid) {
3156                 param->quiet = 1;
3157                 ret = setup_obd_uuid(d ? d : parent, path, param);
3158                 if (ret)
3159                         return ret;
3160         }
3161
3162         if (d) {
3163                 if (param->get_lmv) {
3164                         ret = cb_get_dirstripe(path, d, param);
3165                 } else {
3166                         ret = ioctl(dirfd(d), LL_IOC_LOV_GETSTRIPE,
3167                                      (void *)&param->lmd->lmd_lmm);
3168                 }
3169
3170         } else if (parent) {
3171                 char *fname = strrchr(path, '/');
3172                 fname = (fname == NULL ? path : fname + 1);
3173
3174                 if (param->get_lmv) {
3175                         llapi_printf(LLAPI_MSG_NORMAL,
3176                                      "%s get dirstripe information for file\n",
3177                                      path);
3178                         goto out;
3179                 }
3180
3181                 strncpy((char *)&param->lmd->lmd_lmm, fname, param->lumlen);
3182
3183                 ret = ioctl(dirfd(parent), IOC_MDC_GETFILESTRIPE,
3184                             (void *)&param->lmd->lmd_lmm);
3185         }
3186
3187         if (ret) {
3188                 if (errno == ENODATA && d != NULL) {
3189                         /* We need to "fake" the "use the default" values
3190                          * since the lmm struct is zeroed out at this point.
3191                          * The magic needs to be set in order to satisfy
3192                          * a check later on in the code path.
3193                          * The object_seq needs to be set for the "(Default)"
3194                          * prefix to be displayed. */
3195                         struct lov_user_md *lmm = &param->lmd->lmd_lmm;
3196                         lmm->lmm_magic = LOV_USER_MAGIC_V1;
3197                         if (!param->raw)
3198                                 ostid_set_seq(&lmm->lmm_oi,
3199                                               FID_SEQ_LOV_DEFAULT);
3200                         lmm->lmm_stripe_count = 0;
3201                         lmm->lmm_stripe_size = 0;
3202                         lmm->lmm_stripe_offset = -1;
3203                         goto dump;
3204                 } else if (errno == ENODATA && parent != NULL) {
3205                         if (!param->obduuid && !param->mdtuuid)
3206                                 llapi_printf(LLAPI_MSG_NORMAL,
3207                                              "%s has no stripe info\n", path);
3208                         goto out;
3209                 } else if (errno == ENOENT) {
3210                         llapi_error(LLAPI_MSG_WARN, -ENOENT,
3211                                     "warning: %s: %s does not exist",
3212                                     __func__, path);
3213                         goto out;
3214                 } else if (errno == ENOTTY) {
3215                         ret = -errno;
3216                         llapi_error(LLAPI_MSG_ERROR, ret,
3217                                     "%s: '%s' not on a Lustre fs?",
3218                                     __func__, path);
3219                 } else {
3220                         ret = -errno;
3221                         llapi_error(LLAPI_MSG_ERROR, ret,
3222                                     "error: %s: %s failed for %s",
3223                                      __func__, d ? "LL_IOC_LOV_GETSTRIPE" :
3224                                     "IOC_MDC_GETFILESTRIPE", path);
3225                 }
3226
3227                 return ret;
3228         }
3229
3230 dump:
3231         if (!(param->verbose & VERBOSE_MDTINDEX))
3232                 llapi_lov_dump_user_lmm(param, path, d ? 1 : 0);
3233
3234 out:
3235         /* Do not get down anymore? */
3236         if (param->depth == param->maxdepth)
3237                 return 1;
3238
3239         param->depth++;
3240         return 0;
3241 }
3242
3243 int llapi_getstripe(char *path, struct find_param *param)
3244 {
3245         return param_callback(path, (param->verbose & VERBOSE_MDTINDEX) ?
3246                               cb_get_mdt_index : cb_getstripe,
3247                               cb_common_fini, param);
3248 }
3249
3250 int llapi_obd_statfs(char *path, __u32 type, __u32 index,
3251                      struct obd_statfs *stat_buf,
3252                      struct obd_uuid *uuid_buf)
3253 {
3254         int fd;
3255         char raw[OBD_MAX_IOCTL_BUFFER] = {'\0'};
3256         char *rawbuf = raw;
3257         struct obd_ioctl_data data = { 0 };
3258         int rc = 0;
3259
3260         data.ioc_inlbuf1 = (char *)&type;
3261         data.ioc_inllen1 = sizeof(__u32);
3262         data.ioc_inlbuf2 = (char *)&index;
3263         data.ioc_inllen2 = sizeof(__u32);
3264         data.ioc_pbuf1 = (char *)stat_buf;
3265         data.ioc_plen1 = sizeof(struct obd_statfs);
3266         data.ioc_pbuf2 = (char *)uuid_buf;
3267         data.ioc_plen2 = sizeof(struct obd_uuid);
3268
3269         rc = obd_ioctl_pack(&data, &rawbuf, sizeof(raw));
3270         if (rc != 0) {
3271                 llapi_error(LLAPI_MSG_ERROR, rc,
3272                             "llapi_obd_statfs: error packing ioctl data");
3273                 return rc;
3274         }
3275
3276         fd = open(path, O_RDONLY);
3277         if (errno == EISDIR)
3278                 fd = open(path, O_DIRECTORY | O_RDONLY);
3279
3280         if (fd < 0) {
3281                 rc = errno ? -errno : -EBADF;
3282                 llapi_error(LLAPI_MSG_ERROR, rc, "error: %s: opening '%s'",
3283                             __func__, path);
3284                 return rc;
3285         }
3286         rc = ioctl(fd, IOC_OBD_STATFS, (void *)rawbuf);
3287         if (rc)
3288                 rc = errno ? -errno : -EINVAL;
3289
3290         close(fd);
3291         return rc;
3292 }
3293
3294 #define MAX_STRING_SIZE 128
3295
3296 int llapi_ping(char *obd_type, char *obd_name)
3297 {
3298         char path[MAX_STRING_SIZE];
3299         char buf[1];
3300         int rc, fd;
3301
3302         snprintf(path, MAX_STRING_SIZE, "/proc/fs/lustre/%s/%s/ping",
3303                  obd_type, obd_name);
3304
3305         fd = open(path, O_WRONLY);
3306         if (fd < 0) {
3307                 rc = -errno;
3308                 llapi_error(LLAPI_MSG_ERROR, rc, "error opening %s", path);
3309                 return rc;
3310         }
3311
3312         /* The purpose is to send a byte as a ping, whatever this byte is. */
3313         /* coverity[uninit_use_in_call] */
3314         rc = write(fd, buf, 1);
3315         if (rc < 0)
3316                 rc = -errno;
3317         close(fd);
3318
3319         if (rc == 1)
3320                 return 0;
3321         return rc;
3322 }
3323
3324 int llapi_target_iterate(int type_num, char **obd_type,
3325                          void *args, llapi_cb_t cb)
3326 {
3327         char buf[MAX_STRING_SIZE];
3328         FILE *fp = fopen(DEVICES_LIST, "r");
3329         int i, rc = 0;
3330
3331         if (fp == NULL) {
3332                 rc = -errno;
3333                 llapi_error(LLAPI_MSG_ERROR, rc, "error: opening "DEVICES_LIST);
3334                 return rc;
3335         }
3336
3337         while (fgets(buf, sizeof(buf), fp) != NULL) {
3338                 char *obd_type_name = NULL;
3339                 char *obd_name = NULL;
3340                 char *obd_uuid = NULL;
3341                 char *bufp = buf;
3342                 struct obd_statfs osfs_buffer;
3343
3344                 while(bufp[0] == ' ')
3345                         ++bufp;
3346
3347                 for(i = 0; i < 3; i++) {
3348                         obd_type_name = strsep(&bufp, " ");
3349                 }
3350                 obd_name = strsep(&bufp, " ");
3351                 obd_uuid = strsep(&bufp, " ");
3352
3353                 memset(&osfs_buffer, 0, sizeof (osfs_buffer));
3354
3355                 for (i = 0; i < type_num; i++) {
3356                         if (strcmp(obd_type_name, obd_type[i]) != 0)
3357                                 continue;
3358
3359                         cb(obd_type_name, obd_name, obd_uuid, args);
3360                 }
3361         }
3362         fclose(fp);
3363         return 0;
3364 }
3365
3366 static void do_target_check(char *obd_type_name, char *obd_name,
3367                             char *obd_uuid, void *args)
3368 {
3369         int rc;
3370
3371         rc = llapi_ping(obd_type_name, obd_name);
3372         if (rc == ENOTCONN) {
3373                 llapi_printf(LLAPI_MSG_NORMAL, "%s inactive.\n", obd_name);
3374         } else if (rc) {
3375                 llapi_error(LLAPI_MSG_ERROR, rc, "error: check '%s'", obd_name);
3376         } else {
3377                 llapi_printf(LLAPI_MSG_NORMAL, "%s active.\n", obd_name);
3378         }
3379 }
3380
3381 int llapi_target_check(int type_num, char **obd_type, char *dir)
3382 {
3383         return llapi_target_iterate(type_num, obd_type, NULL, do_target_check);
3384 }
3385
3386 #undef MAX_STRING_SIZE
3387
3388 /* Is this a lustre fs? */
3389 int llapi_is_lustre_mnttype(const char *type)
3390 {
3391         return (strcmp(type, "lustre") == 0 || strcmp(type,"lustre_lite") == 0);
3392 }
3393
3394 /* Is this a lustre client fs? */
3395 int llapi_is_lustre_mnt(struct mntent *mnt)
3396 {
3397         return (llapi_is_lustre_mnttype(mnt->mnt_type) &&
3398                 strstr(mnt->mnt_fsname, ":/") != NULL);
3399 }
3400
3401 int llapi_quotacheck(char *mnt, int check_type)
3402 {
3403         DIR *root;
3404         int rc;
3405
3406         root = opendir(mnt);
3407         if (!root) {
3408                 rc = -errno;
3409                 llapi_error(LLAPI_MSG_ERROR, rc, "open %s failed", mnt);
3410                 return rc;
3411         }
3412
3413         rc = ioctl(dirfd(root), LL_IOC_QUOTACHECK, check_type);
3414         if (rc < 0)
3415                 rc = -errno;
3416
3417         closedir(root);
3418         return rc;
3419 }
3420
3421 int llapi_poll_quotacheck(char *mnt, struct if_quotacheck *qchk)
3422 {
3423         DIR *root;
3424         int poll_intvl = 2;
3425         int rc;
3426
3427         root = opendir(mnt);
3428         if (!root) {
3429                 rc = -errno;
3430                 llapi_error(LLAPI_MSG_ERROR, rc, "open %s failed", mnt);
3431                 return rc;
3432         }
3433
3434         while (1) {
3435                 rc = ioctl(dirfd(root), LL_IOC_POLL_QUOTACHECK, qchk);
3436                 if (!rc)
3437                         break;
3438                 sleep(poll_intvl);
3439                 if (poll_intvl < 30)
3440                         poll_intvl *= 2;
3441         }
3442
3443         closedir(root);
3444         return 0;
3445 }
3446
3447 int llapi_quotactl(char *mnt, struct if_quotactl *qctl)
3448 {
3449         DIR *root;
3450         int rc;
3451
3452         root = opendir(mnt);
3453         if (!root) {
3454                 rc = -errno;
3455                 llapi_error(LLAPI_MSG_ERROR, rc, "open %s failed", mnt);
3456                 return rc;
3457         }
3458
3459         rc = ioctl(dirfd(root), LL_IOC_QUOTACTL, qctl);
3460         if (rc < 0)
3461                 rc = -errno;
3462
3463         closedir(root);
3464         return rc;
3465 }
3466
3467 static int cb_quotachown(char *path, DIR *parent, DIR *d, void *data,
3468                          struct dirent64 *de)
3469 {
3470         struct find_param *param = (struct find_param *)data;
3471         lstat_t *st;
3472         int rc;
3473
3474         LASSERT(parent != NULL || d != NULL);
3475
3476         rc = get_lmd_info(path, parent, d, param->lmd, param->lumlen);
3477         if (rc) {
3478                 if (rc == -ENODATA) {
3479                         if (!param->obduuid && !param->quiet)
3480                                 llapi_error(LLAPI_MSG_ERROR, -ENODATA,
3481                                           "%s has no stripe info", path);
3482                         rc = 0;
3483                 } else if (rc == -ENOENT) {
3484                         rc = 0;
3485                 }
3486                 return rc;
3487         }
3488
3489         st = &param->lmd->lmd_st;
3490
3491         /* libc chown() will do extra check, and if the real owner is
3492          * the same as the ones to set, it won't fall into kernel, so
3493          * invoke syscall directly. */
3494         rc = syscall(SYS_chown, path, -1, -1);
3495         if (rc)
3496                 llapi_error(LLAPI_MSG_ERROR, errno,
3497                             "error: chown %s", path);
3498
3499         rc = chmod(path, st->st_mode);
3500         if (rc) {
3501                 rc = -errno;
3502                 llapi_error(LLAPI_MSG_ERROR, rc, "error: chmod %s (%hu)",
3503                             path, st->st_mode);
3504         }
3505
3506         return rc;
3507 }
3508
3509 int llapi_quotachown(char *path, int flag)
3510 {
3511         struct find_param param;
3512
3513         memset(&param, 0, sizeof(param));
3514         param.recursive = 1;
3515         param.verbose = 0;
3516         param.quiet = 1;
3517
3518         return param_callback(path, cb_quotachown, NULL, &param);
3519 }
3520
3521 #include <pwd.h>
3522 #include <grp.h>
3523 #include <mntent.h>
3524 #include <sys/wait.h>
3525 #include <errno.h>
3526 #include <ctype.h>
3527
3528 static int rmtacl_notify(int ops)
3529 {
3530         FILE *fp;
3531         struct mntent *mnt;
3532         int found = 0, fd = 0, rc = 0;
3533
3534         fp = setmntent(MOUNTED, "r");
3535         if (fp == NULL) {
3536                 rc = -errno;
3537                 llapi_error(LLAPI_MSG_ERROR, rc,
3538                             "error setmntent(%s)", MOUNTED);
3539                 return rc;
3540         }
3541
3542         while (1) {
3543                 mnt = getmntent(fp);
3544                 if (!mnt)
3545                         break;
3546
3547                 if (!llapi_is_lustre_mnt(mnt))
3548                         continue;
3549
3550                 fd = open(mnt->mnt_dir, O_RDONLY | O_DIRECTORY);
3551                 if (fd < 0) {
3552                         rc = -errno;
3553                         llapi_error(LLAPI_MSG_ERROR, rc,
3554                                     "Can't open '%s'\n", mnt->mnt_dir);
3555                         goto out;
3556                 }
3557
3558                 rc = ioctl(fd, LL_IOC_RMTACL, ops);
3559                 close(fd);
3560                 if (rc < 0) {
3561                         rc = -errno;
3562                         llapi_error(LLAPI_MSG_ERROR, rc,
3563                                     "ioctl RMTACL on '%s' err %d\n",
3564                                     mnt->mnt_dir, rc);
3565                         goto out;
3566                 }
3567
3568                 found++;
3569         }
3570
3571 out:
3572         endmntent(fp);
3573         return ((rc != 0) ? rc : found);
3574 }
3575
3576 static char *next_token(char *p, int div)
3577 {
3578         if (p == NULL)
3579                 return NULL;
3580
3581         if (div)
3582                 while (*p && *p != ':' && !isspace(*p))
3583                         p++;
3584         else
3585                 while (*p == ':' || isspace(*p))
3586                         p++;
3587
3588         return *p ? p : NULL;
3589 }
3590
3591 static int rmtacl_name2id(char *name, int is_user)
3592 {
3593         if (is_user) {
3594                 struct passwd *pw;
3595
3596                 pw = getpwnam(name);
3597                 if (pw == NULL)
3598                         return INVALID_ID;
3599                 else
3600                         return (int)(pw->pw_uid);
3601         } else {
3602                 struct group *gr;
3603
3604                 gr = getgrnam(name);
3605                 if (gr == NULL)
3606                         return INVALID_ID;
3607                 else
3608                         return (int)(gr->gr_gid);
3609         }
3610 }
3611
3612 static int isodigit(int c)
3613 {
3614         return (c >= '0' && c <= '7') ? 1 : 0;
3615 }
3616
3617 /*
3618  * Whether the name is just digits string (uid/gid) already or not.
3619  * Return value:
3620  * 1: str is id
3621  * 0: str is not id
3622  */
3623 static int str_is_id(char *str)
3624 {
3625         if (str == NULL)
3626                 return 0;
3627
3628         if (*str == '0') {
3629                 str++;
3630                 if (*str == 'x' || *str == 'X') { /* for Hex. */
3631                         if (!isxdigit(*(++str)))
3632                                 return 0;
3633
3634                         while (isxdigit(*(++str)));
3635                 } else if (isodigit(*str)) { /* for Oct. */
3636                         while (isodigit(*(++str)));
3637                 }
3638         } else if (isdigit(*str)) { /* for Dec. */
3639                 while (isdigit(*(++str)));
3640         }
3641
3642         return (*str == 0) ? 1 : 0;
3643 }
3644
3645 typedef struct {
3646         char *name;
3647         int   length;
3648         int   is_user;
3649         int   next_token;
3650 } rmtacl_name_t;
3651
3652 #define RMTACL_OPTNAME(name) name, sizeof(name) - 1
3653
3654 static rmtacl_name_t rmtacl_namelist[] = {
3655         { RMTACL_OPTNAME("user:"),            1,      0 },
3656         { RMTACL_OPTNAME("group:"),           0,      0 },
3657         { RMTACL_OPTNAME("default:user:"),    1,      0 },
3658         { RMTACL_OPTNAME("default:group:"),   0,      0 },
3659         /* for --tabular option */
3660         { RMTACL_OPTNAME("user"),             1,      1 },
3661         { RMTACL_OPTNAME("group"),            0,      1 },
3662         { 0 }
3663 };
3664
3665 static int rgetfacl_output(char *str)
3666 {
3667         char *start = NULL, *end = NULL;
3668         int is_user = 0, n, id;
3669         char c;
3670         rmtacl_name_t *rn;
3671
3672         if (str == NULL)
3673                 return -1;
3674
3675         for (rn = rmtacl_namelist; rn->name; rn++) {
3676                 if(strncmp(str, rn->name, rn->length) == 0) {
3677                         if (!rn->next_token)
3678                                 start = str + rn->length;
3679                         else
3680                                 start = next_token(str + rn->length, 0);
3681                         is_user = rn->is_user;
3682                         break;
3683                 }
3684         }
3685
3686         end = next_token(start, 1);
3687         if (end == NULL || start == end) {
3688                 n = printf("%s", str);
3689                 return n;
3690         }
3691
3692         c = *end;
3693         *end = 0;
3694         id = rmtacl_name2id(start, is_user);
3695         if (id == INVALID_ID) {
3696                 if (str_is_id(start)) {
3697                         *end = c;
3698                         n = printf("%s", str);
3699                 } else
3700                         return -1;
3701         } else if ((id == NOBODY_UID && is_user) ||
3702                    (id == NOBODY_GID && !is_user)) {
3703                 *end = c;
3704                 n = printf("%s", str);
3705         } else {
3706                 *end = c;
3707                 *start = 0;
3708                 n = printf("%s%d%s", str, id, end);
3709         }
3710         return n;
3711 }
3712
3713 static int child_status(int status)
3714 {
3715         return WIFEXITED(status) ? WEXITSTATUS(status) : -1;
3716 }
3717
3718 static int do_rmtacl(int argc, char *argv[], int ops, int (output_func)(char *))
3719 {
3720         pid_t pid = 0;
3721         int fd[2], status, rc;
3722         FILE *fp;
3723         char buf[PIPE_BUF];
3724
3725         if (output_func) {
3726                 if (pipe(fd) < 0) {
3727                         rc = -errno;
3728                         llapi_error(LLAPI_MSG_ERROR, rc, "Can't create pipe\n");
3729                         return rc;
3730                 }
3731
3732                 pid = fork();
3733                 if (pid < 0) {
3734                         rc = -errno;
3735                         llapi_error(LLAPI_MSG_ERROR, rc, "Can't fork\n");
3736                         close(fd[0]);
3737                         close(fd[1]);
3738                         return rc;
3739                 } else if (!pid) {
3740                         /* child process redirects its output. */
3741                         close(fd[0]);
3742                         close(1);
3743                         if (dup2(fd[1], 1) < 0) {
3744                                 rc = -errno;
3745                                 llapi_error(LLAPI_MSG_ERROR, rc,
3746                                             "Can't dup2 %d\n", fd[1]);
3747                                 close(fd[1]);
3748                                 return rc;
3749                         }
3750                 } else {
3751                         close(fd[1]);
3752                 }
3753         }
3754
3755         if (!pid) {
3756                 status = rmtacl_notify(ops);
3757                 if (status < 0)
3758                         return -errno;
3759
3760                 exit(execvp(argv[0], argv));
3761         }
3762
3763         /* the following is parent process */
3764         fp = fdopen(fd[0], "r");
3765         if (fp == NULL) {
3766                 rc = -errno;
3767                 llapi_error(LLAPI_MSG_ERROR, rc, "fdopen %d failed\n", fd[0]);
3768                 kill(pid, SIGKILL);
3769                 close(fd[0]);
3770                 return rc;
3771         }
3772
3773         while (fgets(buf, PIPE_BUF, fp) != NULL) {
3774                 if (output_func(buf) < 0)
3775                         fprintf(stderr, "WARNING: unexpected error!\n[%s]\n",
3776                                 buf);
3777         }
3778         fclose(fp);
3779         close(fd[0]);
3780
3781         if (waitpid(pid, &status, 0) < 0) {
3782                 rc = -errno;
3783                 llapi_error(LLAPI_MSG_ERROR, rc, "waitpid %d failed\n", pid);
3784                 return rc;
3785         }
3786
3787         return child_status(status);
3788 }
3789
3790 int llapi_lsetfacl(int argc, char *argv[])
3791 {
3792         return do_rmtacl(argc, argv, RMT_LSETFACL, NULL);
3793 }
3794
3795 int llapi_lgetfacl(int argc, char *argv[])
3796 {
3797         return do_rmtacl(argc, argv, RMT_LGETFACL, NULL);
3798 }
3799
3800 int llapi_rsetfacl(int argc, char *argv[])
3801 {
3802         return do_rmtacl(argc, argv, RMT_RSETFACL, NULL);
3803 }
3804
3805 int llapi_rgetfacl(int argc, char *argv[])
3806 {
3807         return do_rmtacl(argc, argv, RMT_RGETFACL, rgetfacl_output);
3808 }
3809
3810 int llapi_cp(int argc, char *argv[])
3811 {
3812         int rc;
3813
3814         rc = rmtacl_notify(RMT_RSETFACL);
3815         if (rc < 0)
3816                 return rc;
3817
3818         exit(execvp(argv[0], argv));
3819 }
3820
3821 int llapi_ls(int argc, char *argv[])
3822 {
3823         int rc;
3824
3825         rc = rmtacl_notify(RMT_LGETFACL);
3826         if (rc < 0)
3827                 return rc;
3828
3829         exit(execvp(argv[0], argv));
3830 }
3831
3832 /* Print mdtname 'name' into 'buf' using 'format'.  Add -MDT0000 if needed.
3833  * format must have %s%s, buf must be > 16
3834  * Eg: if name = "lustre-MDT0000", "lustre", or "lustre-MDT0000_UUID"
3835  *     then buf = "lustre-MDT0000"
3836  */
3837 static int get_mdtname(char *name, char *format, char *buf)
3838 {
3839         char suffix[]="-MDT0000";
3840         int len = strlen(name);
3841
3842         if ((len > 5) && (strncmp(name + len - 5, "_UUID", 5) == 0)) {
3843                 name[len - 5] = '\0';
3844                 len -= 5;
3845         }
3846
3847         if (len > 8) {
3848                 if ((len <= 16) && strncmp(name + len - 8, "-MDT", 4) == 0) {
3849                         suffix[0] = '\0';
3850                 } else {
3851                         /* Not enough room to add suffix */
3852                         llapi_err_noerrno(LLAPI_MSG_ERROR,
3853                                           "MDT name too long |%s|", name);
3854                         return -EINVAL;
3855                 }
3856         }
3857
3858         return sprintf(buf, format, name, suffix);
3859 }
3860
3861 /** ioctl on filsystem root, with mdtindex sent as data
3862  * \param mdtname path, fsname, or mdtname (lutre-MDT0004)
3863  * \param mdtidxp pointer to integer within data to be filled in with the
3864  *    mdt index (0 if no mdt is specified).  NULL won't be filled.
3865  */
3866 int root_ioctl(const char *mdtname, int opc, void *data, int *mdtidxp,
3867                int want_error)
3868 {
3869         char fsname[20];
3870         char *ptr;
3871         int fd, rc;
3872         long index;
3873
3874         /* Take path, fsname, or MDTname.  Assume MDT0000 in the former cases.
3875          Open root and parse mdt index. */
3876         if (mdtname[0] == '/') {
3877                 index = 0;
3878                 rc = get_root_path(WANT_FD | want_error, NULL, &fd,
3879                                    (char *)mdtname, -1);
3880         } else {
3881                 if (get_mdtname((char *)mdtname, "%s%s", fsname) < 0)
3882                         return -EINVAL;
3883                 ptr = fsname + strlen(fsname) - 8;
3884                 *ptr = '\0';
3885                 index = strtol(ptr + 4, NULL, 10);
3886                 rc = get_root_path(WANT_FD | want_error, fsname, &fd, NULL, -1);
3887         }
3888         if (rc < 0) {
3889                 if (want_error)
3890                         llapi_err_noerrno(LLAPI_MSG_ERROR,
3891                                           "Can't open %s: %d\n", mdtname, rc);
3892                 return rc;
3893         }
3894
3895         if (mdtidxp)
3896                 *mdtidxp = index;
3897
3898         rc = ioctl(fd, opc, data);
3899         if (rc == -1)
3900                 rc = -errno;
3901         else
3902                 rc = 0;
3903         if (rc && want_error)
3904                 llapi_error(LLAPI_MSG_ERROR, rc, "ioctl %d err %d", opc, rc);
3905
3906         close(fd);
3907         return rc;
3908 }
3909
3910 /****** Changelog API ********/
3911
3912 static int changelog_ioctl(const char *mdtname, int opc, int id,
3913                            long long recno, int flags)
3914 {
3915         struct ioc_changelog data;
3916         int *idx;
3917
3918         data.icc_id = id;
3919         data.icc_recno = recno;
3920         data.icc_flags = flags;
3921         idx = (int *)(&data.icc_mdtindex);
3922
3923         return root_ioctl(mdtname, opc, &data, idx, WANT_ERROR);
3924 }
3925
3926 #define CHANGELOG_PRIV_MAGIC 0xCA8E1080
3927 struct changelog_private {
3928         int magic;
3929         int flags;
3930         lustre_kernelcomm kuc;
3931 };
3932
3933 /** Start reading from a changelog
3934  * @param priv Opaque private control structure
3935  * @param flags Start flags (e.g. CHANGELOG_FLAG_BLOCK)
3936  * @param device Report changes recorded on this MDT
3937  * @param startrec Report changes beginning with this record number
3938  * (just call llapi_changelog_fini when done; don't need an endrec)
3939  */
3940 int llapi_changelog_start(void **priv, int flags, const char *device,
3941                           long long startrec)
3942 {
3943         struct changelog_private *cp;
3944         int rc;
3945
3946         /* Set up the receiver control struct */
3947         cp = calloc(1, sizeof(*cp));
3948         if (cp == NULL)
3949                 return -ENOMEM;
3950
3951         cp->magic = CHANGELOG_PRIV_MAGIC;
3952         cp->flags = flags;
3953
3954         /* Set up the receiver */
3955         rc = libcfs_ukuc_start(&cp->kuc, 0 /* no group registration */);
3956         if (rc < 0)
3957                 goto out_free;
3958
3959         *priv = cp;
3960
3961         /* Tell the kernel to start sending */
3962         rc = changelog_ioctl(device, OBD_IOC_CHANGELOG_SEND, cp->kuc.lk_wfd,
3963                              startrec, flags);
3964         /* Only the kernel reference keeps the write side open */
3965         close(cp->kuc.lk_wfd);
3966         cp->kuc.lk_wfd = LK_NOFD;
3967         if (rc < 0) {
3968                 /* frees and clears priv */
3969                 llapi_changelog_fini(priv);
3970                 return rc;
3971         }
3972
3973         return 0;
3974
3975 out_free:
3976         free(cp);
3977         return rc;
3978 }
3979
3980 /** Finish reading from a changelog */
3981 int llapi_changelog_fini(void **priv)
3982 {
3983         struct changelog_private *cp = (struct changelog_private *)*priv;
3984
3985         if (!cp || (cp->magic != CHANGELOG_PRIV_MAGIC))
3986                 return -EINVAL;
3987
3988         libcfs_ukuc_stop(&cp->kuc);
3989         free(cp);
3990         *priv = NULL;
3991         return 0;
3992 }
3993
3994 /** Convert a changelog_rec to changelog_ext_rec, in this way client can treat
3995  *  all records in the format of changelog_ext_rec, this can make record
3996  *  analysis simpler.
3997  */
3998 static inline int changelog_extend_rec(struct changelog_ext_rec *ext)
3999 {
4000         if (!CHANGELOG_REC_EXTENDED(ext)) {
4001                 struct changelog_rec *rec = (struct changelog_rec *)ext;
4002
4003                 memmove(ext->cr_name, rec->cr_name, rec->cr_namelen);
4004                 fid_zero(&ext->cr_sfid);
4005                 fid_zero(&ext->cr_spfid);
4006                 return 1;
4007         }
4008
4009         return 0;
4010 }
4011
4012 /** Read the next changelog entry
4013  * @param priv Opaque private control structure
4014  * @param rech Changelog record handle; record will be allocated here
4015  * @return 0 valid message received; rec is set
4016  *         <0 error code
4017  *         1 EOF
4018  */
4019 int llapi_changelog_recv(void *priv, struct changelog_ext_rec **rech)
4020 {
4021         struct changelog_private *cp = (struct changelog_private *)priv;
4022         struct kuc_hdr *kuch;
4023         int rc = 0;
4024
4025         if (!cp || (cp->magic != CHANGELOG_PRIV_MAGIC))
4026                 return -EINVAL;
4027         if (rech == NULL)
4028                 return -EINVAL;
4029         kuch = malloc(KUC_CHANGELOG_MSG_MAXSIZE);
4030         if (kuch == NULL)
4031                 return -ENOMEM;
4032
4033 repeat:
4034         rc = libcfs_ukuc_msg_get(&cp->kuc, (char *)kuch,
4035                                  KUC_CHANGELOG_MSG_MAXSIZE,
4036                                  KUC_TRANSPORT_CHANGELOG);
4037         if (rc < 0)
4038                 goto out_free;
4039
4040         if ((kuch->kuc_transport != KUC_TRANSPORT_CHANGELOG) ||
4041             ((kuch->kuc_msgtype != CL_RECORD) &&
4042              (kuch->kuc_msgtype != CL_EOF))) {
4043                 llapi_err_noerrno(LLAPI_MSG_ERROR,
4044                                   "Unknown changelog message type %d:%d\n",
4045                                   kuch->kuc_transport, kuch->kuc_msgtype);
4046                 rc = -EPROTO;
4047                 goto out_free;
4048         }
4049
4050         if (kuch->kuc_msgtype == CL_EOF) {
4051                 if (cp->flags & CHANGELOG_FLAG_FOLLOW) {
4052                         /* Ignore EOFs */
4053                         goto repeat;
4054                 } else {
4055                         rc = 1;
4056                         goto out_free;
4057                 }
4058         }
4059
4060         /* Our message is a changelog_ext_rec.  Use pointer math to skip
4061          * kuch_hdr and point directly to the message payload.
4062          */
4063         *rech = (struct changelog_ext_rec *)(kuch + 1);
4064         changelog_extend_rec(*rech);
4065
4066         return 0;
4067
4068 out_free:
4069         *rech = NULL;
4070         free(kuch);
4071         return rc;
4072 }
4073
4074 /** Release the changelog record when done with it. */
4075 int llapi_changelog_free(struct changelog_ext_rec **rech)
4076 {
4077         if (*rech) {
4078                 /* We allocated memory starting at the kuc_hdr, but passed
4079                  * the consumer a pointer to the payload.
4080                  * Use pointer math to get back to the header.
4081                  */
4082                 struct kuc_hdr *kuch = (struct kuc_hdr *)*rech - 1;
4083                 free(kuch);
4084         }
4085         *rech = NULL;
4086         return 0;
4087 }
4088
4089 int llapi_changelog_clear(const char *mdtname, const char *idstr,
4090                           long long endrec)
4091 {
4092         long id;
4093
4094         if (endrec < 0) {
4095                 llapi_err_noerrno(LLAPI_MSG_ERROR,
4096                                   "can't purge negative records\n");
4097                 return -EINVAL;
4098         }
4099
4100         id = strtol(idstr + strlen(CHANGELOG_USER_PREFIX), NULL, 10);
4101         if ((id == 0) || (strncmp(idstr, CHANGELOG_USER_PREFIX,
4102                                   strlen(CHANGELOG_USER_PREFIX)) != 0)) {
4103                 llapi_err_noerrno(LLAPI_MSG_ERROR,
4104                                   "expecting id of the form '"
4105                                   CHANGELOG_USER_PREFIX
4106                                   "<num>'; got '%s'\n", idstr);
4107                 return -EINVAL;
4108         }
4109
4110         return changelog_ioctl(mdtname, OBD_IOC_CHANGELOG_CLEAR, id, endrec, 0);
4111 }
4112
4113 int llapi_fid2path(const char *device, const char *fidstr, char *buf,
4114                    int buflen, long long *recno, int *linkno)
4115 {
4116         struct lu_fid fid;
4117         struct getinfo_fid2path *gf;
4118         int rc;
4119
4120         while (*fidstr == '[')
4121                 fidstr++;
4122
4123         sscanf(fidstr, SFID, RFID(&fid));
4124         if (!fid_is_sane(&fid)) {
4125                 llapi_err_noerrno(LLAPI_MSG_ERROR,
4126                                   "bad FID format [%s], should be "DFID"\n",
4127                                   fidstr, (__u64)1, 2, 0);
4128                 return -EINVAL;
4129         }
4130
4131         gf = malloc(sizeof(*gf) + buflen);
4132         if (gf == NULL)
4133                 return -ENOMEM;
4134         gf->gf_fid = fid;
4135         gf->gf_recno = *recno;
4136         gf->gf_linkno = *linkno;
4137         gf->gf_pathlen = buflen;
4138
4139         /* Take path or fsname */
4140         rc = root_ioctl(device, OBD_IOC_FID2PATH, gf, NULL, 0);
4141         if (rc) {
4142                 if (rc != -ENOENT)
4143                         llapi_error(LLAPI_MSG_ERROR, rc, "ioctl err %d", rc);
4144         } else {
4145                 memcpy(buf, gf->gf_path, gf->gf_pathlen);
4146                 *recno = gf->gf_recno;
4147                 *linkno = gf->gf_linkno;
4148         }
4149
4150         free(gf);
4151         return rc;
4152 }
4153
4154 static int fid_from_lma(const char *path, const int fd, lustre_fid *fid)
4155 {
4156         char                     buf[512];
4157         struct lustre_mdt_attrs *lma;
4158         int                      rc;
4159
4160         if (path == NULL)
4161                 rc = fgetxattr(fd, XATTR_NAME_LMA, buf, sizeof(buf));
4162         else
4163                 rc = lgetxattr(path, XATTR_NAME_LMA, buf, sizeof(buf));
4164         if (rc < 0)
4165                 return -errno;
4166         lma = (struct lustre_mdt_attrs *)buf;
4167         fid_le_to_cpu(fid, &lma->lma_self_fid);
4168         return 0;
4169 }
4170
4171 int llapi_fd2fid(const int fd, lustre_fid *fid)
4172 {
4173         int rc;
4174
4175         memset(fid, 0, sizeof(*fid));
4176
4177         rc = ioctl(fd, LL_IOC_PATH2FID, fid) < 0 ? -errno : 0;
4178         if (rc == -EINVAL || rc == -ENOTTY)
4179                 rc = fid_from_lma(NULL, fd, fid);
4180
4181         return rc;
4182 }
4183
4184 int llapi_path2fid(const char *path, lustre_fid *fid)
4185 {
4186         int fd, rc;
4187
4188         memset(fid, 0, sizeof(*fid));
4189         fd = open(path, O_RDONLY | O_NONBLOCK | O_NOFOLLOW);
4190         if (fd < 0) {
4191                 if (errno == ELOOP || errno == ENXIO)
4192                         return fid_from_lma(path, -1, fid);
4193                 return -errno;
4194         }
4195
4196         rc = llapi_fd2fid(fd, fid);
4197         if (rc == -EINVAL || rc == -ENOTTY)
4198                 rc = fid_from_lma(path, -1, fid);
4199
4200         close(fd);
4201         return rc;
4202 }
4203
4204 int llapi_get_connect_flags(const char *mnt, __u64 *flags)
4205 {
4206         DIR *root;
4207         int rc;
4208
4209         root = opendir(mnt);
4210         if (!root) {
4211                 rc = -errno;
4212                 llapi_error(LLAPI_MSG_ERROR, rc, "open %s failed", mnt);
4213                 return rc;
4214         }
4215
4216         rc = ioctl(dirfd(root), LL_IOC_GET_CONNECT_FLAGS, flags);
4217         if (rc < 0) {
4218                 rc = -errno;
4219                 llapi_error(LLAPI_MSG_ERROR, rc,
4220                             "ioctl on %s for getting connect flags failed", mnt);
4221         }
4222         closedir(root);
4223         return rc;
4224 }
4225
4226 int llapi_get_version(char *buffer, int buffer_size,
4227                       char **version)
4228 {
4229         int rc;
4230         int fd;
4231         struct obd_ioctl_data *data = (struct obd_ioctl_data *)buffer;
4232
4233         fd = open(OBD_DEV_PATH, O_RDONLY);
4234         if (fd == -1)
4235                 return -errno;
4236
4237         memset(buffer, 0, buffer_size);
4238         data->ioc_version = OBD_IOCTL_VERSION;
4239         data->ioc_inllen1 = buffer_size - cfs_size_round(sizeof(*data));
4240         data->ioc_inlbuf1 = buffer + cfs_size_round(sizeof(*data));
4241         data->ioc_len = obd_ioctl_packlen(data);
4242
4243         rc = ioctl(fd, OBD_GET_VERSION, buffer);
4244         if (rc == -1) {
4245                 rc = -errno;
4246                 close(fd);
4247                 return rc;
4248         }
4249         close(fd);
4250         *version = data->ioc_bulk;
4251         return 0;
4252 }
4253
4254 /**
4255  * Get a 64-bit value representing the version of file data pointed by fd.
4256  *
4257  * Each write or truncate, flushed on OST, will change this value. You can use
4258  * this value to verify if file data was modified. This only checks the file
4259  * data, not metadata.
4260  *
4261  * \param  flags  0: no flush pages, usually used it the process has already
4262  *                  taken locks;
4263  *                LL_DV_RD_FLUSH: OSTs will take LCK_PR to flush dirty pages
4264  *                  from clients;
4265  *                LL_DV_WR_FLUSH: OSTs will take LCK_PW to flush all caching
4266  *                  pages from clients.
4267  *
4268  * \retval 0 on success.
4269  * \retval -errno on error.
4270  */
4271 int llapi_get_data_version(int fd, __u64 *data_version, __u64 flags)
4272 {
4273         int rc;
4274         struct ioc_data_version idv;
4275
4276         idv.idv_flags = flags;
4277
4278         rc = ioctl(fd, LL_IOC_DATA_VERSION, &idv);
4279         if (rc)
4280                 rc = -errno;
4281         else
4282                 *data_version = idv.idv_version;
4283
4284         return rc;
4285 }
4286
4287 /*
4288  * Create a volatile file and open it for write:
4289  * - file is created as a standard file in the directory
4290  * - file does not appears in directory and directory mtime does not change
4291  * - file is removed at close
4292  * - file modes are rw-------, if user wants another one it must use fchmod()
4293  * \param       directory       Directory where the file is created
4294  * \param       idx             MDT index on which the file is created
4295  * \param       open_flags      Standard open flags
4296  *
4297  * \retval      0 on success.
4298  * \retval      -errno on error.
4299  */
4300 int llapi_create_volatile_idx(char *directory, int idx, int open_flags)
4301 {
4302         char    file_path[PATH_MAX];
4303         char    filename[PATH_MAX];
4304         int     fd;
4305         int     random;
4306         int     rc;
4307
4308         fd = open("/dev/urandom", O_RDONLY);
4309         if (fd < 0) {
4310                 llapi_error(LLAPI_MSG_ERROR, errno,
4311                             "Cannot open /dev/urandom\n");
4312                 return -errno;
4313         }
4314         rc = read(fd, &random, sizeof(random));
4315         close(fd);
4316         if (rc < sizeof(random)) {
4317                 llapi_error(LLAPI_MSG_ERROR, errno,
4318                             "cannot read %zu bytes from /dev/urandom",
4319                             sizeof(random));
4320                 return -errno;
4321         }
4322         if (idx == -1)
4323                 snprintf(filename, sizeof(filename),
4324                          LUSTRE_VOLATILE_HDR"::%.4X", random);
4325         else
4326                 snprintf(filename, sizeof(filename),
4327                          LUSTRE_VOLATILE_HDR":%.4X:%.4X", idx, random);
4328
4329         rc = snprintf(file_path, sizeof(file_path),
4330                       "%s/%s", directory, filename);
4331         if (rc >= sizeof(file_path))
4332                 return -E2BIG;
4333
4334         fd = open(file_path, O_RDWR | O_CREAT | open_flags, S_IRUSR | S_IWUSR);
4335         if (fd < 0) {
4336                 llapi_error(LLAPI_MSG_ERROR, errno,
4337                             "Cannot create volatile file %s in %s\n",
4338                             filename + LUSTRE_VOLATILE_HDR_LEN,
4339                             directory);
4340                 return -errno;
4341         }
4342         return fd;
4343 }
4344
4345 /**
4346  * Swap the layouts between 2 file descriptors
4347  * the 2 files must be open in write
4348  * first fd received the ioctl, second fd is passed as arg
4349  * this is assymetric but avoid use of root path for ioctl
4350  */
4351 int llapi_fswap_layouts(int fd1, int fd2, __u64 dv1, __u64 dv2, __u64 flags)
4352 {
4353         struct lustre_swap_layouts lsl;
4354         int rc;
4355
4356         srandom(time(NULL));
4357         lsl.sl_fd = fd2;
4358         lsl.sl_flags = flags;
4359         lsl.sl_gid = random();
4360         lsl.sl_dv1 = dv1;
4361         lsl.sl_dv2 = dv2;
4362         rc = ioctl(fd1, LL_IOC_LOV_SWAP_LAYOUTS, &lsl);
4363         if (rc)
4364                 rc = -errno;
4365         return rc;
4366 }
4367
4368 /**
4369  * Swap the layouts between 2 files
4370  * the 2 files are open in write
4371  */
4372 int llapi_swap_layouts(const char *path1, const char *path2,
4373                        __u64 dv1, __u64 dv2, __u64 flags)
4374 {
4375         int     fd1, fd2, rc;
4376
4377         fd1 = open(path1, O_WRONLY | O_LOV_DELAY_CREATE);
4378         if (fd1 < 0) {
4379                 rc = -errno;
4380                 llapi_error(LLAPI_MSG_ERROR, rc,
4381                             "error: cannot open '%s' for write", path1);
4382                 goto out;
4383         }
4384
4385         fd2 = open(path2, O_WRONLY | O_LOV_DELAY_CREATE);
4386         if (fd2 < 0) {
4387                 rc = -errno;
4388                 llapi_error(LLAPI_MSG_ERROR, rc,
4389                             "error: cannot open '%s' for write", path2);
4390                 goto out_close;
4391         }
4392
4393         rc = llapi_fswap_layouts(fd1, fd2, dv1, dv2, flags);
4394         if (rc < 0)
4395                 llapi_error(LLAPI_MSG_ERROR, rc,
4396                             "error: cannot swap layout between '%s' and '%s'\n",
4397                             path1, path2);
4398
4399         close(fd2);
4400 out_close:
4401         close(fd1);
4402 out:
4403         return rc;
4404 }