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