Whamcloud - gitweb
f8643c6ebc6b3309bc6401314ccc2fc74235a61c
[fs/lustre-release.git] / lustre / utils / liblustreapi.c
1 /* -*- mode: c; c-basic-offset: 8; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=8:tabstop=8:
3  *
4  * GPL HEADER START
5  *
6  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License version 2 only,
10  * as published by the Free Software Foundation.
11  *
12  * This program is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * General Public License version 2 for more details (a copy is included
16  * in the LICENSE file that accompanied this code).
17  *
18  * You should have received a copy of the GNU General Public License
19  * version 2 along with this program; If not, see
20  * http://www.sun.com/software/products/lustre/docs/GPLv2.pdf
21  *
22  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
23  * CA 95054 USA or visit www.sun.com if you need additional information or
24  * have any questions.
25  *
26  * GPL HEADER END
27  */
28 /*
29  * Copyright  2008 Sun Microsystems, Inc. All rights reserved
30  * Use is subject to license terms.
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 void llapi_err(int level, char *fmt, ...)
133 {
134         va_list args;
135         int tmp_errno = abs(errno);
136
137         if ((level & LLAPI_MSG_MASK) > llapi_msg_level)
138                 return;
139
140         va_start(args, fmt);
141         vfprintf(stderr, fmt, args);
142         va_end(args);
143
144         if (level & LLAPI_MSG_NO_ERRNO)
145                 fprintf(stderr, "\n");
146         else
147                 fprintf(stderr, ": %s (%d)\n", strerror(tmp_errno), tmp_errno);
148 }
149
150 #define llapi_err_noerrno(level, fmt, a...)                             \
151         llapi_err((level) | LLAPI_MSG_NO_ERRNO, fmt, ## a)
152
153 void llapi_printf(int level, char *fmt, ...)
154 {
155         va_list args;
156
157         if ((level & LLAPI_MSG_MASK) > llapi_msg_level)
158                 return;
159
160         va_start(args, fmt);
161         vfprintf(stdout, fmt, args);
162         va_end(args);
163 }
164
165 /**
166  * size_units is unchanged if no specifier used
167  */
168 int parse_size(char *optarg, unsigned long long *size,
169                unsigned long long *size_units, int bytes_spec)
170 {
171         char *end;
172
173         *size = strtoull(optarg, &end, 0);
174
175         if (*end != '\0') {
176                 if ((*end == 'b') && *(end+1) == '\0' &&
177                     (*size & (~0ULL << (64 - 9))) == 0 &&
178                     !bytes_spec) {
179                         *size <<= 9;
180                         *size_units = 1 << 9;
181                 } else if ((*end == 'b') && *(end+1) == '\0' &&
182                            bytes_spec) {
183                         *size_units = 1;
184                 } else if ((*end == 'k' || *end == 'K') &&
185                            *(end+1) == '\0' && (*size &
186                            (~0ULL << (64 - 10))) == 0) {
187                         *size <<= 10;
188                         *size_units = 1 << 10;
189                 } else if ((*end == 'm' || *end == 'M') &&
190                            *(end+1) == '\0' && (*size &
191                            (~0ULL << (64 - 20))) == 0) {
192                         *size <<= 20;
193                         *size_units = 1 << 20;
194                 } else if ((*end == 'g' || *end == 'G') &&
195                            *(end+1) == '\0' && (*size &
196                            (~0ULL << (64 - 30))) == 0) {
197                         *size <<= 30;
198                         *size_units = 1 << 30;
199                 } else if ((*end == 't' || *end == 'T') &&
200                            *(end+1) == '\0' && (*size &
201                            (~0ULL << (64 - 40))) == 0) {
202                         *size <<= 40;
203                         *size_units = 1ULL << 40;
204                 } else if ((*end == 'p' || *end == 'P') &&
205                            *(end+1) == '\0' && (*size &
206                            (~0ULL << (64 - 50))) == 0) {
207                         *size <<= 50;
208                         *size_units = 1ULL << 50;
209                 } else if ((*end == 'e' || *end == 'E') &&
210                            *(end+1) == '\0' && (*size &
211                            (~0ULL << (64 - 60))) == 0) {
212                         *size <<= 60;
213                         *size_units = 1ULL << 60;
214                 } else {
215                         return -1;
216                 }
217         }
218
219         return 0;
220 }
221
222 int llapi_stripe_limit_check(unsigned long long stripe_size, int stripe_offset,
223                              int stripe_count, int stripe_pattern)
224 {
225         int page_size;
226
227         /* 64 KB is the largest common page size I'm aware of (on ia64), but
228          * check the local page size just in case. */
229         page_size = LOV_MIN_STRIPE_SIZE;
230         if (getpagesize() > page_size) {
231                 page_size = getpagesize();
232                 llapi_err_noerrno(LLAPI_MSG_WARN,
233                                   "warning: your page size (%u) is "
234                                   "larger than expected (%u)", page_size,
235                                   LOV_MIN_STRIPE_SIZE);
236         }
237         if (stripe_size < 0 || (stripe_size & (LOV_MIN_STRIPE_SIZE - 1))) {
238                 llapi_err(LLAPI_MSG_ERROR, "error: bad stripe_size %lu, "
239                           "must be an even multiple of %d bytes",
240                           stripe_size, page_size);
241                 return -EINVAL;
242         }
243         if (stripe_offset < -1 || stripe_offset > MAX_OBD_DEVICES) {
244                 errno = -EINVAL;
245                 llapi_err(LLAPI_MSG_ERROR, "error: bad stripe offset %d",
246                           stripe_offset);
247                 return -EINVAL;
248         }
249         if (stripe_count < -1 || stripe_count > LOV_MAX_STRIPE_COUNT) {
250                 errno = -EINVAL;
251                 llapi_err(LLAPI_MSG_ERROR, "error: bad stripe count %d",
252                           stripe_count);
253                 return -EINVAL;
254         }
255         if (stripe_size >= (1ULL << 32)){
256                 errno = -EINVAL;
257                 llapi_err(LLAPI_MSG_ERROR, "warning: stripe size larger than 4G"
258                           " is not currently supported and would wrap");
259                 return -EINVAL;
260         }
261         return 0;
262 }
263
264 static int poolpath(char *fsname, char *pathname, char *pool_pathname);
265
266 int llapi_file_open_pool(const char *name, int flags, int mode,
267                          unsigned long long stripe_size, int stripe_offset,
268                          int stripe_count, int stripe_pattern, char *pool_name)
269 {
270         struct lov_user_md_v3 lum = { 0 };
271         int fd, rc = 0;
272         int isdir = 0;
273         char fsname[MAX_OBD_NAME + 1], *ptr;
274
275         fd = open(name, flags | O_LOV_DELAY_CREATE, mode);
276         if (fd < 0 && errno == EISDIR) {
277                 fd = open(name, O_DIRECTORY | O_RDONLY);
278                 isdir++;
279         }
280
281         if (fd < 0) {
282                 rc = -errno;
283                 llapi_err(LLAPI_MSG_ERROR, "unable to open '%s'", name);
284                 return rc;
285         }
286
287         if ((rc = llapi_stripe_limit_check(stripe_size, stripe_offset,
288                                            stripe_count, stripe_pattern)) != 0){
289                 errno = rc;
290                 goto out;
291         }
292
293         /*  Initialize IOCTL striping pattern structure */
294         lum.lmm_magic = LOV_USER_MAGIC_V3;
295         lum.lmm_pattern = stripe_pattern;
296         lum.lmm_stripe_size = stripe_size;
297         lum.lmm_stripe_count = stripe_count;
298         lum.lmm_stripe_offset = stripe_offset;
299
300         /* in case user give the full pool name <fsname>.<poolname>, skip
301          * the fsname */
302         if (pool_name != NULL) {
303                 ptr = strchr(pool_name, '.');
304                 if (ptr != NULL) {
305                         strncpy(fsname, pool_name, ptr - pool_name);
306                         *ptr = '\0';
307                         /* if fsname matches a filesystem skip it
308                          * if not keep the poolname as is */
309                         if (poolpath(fsname, NULL, NULL) == 0)
310                                 pool_name = ptr + 1;
311                 }
312                 strncpy(lum.lmm_pool_name, pool_name, LOV_MAXPOOLNAME);
313         } else {
314                 /* If no pool is specified at all, use V1 request */
315                 lum.lmm_magic = LOV_USER_MAGIC_V1;
316         }
317
318         if (ioctl(fd, LL_IOC_LOV_SETSTRIPE, &lum)) {
319                 char *errmsg = "stripe already set";
320                 rc = -errno;
321                 if (errno != EEXIST && errno != EALREADY)
322                         errmsg = strerror(errno);
323
324                 llapi_err_noerrno(LLAPI_MSG_ERROR,
325                                   "error on ioctl "LPX64" for '%s' (%d): %s",
326                                   (__u64)LL_IOC_LOV_SETSTRIPE, name, fd,errmsg);
327         }
328 out:
329         if (rc) {
330                 close(fd);
331                 fd = rc;
332         }
333
334         return fd;
335 }
336
337 int llapi_file_open(const char *name, int flags, int mode,
338                     unsigned long long stripe_size, int stripe_offset,
339                     int stripe_count, int stripe_pattern)
340 {
341         return llapi_file_open_pool(name, flags, mode, stripe_size,
342                                     stripe_offset, stripe_count,
343                                     stripe_pattern, NULL);
344 }
345
346 int llapi_file_create(const char *name, unsigned long long stripe_size,
347                       int stripe_offset, int stripe_count, int stripe_pattern)
348 {
349         int fd;
350
351         fd = llapi_file_open_pool(name, O_CREAT | O_WRONLY, 0644, stripe_size,
352                                   stripe_offset, stripe_count, stripe_pattern,
353                                   NULL);
354         if (fd < 0)
355                 return fd;
356
357         close(fd);
358         return 0;
359 }
360
361 int llapi_file_create_pool(const char *name, unsigned long long stripe_size,
362                            int stripe_offset, int stripe_count,
363                            int stripe_pattern, char *pool_name)
364 {
365         int fd;
366
367         fd = llapi_file_open_pool(name, O_CREAT | O_WRONLY, 0644, stripe_size,
368                                   stripe_offset, stripe_count, stripe_pattern,
369                                   pool_name);
370         if (fd < 0)
371                 return fd;
372
373         close(fd);
374         return 0;
375 }
376
377 /*
378  * Find the fsname, the full path, and/or an open fd.
379  * Either the fsname or path must not be NULL
380  */
381 #define WANT_PATH   0x1
382 #define WANT_FSNAME 0x2
383 #define WANT_FD     0x4
384 #define WANT_INDEX  0x8
385 #define WANT_ERROR  0x10
386 static int get_root_path(int want, char *fsname, int *outfd, char *path,
387                          int index)
388 {
389         struct mntent mnt;
390         char buf[PATH_MAX], mntdir[PATH_MAX];
391         char *name = NULL, *ptr;
392         FILE *fp;
393         int idx = 0, len = 0, mntlen, fd;
394         int rc = -ENODEV;
395
396         /* get the mount point */
397         fp = setmntent(MOUNTED, "r");
398         if (fp == NULL) {
399                  llapi_err(LLAPI_MSG_ERROR,
400                            "setmntent(%s) failed: %s:", MOUNTED,
401                            strerror (errno));
402                  return -EIO;
403         }
404         while (1) {
405                 if (getmntent_r(fp, &mnt, buf, sizeof(buf)) == NULL)
406                         break;
407
408                 if (!llapi_is_lustre_mnt(&mnt))
409                         continue;
410
411                 mntlen = strlen(mnt.mnt_dir);
412                 ptr = strrchr(mnt.mnt_fsname, '/');
413                 if (!ptr && !len) {
414                         rc = -EINVAL;
415                         break;
416                 }
417                 ptr++;
418
419                 if ((want & WANT_INDEX) && (idx++ != index))
420                         continue;
421
422                 /* Check the fsname for a match */
423                 if (!(want & WANT_FSNAME) && fsname != NULL &&
424                     (strlen(fsname) > 0) && (strcmp(ptr, fsname) != 0))
425                         continue;
426
427                 /* If the path isn't set return the first one we find */
428                 if (path == NULL || strlen(path) == 0) {
429                         strcpy(mntdir, mnt.mnt_dir);
430                         name = ptr;
431                         rc = 0;
432                         break;
433                 /* Otherwise find the longest matching path */
434                 } else if ((strlen(path) >= mntlen) && (mntlen >= len) &&
435                            (strncmp(mnt.mnt_dir, path, mntlen) == 0)) {
436                         strcpy(mntdir, mnt.mnt_dir);
437                         mntlen = len;
438                         name = ptr;
439                         rc = 0;
440                 }
441         }
442         endmntent(fp);
443
444         /* Found it */
445         if (rc == 0) {
446                 if ((want & WANT_FSNAME) && fsname != NULL)
447                         strcpy(fsname, name);
448                 if ((want & WANT_PATH) && path != NULL)
449                         strcpy(path, mntdir);
450                 if (want & WANT_FD) {
451                         fd = open(mntdir, O_RDONLY | O_DIRECTORY | O_NONBLOCK);
452                         if (fd < 0) {
453                                 perror("open");
454                                 rc = -errno;
455                         } else {
456                                 *outfd = fd;
457                         }
458                 }
459         } else if (want & WANT_ERROR)
460                 llapi_err(LLAPI_MSG_ERROR | LLAPI_MSG_NO_ERRNO,
461                           "can't find fs root for '%s': %d",
462                           (want & WANT_PATH) ? fsname : path, rc);
463         return rc;
464 }
465
466 /*
467  * search lustre mounts
468  *
469  * Calling this function will return to the user the mount point, mntdir, and
470  * the file system name, fsname, if the user passed a buffer to this routine.
471  *
472  * The user inputs are pathname and index. If the pathname is supplied then
473  * the value of the index will be ignored. The pathname will return data if
474  * the pathname is located on a lustre mount. Index is used to pick which
475  * mount point you want in the case of multiple mounted lustre file systems.
476  * See function lfs_osts in lfs.c for a example of the index use.
477  */
478 int llapi_search_mounts(const char *pathname, int index, char *mntdir,
479                         char *fsname)
480 {
481         int want = WANT_PATH, idx = -1;
482
483         if (!pathname) {
484                 want |= WANT_INDEX;
485                 idx = index;
486         } else
487                 strcpy(mntdir, pathname);
488
489         if (fsname)
490                 want |= WANT_FSNAME;
491         return get_root_path(want, fsname, NULL, mntdir, idx);
492 }
493
494 int llapi_search_fsname(const char *pathname, char *fsname)
495 {
496         return get_root_path(WANT_FSNAME | WANT_ERROR, fsname, NULL,
497                              (char *)pathname, -1);
498 }
499
500 /* return the first file matching this pattern */
501 static int first_match(char *pattern, char *buffer)
502 {
503         glob_t glob_info;
504
505         if (glob(pattern, GLOB_BRACE, NULL, &glob_info))
506                 return -ENOENT;
507
508         if (glob_info.gl_pathc < 1) {
509                 globfree(&glob_info);
510                 return -ENOENT;
511         }
512
513         strcpy(buffer, glob_info.gl_pathv[0]);
514
515         globfree(&glob_info);
516         return 0;
517 }
518
519 /*
520  * find the pool directory path under /proc
521  * (can be also used to test if a fsname is known)
522  */
523 static int poolpath(char *fsname, char *pathname, char *pool_pathname)
524 {
525         int rc = 0;
526         char pattern[PATH_MAX + 1];
527         char buffer[PATH_MAX];
528
529         if (fsname == NULL) {
530                 rc = llapi_search_fsname(pathname, buffer);
531                 if (rc != 0)
532                         return rc;
533                 fsname = buffer;
534                 strcpy(pathname, fsname);
535         }
536
537         snprintf(pattern, PATH_MAX, "/proc/fs/lustre/lov/%s-*/pools", fsname);
538         rc = first_match(pattern, buffer);
539         if (rc)
540                 return rc;
541
542         /* in fsname test mode, pool_pathname is NULL */
543         if (pool_pathname != NULL)
544                 strcpy(pool_pathname, buffer);
545
546         return 0;
547 }
548
549 /**
550  * Get the list of pool members.
551  * \param poolname    string of format \<fsname\>.\<poolname\>
552  * \param members     caller-allocated array of char*
553  * \param list_size   size of the members array
554  * \param buffer      caller-allocated buffer for storing OST names
555  * \param buffer_size size of the buffer
556  *
557  * \return number of members retrieved for this pool
558  * \retval -error failure
559  */
560 int llapi_get_poolmembers(const char *poolname, char **members,
561                           int list_size, char *buffer, int buffer_size)
562 {
563         char fsname[PATH_MAX + 1];
564         char *pool, *tmp;
565         char pathname[PATH_MAX + 1];
566         char path[PATH_MAX + 1];
567         char buf[1024];
568         FILE *fd;
569         int rc = 0;
570         int nb_entries = 0;
571         int used = 0;
572
573         /* name is FSNAME.POOLNAME */
574         if (strlen(poolname) > PATH_MAX)
575                 return -EOVERFLOW;
576         strcpy(fsname, poolname);
577         pool = strchr(fsname, '.');
578         if (pool == NULL)
579                 return -EINVAL;
580
581         *pool = '\0';
582         pool++;
583
584         rc = poolpath(fsname, NULL, pathname);
585         if (rc != 0) {
586                 errno = -rc;
587                 llapi_err(LLAPI_MSG_ERROR, "Lustre filesystem '%s' not found",
588                           fsname);
589                 return rc;
590         }
591
592         llapi_printf(LLAPI_MSG_NORMAL, "Pool: %s.%s\n", fsname, pool);
593         sprintf(path, "%s/%s", pathname, pool);
594         if ((fd = fopen(path, "r")) == NULL) {
595                 llapi_err(LLAPI_MSG_ERROR, "Cannot open %s", path);
596                 return -EINVAL;
597         }
598
599         rc = 0;
600         while (fgets(buf, sizeof(buf), fd) != NULL) {
601                 if (nb_entries >= list_size) {
602                         rc = -EOVERFLOW;
603                         break;
604                 }
605                 /* remove '\n' */
606                 if ((tmp = strchr(buf, '\n')) != NULL)
607                         *tmp='\0';
608                 if (used + strlen(buf) + 1 > buffer_size) {
609                         rc = -EOVERFLOW;
610                         break;
611                 }
612
613                 strcpy(buffer + used, buf);
614                 members[nb_entries] = buffer + used;
615                 used += strlen(buf) + 1;
616                 nb_entries++;
617                 rc = nb_entries;
618         }
619
620         fclose(fd);
621         return rc;
622 }
623
624 /**
625  * Get the list of pools in a filesystem.
626  * \param name        filesystem name or path
627  * \param poollist    caller-allocated array of char*
628  * \param list_size   size of the poollist array
629  * \param buffer      caller-allocated buffer for storing pool names
630  * \param buffer_size size of the buffer
631  *
632  * \return number of pools retrieved for this filesystem
633  * \retval -error failure
634  */
635 int llapi_get_poollist(const char *name, char **poollist, int list_size,
636                        char *buffer, int buffer_size)
637 {
638         char fsname[PATH_MAX + 1], rname[PATH_MAX + 1], pathname[PATH_MAX + 1];
639         char *ptr;
640         DIR *dir;
641         struct dirent pool;
642         struct dirent *cookie = NULL;
643         int rc = 0;
644         unsigned int nb_entries = 0;
645         unsigned int used = 0;
646         unsigned int i;
647
648         /* initilize output array */
649         for (i = 0; i < list_size; i++)
650                 poollist[i] = NULL;
651
652         /* is name a pathname ? */
653         ptr = strchr(name, '/');
654         if (ptr != NULL) {
655                 /* only absolute pathname is supported */
656                 if (*name != '/')
657                         return -EINVAL;
658                 if (!realpath(name, rname)) {
659                         rc = -errno;
660                         llapi_err(LLAPI_MSG_ERROR, "invalid path '%s'", name);
661                         return rc;
662                 }
663
664                 rc = poolpath(NULL, rname, pathname);
665                 if (rc != 0) {
666                         errno = -rc;
667                         llapi_err(LLAPI_MSG_ERROR, "'%s' is not"
668                                   " a Lustre filesystem", name);
669                         return rc;
670                 }
671                 strcpy(fsname, rname);
672         } else {
673                 /* name is FSNAME */
674                 strcpy(fsname, name);
675                 rc = poolpath(fsname, NULL, pathname);
676         }
677         if (rc != 0) {
678                 errno = -rc;
679                 llapi_err(LLAPI_MSG_ERROR, "Lustre filesystem '%s' not found",
680                           name);
681                 return rc;
682         }
683
684         llapi_printf(LLAPI_MSG_NORMAL, "Pools from %s:\n", fsname);
685         if ((dir = opendir(pathname)) == NULL) {
686                 llapi_err(LLAPI_MSG_ERROR, "Could not open pool list for '%s'",
687                           name);
688                 return -errno;
689         }
690
691         while(1) {
692                 rc = readdir_r(dir, &pool, &cookie);
693
694                 if (rc != 0) {
695                         llapi_err(LLAPI_MSG_ERROR,
696                                   "Error reading pool list for '%s'", name);
697                         return -errno;
698                 } else if ((rc == 0) && (cookie == NULL))
699                         /* end of directory */
700                         break;
701
702                 /* ignore . and .. */
703                 if (!strcmp(pool.d_name, ".") || !strcmp(pool.d_name, ".."))
704                         continue;
705
706                 /* check output bounds */
707                 if (nb_entries >= list_size)
708                         return -EOVERFLOW;
709
710                 /* +2 for '.' and final '\0' */
711                 if (used + strlen(pool.d_name) + strlen(fsname) + 2
712                     > buffer_size)
713                         return -EOVERFLOW;
714
715                 sprintf(buffer + used, "%s.%s", fsname, pool.d_name);
716                 poollist[nb_entries] = buffer + used;
717                 used += strlen(pool.d_name) + strlen(fsname) + 2;
718                 nb_entries++;
719         }
720
721         closedir(dir);
722         return nb_entries;
723 }
724
725 /* wrapper for lfs.c and obd.c */
726 int llapi_poollist(const char *name)
727 {
728         /* list of pool names (assume that pool count is smaller
729            than OST count) */
730         char *list[FIND_MAX_OSTS];
731         char *buffer;
732         /* fsname-OST0000_UUID < 32 char, 1 per OST */
733         int bufsize = FIND_MAX_OSTS * 32;
734         int i, nb;
735
736         buffer = malloc(bufsize);
737         if (buffer == NULL)
738                 return -ENOMEM;
739
740         if ((name[0] == '/') || (strchr(name, '.') == NULL))
741                 /* name is a path or fsname */
742                 nb = llapi_get_poollist(name, list, FIND_MAX_OSTS, buffer,
743                                         bufsize);
744         else
745                 /* name is a pool name (<fsname>.<poolname>) */
746                 nb = llapi_get_poolmembers(name, list, FIND_MAX_OSTS, buffer,
747                                            bufsize);
748
749         for (i = 0; i < nb; i++)
750                 llapi_printf(LLAPI_MSG_NORMAL, "%s\n", list[i]);
751
752         free(buffer);
753         return (nb < 0 ? nb : 0);
754 }
755
756
757 typedef int (semantic_func_t)(char *path, DIR *parent, DIR *d,
758                               void *data, cfs_dirent_t *de);
759
760 #define MAX_LOV_UUID_COUNT      max(LOV_MAX_STRIPE_COUNT, 1000)
761 #define OBD_NOT_FOUND           (-1)
762
763 static int common_param_init(struct find_param *param)
764 {
765         param->lumlen = lov_mds_md_size(MAX_LOV_UUID_COUNT, LOV_MAGIC_V3);
766         if ((param->lmd = malloc(sizeof(lstat_t) + param->lumlen)) == NULL) {
767                 llapi_err(LLAPI_MSG_ERROR,
768                           "error: allocation of %d bytes for ioctl",
769                           sizeof(lstat_t) + param->lumlen);
770                 return -ENOMEM;
771         }
772
773         param->got_uuids = 0;
774         param->obdindexes = NULL;
775         param->obdindex = OBD_NOT_FOUND;
776         return 0;
777 }
778
779 static void find_param_fini(struct find_param *param)
780 {
781         if (param->obdindexes)
782                 free(param->obdindexes);
783
784         if (param->lmd)
785                 free(param->lmd);
786 }
787
788 int llapi_file_fget_lov_uuid(int fd, struct obd_uuid *lov_name)
789 {
790         int rc = ioctl(fd, OBD_IOC_GETNAME, lov_name);
791         if (rc) {
792                 rc = errno;
793                 llapi_err(LLAPI_MSG_ERROR, "error: can't get lov name.");
794         }
795         return rc;
796 }
797
798 int llapi_file_get_lov_uuid(const char *path, struct obd_uuid *lov_uuid)
799 {
800         int fd, rc;
801
802         fd = open(path, O_RDONLY);
803         if (fd < 0) {
804                 rc = errno;
805                 llapi_err(LLAPI_MSG_ERROR, "error opening %s", path);
806                 return rc;
807         }
808
809         rc = llapi_file_fget_lov_uuid(fd, lov_uuid);
810
811         close(fd);
812
813         return rc;
814 }
815
816 /*
817  * If uuidp is NULL, return the number of available obd uuids.
818  * If uuidp is non-NULL, then it will return the uuids of the obds. If
819  * there are more OSTs then allocated to uuidp, then an error is returned with
820  * the ost_count set to number of available obd uuids.
821  */
822 int llapi_lov_get_uuids(int fd, struct obd_uuid *uuidp, int *ost_count)
823 {
824         struct obd_uuid lov_name;
825         char buf[1024];
826         FILE *fp;
827         int rc = 0, index = 0;
828
829         /* Get the lov name */
830         rc = llapi_file_fget_lov_uuid(fd, &lov_name);
831         if (rc)
832                 return rc;
833
834         /* Now get the ost uuids from /proc */
835         snprintf(buf, sizeof(buf), "/proc/fs/lustre/lov/%s/target_obd",
836                  lov_name.uuid);
837         fp = fopen(buf, "r");
838         if (fp == NULL) {
839                 rc = errno;
840                 llapi_err(LLAPI_MSG_ERROR, "error: opening '%s'", buf);
841                 return rc;
842         }
843
844         while (fgets(buf, sizeof(buf), fp) != NULL) {
845                 if (uuidp && (index < *ost_count)) {
846                         if (sscanf(buf, "%d: %s", &index, uuidp[index].uuid) <2)
847                                 break;
848                 }
849                 index++;
850         }
851
852         fclose(fp);
853
854         if (uuidp && (index >= *ost_count))
855                 return -EOVERFLOW;
856
857         *ost_count = index;
858         return rc;
859 }
860
861 int llapi_get_obd_count(char *mnt, int *count, int is_mdt)
862 {
863         DIR *root;
864         int rc;
865
866         root = opendir(mnt);
867         if (!root) {
868                 llapi_err(LLAPI_MSG_ERROR, "open %s failed", mnt);
869                 return -1;
870         }
871
872         *count = is_mdt;
873         rc = ioctl(dirfd(root), LL_IOC_GETOBDCOUNT, count);
874
875         closedir(root);
876         return rc;
877 }
878
879 /* Check if user specified value matches a real uuid.  Ignore _UUID,
880  * -osc-4ba41334, other trailing gunk in comparison.
881  * @param real_uuid ends in "_UUID"
882  * @param search_uuid may or may not end in "_UUID"
883  */
884 int llapi_uuid_match(char *real_uuid, char *search_uuid)
885 {
886         int cmplen = strlen(real_uuid) - 5;
887
888         if ((strlen(search_uuid) > cmplen) && isxdigit(search_uuid[cmplen])) {
889                 /* OST00000003 doesn't match OST0000 */
890                 llapi_err(LLAPI_MSG_ERROR, "Bad UUID format '%s'", search_uuid);
891                 return 0;
892         }
893
894         return (strncmp(search_uuid, real_uuid, cmplen) == 0);
895 }
896
897 /* Here, param->obduuid points to a single obduuid, the index of which is
898  * returned in param->obdindex */
899 static int setup_obd_uuid(DIR *dir, char *dname, struct find_param *param)
900 {
901         struct obd_uuid lov_uuid;
902         char uuid[sizeof(struct obd_uuid)];
903         char buf[1024];
904         FILE *fp;
905         int rc = 0, index;
906
907         /* Get the lov name */
908         rc = llapi_file_fget_lov_uuid(dirfd(dir), &lov_uuid);
909         if (rc) {
910                 if (errno != ENOTTY) {
911                         rc = errno;
912                         llapi_err(LLAPI_MSG_ERROR,
913                                   "error: can't get lov name: %s", dname);
914                 } else {
915                         rc = 0;
916                 }
917                 return rc;
918         }
919
920         param->got_uuids = 1;
921
922         /* Now get the ost uuids from /proc */
923         snprintf(buf, sizeof(buf), "/proc/fs/lustre/lov/%s/target_obd",
924                  lov_uuid.uuid);
925         fp = fopen(buf, "r");
926         if (fp == NULL) {
927                 rc = errno;
928                 llapi_err(LLAPI_MSG_ERROR, "error: opening '%s'", buf);
929                 return rc;
930         }
931
932         if (!param->obduuid && !param->quiet && !param->obds_printed)
933                 llapi_printf(LLAPI_MSG_NORMAL, "OBDS:\n");
934
935         while (fgets(buf, sizeof(buf), fp) != NULL) {
936                 if (sscanf(buf, "%d: %s", &index, uuid) < 2)
937                         break;
938
939                 if (param->obduuid) {
940                         if (llapi_uuid_match(uuid, param->obduuid->uuid)) {
941                                 param->obdindex = index;
942                                 break;
943                         }
944                 } else if (!param->quiet && !param->obds_printed) {
945                         /* Print everything */
946                         llapi_printf(LLAPI_MSG_NORMAL, "%s", buf);
947                 }
948         }
949         param->obds_printed = 1;
950
951         fclose(fp);
952
953         if (!param->quiet && param->obduuid &&
954             (param->obdindex == OBD_NOT_FOUND)) {
955                 llapi_err_noerrno(LLAPI_MSG_ERROR,
956                                   "error: %s: unknown obduuid: %s",
957                                   __FUNCTION__, param->obduuid->uuid);
958                 rc = -EINVAL;
959         }
960
961         return (rc);
962 }
963
964 /* In this case, param->obduuid will be an array of obduuids and
965  * obd index for all these obduuids will be returned in
966  * param->obdindexes */
967 static int setup_obd_indexes(DIR *dir, struct find_param *param)
968 {
969         struct obd_uuid *uuids = NULL;
970         int obdcount = INIT_ALLOC_NUM_OSTS;
971         int ret, obd_valid = 0, obdnum, i;
972
973         uuids = (struct obd_uuid *)malloc(INIT_ALLOC_NUM_OSTS *
974                                           sizeof(struct obd_uuid));
975         if (uuids == NULL)
976                 return -ENOMEM;
977
978 retry_get_uuids:
979         ret = llapi_lov_get_uuids(dirfd(dir), uuids,
980                                   &obdcount);
981         if (ret) {
982                 struct obd_uuid *uuids_temp;
983
984                 if (ret == -EOVERFLOW) {
985                         uuids_temp = realloc(uuids, obdcount *
986                                              sizeof(struct obd_uuid));
987                         if (uuids_temp != NULL)
988                                 goto retry_get_uuids;
989                         else
990                                 ret = -ENOMEM;
991                 }
992
993                 llapi_err(LLAPI_MSG_ERROR, "get ost uuid failed");
994                 return ret;
995         }
996
997         param->obdindexes = malloc(param->num_obds * sizeof(param->obdindex));
998         if (param->obdindexes == NULL)
999                 return -ENOMEM;
1000
1001         for (obdnum = 0; obdnum < param->num_obds; obdnum++) {
1002                 for (i = 0; i < obdcount; i++) {
1003                         if (llapi_uuid_match(uuids[i].uuid,
1004                                              param->obduuid[obdnum].uuid)) {
1005                                 param->obdindexes[obdnum] = i;
1006                                 obd_valid++;
1007                                 break;
1008                         }
1009                 }
1010                 if (i >= obdcount) {
1011                         param->obdindexes[obdnum] = OBD_NOT_FOUND;
1012                         llapi_err_noerrno(LLAPI_MSG_ERROR,
1013                                           "error: %s: unknown obduuid: %s",
1014                                           __FUNCTION__,
1015                                           param->obduuid[obdnum].uuid);
1016                         ret = -EINVAL;
1017                 }
1018         }
1019
1020         if (obd_valid == 0)
1021                 param->obdindex = OBD_NOT_FOUND;
1022         else
1023                 param->obdindex = obd_valid;
1024
1025         param->got_uuids = 1;
1026
1027         return ret;
1028 }
1029
1030 static void lov_dump_user_lmm_header(struct lov_user_md *lum, char *path,
1031                                      int is_dir, int verbose, int quiet,
1032                                      char *pool_name)
1033 {
1034         char *prefix = is_dir ? "" : "lmm_";
1035         char nl = is_dir ? ' ' : '\n';
1036
1037         if (verbose && path)
1038                 llapi_printf(LLAPI_MSG_NORMAL, "%s\n", path);
1039
1040         if ((verbose & VERBOSE_DETAIL) && !is_dir) {
1041                 llapi_printf(LLAPI_MSG_NORMAL, "lmm_magic:          0x%08X\n",
1042                              lum->lmm_magic);
1043                 llapi_printf(LLAPI_MSG_NORMAL, "lmm_object_gr:      "LPX64"\n",
1044                              lum->lmm_object_gr);
1045                 llapi_printf(LLAPI_MSG_NORMAL, "lmm_object_id:      "LPX64"\n",
1046                              lum->lmm_object_id);
1047         }
1048
1049         if (verbose & VERBOSE_COUNT) {
1050                 if (!quiet)
1051                         llapi_printf(LLAPI_MSG_NORMAL, "%sstripe_count:   ",
1052                                      prefix);
1053                 llapi_printf(LLAPI_MSG_NORMAL, "%hd%c",
1054                              (__s16)lum->lmm_stripe_count, nl);
1055         }
1056
1057         if (verbose & VERBOSE_SIZE) {
1058                 if (!quiet)
1059                         llapi_printf(LLAPI_MSG_NORMAL, "%sstripe_size:    ",
1060                                      prefix);
1061                 llapi_printf(LLAPI_MSG_NORMAL, "%u%c", lum->lmm_stripe_size,
1062                              nl);
1063         }
1064
1065         if ((verbose & VERBOSE_DETAIL) && !is_dir) {
1066                 llapi_printf(LLAPI_MSG_NORMAL, "lmm_stripe_pattern: %x%c",
1067                              lum->lmm_pattern, nl);
1068         }
1069
1070         if (verbose & VERBOSE_OFFSET) {
1071                 if (!quiet)
1072                         llapi_printf(LLAPI_MSG_NORMAL, "%sstripe_offset:   ",
1073                                      prefix);
1074                 llapi_printf(LLAPI_MSG_NORMAL, "%u%c",
1075                              lum->lmm_objects[0].l_ost_idx, nl);
1076         }
1077
1078         if ((verbose & VERBOSE_POOL) && (pool_name != NULL))
1079                 llapi_printf(LLAPI_MSG_NORMAL, "pool: %s%c", pool_name, nl);
1080
1081         if (is_dir)
1082                 llapi_printf(LLAPI_MSG_NORMAL, "\n");
1083 }
1084
1085 void lov_dump_user_lmm_v1v3(struct lov_user_md *lum, char *pool_name,
1086                             struct lov_user_ost_data_v1 *objects,
1087                             char *path, int is_dir,
1088                             int obdindex, int quiet, int header, int body)
1089 {
1090         int i, obdstripe = 0;
1091
1092         if (obdindex != OBD_NOT_FOUND) {
1093                 for (i = 0; !is_dir && i < lum->lmm_stripe_count; i++) {
1094                         if (obdindex == objects[i].l_ost_idx) {
1095                                 llapi_printf(LLAPI_MSG_NORMAL, "%s\n", path);
1096                                 obdstripe = 1;
1097                                 break;
1098                         }
1099                 }
1100         } else {
1101                 if (!quiet)
1102                         llapi_printf(LLAPI_MSG_NORMAL, "%s\n", path);
1103                 obdstripe = 1;
1104         }
1105
1106         /* if it's a directory */
1107         if (is_dir) {
1108                 if (obdstripe == 1) {
1109                         if (lum->lmm_object_gr == LOV_OBJECT_GROUP_DEFAULT) {
1110                                 llapi_printf(LLAPI_MSG_NORMAL, "(Default) ");
1111                                 lum->lmm_object_gr = LOV_OBJECT_GROUP_CLEAR;
1112                         }
1113                         /* maintain original behavior */
1114                         if (!header)
1115                                 header |= VERBOSE_ALL;
1116                         lov_dump_user_lmm_header(lum, path, is_dir, header,
1117                                                  quiet, pool_name);
1118                 }
1119                 return;
1120         }
1121
1122         if (header && (obdstripe == 1))
1123                 lov_dump_user_lmm_header(lum, NULL, is_dir, header, quiet,
1124                                          pool_name);
1125
1126         if (body) {
1127                 if ((!quiet) && (obdstripe == 1))
1128                         llapi_printf(LLAPI_MSG_NORMAL,
1129                                      "\tobdidx\t\t objid\t\tobjid\t\t group\n");
1130
1131                 for (i = 0; i < lum->lmm_stripe_count; i++) {
1132                         int idx = objects[i].l_ost_idx;
1133                         long long oid = objects[i].l_object_id;
1134                         long long gr = objects[i].l_object_gr;
1135                         if ((obdindex == OBD_NOT_FOUND) || (obdindex == idx))
1136                                 llapi_printf(LLAPI_MSG_NORMAL,
1137                                            "\t%6u\t%14llu\t%#13llx\t%14llu%s\n",
1138                                            idx, oid, oid, gr,
1139                                            obdindex == idx ? " *" : "");
1140                 }
1141                 llapi_printf(LLAPI_MSG_NORMAL, "\n");
1142         }
1143 }
1144
1145 void lov_dump_user_lmm_join(struct lov_user_md_v1 *lum, char *path,
1146                             int is_dir, int obdindex, int quiet,
1147                             int header, int body)
1148 {
1149         struct lov_user_md_join *lumj = (struct lov_user_md_join *)lum;
1150         int i, obdstripe = 0;
1151
1152         if (obdindex != OBD_NOT_FOUND) {
1153                 for (i = 0; i < lumj->lmm_stripe_count; i++) {
1154                         if (obdindex == lumj->lmm_objects[i].l_ost_idx) {
1155                                 llapi_printf(LLAPI_MSG_NORMAL, "%s\n", path);
1156                                 obdstripe = 1;
1157                                 break;
1158                         }
1159                 }
1160         } else {
1161                 if (!quiet)
1162                         llapi_printf(LLAPI_MSG_NORMAL, "%s\n", path);
1163                 obdstripe = 1;
1164         }
1165
1166         if (header && obdstripe == 1) {
1167                 lov_dump_user_lmm_header(lum, NULL, 0, header, quiet, NULL);
1168
1169                 llapi_printf(LLAPI_MSG_NORMAL, "lmm_extent_count:   %x\n",
1170                              lumj->lmm_extent_count);
1171         }
1172
1173         if (body) {
1174                 unsigned long long start = -1, end = 0;
1175                 if (!quiet && obdstripe == 1)
1176                         llapi_printf(LLAPI_MSG_NORMAL,
1177                                      "joined\tobdidx\t\t objid\t\tobjid\t\t "
1178                                      "group\t\tstart\t\tend\n");
1179                 for (i = 0; i < lumj->lmm_stripe_count; i++) {
1180                         int idx = lumj->lmm_objects[i].l_ost_idx;
1181                         long long oid = lumj->lmm_objects[i].l_object_id;
1182                         long long gr = lumj->lmm_objects[i].l_object_gr;
1183                         if (obdindex == OBD_NOT_FOUND || obdindex == idx)
1184                                 llapi_printf(LLAPI_MSG_NORMAL,
1185                                              "\t%6u\t%14llu\t%#13llx\t%14llu%s",
1186                                              idx, oid, oid, gr,
1187                                              obdindex == idx ? " *" : "");
1188                         if (start != lumj->lmm_objects[i].l_extent_start ||
1189                             end != lumj->lmm_objects[i].l_extent_end) {
1190                                 start = lumj->lmm_objects[i].l_extent_start;
1191                                 llapi_printf(LLAPI_MSG_NORMAL,"\t%14llu",start);
1192                                 end = lumj->lmm_objects[i].l_extent_end;
1193                                 if (end == (unsigned long long)-1)
1194                                         llapi_printf(LLAPI_MSG_NORMAL,
1195                                                      "\t\tEOF\n");
1196                                 else
1197                                         llapi_printf(LLAPI_MSG_NORMAL,
1198                                                      "\t\t%llu\n", end);
1199                         } else {
1200                                 llapi_printf(LLAPI_MSG_NORMAL, "\t\t\t\t\n");
1201                         }
1202                 }
1203                 llapi_printf(LLAPI_MSG_NORMAL, "\n");
1204         }
1205 }
1206
1207 void llapi_lov_dump_user_lmm(struct find_param *param,
1208                              char *path, int is_dir)
1209 {
1210         switch(*(__u32 *)&param->lmd->lmd_lmm) { /* lum->lmm_magic */
1211         case LOV_USER_MAGIC_V1:
1212                 lov_dump_user_lmm_v1v3(&param->lmd->lmd_lmm, NULL,
1213                                        param->lmd->lmd_lmm.lmm_objects,
1214                                        path, is_dir,
1215                                        param->obdindex, param->quiet,
1216                                        param->verbose,
1217                                        (param->verbose || !param->obduuid));
1218                 break;
1219         case LOV_USER_MAGIC_JOIN:
1220                 lov_dump_user_lmm_join(&param->lmd->lmd_lmm, path, is_dir,
1221                                        param->obdindex, param->quiet,
1222                                        param->verbose,
1223                                        (param->verbose || !param->obduuid));
1224                 break;
1225         case LOV_USER_MAGIC_V3: {
1226                 char pool_name[LOV_MAXPOOLNAME + 1];
1227                 struct lov_user_ost_data_v1 *objects;
1228                 struct lov_user_md_v3 *lmmv3 = (void *)&param->lmd->lmd_lmm;
1229
1230                 strncpy(pool_name, lmmv3->lmm_pool_name, LOV_MAXPOOLNAME);
1231                 pool_name[LOV_MAXPOOLNAME] = '\0';
1232                 objects = lmmv3->lmm_objects;
1233                 lov_dump_user_lmm_v1v3(&param->lmd->lmd_lmm, pool_name,
1234                                        objects, path, is_dir,
1235                                        param->obdindex, param->quiet,
1236                                        param->verbose,
1237                                        (param->verbose || !param->obduuid));
1238                 break;
1239         }
1240         default:
1241                 llapi_printf(LLAPI_MSG_NORMAL, "unknown lmm_magic:  %#x "
1242                              "(expecting one of %#x %#x %#x)\n",
1243                              *(__u32 *)&param->lmd->lmd_lmm,
1244                              LOV_USER_MAGIC_V1, LOV_USER_MAGIC_JOIN,
1245                              LOV_USER_MAGIC_V3);
1246                 return;
1247         }
1248 }
1249
1250 int llapi_file_get_stripe(const char *path, struct lov_user_md *lum)
1251 {
1252         const char *fname;
1253         char *dname;
1254         int fd, rc = 0;
1255
1256         fname = strrchr(path, '/');
1257
1258         /* It should be a file (or other non-directory) */
1259         if (fname == NULL) {
1260                 dname = (char *)malloc(2);
1261                 if (dname == NULL)
1262                         return ENOMEM;
1263                 strcpy(dname, ".");
1264                 fname = (char *)path;
1265         } else {
1266                 dname = (char *)malloc(fname - path + 1);
1267                 if (dname == NULL)
1268                         return ENOMEM;
1269                 strncpy(dname, path, fname - path);
1270                 dname[fname - path] = '\0';
1271                 fname++;
1272         }
1273
1274         if ((fd = open(dname, O_RDONLY)) == -1) {
1275                 rc = errno;
1276                 free(dname);
1277                 return rc;
1278         }
1279
1280         strcpy((char *)lum, fname);
1281         if (ioctl(fd, IOC_MDC_GETFILESTRIPE, (void *)lum) == -1)
1282                 rc = errno;
1283
1284         if (close(fd) == -1 && rc == 0)
1285                 rc = errno;
1286
1287         free(dname);
1288
1289         return rc;
1290 }
1291
1292 int llapi_file_lookup(int dirfd, const char *name)
1293 {
1294         struct obd_ioctl_data data = { 0 };
1295         char rawbuf[8192];
1296         char *buf = rawbuf;
1297         int rc;
1298
1299         if (dirfd < 0 || name == NULL)
1300                 return -EINVAL;
1301
1302         data.ioc_version = OBD_IOCTL_VERSION;
1303         data.ioc_len = sizeof(data);
1304         data.ioc_inlbuf1 = (char *)name;
1305         data.ioc_inllen1 = strlen(name) + 1;
1306
1307         rc = obd_ioctl_pack(&data, &buf, sizeof(rawbuf));
1308         if (rc) {
1309                 llapi_err(LLAPI_MSG_ERROR,
1310                           "error: IOC_MDC_LOOKUP pack failed for '%s': rc %d",
1311                           name, rc);
1312                 return rc;
1313         }
1314
1315         return ioctl(dirfd, IOC_MDC_LOOKUP, buf);
1316 }
1317
1318 int llapi_mds_getfileinfo(char *path, DIR *parent,
1319                           struct lov_user_mds_data *lmd)
1320 {
1321         lstat_t *st = &lmd->lmd_st;
1322         char *fname = strrchr(path, '/');
1323         int ret = 0;
1324
1325         if (parent == NULL)
1326                 return -EINVAL;
1327
1328         fname = (fname == NULL ? path : fname + 1);
1329         /* retrieve needed file info */
1330         strncpy((char *)lmd, fname,
1331                 lov_mds_md_size(MAX_LOV_UUID_COUNT, LOV_MAGIC));
1332         ret = ioctl(dirfd(parent), IOC_MDC_GETFILEINFO, (void *)lmd);
1333
1334         if (ret) {
1335                 if (errno == ENOTTY) {
1336                         /* ioctl is not supported, it is not a lustre fs.
1337                          * Do the regular lstat(2) instead. */
1338                         ret = lstat_f(path, st);
1339                         if (ret) {
1340                                 llapi_err(LLAPI_MSG_ERROR,
1341                                           "error: %s: lstat failed for %s",
1342                                           __FUNCTION__, path);
1343                                 return ret;
1344                         }
1345                 } else if (errno == ENOENT) {
1346                         llapi_err(LLAPI_MSG_WARN,
1347                                   "warning: %s: %s does not exist",
1348                                   __FUNCTION__, path);
1349                         return -ENOENT;
1350                 } else {
1351                         llapi_err(LLAPI_MSG_ERROR,
1352                                  "error: %s: IOC_MDC_GETFILEINFO failed for %s",
1353                                  __FUNCTION__, path);
1354                         return ret;
1355                 }
1356         }
1357
1358         return 0;
1359 }
1360
1361 static DIR *opendir_parent(char *path)
1362 {
1363         DIR *parent;
1364         char *fname;
1365         char c;
1366
1367         fname = strrchr(path, '/');
1368         if (fname == NULL)
1369                 return opendir(".");
1370
1371         c = fname[1];
1372         fname[1] = '\0';
1373         parent = opendir(path);
1374         fname[1] = c;
1375         return parent;
1376 }
1377
1378 static int llapi_semantic_traverse(char *path, int size, DIR *parent,
1379                                    semantic_func_t sem_init,
1380                                    semantic_func_t sem_fini, void *data,
1381                                    cfs_dirent_t *de)
1382 {
1383         cfs_dirent_t *dent;
1384         int len, ret;
1385         DIR *d, *p = NULL;
1386
1387         ret = 0;
1388         len = strlen(path);
1389
1390         d = opendir(path);
1391         if (!d && errno != ENOTDIR) {
1392                 llapi_err(LLAPI_MSG_ERROR, "%s: Failed to open '%s'",
1393                           __FUNCTION__, path);
1394                 return -EINVAL;
1395         } else if (!d && !parent) {
1396                 /* ENOTDIR. Open the parent dir. */
1397                 p = opendir_parent(path);
1398                 if (!p)
1399                         GOTO(out, ret = -EINVAL);
1400         }
1401
1402         if (sem_init && (ret = sem_init(path, parent ?: p, d, data, de)))
1403                 goto err;
1404
1405         if (!d)
1406                 GOTO(out, ret = 0);
1407
1408         while ((dent = readdir64(d)) != NULL) {
1409                 ((struct find_param *)data)->have_fileinfo = 0;
1410
1411                 if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
1412                         continue;
1413
1414                 /* Don't traverse .lustre directory */
1415                 if (!(strcmp(dent->d_name, dot_lustre_name)))
1416                         continue;
1417
1418                 path[len] = 0;
1419                 if ((len + dent->d_reclen + 2) > size) {
1420                         llapi_err(LLAPI_MSG_ERROR,
1421                                   "error: %s: string buffer is too small",
1422                                   __FUNCTION__);
1423                         break;
1424                 }
1425                 strcat(path, "/");
1426                 strcat(path, dent->d_name);
1427
1428                 if (dent->d_type == DT_UNKNOWN) {
1429                         lstat_t *st = &((struct find_param *)data)->lmd->lmd_st;
1430
1431                         ret = llapi_mds_getfileinfo(path, d,
1432                                              ((struct find_param *)data)->lmd);
1433                         if (ret == 0) {
1434                                 ((struct find_param *)data)->have_fileinfo = 1;
1435                                 dent->d_type =
1436                                         llapi_filetype_dir_table[st->st_mode &
1437                                                                  S_IFMT];
1438                         }
1439                         if (ret == -ENOENT)
1440                                 continue;
1441                 }
1442
1443                 switch (dent->d_type) {
1444                 case DT_UNKNOWN:
1445                         llapi_err(LLAPI_MSG_ERROR,
1446                                   "error: %s: '%s' is UNKNOWN type %d",
1447                                   __FUNCTION__, dent->d_name, dent->d_type);
1448                         break;
1449                 case DT_DIR:
1450                         ret = llapi_semantic_traverse(path, size, d, sem_init,
1451                                                       sem_fini, data, dent);
1452                         if (ret < 0)
1453                                 goto out;
1454                         break;
1455                 default:
1456                         ret = 0;
1457                         if (sem_init) {
1458                                 ret = sem_init(path, d, NULL, data, dent);
1459                                 if (ret < 0)
1460                                         goto out;
1461                         }
1462                         if (sem_fini && ret == 0)
1463                                 sem_fini(path, d, NULL, data, dent);
1464                 }
1465         }
1466
1467 out:
1468         path[len] = 0;
1469
1470         if (sem_fini)
1471                 sem_fini(path, parent, d, data, de);
1472 err:
1473         if (d)
1474                 closedir(d);
1475         if (p)
1476                 closedir(p);
1477         return ret;
1478 }
1479
1480 /* Check if the value matches 1 of the given criteria (e.g. --atime +/-N).
1481  * @mds indicates if this is MDS timestamps and there are attributes on OSTs.
1482  *
1483  * The result is -1 if it does not match, 0 if not yet clear, 1 if matches.
1484  * The table below gives the answers for the specified parameters (value and
1485  * sign), 1st column is the answer for the MDS value, the 2nd is for the OST:
1486  * --------------------------------------
1487  * 1 | file > limit; sign > 0 | -1 / -1 |
1488  * 2 | file = limit; sign > 0 |  ? /  1 |
1489  * 3 | file < limit; sign > 0 |  ? /  1 |
1490  * 4 | file > limit; sign = 0 | -1 / -1 |
1491  * 5 | file = limit; sign = 0 |  ? /  1 |  <- (see the Note below)
1492  * 6 | file < limit; sign = 0 |  ? / -1 |
1493  * 7 | file > limit; sign < 0 |  1 /  1 |
1494  * 8 | file = limit; sign < 0 |  ? / -1 |
1495  * 9 | file < limit; sign < 0 |  ? / -1 |
1496  * --------------------------------------
1497  * Note: 5th actually means that the value is within the interval
1498  * (limit - margin, limit]. */
1499 static int find_value_cmp(unsigned int file, unsigned int limit, int sign,
1500                           unsigned long long margin, int mds)
1501 {
1502         if (sign > 0) {
1503                 if (file < limit)
1504                         return mds ? 0 : 1;
1505         }
1506
1507         if (sign == 0) {
1508                 if (file <= limit && file + margin > limit)
1509                         return mds ? 0 : 1;
1510                 if (file + margin <= limit)
1511                         return mds ? 0 : -1;
1512         }
1513
1514         if (sign < 0) {
1515                 if (file > limit)
1516                         return 1;
1517                 if (mds)
1518                         return 0;
1519         }
1520
1521         return -1;
1522 }
1523
1524 /* Check if the file time matches all the given criteria (e.g. --atime +/-N).
1525  * Return -1 or 1 if file timestamp does not or does match the given criteria
1526  * correspondingly. Return 0 if the MDS time is being checked and there are
1527  * attributes on OSTs and it is not yet clear if the timespamp matches.
1528  *
1529  * If 0 is returned, we need to do another RPC to the OSTs to obtain the
1530  * updated timestamps. */
1531 static int find_time_check(lstat_t *st, struct find_param *param, int mds)
1532 {
1533         int ret;
1534         int rc = 0;
1535
1536         /* Check if file is accepted. */
1537         if (param->atime) {
1538                 ret = find_value_cmp(st->st_atime, param->atime,
1539                                      param->asign, 24 * 60 * 60, mds);
1540                 if (ret < 0)
1541                         return ret;
1542                 rc = ret;
1543         }
1544
1545         if (param->mtime) {
1546                 ret = find_value_cmp(st->st_mtime, param->mtime,
1547                                      param->msign, 24 * 60 * 60, mds);
1548                 if (ret < 0)
1549                         return ret;
1550
1551                 /* If the previous check matches, but this one is not yet clear,
1552                  * we should return 0 to do an RPC on OSTs. */
1553                 if (rc == 1)
1554                         rc = ret;
1555         }
1556
1557         if (param->ctime) {
1558                 ret = find_value_cmp(st->st_ctime, param->ctime,
1559                                      param->csign, 24 * 60 * 60, mds);
1560                 if (ret < 0)
1561                         return ret;
1562
1563                 /* If the previous check matches, but this one is not yet clear,
1564                  * we should return 0 to do an RPC on OSTs. */
1565                 if (rc == 1)
1566                         rc = ret;
1567         }
1568
1569         return rc;
1570 }
1571
1572 static int cb_find_init(char *path, DIR *parent, DIR *dir,
1573                         void *data, cfs_dirent_t *de)
1574 {
1575         struct find_param *param = (struct find_param *)data;
1576         int decision = 1; /* 1 is accepted; -1 is rejected. */
1577         lstat_t *st = &param->lmd->lmd_st;
1578         int lustre_fs = 1;
1579         int checked_type = 0;
1580         int ret = 0;
1581
1582         LASSERT(parent != NULL || dir != NULL);
1583
1584         param->lmd->lmd_lmm.lmm_stripe_count = 0;
1585
1586         /* If a regular expression is presented, make the initial decision */
1587         if (param->pattern != NULL) {
1588                 char *fname = strrchr(path, '/');
1589                 fname = (fname == NULL ? path : fname + 1);
1590                 ret = fnmatch(param->pattern, fname, 0);
1591                 if ((ret == FNM_NOMATCH && !param->exclude_pattern) ||
1592                     (ret == 0 && param->exclude_pattern))
1593                         goto decided;
1594         }
1595
1596         /* See if we can check the file type from the dirent. */
1597         if (param->type && de != NULL && de->d_type != DT_UNKNOWN &&
1598             de->d_type < DT_MAX) {
1599                 checked_type = 1;
1600                 if (llapi_dir_filetype_table[de->d_type] == param->type) {
1601                         if (param->exclude_type)
1602                                 goto decided;
1603                 } else {
1604                         if (!param->exclude_type)
1605                                 goto decided;
1606                 }
1607         }
1608
1609
1610         /* If a time or OST should be checked, the decision is not taken yet. */
1611         if (param->atime || param->ctime || param->mtime || param->obduuid ||
1612             param->size)
1613                 decision = 0;
1614
1615         ret = 0;
1616         /* Request MDS for the stat info. */
1617         if (param->have_fileinfo == 0) {
1618                 if (dir) {
1619                         /* retrieve needed file info */
1620                         ret = ioctl(dirfd(dir), LL_IOC_MDC_GETINFO,
1621                                     (void *)param->lmd);
1622                 } else {
1623                         char *fname = strrchr(path, '/');
1624                         fname = (fname == NULL ? path : fname + 1);
1625
1626                         /* retrieve needed file info */
1627                         strncpy((char *)param->lmd, fname, param->lumlen);
1628                         ret = ioctl(dirfd(parent), IOC_MDC_GETFILEINFO,
1629                                    (void *)param->lmd);
1630                 }
1631         }
1632
1633         if (ret) {
1634                 if (errno == ENOTTY) {
1635                         /* ioctl is not supported, it is not a lustre fs.
1636                          * Do the regular lstat(2) instead. */
1637                         lustre_fs = 0;
1638                         ret = lstat_f(path, st);
1639                         if (ret) {
1640                                 llapi_err(LLAPI_MSG_ERROR,
1641                                           "error: %s: lstat failed for %s",
1642                                           __FUNCTION__, path);
1643                                 return ret;
1644                         }
1645                 } else if (errno == ENOENT) {
1646                         llapi_err(LLAPI_MSG_WARN,
1647                                   "warning: %s: %s does not exist",
1648                                   __FUNCTION__, path);
1649                         goto decided;
1650                 } else {
1651                         llapi_err(LLAPI_MSG_ERROR,"error: %s: %s failed for %s",
1652                                   __FUNCTION__, dir ? "LL_IOC_MDC_GETINFO" :
1653                                   "IOC_MDC_GETFILEINFO", path);
1654                         return ret;
1655                 }
1656         }
1657
1658         if (param->type && !checked_type) {
1659                 if ((st->st_mode & S_IFMT) == param->type) {
1660                         if (param->exclude_type)
1661                                 goto decided;
1662                 } else {
1663                         if (!param->exclude_type)
1664                                 goto decided;
1665                 }
1666         }
1667
1668         /* Prepare odb. */
1669         if (param->obduuid) {
1670                 if (lustre_fs && param->got_uuids &&
1671                     param->st_dev != st->st_dev) {
1672                         /* A lustre/lustre mount point is crossed. */
1673                         param->got_uuids = 0;
1674                         param->obds_printed = 0;
1675                         param->obdindex = OBD_NOT_FOUND;
1676                 }
1677
1678                 if (lustre_fs && !param->got_uuids) {
1679                         ret = setup_obd_indexes(dir ? dir : parent, param);
1680                         if (ret)
1681                                 return ret;
1682
1683                         param->st_dev = st->st_dev;
1684                 } else if (!lustre_fs && param->got_uuids) {
1685                         /* A lustre/non-lustre mount point is crossed. */
1686                         param->got_uuids = 0;
1687                         param->obdindex = OBD_NOT_FOUND;
1688                 }
1689         }
1690
1691         /* If an OBD UUID is specified but no one matches, skip this file. */
1692         if (param->obduuid && param->obdindex == OBD_NOT_FOUND)
1693                 goto decided;
1694
1695         /* If a OST UUID is given, and some OST matches, check it here. */
1696         if (param->obdindex != OBD_NOT_FOUND) {
1697                 if (!S_ISREG(st->st_mode))
1698                         goto decided;
1699
1700                 /* Only those files should be accepted, which have a
1701                  * stripe on the specified OST. */
1702                 if (!param->lmd->lmd_lmm.lmm_stripe_count) {
1703                         goto decided;
1704                 } else {
1705                         int i, j;
1706                         struct lov_user_ost_data_v1 *lmm_objects;
1707
1708                         if (param->lmd->lmd_lmm.lmm_magic ==
1709                             LOV_USER_MAGIC_V3) {
1710                                 struct lov_user_md_v3 *lmmv3 =
1711                                         (void *)&param->lmd->lmd_lmm;
1712
1713                                 lmm_objects = lmmv3->lmm_objects;
1714                         } else {
1715                                 lmm_objects = param->lmd->lmd_lmm.lmm_objects;
1716                         }
1717
1718                         for (i = 0;
1719                              i < param->lmd->lmd_lmm.lmm_stripe_count; i++) {
1720                                 for (j = 0; j < param->num_obds; j++) {
1721                                         if (param->obdindexes[j] ==
1722                                             lmm_objects[i].l_ost_idx)
1723                                                 goto obd_matches;
1724                                 }
1725                         }
1726
1727                         if (i == param->lmd->lmd_lmm.lmm_stripe_count)
1728                                 goto decided;
1729                 }
1730         }
1731
1732         if (param->check_uid) {
1733                 if (st->st_uid == param->uid) {
1734                         if (param->exclude_uid)
1735                                 goto decided;
1736                 } else {
1737                         if (!param->exclude_uid)
1738                                 goto decided;
1739                 }
1740         }
1741
1742         if (param->check_gid) {
1743                 if (st->st_gid == param->gid) {
1744                         if (param->exclude_gid)
1745                                 goto decided;
1746                 } else {
1747                         if (!param->exclude_gid)
1748                                 goto decided;
1749                 }
1750         }
1751
1752         if (param->check_pool) {
1753                 struct lov_user_md_v3 *lmmv3 = (void *)&param->lmd->lmd_lmm;
1754
1755                 /* empty requested pool is taken as no pool search => V1 */
1756                 if (((param->lmd->lmd_lmm.lmm_magic == LOV_USER_MAGIC_V1) &&
1757                      (param->poolname[0] == '\0')) ||
1758                     ((param->lmd->lmd_lmm.lmm_magic == LOV_USER_MAGIC_V3) &&
1759                      (strncmp(lmmv3->lmm_pool_name,
1760                               param->poolname, LOV_MAXPOOLNAME) == 0)) ||
1761                     ((param->lmd->lmd_lmm.lmm_magic == LOV_USER_MAGIC_V3) &&
1762                      (strcmp(param->poolname, "*") == 0))) {
1763                         if (param->exclude_pool)
1764                                 goto decided;
1765                 } else {
1766                         if (!param->exclude_pool)
1767                                 goto decided;
1768                 }
1769         }
1770
1771         /* Check the time on mds. */
1772         if (!decision) {
1773                 int for_mds;
1774
1775                 for_mds = lustre_fs ? (S_ISREG(st->st_mode) &&
1776                                        param->lmd->lmd_lmm.lmm_stripe_count)
1777                                     : 0;
1778                 decision = find_time_check(st, param, for_mds);
1779         }
1780
1781 obd_matches:
1782         /* If file still fits the request, ask ost for updated info.
1783            The regular stat is almost of the same speed as some new
1784            'glimpse-size-ioctl'. */
1785         if (!decision && S_ISREG(st->st_mode) &&
1786             (param->lmd->lmd_lmm.lmm_stripe_count || param->size)) {
1787                 if (param->obdindex != OBD_NOT_FOUND) {
1788                         /* Check whether the obd is active or not, if it is
1789                          * not active, just print the object affected by this
1790                          * failed ost
1791                          * */
1792                         struct obd_statfs stat_buf;
1793                         struct obd_uuid uuid_buf;
1794
1795                         memset(&stat_buf, 0, sizeof(struct obd_statfs));
1796                         memset(&uuid_buf, 0, sizeof(struct obd_uuid));
1797                         ret = llapi_obd_statfs(path, LL_STATFS_LOV,
1798                                                param->obdindex, &stat_buf,
1799                                                &uuid_buf);
1800                         if (ret) {
1801                                 if (ret == -ENODATA || ret == -ENODEV
1802                                     || ret == -EIO)
1803                                         errno = EIO;
1804                                 llapi_printf(LLAPI_MSG_NORMAL,
1805                                              "obd_uuid: %s failed %s ",
1806                                              param->obduuid->uuid,
1807                                              strerror(errno));
1808                                 goto print_path;
1809                         }
1810                 }
1811                 if (dir) {
1812                         ret = ioctl(dirfd(dir), IOC_LOV_GETINFO,
1813                                     (void *)param->lmd);
1814                 } else if (parent) {
1815                         ret = ioctl(dirfd(parent), IOC_LOV_GETINFO,
1816                                     (void *)param->lmd);
1817                 }
1818
1819                 if (ret) {
1820                         if (errno == ENOENT) {
1821                                 llapi_err(LLAPI_MSG_ERROR,
1822                                           "warning: %s: %s does not exist",
1823                                           __FUNCTION__, path);
1824                                 goto decided;
1825                         } else {
1826                                 llapi_err(LLAPI_MSG_ERROR,
1827                                           "%s: IOC_LOV_GETINFO on %s failed",
1828                                           __FUNCTION__, path);
1829                                 return ret;
1830                         }
1831                 }
1832
1833                 /* Check the time on osc. */
1834                 decision = find_time_check(st, param, 0);
1835                 if (decision == -1)
1836                         goto decided;
1837         }
1838
1839         if (param->size)
1840                 decision = find_value_cmp(st->st_size, param->size,
1841                                           param->size_sign, param->size_units,
1842                                           0);
1843
1844 print_path:
1845         if (decision != -1) {
1846                 llapi_printf(LLAPI_MSG_NORMAL, "%s", path);
1847                 if (param->zeroend)
1848                         llapi_printf(LLAPI_MSG_NORMAL, "%c", '\0');
1849                 else
1850                         llapi_printf(LLAPI_MSG_NORMAL, "\n");
1851         }
1852
1853 decided:
1854         /* Do not get down anymore? */
1855         if (param->depth == param->maxdepth)
1856                 return 1;
1857
1858         param->depth++;
1859         return 0;
1860 }
1861
1862 static int cb_common_fini(char *path, DIR *parent, DIR *d, void *data,
1863                           cfs_dirent_t *de)
1864 {
1865         struct find_param *param = (struct find_param *)data;
1866         param->depth--;
1867         return 0;
1868 }
1869
1870 int llapi_find(char *path, struct find_param *param)
1871 {
1872         char *buf;
1873         int ret, len = strlen(path);
1874
1875         if (len > PATH_MAX) {
1876                 llapi_err(LLAPI_MSG_ERROR, "%s: Path name '%s' is too long",
1877                           __FUNCTION__, path);
1878                 return -EINVAL;
1879         }
1880
1881         buf = (char *)malloc(PATH_MAX + 1);
1882         if (!buf)
1883                 return -ENOMEM;
1884
1885         ret = common_param_init(param);
1886         if (ret) {
1887                 free(buf);
1888                 return ret;
1889         }
1890
1891         param->depth = 0;
1892
1893         strncpy(buf, path, PATH_MAX + 1);
1894         ret = llapi_semantic_traverse(buf, PATH_MAX + 1, NULL, cb_find_init,
1895                                       cb_common_fini, param, NULL);
1896
1897         find_param_fini(param);
1898         free(buf);
1899         return ret < 0 ? ret : 0;
1900 }
1901
1902 static int cb_getstripe(char *path, DIR *parent, DIR *d, void *data,
1903                         cfs_dirent_t *de)
1904 {
1905         struct find_param *param = (struct find_param *)data;
1906         int ret = 0;
1907
1908         LASSERT(parent != NULL || d != NULL);
1909
1910         /* Prepare odb. */
1911         if (!param->got_uuids) {
1912                 ret = setup_obd_uuid(d ? d : parent, path, param);
1913                 if (ret)
1914                         return ret;
1915         }
1916
1917         if (d) {
1918                 ret = ioctl(dirfd(d), LL_IOC_LOV_GETSTRIPE,
1919                             (void *)&param->lmd->lmd_lmm);
1920         } else if (parent) {
1921                 char *fname = strrchr(path, '/');
1922                 fname = (fname == NULL ? path : fname + 1);
1923
1924                 strncpy((char *)&param->lmd->lmd_lmm, fname, param->lumlen);
1925                 ret = ioctl(dirfd(parent), IOC_MDC_GETFILESTRIPE,
1926                             (void *)&param->lmd->lmd_lmm);
1927         }
1928
1929         if (ret) {
1930                 if (errno == ENODATA) {
1931                         if (!param->obduuid && !param->quiet)
1932                                 llapi_printf(LLAPI_MSG_NORMAL,
1933                                              "%s has no stripe info\n", path);
1934                         goto out;
1935                 } else if (errno == ENOTTY) {
1936                         llapi_err(LLAPI_MSG_ERROR,
1937                                   "%s: '%s' not on a Lustre fs?",
1938                                   __FUNCTION__, path);
1939                 } else if (errno == ENOENT) {
1940                         llapi_err(LLAPI_MSG_WARN,
1941                                   "warning: %s: %s does not exist",
1942                                   __FUNCTION__, path);
1943                         goto out;
1944                 } else {
1945                         llapi_err(LLAPI_MSG_ERROR,
1946                                   "error: %s: %s failed for %s",
1947                                    __FUNCTION__, d ? "LL_IOC_LOV_GETSTRIPE" :
1948                                   "IOC_MDC_GETFILESTRIPE", path);
1949                 }
1950
1951                 return ret;
1952         }
1953
1954         llapi_lov_dump_user_lmm(param, path, d ? 1 : 0);
1955 out:
1956         /* Do not get down anymore? */
1957         if (param->depth == param->maxdepth)
1958                 return 1;
1959
1960         param->depth++;
1961         return 0;
1962 }
1963
1964 int llapi_getstripe(char *path, struct find_param *param)
1965 {
1966         char *buf;
1967         int ret = 0, len = strlen(path);
1968
1969         if (len > PATH_MAX) {
1970                 llapi_err(LLAPI_MSG_ERROR,
1971                           "%s: Path name '%s' is too long",
1972                           __FUNCTION__, path);
1973                 return -EINVAL;
1974         }
1975
1976         buf = (char *)malloc(PATH_MAX + 1);
1977         if (!buf)
1978                 return -ENOMEM;
1979
1980         ret = common_param_init(param);
1981         if (ret) {
1982                 free(buf);
1983                 return ret;
1984         }
1985
1986         param->depth = 0;
1987
1988         strncpy(buf, path, PATH_MAX + 1);
1989         ret = llapi_semantic_traverse(buf, PATH_MAX + 1, NULL, cb_getstripe,
1990                                       cb_common_fini, param, NULL);
1991         find_param_fini(param);
1992         free(buf);
1993         return ret < 0 ? ret : 0;
1994 }
1995
1996 int llapi_obd_statfs(char *path, __u32 type, __u32 index,
1997                      struct obd_statfs *stat_buf,
1998                      struct obd_uuid *uuid_buf)
1999 {
2000         int fd;
2001         char raw[OBD_MAX_IOCTL_BUFFER] = {'\0'};
2002         char *rawbuf = raw;
2003         struct obd_ioctl_data data = { 0 };
2004         int rc = 0;
2005
2006         data.ioc_inlbuf1 = (char *)&type;
2007         data.ioc_inllen1 = sizeof(__u32);
2008         data.ioc_inlbuf2 = (char *)&index;
2009         data.ioc_inllen2 = sizeof(__u32);
2010         data.ioc_pbuf1 = (char *)stat_buf;
2011         data.ioc_plen1 = sizeof(struct obd_statfs);
2012         data.ioc_pbuf2 = (char *)uuid_buf;
2013         data.ioc_plen2 = sizeof(struct obd_uuid);
2014
2015         if ((rc = obd_ioctl_pack(&data, &rawbuf, sizeof(raw))) != 0) {
2016                 llapi_err(LLAPI_MSG_ERROR,
2017                           "llapi_obd_statfs: error packing ioctl data");
2018                 return rc;
2019         }
2020
2021         fd = open(path, O_RDONLY);
2022         if (errno == EISDIR)
2023                 fd = open(path, O_DIRECTORY | O_RDONLY);
2024
2025         if (fd < 0) {
2026                 rc = errno ? -errno : -EBADF;
2027                 llapi_err(LLAPI_MSG_ERROR, "error: %s: opening '%s'",
2028                           __FUNCTION__, path);
2029                 return rc;
2030         }
2031         rc = ioctl(fd, IOC_OBD_STATFS, (void *)rawbuf);
2032         if (rc)
2033                 rc = errno ? -errno : -EINVAL;
2034
2035         close(fd);
2036         return rc;
2037 }
2038
2039 #define MAX_STRING_SIZE 128
2040 #define DEVICES_LIST "/proc/fs/lustre/devices"
2041
2042 int llapi_ping(char *obd_type, char *obd_name)
2043 {
2044         char path[MAX_STRING_SIZE];
2045         char buf[1];
2046         int rc, fd;
2047
2048         snprintf(path, MAX_STRING_SIZE, "/proc/fs/lustre/%s/%s/ping",
2049                  obd_type, obd_name);
2050
2051         fd = open(path, O_WRONLY);
2052         if (fd < 0) {
2053                 rc = errno;
2054                 llapi_err(LLAPI_MSG_ERROR, "error opening %s", path);
2055                 return rc;
2056         }
2057
2058         rc = write(fd, buf, 1);
2059         close(fd);
2060
2061         if (rc == 1)
2062                 return 0;
2063         return rc;
2064 }
2065
2066 int llapi_target_iterate(int type_num, char **obd_type,void *args,llapi_cb_t cb)
2067 {
2068         char buf[MAX_STRING_SIZE];
2069         FILE *fp = fopen(DEVICES_LIST, "r");
2070         int i, rc = 0;
2071
2072         if (fp == NULL) {
2073                 rc = errno;
2074                 llapi_err(LLAPI_MSG_ERROR, "error: opening "DEVICES_LIST);
2075                 return rc;
2076         }
2077
2078         while (fgets(buf, sizeof(buf), fp) != NULL) {
2079                 char *obd_type_name = NULL;
2080                 char *obd_name = NULL;
2081                 char *obd_uuid = NULL;
2082                 char *bufp = buf;
2083                 struct obd_ioctl_data datal = { 0, };
2084                 struct obd_statfs osfs_buffer;
2085
2086                 while(bufp[0] == ' ')
2087                         ++bufp;
2088
2089                 for(i = 0; i < 3; i++) {
2090                         obd_type_name = strsep(&bufp, " ");
2091                 }
2092                 obd_name = strsep(&bufp, " ");
2093                 obd_uuid = strsep(&bufp, " ");
2094
2095                 memset(&osfs_buffer, 0, sizeof (osfs_buffer));
2096
2097                 datal.ioc_pbuf1 = (char *)&osfs_buffer;
2098                 datal.ioc_plen1 = sizeof(osfs_buffer);
2099
2100                 for (i = 0; i < type_num; i++) {
2101                         if (strcmp(obd_type_name, obd_type[i]) != 0)
2102                                 continue;
2103
2104                         cb(obd_type_name, obd_name, obd_uuid, args);
2105                 }
2106         }
2107         fclose(fp);
2108         return rc;
2109 }
2110
2111 static void do_target_check(char *obd_type_name, char *obd_name,
2112                             char *obd_uuid, void *args)
2113 {
2114         int rc;
2115
2116         rc = llapi_ping(obd_type_name, obd_name);
2117         if (rc == ENOTCONN) {
2118                 llapi_printf(LLAPI_MSG_NORMAL, "%s inactive.\n", obd_name);
2119         } else if (rc) {
2120                 llapi_err(LLAPI_MSG_ERROR, "error: check '%s'", obd_name);
2121         } else {
2122                 llapi_printf(LLAPI_MSG_NORMAL, "%s active.\n", obd_name);
2123         }
2124 }
2125
2126 int llapi_target_check(int type_num, char **obd_type, char *dir)
2127 {
2128         return llapi_target_iterate(type_num, obd_type, NULL, do_target_check);
2129 }
2130
2131 #undef MAX_STRING_SIZE
2132
2133 int llapi_catinfo(char *dir, char *keyword, char *node_name)
2134 {
2135         char raw[OBD_MAX_IOCTL_BUFFER];
2136         char out[LLOG_CHUNK_SIZE];
2137         char *buf = raw;
2138         struct obd_ioctl_data data = { 0 };
2139         char key[30];
2140         DIR *root;
2141         int rc;
2142
2143         sprintf(key, "%s", keyword);
2144         memset(raw, 0, sizeof(raw));
2145         memset(out, 0, sizeof(out));
2146         data.ioc_inlbuf1 = key;
2147         data.ioc_inllen1 = strlen(key) + 1;
2148         if (node_name) {
2149                 data.ioc_inlbuf2 = node_name;
2150                 data.ioc_inllen2 = strlen(node_name) + 1;
2151         }
2152         data.ioc_pbuf1 = out;
2153         data.ioc_plen1 = sizeof(out);
2154         rc = obd_ioctl_pack(&data, &buf, sizeof(raw));
2155         if (rc)
2156                 return rc;
2157
2158         root = opendir(dir);
2159         if (root == NULL) {
2160                 rc = errno;
2161                 llapi_err(LLAPI_MSG_ERROR, "open %s failed", dir);
2162                 return rc;
2163         }
2164
2165         rc = ioctl(dirfd(root), OBD_IOC_LLOG_CATINFO, buf);
2166         if (rc)
2167                 llapi_err(LLAPI_MSG_ERROR, "ioctl OBD_IOC_CATINFO failed");
2168         else
2169                 llapi_printf(LLAPI_MSG_NORMAL, "%s", data.ioc_pbuf1);
2170
2171         closedir(root);
2172         return rc;
2173 }
2174
2175 /* Is this a lustre fs? */
2176 int llapi_is_lustre_mnttype(const char *type)
2177 {
2178         return (strcmp(type, "lustre") == 0 || strcmp(type,"lustre_lite") == 0);
2179 }
2180
2181 /* Is this a lustre client fs? */
2182 int llapi_is_lustre_mnt(struct mntent *mnt)
2183 {
2184         return (llapi_is_lustre_mnttype(mnt->mnt_type) &&
2185                 strstr(mnt->mnt_fsname, ":/") != NULL);
2186 }
2187
2188 int llapi_quotacheck(char *mnt, int check_type)
2189 {
2190         DIR *root;
2191         int rc;
2192
2193         root = opendir(mnt);
2194         if (!root) {
2195                 llapi_err(LLAPI_MSG_ERROR, "open %s failed", mnt);
2196                 return -1;
2197         }
2198
2199         rc = ioctl(dirfd(root), LL_IOC_QUOTACHECK, check_type);
2200
2201         closedir(root);
2202         return rc;
2203 }
2204
2205 int llapi_poll_quotacheck(char *mnt, struct if_quotacheck *qchk)
2206 {
2207         DIR *root;
2208         int poll_intvl = 2;
2209         int rc;
2210
2211         root = opendir(mnt);
2212         if (!root) {
2213                 llapi_err(LLAPI_MSG_ERROR, "open %s failed", mnt);
2214                 return -1;
2215         }
2216
2217         while (1) {
2218                 rc = ioctl(dirfd(root), LL_IOC_POLL_QUOTACHECK, qchk);
2219                 if (!rc)
2220                         break;
2221                 sleep(poll_intvl);
2222                 if (poll_intvl < 30)
2223                         poll_intvl *= 2;
2224         }
2225
2226         closedir(root);
2227         return rc;
2228 }
2229
2230 int llapi_quotactl(char *mnt, struct if_quotactl *qctl)
2231 {
2232         DIR *root;
2233         int rc;
2234
2235         root = opendir(mnt);
2236         if (!root) {
2237                 llapi_err(LLAPI_MSG_ERROR, "open %s failed", mnt);
2238                 return -1;
2239         }
2240
2241         rc = ioctl(dirfd(root), LL_IOC_QUOTACTL, qctl);
2242
2243         closedir(root);
2244         return rc;
2245 }
2246
2247 static int cb_quotachown(char *path, DIR *parent, DIR *d, void *data,
2248                          cfs_dirent_t *de)
2249 {
2250         struct find_param *param = (struct find_param *)data;
2251         lstat_t *st;
2252         int rc;
2253
2254         LASSERT(parent != NULL || d != NULL);
2255
2256         if (d) {
2257                 rc = ioctl(dirfd(d), LL_IOC_MDC_GETINFO,
2258                            (void *)param->lmd);
2259         } else if (parent) {
2260                 char *fname = strrchr(path, '/');
2261                 fname = (fname == NULL ? path : fname + 1);
2262
2263                 strncpy((char *)param->lmd, fname, param->lumlen);
2264                 rc = ioctl(dirfd(parent), IOC_MDC_GETFILEINFO,
2265                            (void *)param->lmd);
2266         } else {
2267                 return 0;
2268         }
2269
2270         if (rc) {
2271                 if (errno == ENODATA) {
2272                         if (!param->obduuid && !param->quiet)
2273                                 llapi_err(LLAPI_MSG_ERROR,
2274                                           "%s has no stripe info", path);
2275                         rc = 0;
2276                 } else if (errno == ENOENT) {
2277                         llapi_err(LLAPI_MSG_ERROR,
2278                                   "warning: %s: %s does not exist",
2279                                   __FUNCTION__, path);
2280                         rc = 0;
2281                 } else if (errno != EISDIR) {
2282                         rc = errno;
2283                         llapi_err(LLAPI_MSG_ERROR, "%s ioctl failed for %s.",
2284                                   d ? "LL_IOC_MDC_GETINFO" :
2285                                   "IOC_MDC_GETFILEINFO", path);
2286                 }
2287                 return rc;
2288         }
2289
2290         st = &param->lmd->lmd_st;
2291
2292         /* libc chown() will do extra check, and if the real owner is
2293          * the same as the ones to set, it won't fall into kernel, so
2294          * invoke syscall directly. */
2295         rc = syscall(SYS_chown, path, -1, -1);
2296         if (rc)
2297                 llapi_err(LLAPI_MSG_ERROR,"error: chown %s (%u,%u)", path);
2298
2299         rc = chmod(path, st->st_mode);
2300         if (rc)
2301                 llapi_err(LLAPI_MSG_ERROR, "error: chmod %s (%hu)",
2302                           path, st->st_mode);
2303
2304         return rc;
2305 }
2306
2307 int llapi_quotachown(char *path, int flag)
2308 {
2309         struct find_param param;
2310         char *buf;
2311         int ret = 0, len = strlen(path);
2312
2313         if (len > PATH_MAX) {
2314                 llapi_err(LLAPI_MSG_ERROR, "%s: Path name '%s' is too long",
2315                           __FUNCTION__, path);
2316                 return -EINVAL;
2317         }
2318
2319         buf = (char *)malloc(PATH_MAX + 1);
2320         if (!buf)
2321                 return -ENOMEM;
2322
2323         memset(&param, 0, sizeof(param));
2324         param.recursive = 1;
2325         param.verbose = 0;
2326         param.quiet = 1;
2327
2328         ret = common_param_init(&param);
2329         if (ret)
2330                 goto out;
2331
2332         strncpy(buf, path, PATH_MAX + 1);
2333         ret = llapi_semantic_traverse(buf, PATH_MAX + 1, NULL, cb_quotachown,
2334                                       NULL, &param, NULL);
2335 out:
2336         find_param_fini(&param);
2337         free(buf);
2338         return ret;
2339 }
2340
2341 #include <pwd.h>
2342 #include <grp.h>
2343 #include <mntent.h>
2344 #include <sys/wait.h>
2345 #include <errno.h>
2346 #include <ctype.h>
2347
2348 static int rmtacl_notify(int ops)
2349 {
2350         FILE *fp;
2351         struct mntent *mnt;
2352         int found = 0, fd, rc;
2353
2354         fp = setmntent(MOUNTED, "r");
2355         if (fp == NULL) {
2356                 perror("setmntent");
2357                 return -1;
2358         }
2359
2360         while (1) {
2361                 mnt = getmntent(fp);
2362                 if (!mnt)
2363                         break;
2364
2365                 if (!llapi_is_lustre_mnt(mnt))
2366                         continue;
2367
2368                 fd = open(mnt->mnt_dir, O_RDONLY | O_DIRECTORY);
2369                 if (fd < 0) {
2370                         perror("open");
2371                         return -1;
2372                 }
2373
2374                 rc = ioctl(fd, LL_IOC_RMTACL, ops);
2375                 if (rc < 0) {
2376                         perror("ioctl");
2377                 return -1;
2378                 }
2379
2380                 found++;
2381         }
2382         endmntent(fp);
2383         return found;
2384 }
2385
2386 static char *next_token(char *p, int div)
2387 {
2388         if (p == NULL)
2389                 return NULL;
2390
2391         if (div)
2392                 while (*p && *p != ':' && !isspace(*p))
2393                         p++;
2394         else
2395                 while (*p == ':' || isspace(*p))
2396                         p++;
2397
2398         return *p ? p : NULL;
2399 }
2400
2401 static int rmtacl_name2id(char *name, int is_user)
2402 {
2403         if (is_user) {
2404                 struct passwd *pw;
2405
2406                 if ((pw = getpwnam(name)) == NULL)
2407                         return INVALID_ID;
2408                 else
2409                         return (int)(pw->pw_uid);
2410         } else {
2411                 struct group *gr;
2412
2413                 if ((gr = getgrnam(name)) == NULL)
2414                         return INVALID_ID;
2415                 else
2416                         return (int)(gr->gr_gid);
2417         }
2418 }
2419
2420 static int isodigit(int c)
2421 {
2422         return (c >= '0' && c <= '7') ? 1 : 0;
2423 }
2424
2425 /*
2426  * Whether the name is just digits string (uid/gid) already or not.
2427  * Return value:
2428  * 1: str is id
2429  * 0: str is not id
2430  */
2431 static int str_is_id(char *str)
2432 {
2433         if (str == NULL)
2434                 return 0;
2435
2436         if (*str == '0') {
2437                 str++;
2438                 if (*str == 'x' || *str == 'X') { /* for Hex. */
2439                         if (!isxdigit(*(++str)))
2440                                 return 0;
2441
2442                         while (isxdigit(*(++str)));
2443                 } else if (isodigit(*str)) { /* for Oct. */
2444                         while (isodigit(*(++str)));
2445                 }
2446         } else if (isdigit(*str)) { /* for Dec. */
2447                 while (isdigit(*(++str)));
2448         }
2449
2450         return (*str == 0) ? 1 : 0;
2451 }
2452
2453 typedef struct {
2454         char *name;
2455         int   length;
2456         int   is_user;
2457         int   next_token;
2458 } rmtacl_name_t;
2459
2460 #define RMTACL_OPTNAME(name) name, sizeof(name) - 1
2461
2462 static rmtacl_name_t rmtacl_namelist[] = {
2463         { RMTACL_OPTNAME("user:"),            1,      0 },
2464         { RMTACL_OPTNAME("group:"),           0,      0 },
2465         { RMTACL_OPTNAME("default:user:"),    1,      0 },
2466         { RMTACL_OPTNAME("default:group:"),   0,      0 },
2467         /* for --tabular option */
2468         { RMTACL_OPTNAME("user"),             1,      1 },
2469         { RMTACL_OPTNAME("group"),            0,      1 },
2470         { 0 }
2471 };
2472
2473 static int rgetfacl_output(char *str)
2474 {
2475         char *start = NULL, *end = NULL;
2476         int is_user = 0, n, id;
2477         char c;
2478         rmtacl_name_t *rn;
2479
2480         if (str == NULL)
2481                 return -1;
2482
2483         for (rn = rmtacl_namelist; rn->name; rn++) {
2484                 if(strncmp(str, rn->name, rn->length) == 0) {
2485                         if (!rn->next_token)
2486                                 start = str + rn->length;
2487                         else
2488                                 start = next_token(str + rn->length, 0);
2489                         is_user = rn->is_user;
2490                         break;
2491                 }
2492         }
2493
2494         end = next_token(start, 1);
2495         if (end == NULL || start == end) {
2496                 n = printf("%s", str);
2497                 return n;
2498         }
2499
2500         c = *end;
2501         *end = 0;
2502         id = rmtacl_name2id(start, is_user);
2503         if (id == INVALID_ID) {
2504                 if (str_is_id(start)) {
2505                         *end = c;
2506                         n = printf("%s", str);
2507                 } else
2508                         return -1;
2509         } else if ((id == NOBODY_UID && is_user) ||
2510                    (id == NOBODY_GID && !is_user)) {
2511                 *end = c;
2512                 n = printf("%s", str);
2513         } else {
2514                 *end = c;
2515                 *start = 0;
2516                 n = printf("%s%d%s", str, id, end);
2517         }
2518         return n;
2519 }
2520
2521 static int child_status(int status)
2522 {
2523         return WIFEXITED(status) ? WEXITSTATUS(status) : -1;
2524 }
2525
2526 static int do_rmtacl(int argc, char *argv[], int ops, int (output_func)(char *))
2527 {
2528         pid_t pid = 0;
2529         int fd[2], status;
2530         FILE *fp;
2531         char buf[PIPE_BUF];
2532
2533         if (output_func) {
2534                 if (pipe(fd) < 0) {
2535                         perror("pipe");
2536                         return -1;
2537                 }
2538
2539                 if ((pid = fork()) < 0) {
2540                         perror("fork");
2541                         close(fd[0]);
2542                         close(fd[1]);
2543                         return -1;
2544                 } else if (!pid) {
2545                         /* child process redirects its output. */
2546                         close(fd[0]);
2547                         close(1);
2548                         if (dup2(fd[1], 1) < 0) {
2549                                 perror("dup2");
2550                                 close(fd[1]);
2551                                 return -1;
2552                         }
2553                 } else {
2554                         close(fd[1]);
2555                 }
2556         }
2557
2558         if (!pid) {
2559                 status = rmtacl_notify(ops);
2560                 if (status < 0)
2561                         return -1;
2562
2563                 exit(execvp(argv[0], argv));
2564         }
2565
2566         /* the following is parent process */
2567         if ((fp = fdopen(fd[0], "r")) == NULL) {
2568                 perror("fdopen");
2569                 kill(pid, SIGKILL);
2570                 close(fd[0]);
2571                 return -1;
2572         }
2573
2574         while (fgets(buf, PIPE_BUF, fp) != NULL) {
2575                 if (output_func(buf) < 0)
2576                         fprintf(stderr, "WARNING: unexpected error!\n[%s]\n",
2577                                 buf);
2578         }
2579         fclose(fp);
2580         close(fd[0]);
2581
2582         if (waitpid(pid, &status, 0) < 0) {
2583                 perror("waitpid");
2584                 return -1;
2585         }
2586
2587         return child_status(status);
2588 }
2589
2590 int llapi_lsetfacl(int argc, char *argv[])
2591 {
2592         return do_rmtacl(argc, argv, RMT_LSETFACL, NULL);
2593 }
2594
2595 int llapi_lgetfacl(int argc, char *argv[])
2596 {
2597         return do_rmtacl(argc, argv, RMT_LGETFACL, NULL);
2598 }
2599
2600 int llapi_rsetfacl(int argc, char *argv[])
2601 {
2602         return do_rmtacl(argc, argv, RMT_RSETFACL, NULL);
2603 }
2604
2605 int llapi_rgetfacl(int argc, char *argv[])
2606 {
2607         return do_rmtacl(argc, argv, RMT_RGETFACL, rgetfacl_output);
2608 }
2609
2610 int llapi_cp(int argc, char *argv[])
2611 {
2612         int rc;
2613
2614         rc = rmtacl_notify(RMT_RSETFACL);
2615         if (rc < 0)
2616                 return -1;
2617
2618         exit(execvp(argv[0], argv));
2619 }
2620
2621 int llapi_ls(int argc, char *argv[])
2622 {
2623         int rc;
2624
2625         rc = rmtacl_notify(RMT_LGETFACL);
2626         if (rc < 0)
2627                 return -1;
2628
2629         exit(execvp(argv[0], argv));
2630 }
2631
2632 /* Print mdtname 'name' into 'buf' using 'format'.  Add -MDT0000 if needed.
2633  * format must have %s%s, buf must be > 16
2634  */
2635 static int get_mdtname(char *name, char *format, char *buf)
2636 {
2637         char suffix[]="-MDT0000";
2638         int len = strlen(name);
2639
2640         if ((len > 5) && (strncmp(name + len - 5, "_UUID", 5) == 0)) {
2641                 name[len - 5] = '\0';
2642                 len -= 5;
2643         }
2644
2645         if (len > 8) {
2646                 if ((len <= 16) && strncmp(name + len - 8, "-MDT", 4) == 0) {
2647                         suffix[0] = '\0';
2648                 } else {
2649                         /* Not enough room to add suffix */
2650                         llapi_err(LLAPI_MSG_ERROR | LLAPI_MSG_NO_ERRNO,
2651                                   "MDT name too long |%s|", name);
2652                         return -EINVAL;
2653                 }
2654         }
2655
2656         return sprintf(buf, format, name, suffix);
2657 }
2658
2659 /****** Changelog API ********/
2660 #define CHANGELOG_PRIV_MAGIC 0xCA8E1080
2661 struct changelog_private {
2662         int magic;
2663         int flags;
2664         lustre_netlink lnl;
2665 };
2666
2667 /** Start reading from a changelog
2668  * @param priv Opaque private control structure
2669  * @param flags Start flags (e.g. CHANGELOG_FLAG_BLOCK)
2670  * @param device Report changes recorded on this MDT
2671  * @param startrec Report changes beginning with this record number
2672  * (just call llapi_changelog_fini when done; don't need an endrec)
2673  */
2674 int llapi_changelog_start(void **priv, int flags, const char *device,
2675                           long long startrec)
2676 {
2677         struct changelog_private *cp;
2678         struct changelog_show cs = {};
2679         char mdtname[20];
2680         char pattern[100];
2681         char trigger[100];
2682         int fd, rc, pid;
2683
2684         /* Find mdtname from path, fsname, mdtname, or mdtname_UUID */
2685         if (device[0] == '/') {
2686                 if ((rc = llapi_search_fsname(device, mdtname)))
2687                         return rc;
2688                 if ((rc = get_mdtname(mdtname, "%s%s", mdtname)) < 0)
2689                         return rc;
2690         } else {
2691                 if ((rc = get_mdtname((char *)device, "%s%s", mdtname)) < 0)
2692                         return rc;
2693         }
2694
2695         /* Find corresponding mdc trigger */
2696         snprintf(pattern, PATH_MAX,
2697                  "/proc/fs/lustre/mdc/%s-*/changelog_trigger", mdtname);
2698         rc = first_match(pattern, trigger);
2699         if (rc)
2700                 return rc;
2701
2702         /* Make sure we can write the trigger */
2703         fd = open(trigger, O_WRONLY);
2704         if (fd < 0)
2705                 return -errno;
2706
2707         /* Set up the receiver control struct */
2708         cp = malloc(sizeof(*cp));
2709         if (cp == NULL) {
2710                 close(fd);
2711                 return -ENOMEM;
2712         }
2713
2714         cp->magic = CHANGELOG_PRIV_MAGIC;
2715         cp->flags = flags;
2716         /* Start the receiver */
2717         rc = libcfs_ulnl_start(&cp->lnl, 0 /* unicast */);
2718         if (rc < 0)
2719                 goto out_free;
2720
2721         /* We need to trigger Lustre to start sending messages now.
2722            We could send a lnl message to a kernel listener,
2723            or write into proc.  Proc has the advantage of running in this
2724            context, avoiding the need for a kernel thread. */
2725         cs.cs_pid = getpid();
2726         cs.cs_startrec = startrec;
2727         cs.cs_flags = flags & CHANGELOG_FLAG_BLOCK ? LNL_FL_BLOCK : 0;
2728         if ((pid = fork()) < 0) {
2729                 goto out_free;
2730         } else if (!pid) {
2731                 /* Write triggers Lustre to start sending, but it
2732                    won't return until it is complete, meaning everything
2733                    got shipped through lnl (or error).  So we trigger it
2734                    from a child process here, allowing the llapi call to
2735                    return and wait for the lnl messages. */
2736                 rc = write(fd, &cs, sizeof(cs));
2737                 exit(rc);
2738         }
2739
2740         close(fd);
2741         *priv = cp;
2742         return 0;
2743
2744 out_free:
2745         free(cp);
2746         close(fd);
2747         return rc;
2748 }
2749
2750 /** Finish reading from a changelog */
2751 int llapi_changelog_fini(void **priv)
2752 {
2753         struct changelog_private *cp = (struct changelog_private *)*priv;
2754
2755         if (!cp || (cp->magic != CHANGELOG_PRIV_MAGIC))
2756                 return -EINVAL;
2757
2758         libcfs_ulnl_stop(&cp->lnl);
2759         free(cp);
2760         *priv = NULL;
2761         return 0;
2762 }
2763
2764 /** Read the next changelog entry
2765  * @param priv Opaque private control structure
2766  * @param rech Changelog record handle; record will be allocated here
2767  * @return 0 valid message received; rec is set
2768  *         <0 error code
2769  *         1 EOF
2770  */
2771 int llapi_changelog_recv(void *priv, struct changelog_rec **rech)
2772 {
2773         struct changelog_private *cp = (struct changelog_private *)priv;
2774         struct lnl_hdr *lnlh;
2775         int rc = 0;
2776
2777         if (!cp || (cp->magic != CHANGELOG_PRIV_MAGIC))
2778                 return -EINVAL;
2779         if (rech == NULL)
2780                 return -EINVAL;
2781
2782 repeat:
2783         rc = libcfs_ulnl_msg_get(&cp->lnl, CR_MAXSIZE, LNL_TRANSPORT_CHANGELOG,
2784                                  &lnlh);
2785         if (rc < 0)
2786                 return rc;
2787
2788         if ((lnlh->lnl_transport != LNL_TRANSPORT_CHANGELOG) ||
2789             ((lnlh->lnl_msgtype != CL_RECORD) &&
2790              (lnlh->lnl_msgtype != CL_EOF))) {
2791                 llapi_err(LLAPI_MSG_ERROR | LLAPI_MSG_NO_ERRNO,
2792                           "Unknown changelog message type %d:%d\n",
2793                           lnlh->lnl_transport, lnlh->lnl_msgtype);
2794                 rc = -EPROTO;
2795                 goto out_free;
2796         }
2797
2798         if (lnlh->lnl_msgtype == CL_EOF) {
2799                 if (cp->flags & CHANGELOG_FLAG_FOLLOW) {
2800                         /* Ignore EOFs */
2801                         goto repeat;
2802                 } else {
2803                         rc = 1;
2804                         goto out_free;
2805                 }
2806         }
2807
2808         /* Our message is a changelog_rec */
2809         *rech = (struct changelog_rec *)(lnlh + 1);
2810
2811         return 0;
2812
2813 out_free:
2814         libcfs_ulnl_msg_free(&lnlh);
2815         *rech = NULL;
2816         return rc;
2817 }
2818
2819 /** Release the changelog record when done with it. */
2820 int llapi_changelog_free(struct changelog_rec **rech)
2821 {
2822         if (*rech) {
2823                 struct lnl_hdr *lnlh = (struct lnl_hdr *)*rech - 1;
2824                 libcfs_ulnl_msg_free(&lnlh);
2825         }
2826         *rech = NULL;
2827         return 0;
2828 }
2829
2830 int llapi_changelog_clear(const char *mdtname, const char *idstr,
2831                           long long endrec)
2832 {
2833         struct ioc_changelog_clear data;
2834         char fsname[17];
2835         char *ptr;
2836         int id, fd, index, rc;
2837
2838         if (endrec < 0) {
2839                 llapi_err(LLAPI_MSG_ERROR | LLAPI_MSG_NO_ERRNO,
2840                           "can't purge negative records\n");
2841                 return -EINVAL;
2842         }
2843
2844         id = strtol(idstr + strlen(CHANGELOG_USER_PREFIX), NULL, 10);
2845         if ((id == 0) || (strncmp(idstr, CHANGELOG_USER_PREFIX,
2846                                   strlen(CHANGELOG_USER_PREFIX)) != 0)) {
2847                 llapi_err(LLAPI_MSG_ERROR | LLAPI_MSG_NO_ERRNO,
2848                           "expecting id of the form '"CHANGELOG_USER_PREFIX
2849                           "<num>'; got '%s'\n", idstr);
2850                 return -EINVAL;
2851         }
2852
2853         /* Take path, fsname, or MDTNAME.  Assume MDT0000 in the former cases */
2854         if (mdtname[0] == '/') {
2855                 index = 0;
2856                 fd = open(mdtname, O_RDONLY | O_DIRECTORY | O_NONBLOCK);
2857                 rc = fd < 0 ? -errno : 0;
2858         } else {
2859                 if (get_mdtname((char *)mdtname, "%s%s", fsname) < 0)
2860                         return -EINVAL;
2861                 ptr = fsname + strlen(fsname) - 8;
2862                 *ptr = '\0';
2863                 index = strtol(ptr + 4, NULL, 10);
2864                 rc = get_root_path(WANT_FD | WANT_ERROR, fsname, &fd, NULL, -1);
2865         }
2866         if (rc < 0) {
2867                 llapi_err(LLAPI_MSG_ERROR | LLAPI_MSG_NO_ERRNO,
2868                           "Can't open %s: %d\n", mdtname, rc);
2869                 return rc;
2870         }
2871
2872         data.icc_mdtindex = index;
2873         data.icc_id = id;
2874         data.icc_recno = endrec;
2875         rc = ioctl(fd, OBD_IOC_CHANGELOG_CLEAR, &data);
2876         if (rc)
2877                 llapi_err(LLAPI_MSG_ERROR, "ioctl err %d", rc);
2878
2879         close(fd);
2880         return rc;
2881 }
2882
2883 int llapi_fid2path(const char *device, const char *fidstr, char *buf,
2884                    int buflen, long long *recno, int *linkno)
2885 {
2886         char path[PATH_MAX];
2887         struct lu_fid fid;
2888         struct getinfo_fid2path *gf;
2889         int fd, rc;
2890
2891         while (*fidstr == '[')
2892                 fidstr++;
2893
2894         sscanf(fidstr, SFID, RFID(&fid));
2895         if (!fid_is_sane(&fid)) {
2896                 llapi_err(LLAPI_MSG_ERROR | LLAPI_MSG_NO_ERRNO,
2897                           "bad FID format [%s], should be "DFID"\n",
2898                           fidstr, (__u64)1, 2, 0);
2899                 return -EINVAL;
2900         }
2901
2902         /* Take path or fsname */
2903         if (device[0] == '/') {
2904                 strcpy(path, device);
2905         } else {
2906                 rc = get_root_path(WANT_PATH | WANT_ERROR, (char *)device,
2907                                    NULL, path, -1);
2908                 if (rc < 0)
2909                         return rc;
2910         }
2911         sprintf(path, "%s/%s/fid/%s", path, dot_lustre_name, fidstr);
2912         fd = open(path, O_RDONLY | O_NONBLOCK);
2913         if (fd < 0)
2914                 return -errno;
2915
2916         gf = malloc(sizeof(*gf) + buflen);
2917         gf->gf_fid = fid;
2918         gf->gf_recno = *recno;
2919         gf->gf_linkno = *linkno;
2920         gf->gf_pathlen = buflen;
2921         rc = ioctl(fd, OBD_IOC_FID2PATH, gf);
2922         if (rc) {
2923                 llapi_err(LLAPI_MSG_ERROR, "ioctl err %d", rc);
2924         } else {
2925                 memcpy(buf, gf->gf_path, gf->gf_pathlen);
2926                 *recno = gf->gf_recno;
2927                 *linkno = gf->gf_linkno;
2928         }
2929
2930         free(gf);
2931         close(fd);
2932         return rc;
2933 }
2934
2935 static int path2fid_from_lma(const char *path, lustre_fid *fid)
2936 {
2937         char buf[512];
2938         struct lustre_mdt_attrs *lma;
2939         int rc;
2940
2941         rc = lgetxattr(path, XATTR_NAME_LMA, buf, sizeof(buf));
2942         if (rc < 0)
2943                 return -errno;
2944         lma = (struct lustre_mdt_attrs *)buf;
2945         fid_be_to_cpu(fid, &lma->lma_self_fid);
2946         return 0;
2947 }
2948
2949 int llapi_path2fid(const char *path, lustre_fid *fid)
2950 {
2951         int fd, rc;
2952
2953         memset(fid, 0, sizeof(*fid));
2954         fd = open(path, O_RDONLY | O_NONBLOCK | O_NOFOLLOW);
2955         if (fd < 0) {
2956                 if (errno == ELOOP) /* symbolic link */
2957                         return path2fid_from_lma(path, fid);
2958                 return -errno;
2959         }
2960
2961         rc = ioctl(fd, LL_IOC_PATH2FID, fid) < 0 ? -errno : 0;
2962         if (rc == -EINVAL) /* char special device */
2963                 rc = path2fid_from_lma(path, fid);
2964
2965         close(fd);
2966         return rc;
2967 }
2968
2969 /****** HSM Copytool API ********/
2970 #define CT_PRIV_MAGIC 0xC0BE2001
2971 struct copytool_private {
2972         int magic;
2973         lustre_netlink lnl;
2974         int archive_num_count;
2975         int archive_nums[0];
2976 };
2977
2978 #include <libcfs/libcfs.h>
2979
2980 /** Register a copytool
2981  * @param priv Opaque private control structure
2982  * @param flags Open flags, currently unused (e.g. O_NONBLOCK)
2983  * @param archive_num_count
2984  * @param archive_nums Which archive numbers this copytool is responsible for
2985  */
2986 int llapi_copytool_start(void **priv, int flags, int archive_num_count,
2987                          int *archive_nums)
2988 {
2989         struct copytool_private *ct;
2990         int rc;
2991
2992         if (archive_num_count > 0 && archive_nums == NULL) {
2993                 llapi_err(LLAPI_MSG_ERROR | LLAPI_MSG_NO_ERRNO,
2994                           "NULL archive numbers");
2995                 return -EINVAL;
2996         }
2997
2998         ct = malloc(sizeof(*ct) +
2999                     archive_num_count * sizeof(ct->archive_nums[0]));
3000         if (ct == NULL)
3001                 return -ENOMEM;
3002
3003         ct->magic = CT_PRIV_MAGIC;
3004         ct->archive_num_count = archive_num_count;
3005         if (ct->archive_num_count > 0)
3006                 memcpy(ct->archive_nums, archive_nums, archive_num_count *
3007                        sizeof(ct->archive_nums[0]));
3008
3009         rc = libcfs_ulnl_start(&ct->lnl, LNL_GRP_HSM);
3010         if (rc < 0)
3011                 goto out_err;
3012
3013         *priv = ct;
3014         return 0;
3015
3016 out_err:
3017         free(ct);
3018         return rc;
3019 }
3020
3021 /** Deregister a copytool */
3022 int llapi_copytool_fini(void **priv)
3023 {
3024         struct copytool_private *ct = (struct copytool_private *)*priv;
3025
3026         if (!ct || (ct->magic != CT_PRIV_MAGIC))
3027                 return -EINVAL;
3028
3029         libcfs_ulnl_stop(&ct->lnl);
3030         free(ct);
3031         *priv = NULL;
3032         return 0;
3033 }
3034
3035 /** Wait for the next hsm_action_list
3036  * @param priv Opaque private control structure
3037  * @param halh Action list handle, will be allocated here
3038  * @param msgsize Number of bytes in the message, will be set here
3039  * @return 0 valid message received; halh and msgsize are set
3040  *         <0 error code
3041  */
3042 int llapi_copytool_recv(void *priv, struct hsm_action_list **halh, int *msgsize)
3043 {
3044         struct copytool_private *ct = (struct copytool_private *)priv;
3045         struct lnl_hdr *lnlh;
3046         struct hsm_action_list *hal;
3047         int rc = 0;
3048
3049         if (!ct || (ct->magic != CT_PRIV_MAGIC))
3050                 return -EINVAL;
3051         if (halh == NULL || msgsize == NULL)
3052                 return -EINVAL;
3053
3054         rc = libcfs_ulnl_msg_get(&ct->lnl, HAL_MAXSIZE,
3055                                  LNL_TRANSPORT_HSM, &lnlh);
3056         if (rc < 0)
3057                 return rc;
3058
3059         /* Handle generic messages */
3060         if (lnlh->lnl_transport == LNL_TRANSPORT_GENERIC &&
3061             lnlh->lnl_msgtype == LNL_MSG_SHUTDOWN) {
3062                 rc = -ESHUTDOWN;
3063                 goto out_free;
3064         }
3065
3066         if (lnlh->lnl_transport != LNL_TRANSPORT_HSM ||
3067             lnlh->lnl_msgtype != HMT_ACTION_LIST) {
3068                 llapi_err(LLAPI_MSG_ERROR | LLAPI_MSG_NO_ERRNO,
3069                           "Unknown HSM message type %d:%d\n",
3070                           lnlh->lnl_transport, lnlh->lnl_msgtype);
3071                 rc = -EPROTO;
3072                 goto out_free;
3073         }
3074
3075         /* Our message is an hsm_action_list */
3076
3077         hal = (struct hsm_action_list *)(lnlh + 1);
3078
3079         /* Check that we have registered for this archive # */
3080         for (rc = 0; rc < ct->archive_num_count; rc++) {
3081                 if (hal->hal_archive_num == ct->archive_nums[rc])
3082                         break;
3083         }
3084         if (rc >= ct->archive_num_count) {
3085                 CDEBUG(D_INFO, "This copytool does not service archive #%d, "
3086                        "ignoring this request.\n", hal->hal_archive_num);
3087                 rc = 0;
3088                 goto out_free;
3089         }
3090
3091         *halh = hal;
3092         *msgsize = lnlh->lnl_msglen - sizeof(*lnlh);
3093         return 0;
3094
3095 out_free:
3096         libcfs_ulnl_msg_free(&lnlh);
3097         *halh = NULL;
3098         *msgsize = 0;
3099         return rc;
3100 }
3101
3102 /** Release the action list when done with it. */
3103 int llapi_copytool_free(struct hsm_action_list **hal)
3104 {
3105         if (*hal) {
3106                 struct lnl_hdr *lnlh = (struct lnl_hdr *)*hal - 1;
3107                 libcfs_ulnl_msg_free(&lnlh);
3108         }
3109         *hal = NULL;
3110         return 0;
3111 }
3112
3113
3114