Whamcloud - gitweb
b=20500
[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 /* Here, param->obduuid points to a single obduuid, the index of which is
880  * returned in param->obdindex */
881 static int setup_obd_uuid(DIR *dir, char *dname, struct find_param *param)
882 {
883         struct obd_uuid lov_uuid;
884         char uuid[sizeof(struct obd_uuid)];
885         char buf[1024];
886         FILE *fp;
887         int rc = 0, index;
888
889         /* Get the lov name */
890         rc = llapi_file_fget_lov_uuid(dirfd(dir), &lov_uuid);
891         if (rc) {
892                 if (errno != ENOTTY) {
893                         rc = errno;
894                         llapi_err(LLAPI_MSG_ERROR,
895                                   "error: can't get lov name: %s", dname);
896                 } else {
897                         rc = 0;
898                 }
899                 return rc;
900         }
901
902         param->got_uuids = 1;
903
904         /* Now get the ost uuids from /proc */
905         snprintf(buf, sizeof(buf), "/proc/fs/lustre/lov/%s/target_obd",
906                  lov_uuid.uuid);
907         fp = fopen(buf, "r");
908         if (fp == NULL) {
909                 rc = errno;
910                 llapi_err(LLAPI_MSG_ERROR, "error: opening '%s'", buf);
911                 return rc;
912         }
913
914         if (!param->obduuid && !param->quiet && !param->obds_printed)
915                 llapi_printf(LLAPI_MSG_NORMAL, "OBDS:\n");
916
917         while (fgets(buf, sizeof(buf), fp) != NULL) {
918                 if (sscanf(buf, "%d: %s", &index, uuid) < 2)
919                         break;
920
921                 if (param->obduuid) {
922                         if (strncmp(param->obduuid->uuid, uuid,
923                                     sizeof(uuid)) == 0) {
924                                 param->obdindex = index;
925                                 break;
926                         }
927                 } else if (!param->quiet && !param->obds_printed) {
928                         /* Print everything */
929                         llapi_printf(LLAPI_MSG_NORMAL, "%s", buf);
930                 }
931         }
932         param->obds_printed = 1;
933
934         fclose(fp);
935
936         if (!param->quiet && param->obduuid &&
937             (param->obdindex == OBD_NOT_FOUND)) {
938                 llapi_err_noerrno(LLAPI_MSG_ERROR,
939                                   "error: %s: unknown obduuid: %s",
940                                   __FUNCTION__, param->obduuid->uuid);
941                 //rc = EINVAL;
942         }
943
944         return (rc);
945 }
946
947 /* In this case, param->obduuid will be an array of obduuids and
948  * obd index for all these obduuids will be returned in
949  * param->obdindexes */
950 static int setup_obd_indexes(DIR *dir, struct find_param *param)
951 {
952         struct obd_uuid *uuids = NULL;
953         int obdcount = INIT_ALLOC_NUM_OSTS;
954         int ret, obd_valid = 0, obdnum, i;
955
956         uuids = (struct obd_uuid *)malloc(INIT_ALLOC_NUM_OSTS *
957                                           sizeof(struct obd_uuid));
958         if (uuids == NULL)
959                 return -ENOMEM;
960
961 retry_get_uuids:
962         ret = llapi_lov_get_uuids(dirfd(dir), uuids,
963                                   &obdcount);
964         if (ret) {
965                 struct obd_uuid *uuids_temp;
966
967                 if (ret == -EOVERFLOW) {
968                         uuids_temp = realloc(uuids, obdcount *
969                                              sizeof(struct obd_uuid));
970                         if (uuids_temp != NULL)
971                                 goto retry_get_uuids;
972                         else
973                                 ret = -ENOMEM;
974                 }
975
976                 llapi_err(LLAPI_MSG_ERROR, "get ost uuid failed");
977                 return ret;
978         }
979
980         param->obdindexes = malloc(param->num_obds * sizeof(param->obdindex));
981         if (param->obdindexes == NULL)
982                 return -ENOMEM;
983
984         for (obdnum = 0; obdnum < param->num_obds; obdnum++) {
985                 for (i = 0; i <= obdcount; i++) {
986                         if (strcmp((char *)&param->obduuid[obdnum].uuid,
987                                    (char *)&uuids[i]) == 0) {
988                                 param->obdindexes[obdnum] = i;
989                                 obd_valid++;
990                                 break;
991                         }
992                 }
993                 if (i == obdcount)
994                         param->obdindexes[obdnum] = OBD_NOT_FOUND;
995         }
996
997         if (obd_valid == 0)
998                 param->obdindex = OBD_NOT_FOUND;
999         else
1000                 param->obdindex = obd_valid;
1001
1002         param->got_uuids = 1;
1003
1004         return 0;
1005 }
1006
1007 static void lov_dump_user_lmm_header(struct lov_user_md *lum, char *path,
1008                                      int is_dir, int verbose, int quiet,
1009                                      char *pool_name)
1010 {
1011         char *prefix = is_dir ? "" : "lmm_";
1012         char nl = is_dir ? ' ' : '\n';
1013
1014         if (verbose && path)
1015                 llapi_printf(LLAPI_MSG_NORMAL, "%s\n", path);
1016
1017         if ((verbose & VERBOSE_DETAIL) && !is_dir) {
1018                 llapi_printf(LLAPI_MSG_NORMAL, "lmm_magic:          0x%08X\n",
1019                              lum->lmm_magic);
1020                 llapi_printf(LLAPI_MSG_NORMAL, "lmm_object_gr:      "LPX64"\n",
1021                              lum->lmm_object_gr);
1022                 llapi_printf(LLAPI_MSG_NORMAL, "lmm_object_id:      "LPX64"\n",
1023                              lum->lmm_object_id);
1024         }
1025
1026         if (verbose & VERBOSE_COUNT) {
1027                 if (!quiet)
1028                         llapi_printf(LLAPI_MSG_NORMAL, "%sstripe_count:   ",
1029                                      prefix);
1030                 llapi_printf(LLAPI_MSG_NORMAL, "%hd%c",
1031                              (__s16)lum->lmm_stripe_count, nl);
1032         }
1033
1034         if (verbose & VERBOSE_SIZE) {
1035                 if (!quiet)
1036                         llapi_printf(LLAPI_MSG_NORMAL, "%sstripe_size:    ",
1037                                      prefix);
1038                 llapi_printf(LLAPI_MSG_NORMAL, "%u%c", lum->lmm_stripe_size,
1039                              nl);
1040         }
1041
1042         if ((verbose & VERBOSE_DETAIL) && !is_dir) {
1043                 llapi_printf(LLAPI_MSG_NORMAL, "lmm_stripe_pattern: %x%c",
1044                              lum->lmm_pattern, nl);
1045         }
1046
1047         if (verbose & VERBOSE_OFFSET) {
1048                 if (!quiet)
1049                         llapi_printf(LLAPI_MSG_NORMAL, "%sstripe_offset:   ",
1050                                      prefix);
1051                 llapi_printf(LLAPI_MSG_NORMAL, "%u%c",
1052                              lum->lmm_objects[0].l_ost_idx, nl);
1053         }
1054
1055         if ((verbose & VERBOSE_POOL) && (pool_name != NULL))
1056                 llapi_printf(LLAPI_MSG_NORMAL, "pool: %s%c", pool_name, nl);
1057
1058         if (is_dir)
1059                 llapi_printf(LLAPI_MSG_NORMAL, "\n");
1060 }
1061
1062 void lov_dump_user_lmm_v1v3(struct lov_user_md *lum, char *pool_name,
1063                             struct lov_user_ost_data_v1 *objects,
1064                             char *path, int is_dir,
1065                             int obdindex, int quiet, int header, int body)
1066 {
1067         int i, obdstripe = 0;
1068
1069         if (obdindex != OBD_NOT_FOUND) {
1070                 for (i = 0; !is_dir && i < lum->lmm_stripe_count; i++) {
1071                         if (obdindex == objects[i].l_ost_idx) {
1072                                 llapi_printf(LLAPI_MSG_NORMAL, "%s\n", path);
1073                                 obdstripe = 1;
1074                                 break;
1075                         }
1076                 }
1077         } else {
1078                 if (!quiet)
1079                         llapi_printf(LLAPI_MSG_NORMAL, "%s\n", path);
1080                 obdstripe = 1;
1081         }
1082
1083         /* if it's a directory */
1084         if (is_dir) {
1085                 if (obdstripe == 1) {
1086                         if (lum->lmm_object_gr == LOV_OBJECT_GROUP_DEFAULT) {
1087                                 llapi_printf(LLAPI_MSG_NORMAL, "(Default) ");
1088                                 lum->lmm_object_gr = LOV_OBJECT_GROUP_CLEAR;
1089                         }
1090                         /* maintain original behavior */
1091                         if (!header)
1092                                 header |= VERBOSE_ALL;
1093                         lov_dump_user_lmm_header(lum, path, is_dir, header,
1094                                                  quiet, pool_name);
1095                 }
1096                 return;
1097         }
1098
1099         if (header && (obdstripe == 1))
1100                 lov_dump_user_lmm_header(lum, NULL, is_dir, header, quiet,
1101                                          pool_name);
1102
1103         if (body) {
1104                 if ((!quiet) && (obdstripe == 1))
1105                         llapi_printf(LLAPI_MSG_NORMAL,
1106                                      "\tobdidx\t\t objid\t\tobjid\t\t group\n");
1107
1108                 for (i = 0; i < lum->lmm_stripe_count; i++) {
1109                         int idx = objects[i].l_ost_idx;
1110                         long long oid = objects[i].l_object_id;
1111                         long long gr = objects[i].l_object_gr;
1112                         if ((obdindex == OBD_NOT_FOUND) || (obdindex == idx))
1113                                 llapi_printf(LLAPI_MSG_NORMAL,
1114                                            "\t%6u\t%14llu\t%#13llx\t%14llu%s\n",
1115                                            idx, oid, oid, gr,
1116                                            obdindex == idx ? " *" : "");
1117                 }
1118                 llapi_printf(LLAPI_MSG_NORMAL, "\n");
1119         }
1120 }
1121
1122 void lov_dump_user_lmm_join(struct lov_user_md_v1 *lum, char *path,
1123                             int is_dir, int obdindex, int quiet,
1124                             int header, int body)
1125 {
1126         struct lov_user_md_join *lumj = (struct lov_user_md_join *)lum;
1127         int i, obdstripe = 0;
1128
1129         if (obdindex != OBD_NOT_FOUND) {
1130                 for (i = 0; i < lumj->lmm_stripe_count; i++) {
1131                         if (obdindex == lumj->lmm_objects[i].l_ost_idx) {
1132                                 llapi_printf(LLAPI_MSG_NORMAL, "%s\n", path);
1133                                 obdstripe = 1;
1134                                 break;
1135                         }
1136                 }
1137         } else {
1138                 if (!quiet)
1139                         llapi_printf(LLAPI_MSG_NORMAL, "%s\n", path);
1140                 obdstripe = 1;
1141         }
1142
1143         if (header && obdstripe == 1) {
1144                 lov_dump_user_lmm_header(lum, NULL, 0, header, quiet, NULL);
1145
1146                 llapi_printf(LLAPI_MSG_NORMAL, "lmm_extent_count:   %x\n",
1147                              lumj->lmm_extent_count);
1148         }
1149
1150         if (body) {
1151                 unsigned long long start = -1, end = 0;
1152                 if (!quiet && obdstripe == 1)
1153                         llapi_printf(LLAPI_MSG_NORMAL,
1154                                      "joined\tobdidx\t\t objid\t\tobjid\t\t "
1155                                      "group\t\tstart\t\tend\n");
1156                 for (i = 0; i < lumj->lmm_stripe_count; i++) {
1157                         int idx = lumj->lmm_objects[i].l_ost_idx;
1158                         long long oid = lumj->lmm_objects[i].l_object_id;
1159                         long long gr = lumj->lmm_objects[i].l_object_gr;
1160                         if (obdindex == OBD_NOT_FOUND || obdindex == idx)
1161                                 llapi_printf(LLAPI_MSG_NORMAL,
1162                                              "\t%6u\t%14llu\t%#13llx\t%14llu%s",
1163                                              idx, oid, oid, gr,
1164                                              obdindex == idx ? " *" : "");
1165                         if (start != lumj->lmm_objects[i].l_extent_start ||
1166                             end != lumj->lmm_objects[i].l_extent_end) {
1167                                 start = lumj->lmm_objects[i].l_extent_start;
1168                                 llapi_printf(LLAPI_MSG_NORMAL,"\t%14llu",start);
1169                                 end = lumj->lmm_objects[i].l_extent_end;
1170                                 if (end == (unsigned long long)-1)
1171                                         llapi_printf(LLAPI_MSG_NORMAL,
1172                                                      "\t\tEOF\n");
1173                                 else
1174                                         llapi_printf(LLAPI_MSG_NORMAL,
1175                                                      "\t\t%llu\n", end);
1176                         } else {
1177                                 llapi_printf(LLAPI_MSG_NORMAL, "\t\t\t\t\n");
1178                         }
1179                 }
1180                 llapi_printf(LLAPI_MSG_NORMAL, "\n");
1181         }
1182 }
1183
1184 void llapi_lov_dump_user_lmm(struct find_param *param,
1185                              char *path, int is_dir)
1186 {
1187         switch(*(__u32 *)&param->lmd->lmd_lmm) { /* lum->lmm_magic */
1188         case LOV_USER_MAGIC_V1:
1189                 lov_dump_user_lmm_v1v3(&param->lmd->lmd_lmm, NULL,
1190                                        param->lmd->lmd_lmm.lmm_objects,
1191                                        path, is_dir,
1192                                        param->obdindex, param->quiet,
1193                                        param->verbose,
1194                                        (param->verbose || !param->obduuid));
1195                 break;
1196         case LOV_USER_MAGIC_JOIN:
1197                 lov_dump_user_lmm_join(&param->lmd->lmd_lmm, path, is_dir,
1198                                        param->obdindex, param->quiet,
1199                                        param->verbose,
1200                                        (param->verbose || !param->obduuid));
1201                 break;
1202         case LOV_USER_MAGIC_V3: {
1203                 char pool_name[LOV_MAXPOOLNAME + 1];
1204                 struct lov_user_ost_data_v1 *objects;
1205                 struct lov_user_md_v3 *lmmv3 = (void *)&param->lmd->lmd_lmm;
1206
1207                 strncpy(pool_name, lmmv3->lmm_pool_name, LOV_MAXPOOLNAME);
1208                 pool_name[LOV_MAXPOOLNAME] = '\0';
1209                 objects = lmmv3->lmm_objects;
1210                 lov_dump_user_lmm_v1v3(&param->lmd->lmd_lmm, pool_name,
1211                                        objects, path, is_dir,
1212                                        param->obdindex, param->quiet,
1213                                        param->verbose,
1214                                        (param->verbose || !param->obduuid));
1215                 break;
1216         }
1217         default:
1218                 llapi_printf(LLAPI_MSG_NORMAL, "unknown lmm_magic:  %#x "
1219                              "(expecting one of %#x %#x %#x)\n",
1220                              *(__u32 *)&param->lmd->lmd_lmm,
1221                              LOV_USER_MAGIC_V1, LOV_USER_MAGIC_JOIN,
1222                              LOV_USER_MAGIC_V3);
1223                 return;
1224         }
1225 }
1226
1227 int llapi_file_get_stripe(const char *path, struct lov_user_md *lum)
1228 {
1229         const char *fname;
1230         char *dname;
1231         int fd, rc = 0;
1232
1233         fname = strrchr(path, '/');
1234
1235         /* It should be a file (or other non-directory) */
1236         if (fname == NULL) {
1237                 dname = (char *)malloc(2);
1238                 if (dname == NULL)
1239                         return ENOMEM;
1240                 strcpy(dname, ".");
1241                 fname = (char *)path;
1242         } else {
1243                 dname = (char *)malloc(fname - path + 1);
1244                 if (dname == NULL)
1245                         return ENOMEM;
1246                 strncpy(dname, path, fname - path);
1247                 dname[fname - path] = '\0';
1248                 fname++;
1249         }
1250
1251         if ((fd = open(dname, O_RDONLY)) == -1) {
1252                 rc = errno;
1253                 free(dname);
1254                 return rc;
1255         }
1256
1257         strcpy((char *)lum, fname);
1258         if (ioctl(fd, IOC_MDC_GETFILESTRIPE, (void *)lum) == -1)
1259                 rc = errno;
1260
1261         if (close(fd) == -1 && rc == 0)
1262                 rc = errno;
1263
1264         free(dname);
1265
1266         return rc;
1267 }
1268
1269 int llapi_file_lookup(int dirfd, const char *name)
1270 {
1271         struct obd_ioctl_data data = { 0 };
1272         char rawbuf[8192];
1273         char *buf = rawbuf;
1274         int rc;
1275
1276         if (dirfd < 0 || name == NULL)
1277                 return -EINVAL;
1278
1279         data.ioc_version = OBD_IOCTL_VERSION;
1280         data.ioc_len = sizeof(data);
1281         data.ioc_inlbuf1 = (char *)name;
1282         data.ioc_inllen1 = strlen(name) + 1;
1283
1284         rc = obd_ioctl_pack(&data, &buf, sizeof(rawbuf));
1285         if (rc) {
1286                 llapi_err(LLAPI_MSG_ERROR,
1287                           "error: IOC_MDC_LOOKUP pack failed for '%s': rc %d",
1288                           name, rc);
1289                 return rc;
1290         }
1291
1292         return ioctl(dirfd, IOC_MDC_LOOKUP, buf);
1293 }
1294
1295 int llapi_mds_getfileinfo(char *path, DIR *parent,
1296                           struct lov_user_mds_data *lmd)
1297 {
1298         lstat_t *st = &lmd->lmd_st;
1299         char *fname = strrchr(path, '/');
1300         int ret = 0;
1301
1302         if (parent == NULL)
1303                 return -EINVAL;
1304
1305         fname = (fname == NULL ? path : fname + 1);
1306         /* retrieve needed file info */
1307         strncpy((char *)lmd, fname,
1308                 lov_mds_md_size(MAX_LOV_UUID_COUNT, LOV_MAGIC));
1309         ret = ioctl(dirfd(parent), IOC_MDC_GETFILEINFO, (void *)lmd);
1310
1311         if (ret) {
1312                 if (errno == ENOTTY) {
1313                         /* ioctl is not supported, it is not a lustre fs.
1314                          * Do the regular lstat(2) instead. */
1315                         ret = lstat_f(path, st);
1316                         if (ret) {
1317                                 llapi_err(LLAPI_MSG_ERROR,
1318                                           "error: %s: lstat failed for %s",
1319                                           __FUNCTION__, path);
1320                                 return ret;
1321                         }
1322                 } else if (errno == ENOENT) {
1323                         llapi_err(LLAPI_MSG_WARN,
1324                                   "warning: %s: %s does not exist",
1325                                   __FUNCTION__, path);
1326                         return -ENOENT;
1327                 } else {
1328                         llapi_err(LLAPI_MSG_ERROR,
1329                                  "error: %s: IOC_MDC_GETFILEINFO failed for %s",
1330                                  __FUNCTION__, path);
1331                         return ret;
1332                 }
1333         }
1334
1335         return 0;
1336 }
1337
1338 static DIR *opendir_parent(char *path)
1339 {
1340         DIR *parent;
1341         char *fname;
1342         char c;
1343
1344         fname = strrchr(path, '/');
1345         if (fname == NULL)
1346                 return opendir(".");
1347
1348         c = fname[1];
1349         fname[1] = '\0';
1350         parent = opendir(path);
1351         fname[1] = c;
1352         return parent;
1353 }
1354
1355 static int llapi_semantic_traverse(char *path, int size, DIR *parent,
1356                                    semantic_func_t sem_init,
1357                                    semantic_func_t sem_fini, void *data,
1358                                    cfs_dirent_t *de)
1359 {
1360         cfs_dirent_t *dent;
1361         int len, ret;
1362         DIR *d, *p = NULL;
1363
1364         ret = 0;
1365         len = strlen(path);
1366
1367         d = opendir(path);
1368         if (!d && errno != ENOTDIR) {
1369                 llapi_err(LLAPI_MSG_ERROR, "%s: Failed to open '%s'",
1370                           __FUNCTION__, path);
1371                 return -EINVAL;
1372         } else if (!d && !parent) {
1373                 /* ENOTDIR. Open the parent dir. */
1374                 p = opendir_parent(path);
1375                 if (!p)
1376                         GOTO(out, ret = -EINVAL);
1377         }
1378
1379         if (sem_init && (ret = sem_init(path, parent ?: p, d, data, de)))
1380                 goto err;
1381
1382         if (!d)
1383                 GOTO(out, ret = 0);
1384
1385         while ((dent = readdir64(d)) != NULL) {
1386                 ((struct find_param *)data)->have_fileinfo = 0;
1387
1388                 if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
1389                         continue;
1390
1391                 /* Don't traverse .lustre directory */
1392                 if (!(strcmp(dent->d_name, dot_lustre_name)))
1393                         continue;
1394
1395                 path[len] = 0;
1396                 if ((len + dent->d_reclen + 2) > size) {
1397                         llapi_err(LLAPI_MSG_ERROR,
1398                                   "error: %s: string buffer is too small",
1399                                   __FUNCTION__);
1400                         break;
1401                 }
1402                 strcat(path, "/");
1403                 strcat(path, dent->d_name);
1404
1405                 if (dent->d_type == DT_UNKNOWN) {
1406                         lstat_t *st = &((struct find_param *)data)->lmd->lmd_st;
1407
1408                         ret = llapi_mds_getfileinfo(path, d,
1409                                              ((struct find_param *)data)->lmd);
1410                         if (ret == 0) {
1411                                 ((struct find_param *)data)->have_fileinfo = 1;
1412                                 dent->d_type =
1413                                         llapi_filetype_dir_table[st->st_mode &
1414                                                                  S_IFMT];
1415                         }
1416                         if (ret == -ENOENT)
1417                                 continue;
1418                 }
1419
1420                 switch (dent->d_type) {
1421                 case DT_UNKNOWN:
1422                         llapi_err(LLAPI_MSG_ERROR,
1423                                   "error: %s: '%s' is UNKNOWN type %d",
1424                                   __FUNCTION__, dent->d_name, dent->d_type);
1425                         break;
1426                 case DT_DIR:
1427                         ret = llapi_semantic_traverse(path, size, d, sem_init,
1428                                                       sem_fini, data, dent);
1429                         if (ret < 0)
1430                                 goto out;
1431                         break;
1432                 default:
1433                         ret = 0;
1434                         if (sem_init) {
1435                                 ret = sem_init(path, d, NULL, data, dent);
1436                                 if (ret < 0)
1437                                         goto out;
1438                         }
1439                         if (sem_fini && ret == 0)
1440                                 sem_fini(path, d, NULL, data, dent);
1441                 }
1442         }
1443
1444 out:
1445         path[len] = 0;
1446
1447         if (sem_fini)
1448                 sem_fini(path, parent, d, data, de);
1449 err:
1450         if (d)
1451                 closedir(d);
1452         if (p)
1453                 closedir(p);
1454         return ret;
1455 }
1456
1457 /* Check if the value matches 1 of the given criteria (e.g. --atime +/-N).
1458  * @mds indicates if this is MDS timestamps and there are attributes on OSTs.
1459  *
1460  * The result is -1 if it does not match, 0 if not yet clear, 1 if matches.
1461  * The table below gives the answers for the specified parameters (value and
1462  * sign), 1st column is the answer for the MDS value, the 2nd is for the OST:
1463  * --------------------------------------
1464  * 1 | file > limit; sign > 0 | -1 / -1 |
1465  * 2 | file = limit; sign > 0 |  ? /  1 |
1466  * 3 | file < limit; sign > 0 |  ? /  1 |
1467  * 4 | file > limit; sign = 0 | -1 / -1 |
1468  * 5 | file = limit; sign = 0 |  ? /  1 |  <- (see the Note below)
1469  * 6 | file < limit; sign = 0 |  ? / -1 |
1470  * 7 | file > limit; sign < 0 |  1 /  1 |
1471  * 8 | file = limit; sign < 0 |  ? / -1 |
1472  * 9 | file < limit; sign < 0 |  ? / -1 |
1473  * --------------------------------------
1474  * Note: 5th actually means that the value is within the interval
1475  * (limit - margin, limit]. */
1476 static int find_value_cmp(unsigned int file, unsigned int limit, int sign,
1477                           unsigned long long margin, int mds)
1478 {
1479         if (sign > 0) {
1480                 if (file < limit)
1481                         return mds ? 0 : 1;
1482         }
1483
1484         if (sign == 0) {
1485                 if (file <= limit && file + margin > limit)
1486                         return mds ? 0 : 1;
1487                 if (file + margin <= limit)
1488                         return mds ? 0 : -1;
1489         }
1490
1491         if (sign < 0) {
1492                 if (file > limit)
1493                         return 1;
1494                 if (mds)
1495                         return 0;
1496         }
1497
1498         return -1;
1499 }
1500
1501 /* Check if the file time matches all the given criteria (e.g. --atime +/-N).
1502  * Return -1 or 1 if file timestamp does not or does match the given criteria
1503  * correspondingly. Return 0 if the MDS time is being checked and there are
1504  * attributes on OSTs and it is not yet clear if the timespamp matches.
1505  *
1506  * If 0 is returned, we need to do another RPC to the OSTs to obtain the
1507  * updated timestamps. */
1508 static int find_time_check(lstat_t *st, struct find_param *param, int mds)
1509 {
1510         int ret;
1511         int rc = 0;
1512
1513         /* Check if file is accepted. */
1514         if (param->atime) {
1515                 ret = find_value_cmp(st->st_atime, param->atime,
1516                                      param->asign, 24 * 60 * 60, mds);
1517                 if (ret < 0)
1518                         return ret;
1519                 rc = ret;
1520         }
1521
1522         if (param->mtime) {
1523                 ret = find_value_cmp(st->st_mtime, param->mtime,
1524                                      param->msign, 24 * 60 * 60, mds);
1525                 if (ret < 0)
1526                         return ret;
1527
1528                 /* If the previous check matches, but this one is not yet clear,
1529                  * we should return 0 to do an RPC on OSTs. */
1530                 if (rc == 1)
1531                         rc = ret;
1532         }
1533
1534         if (param->ctime) {
1535                 ret = find_value_cmp(st->st_ctime, param->ctime,
1536                                      param->csign, 24 * 60 * 60, mds);
1537                 if (ret < 0)
1538                         return ret;
1539
1540                 /* If the previous check matches, but this one is not yet clear,
1541                  * we should return 0 to do an RPC on OSTs. */
1542                 if (rc == 1)
1543                         rc = ret;
1544         }
1545
1546         return rc;
1547 }
1548
1549 static int cb_find_init(char *path, DIR *parent, DIR *dir,
1550                         void *data, cfs_dirent_t *de)
1551 {
1552         struct find_param *param = (struct find_param *)data;
1553         int decision = 1; /* 1 is accepted; -1 is rejected. */
1554         lstat_t *st = &param->lmd->lmd_st;
1555         int lustre_fs = 1;
1556         int checked_type = 0;
1557         int ret = 0;
1558
1559         LASSERT(parent != NULL || dir != NULL);
1560
1561         param->lmd->lmd_lmm.lmm_stripe_count = 0;
1562
1563         /* If a regular expression is presented, make the initial decision */
1564         if (param->pattern != NULL) {
1565                 char *fname = strrchr(path, '/');
1566                 fname = (fname == NULL ? path : fname + 1);
1567                 ret = fnmatch(param->pattern, fname, 0);
1568                 if ((ret == FNM_NOMATCH && !param->exclude_pattern) ||
1569                     (ret == 0 && param->exclude_pattern))
1570                         goto decided;
1571         }
1572
1573         /* See if we can check the file type from the dirent. */
1574         if (param->type && de != NULL && de->d_type != DT_UNKNOWN &&
1575             de->d_type < DT_MAX) {
1576                 checked_type = 1;
1577                 if (llapi_dir_filetype_table[de->d_type] == param->type) {
1578                         if (param->exclude_type)
1579                                 goto decided;
1580                 } else {
1581                         if (!param->exclude_type)
1582                                 goto decided;
1583                 }
1584         }
1585
1586
1587         /* If a time or OST should be checked, the decision is not taken yet. */
1588         if (param->atime || param->ctime || param->mtime || param->obduuid ||
1589             param->size)
1590                 decision = 0;
1591
1592         ret = 0;
1593         /* Request MDS for the stat info. */
1594         if (param->have_fileinfo == 0) {
1595                 if (dir) {
1596                         /* retrieve needed file info */
1597                         ret = ioctl(dirfd(dir), LL_IOC_MDC_GETINFO,
1598                                     (void *)param->lmd);
1599                 } else {
1600                         char *fname = strrchr(path, '/');
1601                         fname = (fname == NULL ? path : fname + 1);
1602
1603                         /* retrieve needed file info */
1604                         strncpy((char *)param->lmd, fname, param->lumlen);
1605                         ret = ioctl(dirfd(parent), IOC_MDC_GETFILEINFO,
1606                                    (void *)param->lmd);
1607                 }
1608         }
1609
1610         if (ret) {
1611                 if (errno == ENOTTY) {
1612                         /* ioctl is not supported, it is not a lustre fs.
1613                          * Do the regular lstat(2) instead. */
1614                         lustre_fs = 0;
1615                         ret = lstat_f(path, st);
1616                         if (ret) {
1617                                 llapi_err(LLAPI_MSG_ERROR,
1618                                           "error: %s: lstat failed for %s",
1619                                           __FUNCTION__, path);
1620                                 return ret;
1621                         }
1622                 } else if (errno == ENOENT) {
1623                         llapi_err(LLAPI_MSG_WARN,
1624                                   "warning: %s: %s does not exist",
1625                                   __FUNCTION__, path);
1626                         goto decided;
1627                 } else {
1628                         llapi_err(LLAPI_MSG_ERROR,"error: %s: %s failed for %s",
1629                                   __FUNCTION__, dir ? "LL_IOC_MDC_GETINFO" :
1630                                   "IOC_MDC_GETFILEINFO", path);
1631                         return ret;
1632                 }
1633         }
1634
1635         if (param->type && !checked_type) {
1636                 if ((st->st_mode & S_IFMT) == param->type) {
1637                         if (param->exclude_type)
1638                                 goto decided;
1639                 } else {
1640                         if (!param->exclude_type)
1641                                 goto decided;
1642                 }
1643         }
1644
1645         /* Prepare odb. */
1646         if (param->obduuid) {
1647                 if (lustre_fs && param->got_uuids &&
1648                     param->st_dev != st->st_dev) {
1649                         /* A lustre/lustre mount point is crossed. */
1650                         param->got_uuids = 0;
1651                         param->obds_printed = 0;
1652                         param->obdindex = OBD_NOT_FOUND;
1653                 }
1654
1655                 if (lustre_fs && !param->got_uuids) {
1656                         ret = setup_obd_indexes(dir ? dir : parent, param);
1657                         if (ret)
1658                                 return ret;
1659
1660                         param->st_dev = st->st_dev;
1661                 } else if (!lustre_fs && param->got_uuids) {
1662                         /* A lustre/non-lustre mount point is crossed. */
1663                         param->got_uuids = 0;
1664                         param->obdindex = OBD_NOT_FOUND;
1665                 }
1666         }
1667
1668         /* If an OBD UUID is specified but no one matches, skip this file. */
1669         if (param->obduuid && param->obdindex == OBD_NOT_FOUND)
1670                 goto decided;
1671
1672         /* If a OST UUID is given, and some OST matches, check it here. */
1673         if (param->obdindex != OBD_NOT_FOUND) {
1674                 if (!S_ISREG(st->st_mode))
1675                         goto decided;
1676
1677                 /* Only those files should be accepted, which have a
1678                  * stripe on the specified OST. */
1679                 if (!param->lmd->lmd_lmm.lmm_stripe_count) {
1680                         goto decided;
1681                 } else {
1682                         int i, j;
1683                         struct lov_user_ost_data_v1 *lmm_objects;
1684
1685                         if (param->lmd->lmd_lmm.lmm_magic ==
1686                             LOV_USER_MAGIC_V3) {
1687                                 struct lov_user_md_v3 *lmmv3 =
1688                                         (void *)&param->lmd->lmd_lmm;
1689
1690                                 lmm_objects = lmmv3->lmm_objects;
1691                         } else {
1692                                 lmm_objects = param->lmd->lmd_lmm.lmm_objects;
1693                         }
1694
1695                         for (i = 0;
1696                              i < param->lmd->lmd_lmm.lmm_stripe_count; i++) {
1697                                 for (j = 0; j < param->num_obds; j++) {
1698                                         if (param->obdindexes[j] ==
1699                                             lmm_objects[i].l_ost_idx)
1700                                                 goto obd_matches;
1701                                 }
1702                         }
1703
1704                         if (i == param->lmd->lmd_lmm.lmm_stripe_count)
1705                                 goto decided;
1706                 }
1707         }
1708
1709         if (param->check_uid) {
1710                 if (st->st_uid == param->uid) {
1711                         if (param->exclude_uid)
1712                                 goto decided;
1713                 } else {
1714                         if (!param->exclude_uid)
1715                                 goto decided;
1716                 }
1717         }
1718
1719         if (param->check_gid) {
1720                 if (st->st_gid == param->gid) {
1721                         if (param->exclude_gid)
1722                                 goto decided;
1723                 } else {
1724                         if (!param->exclude_gid)
1725                                 goto decided;
1726                 }
1727         }
1728
1729         if (param->check_pool) {
1730                 struct lov_user_md_v3 *lmmv3 = (void *)&param->lmd->lmd_lmm;
1731
1732                 /* empty requested pool is taken as no pool search => V1 */
1733                 if (((param->lmd->lmd_lmm.lmm_magic == LOV_USER_MAGIC_V1) &&
1734                      (param->poolname[0] == '\0')) ||
1735                     ((param->lmd->lmd_lmm.lmm_magic == LOV_USER_MAGIC_V3) &&
1736                      (strncmp(lmmv3->lmm_pool_name,
1737                               param->poolname, LOV_MAXPOOLNAME) == 0)) ||
1738                     ((param->lmd->lmd_lmm.lmm_magic == LOV_USER_MAGIC_V3) &&
1739                      (strcmp(param->poolname, "*") == 0))) {
1740                         if (param->exclude_pool)
1741                                 goto decided;
1742                 } else {
1743                         if (!param->exclude_pool)
1744                                 goto decided;
1745                 }
1746         }
1747
1748         /* Check the time on mds. */
1749         if (!decision) {
1750                 int for_mds;
1751
1752                 for_mds = lustre_fs ? (S_ISREG(st->st_mode) &&
1753                                        param->lmd->lmd_lmm.lmm_stripe_count)
1754                                     : 0;
1755                 decision = find_time_check(st, param, for_mds);
1756         }
1757
1758 obd_matches:
1759         /* If file still fits the request, ask ost for updated info.
1760            The regular stat is almost of the same speed as some new
1761            'glimpse-size-ioctl'. */
1762         if (!decision && S_ISREG(st->st_mode) &&
1763             (param->lmd->lmd_lmm.lmm_stripe_count || param->size)) {
1764                 if (param->obdindex != OBD_NOT_FOUND) {
1765                         /* Check whether the obd is active or not, if it is
1766                          * not active, just print the object affected by this
1767                          * failed ost
1768                          * */
1769                         struct obd_statfs stat_buf;
1770                         struct obd_uuid uuid_buf;
1771
1772                         memset(&stat_buf, 0, sizeof(struct obd_statfs));
1773                         memset(&uuid_buf, 0, sizeof(struct obd_uuid));
1774                         ret = llapi_obd_statfs(path, LL_STATFS_LOV,
1775                                                param->obdindex, &stat_buf,
1776                                                &uuid_buf);
1777                         if (ret) {
1778                                 if (ret == -ENODATA || ret == -ENODEV
1779                                     || ret == -EIO)
1780                                         errno = EIO;
1781                                 llapi_printf(LLAPI_MSG_NORMAL,
1782                                              "obd_uuid: %s failed %s ",
1783                                              param->obduuid->uuid,
1784                                              strerror(errno));
1785                                 goto print_path;
1786                         }
1787                 }
1788                 if (dir) {
1789                         ret = ioctl(dirfd(dir), IOC_LOV_GETINFO,
1790                                     (void *)param->lmd);
1791                 } else if (parent) {
1792                         ret = ioctl(dirfd(parent), IOC_LOV_GETINFO,
1793                                     (void *)param->lmd);
1794                 }
1795
1796                 if (ret) {
1797                         if (errno == ENOENT) {
1798                                 llapi_err(LLAPI_MSG_ERROR,
1799                                           "warning: %s: %s does not exist",
1800                                           __FUNCTION__, path);
1801                                 goto decided;
1802                         } else {
1803                                 llapi_err(LLAPI_MSG_ERROR,
1804                                           "%s: IOC_LOV_GETINFO on %s failed",
1805                                           __FUNCTION__, path);
1806                                 return ret;
1807                         }
1808                 }
1809
1810                 /* Check the time on osc. */
1811                 decision = find_time_check(st, param, 0);
1812                 if (decision == -1)
1813                         goto decided;
1814         }
1815
1816         if (param->size)
1817                 decision = find_value_cmp(st->st_size, param->size,
1818                                           param->size_sign, param->size_units,
1819                                           0);
1820
1821 print_path:
1822         if (decision != -1) {
1823                 llapi_printf(LLAPI_MSG_NORMAL, "%s", path);
1824                 if (param->zeroend)
1825                         llapi_printf(LLAPI_MSG_NORMAL, "%c", '\0');
1826                 else
1827                         llapi_printf(LLAPI_MSG_NORMAL, "\n");
1828         }
1829
1830 decided:
1831         /* Do not get down anymore? */
1832         if (param->depth == param->maxdepth)
1833                 return 1;
1834
1835         param->depth++;
1836         return 0;
1837 }
1838
1839 static int cb_common_fini(char *path, DIR *parent, DIR *d, void *data,
1840                           cfs_dirent_t *de)
1841 {
1842         struct find_param *param = (struct find_param *)data;
1843         param->depth--;
1844         return 0;
1845 }
1846
1847 int llapi_find(char *path, struct find_param *param)
1848 {
1849         char *buf;
1850         int ret, len = strlen(path);
1851
1852         if (len > PATH_MAX) {
1853                 llapi_err(LLAPI_MSG_ERROR, "%s: Path name '%s' is too long",
1854                           __FUNCTION__, path);
1855                 return -EINVAL;
1856         }
1857
1858         buf = (char *)malloc(PATH_MAX + 1);
1859         if (!buf)
1860                 return -ENOMEM;
1861
1862         ret = common_param_init(param);
1863         if (ret) {
1864                 free(buf);
1865                 return ret;
1866         }
1867
1868         param->depth = 0;
1869
1870         strncpy(buf, path, PATH_MAX + 1);
1871         ret = llapi_semantic_traverse(buf, PATH_MAX + 1, NULL, cb_find_init,
1872                                       cb_common_fini, param, NULL);
1873
1874         find_param_fini(param);
1875         free(buf);
1876         return ret < 0 ? ret : 0;
1877 }
1878
1879 static int cb_getstripe(char *path, DIR *parent, DIR *d, void *data,
1880                         cfs_dirent_t *de)
1881 {
1882         struct find_param *param = (struct find_param *)data;
1883         int ret = 0;
1884
1885         LASSERT(parent != NULL || d != NULL);
1886
1887         /* Prepare odb. */
1888         if (!param->got_uuids) {
1889                 ret = setup_obd_uuid(d ? d : parent, path, param);
1890                 if (ret)
1891                         return ret;
1892         }
1893
1894         if (d) {
1895                 ret = ioctl(dirfd(d), LL_IOC_LOV_GETSTRIPE,
1896                             (void *)&param->lmd->lmd_lmm);
1897         } else if (parent) {
1898                 char *fname = strrchr(path, '/');
1899                 fname = (fname == NULL ? path : fname + 1);
1900
1901                 strncpy((char *)&param->lmd->lmd_lmm, fname, param->lumlen);
1902                 ret = ioctl(dirfd(parent), IOC_MDC_GETFILESTRIPE,
1903                             (void *)&param->lmd->lmd_lmm);
1904         }
1905
1906         if (ret) {
1907                 if (errno == ENODATA) {
1908                         if (!param->obduuid && !param->quiet)
1909                                 llapi_printf(LLAPI_MSG_NORMAL,
1910                                              "%s has no stripe info\n", path);
1911                         goto out;
1912                 } else if (errno == ENOTTY) {
1913                         llapi_err(LLAPI_MSG_ERROR,
1914                                   "%s: '%s' not on a Lustre fs?",
1915                                   __FUNCTION__, path);
1916                 } else if (errno == ENOENT) {
1917                         llapi_err(LLAPI_MSG_WARN,
1918                                   "warning: %s: %s does not exist",
1919                                   __FUNCTION__, path);
1920                         goto out;
1921                 } else {
1922                         llapi_err(LLAPI_MSG_ERROR,
1923                                   "error: %s: %s failed for %s",
1924                                    __FUNCTION__, d ? "LL_IOC_LOV_GETSTRIPE" :
1925                                   "IOC_MDC_GETFILESTRIPE", path);
1926                 }
1927
1928                 return ret;
1929         }
1930
1931         llapi_lov_dump_user_lmm(param, path, d ? 1 : 0);
1932 out:
1933         /* Do not get down anymore? */
1934         if (param->depth == param->maxdepth)
1935                 return 1;
1936
1937         param->depth++;
1938         return 0;
1939 }
1940
1941 int llapi_getstripe(char *path, struct find_param *param)
1942 {
1943         char *buf;
1944         int ret = 0, len = strlen(path);
1945
1946         if (len > PATH_MAX) {
1947                 llapi_err(LLAPI_MSG_ERROR,
1948                           "%s: Path name '%s' is too long",
1949                           __FUNCTION__, path);
1950                 return -EINVAL;
1951         }
1952
1953         buf = (char *)malloc(PATH_MAX + 1);
1954         if (!buf)
1955                 return -ENOMEM;
1956
1957         ret = common_param_init(param);
1958         if (ret) {
1959                 free(buf);
1960                 return ret;
1961         }
1962
1963         param->depth = 0;
1964
1965         strncpy(buf, path, PATH_MAX + 1);
1966         ret = llapi_semantic_traverse(buf, PATH_MAX + 1, NULL, cb_getstripe,
1967                                       cb_common_fini, param, NULL);
1968         find_param_fini(param);
1969         free(buf);
1970         return ret < 0 ? ret : 0;
1971 }
1972
1973 int llapi_obd_statfs(char *path, __u32 type, __u32 index,
1974                      struct obd_statfs *stat_buf,
1975                      struct obd_uuid *uuid_buf)
1976 {
1977         int fd;
1978         char raw[OBD_MAX_IOCTL_BUFFER] = {'\0'};
1979         char *rawbuf = raw;
1980         struct obd_ioctl_data data = { 0 };
1981         int rc = 0;
1982
1983         data.ioc_inlbuf1 = (char *)&type;
1984         data.ioc_inllen1 = sizeof(__u32);
1985         data.ioc_inlbuf2 = (char *)&index;
1986         data.ioc_inllen2 = sizeof(__u32);
1987         data.ioc_pbuf1 = (char *)stat_buf;
1988         data.ioc_plen1 = sizeof(struct obd_statfs);
1989         data.ioc_pbuf2 = (char *)uuid_buf;
1990         data.ioc_plen2 = sizeof(struct obd_uuid);
1991
1992         if ((rc = obd_ioctl_pack(&data, &rawbuf, sizeof(raw))) != 0) {
1993                 llapi_err(LLAPI_MSG_ERROR,
1994                           "llapi_obd_statfs: error packing ioctl data");
1995                 return rc;
1996         }
1997
1998         fd = open(path, O_RDONLY);
1999         if (errno == EISDIR)
2000                 fd = open(path, O_DIRECTORY | O_RDONLY);
2001
2002         if (fd < 0) {
2003                 rc = errno ? -errno : -EBADF;
2004                 llapi_err(LLAPI_MSG_ERROR, "error: %s: opening '%s'",
2005                           __FUNCTION__, path);
2006                 return rc;
2007         }
2008         rc = ioctl(fd, IOC_OBD_STATFS, (void *)rawbuf);
2009         if (rc)
2010                 rc = errno ? -errno : -EINVAL;
2011
2012         close(fd);
2013         return rc;
2014 }
2015
2016 #define MAX_STRING_SIZE 128
2017 #define DEVICES_LIST "/proc/fs/lustre/devices"
2018
2019 int llapi_ping(char *obd_type, char *obd_name)
2020 {
2021         char path[MAX_STRING_SIZE];
2022         char buf[1];
2023         int rc, fd;
2024
2025         snprintf(path, MAX_STRING_SIZE, "/proc/fs/lustre/%s/%s/ping",
2026                  obd_type, obd_name);
2027
2028         fd = open(path, O_WRONLY);
2029         if (fd < 0) {
2030                 rc = errno;
2031                 llapi_err(LLAPI_MSG_ERROR, "error opening %s", path);
2032                 return rc;
2033         }
2034
2035         rc = write(fd, buf, 1);
2036         close(fd);
2037
2038         if (rc == 1)
2039                 return 0;
2040         return rc;
2041 }
2042
2043 int llapi_target_iterate(int type_num, char **obd_type,void *args,llapi_cb_t cb)
2044 {
2045         char buf[MAX_STRING_SIZE];
2046         FILE *fp = fopen(DEVICES_LIST, "r");
2047         int i, rc = 0;
2048
2049         if (fp == NULL) {
2050                 rc = errno;
2051                 llapi_err(LLAPI_MSG_ERROR, "error: opening "DEVICES_LIST);
2052                 return rc;
2053         }
2054
2055         while (fgets(buf, sizeof(buf), fp) != NULL) {
2056                 char *obd_type_name = NULL;
2057                 char *obd_name = NULL;
2058                 char *obd_uuid = NULL;
2059                 char *bufp = buf;
2060                 struct obd_ioctl_data datal = { 0, };
2061                 struct obd_statfs osfs_buffer;
2062
2063                 while(bufp[0] == ' ')
2064                         ++bufp;
2065
2066                 for(i = 0; i < 3; i++) {
2067                         obd_type_name = strsep(&bufp, " ");
2068                 }
2069                 obd_name = strsep(&bufp, " ");
2070                 obd_uuid = strsep(&bufp, " ");
2071
2072                 memset(&osfs_buffer, 0, sizeof (osfs_buffer));
2073
2074                 datal.ioc_pbuf1 = (char *)&osfs_buffer;
2075                 datal.ioc_plen1 = sizeof(osfs_buffer);
2076
2077                 for (i = 0; i < type_num; i++) {
2078                         if (strcmp(obd_type_name, obd_type[i]) != 0)
2079                                 continue;
2080
2081                         cb(obd_type_name, obd_name, obd_uuid, args);
2082                 }
2083         }
2084         fclose(fp);
2085         return rc;
2086 }
2087
2088 static void do_target_check(char *obd_type_name, char *obd_name,
2089                             char *obd_uuid, void *args)
2090 {
2091         int rc;
2092
2093         rc = llapi_ping(obd_type_name, obd_name);
2094         if (rc == ENOTCONN) {
2095                 llapi_printf(LLAPI_MSG_NORMAL, "%s inactive.\n", obd_name);
2096         } else if (rc) {
2097                 llapi_err(LLAPI_MSG_ERROR, "error: check '%s'", obd_name);
2098         } else {
2099                 llapi_printf(LLAPI_MSG_NORMAL, "%s active.\n", obd_name);
2100         }
2101 }
2102
2103 int llapi_target_check(int type_num, char **obd_type, char *dir)
2104 {
2105         return llapi_target_iterate(type_num, obd_type, NULL, do_target_check);
2106 }
2107
2108 #undef MAX_STRING_SIZE
2109
2110 int llapi_catinfo(char *dir, char *keyword, char *node_name)
2111 {
2112         char raw[OBD_MAX_IOCTL_BUFFER];
2113         char out[LLOG_CHUNK_SIZE];
2114         char *buf = raw;
2115         struct obd_ioctl_data data = { 0 };
2116         char key[30];
2117         DIR *root;
2118         int rc;
2119
2120         sprintf(key, "%s", keyword);
2121         memset(raw, 0, sizeof(raw));
2122         memset(out, 0, sizeof(out));
2123         data.ioc_inlbuf1 = key;
2124         data.ioc_inllen1 = strlen(key) + 1;
2125         if (node_name) {
2126                 data.ioc_inlbuf2 = node_name;
2127                 data.ioc_inllen2 = strlen(node_name) + 1;
2128         }
2129         data.ioc_pbuf1 = out;
2130         data.ioc_plen1 = sizeof(out);
2131         rc = obd_ioctl_pack(&data, &buf, sizeof(raw));
2132         if (rc)
2133                 return rc;
2134
2135         root = opendir(dir);
2136         if (root == NULL) {
2137                 rc = errno;
2138                 llapi_err(LLAPI_MSG_ERROR, "open %s failed", dir);
2139                 return rc;
2140         }
2141
2142         rc = ioctl(dirfd(root), OBD_IOC_LLOG_CATINFO, buf);
2143         if (rc)
2144                 llapi_err(LLAPI_MSG_ERROR, "ioctl OBD_IOC_CATINFO failed");
2145         else
2146                 llapi_printf(LLAPI_MSG_NORMAL, "%s", data.ioc_pbuf1);
2147
2148         closedir(root);
2149         return rc;
2150 }
2151
2152 /* Is this a lustre fs? */
2153 int llapi_is_lustre_mnttype(const char *type)
2154 {
2155         return (strcmp(type, "lustre") == 0 || strcmp(type,"lustre_lite") == 0);
2156 }
2157
2158 /* Is this a lustre client fs? */
2159 int llapi_is_lustre_mnt(struct mntent *mnt)
2160 {
2161         return (llapi_is_lustre_mnttype(mnt->mnt_type) &&
2162                 strstr(mnt->mnt_fsname, ":/") != NULL);
2163 }
2164
2165 int llapi_quotacheck(char *mnt, int check_type)
2166 {
2167         DIR *root;
2168         int rc;
2169
2170         root = opendir(mnt);
2171         if (!root) {
2172                 llapi_err(LLAPI_MSG_ERROR, "open %s failed", mnt);
2173                 return -1;
2174         }
2175
2176         rc = ioctl(dirfd(root), LL_IOC_QUOTACHECK, check_type);
2177
2178         closedir(root);
2179         return rc;
2180 }
2181
2182 int llapi_poll_quotacheck(char *mnt, struct if_quotacheck *qchk)
2183 {
2184         DIR *root;
2185         int poll_intvl = 2;
2186         int rc;
2187
2188         root = opendir(mnt);
2189         if (!root) {
2190                 llapi_err(LLAPI_MSG_ERROR, "open %s failed", mnt);
2191                 return -1;
2192         }
2193
2194         while (1) {
2195                 rc = ioctl(dirfd(root), LL_IOC_POLL_QUOTACHECK, qchk);
2196                 if (!rc)
2197                         break;
2198                 sleep(poll_intvl);
2199                 if (poll_intvl < 30)
2200                         poll_intvl *= 2;
2201         }
2202
2203         closedir(root);
2204         return rc;
2205 }
2206
2207 int llapi_quotactl(char *mnt, struct if_quotactl *qctl)
2208 {
2209         DIR *root;
2210         int rc;
2211
2212         root = opendir(mnt);
2213         if (!root) {
2214                 llapi_err(LLAPI_MSG_ERROR, "open %s failed", mnt);
2215                 return -1;
2216         }
2217
2218         rc = ioctl(dirfd(root), LL_IOC_QUOTACTL, qctl);
2219
2220         closedir(root);
2221         return rc;
2222 }
2223
2224 static int cb_quotachown(char *path, DIR *parent, DIR *d, void *data,
2225                          cfs_dirent_t *de)
2226 {
2227         struct find_param *param = (struct find_param *)data;
2228         lstat_t *st;
2229         int rc;
2230
2231         LASSERT(parent != NULL || d != NULL);
2232
2233         if (d) {
2234                 rc = ioctl(dirfd(d), LL_IOC_MDC_GETINFO,
2235                            (void *)param->lmd);
2236         } else if (parent) {
2237                 char *fname = strrchr(path, '/');
2238                 fname = (fname == NULL ? path : fname + 1);
2239
2240                 strncpy((char *)param->lmd, fname, param->lumlen);
2241                 rc = ioctl(dirfd(parent), IOC_MDC_GETFILEINFO,
2242                            (void *)param->lmd);
2243         } else {
2244                 return 0;
2245         }
2246
2247         if (rc) {
2248                 if (errno == ENODATA) {
2249                         if (!param->obduuid && !param->quiet)
2250                                 llapi_err(LLAPI_MSG_ERROR,
2251                                           "%s has no stripe info", path);
2252                         rc = 0;
2253                 } else if (errno == ENOENT) {
2254                         llapi_err(LLAPI_MSG_ERROR,
2255                                   "warning: %s: %s does not exist",
2256                                   __FUNCTION__, path);
2257                         rc = 0;
2258                 } else if (errno != EISDIR) {
2259                         rc = errno;
2260                         llapi_err(LLAPI_MSG_ERROR, "%s ioctl failed for %s.",
2261                                   d ? "LL_IOC_MDC_GETINFO" :
2262                                   "IOC_MDC_GETFILEINFO", path);
2263                 }
2264                 return rc;
2265         }
2266
2267         st = &param->lmd->lmd_st;
2268
2269         /* libc chown() will do extra check, and if the real owner is
2270          * the same as the ones to set, it won't fall into kernel, so
2271          * invoke syscall directly. */
2272         rc = syscall(SYS_chown, path, -1, -1);
2273         if (rc)
2274                 llapi_err(LLAPI_MSG_ERROR,"error: chown %s (%u,%u)", path);
2275
2276         rc = chmod(path, st->st_mode);
2277         if (rc)
2278                 llapi_err(LLAPI_MSG_ERROR, "error: chmod %s (%hu)",
2279                           path, st->st_mode);
2280
2281         return rc;
2282 }
2283
2284 int llapi_quotachown(char *path, int flag)
2285 {
2286         struct find_param param;
2287         char *buf;
2288         int ret = 0, len = strlen(path);
2289
2290         if (len > PATH_MAX) {
2291                 llapi_err(LLAPI_MSG_ERROR, "%s: Path name '%s' is too long",
2292                           __FUNCTION__, path);
2293                 return -EINVAL;
2294         }
2295
2296         buf = (char *)malloc(PATH_MAX + 1);
2297         if (!buf)
2298                 return -ENOMEM;
2299
2300         memset(&param, 0, sizeof(param));
2301         param.recursive = 1;
2302         param.verbose = 0;
2303         param.quiet = 1;
2304
2305         ret = common_param_init(&param);
2306         if (ret)
2307                 goto out;
2308
2309         strncpy(buf, path, PATH_MAX + 1);
2310         ret = llapi_semantic_traverse(buf, PATH_MAX + 1, NULL, cb_quotachown,
2311                                       NULL, &param, NULL);
2312 out:
2313         find_param_fini(&param);
2314         free(buf);
2315         return ret;
2316 }
2317
2318 #include <pwd.h>
2319 #include <grp.h>
2320 #include <mntent.h>
2321 #include <sys/wait.h>
2322 #include <errno.h>
2323 #include <ctype.h>
2324
2325 static int rmtacl_notify(int ops)
2326 {
2327         FILE *fp;
2328         struct mntent *mnt;
2329         int found = 0, fd, rc;
2330
2331         fp = setmntent(MOUNTED, "r");
2332         if (fp == NULL) {
2333                 perror("setmntent");
2334                 return -1;
2335         }
2336
2337         while (1) {
2338                 mnt = getmntent(fp);
2339                 if (!mnt)
2340                         break;
2341
2342                 if (!llapi_is_lustre_mnt(mnt))
2343                         continue;
2344
2345                 fd = open(mnt->mnt_dir, O_RDONLY | O_DIRECTORY);
2346                 if (fd < 0) {
2347                         perror("open");
2348                         return -1;
2349                 }
2350
2351                 rc = ioctl(fd, LL_IOC_RMTACL, ops);
2352                 if (rc < 0) {
2353                         perror("ioctl");
2354                 return -1;
2355                 }
2356
2357                 found++;
2358         }
2359         endmntent(fp);
2360         return found;
2361 }
2362
2363 static char *next_token(char *p, int div)
2364 {
2365         if (p == NULL)
2366                 return NULL;
2367
2368         if (div)
2369                 while (*p && *p != ':' && !isspace(*p))
2370                         p++;
2371         else
2372                 while (*p == ':' || isspace(*p))
2373                         p++;
2374
2375         return *p ? p : NULL;
2376 }
2377
2378 static int rmtacl_name2id(char *name, int is_user)
2379 {
2380         if (is_user) {
2381                 struct passwd *pw;
2382
2383                 if ((pw = getpwnam(name)) == NULL)
2384                         return INVALID_ID;
2385                 else
2386                         return (int)(pw->pw_uid);
2387         } else {
2388                 struct group *gr;
2389
2390                 if ((gr = getgrnam(name)) == NULL)
2391                         return INVALID_ID;
2392                 else
2393                         return (int)(gr->gr_gid);
2394         }
2395 }
2396
2397 static int isodigit(int c)
2398 {
2399         return (c >= '0' && c <= '7') ? 1 : 0;
2400 }
2401
2402 /*
2403  * Whether the name is just digits string (uid/gid) already or not.
2404  * Return value:
2405  * 1: str is id
2406  * 0: str is not id
2407  */
2408 static int str_is_id(char *str)
2409 {
2410         if (str == NULL)
2411                 return 0;
2412
2413         if (*str == '0') {
2414                 str++;
2415                 if (*str == 'x' || *str == 'X') { /* for Hex. */
2416                         if (!isxdigit(*(++str)))
2417                                 return 0;
2418
2419                         while (isxdigit(*(++str)));
2420                 } else if (isodigit(*str)) { /* for Oct. */
2421                         while (isodigit(*(++str)));
2422                 }
2423         } else if (isdigit(*str)) { /* for Dec. */
2424                 while (isdigit(*(++str)));
2425         }
2426
2427         return (*str == 0) ? 1 : 0;
2428 }
2429
2430 typedef struct {
2431         char *name;
2432         int   length;
2433         int   is_user;
2434         int   next_token;
2435 } rmtacl_name_t;
2436
2437 #define RMTACL_OPTNAME(name) name, sizeof(name) - 1
2438
2439 static rmtacl_name_t rmtacl_namelist[] = {
2440         { RMTACL_OPTNAME("user:"),            1,      0 },
2441         { RMTACL_OPTNAME("group:"),           0,      0 },
2442         { RMTACL_OPTNAME("default:user:"),    1,      0 },
2443         { RMTACL_OPTNAME("default:group:"),   0,      0 },
2444         /* for --tabular option */
2445         { RMTACL_OPTNAME("user"),             1,      1 },
2446         { RMTACL_OPTNAME("group"),            0,      1 },
2447         { 0 }
2448 };
2449
2450 static int rgetfacl_output(char *str)
2451 {
2452         char *start = NULL, *end = NULL;
2453         int is_user = 0, n, id;
2454         char c;
2455         rmtacl_name_t *rn;
2456
2457         if (str == NULL)
2458                 return -1;
2459
2460         for (rn = rmtacl_namelist; rn->name; rn++) {
2461                 if(strncmp(str, rn->name, rn->length) == 0) {
2462                         if (!rn->next_token)
2463                                 start = str + rn->length;
2464                         else
2465                                 start = next_token(str + rn->length, 0);
2466                         is_user = rn->is_user;
2467                         break;
2468                 }
2469         }
2470
2471         end = next_token(start, 1);
2472         if (end == NULL || start == end) {
2473                 n = printf("%s", str);
2474                 return n;
2475         }
2476
2477         c = *end;
2478         *end = 0;
2479         id = rmtacl_name2id(start, is_user);
2480         if (id == INVALID_ID) {
2481                 if (str_is_id(start)) {
2482                         *end = c;
2483                         n = printf("%s", str);
2484                 } else
2485                         return -1;
2486         } else if ((id == NOBODY_UID && is_user) ||
2487                    (id == NOBODY_GID && !is_user)) {
2488                 *end = c;
2489                 n = printf("%s", str);
2490         } else {
2491                 *end = c;
2492                 *start = 0;
2493                 n = printf("%s%d%s", str, id, end);
2494         }
2495         return n;
2496 }
2497
2498 static int child_status(int status)
2499 {
2500         return WIFEXITED(status) ? WEXITSTATUS(status) : -1;
2501 }
2502
2503 static int do_rmtacl(int argc, char *argv[], int ops, int (output_func)(char *))
2504 {
2505         pid_t pid = 0;
2506         int fd[2], status;
2507         FILE *fp;
2508         char buf[PIPE_BUF];
2509
2510         if (output_func) {
2511                 if (pipe(fd) < 0) {
2512                         perror("pipe");
2513                         return -1;
2514                 }
2515
2516                 if ((pid = fork()) < 0) {
2517                         perror("fork");
2518                         close(fd[0]);
2519                         close(fd[1]);
2520                         return -1;
2521                 } else if (!pid) {
2522                         /* child process redirects its output. */
2523                         close(fd[0]);
2524                         close(1);
2525                         if (dup2(fd[1], 1) < 0) {
2526                                 perror("dup2");
2527                                 close(fd[1]);
2528                                 return -1;
2529                         }
2530                 } else {
2531                         close(fd[1]);
2532                 }
2533         }
2534
2535         if (!pid) {
2536                 status = rmtacl_notify(ops);
2537                 if (status < 0)
2538                         return -1;
2539
2540                 exit(execvp(argv[0], argv));
2541         }
2542
2543         /* the following is parent process */
2544         if ((fp = fdopen(fd[0], "r")) == NULL) {
2545                 perror("fdopen");
2546                 kill(pid, SIGKILL);
2547                 close(fd[0]);
2548                 return -1;
2549         }
2550
2551         while (fgets(buf, PIPE_BUF, fp) != NULL) {
2552                 if (output_func(buf) < 0)
2553                         fprintf(stderr, "WARNING: unexpected error!\n[%s]\n",
2554                                 buf);
2555         }
2556         fclose(fp);
2557         close(fd[0]);
2558
2559         if (waitpid(pid, &status, 0) < 0) {
2560                 perror("waitpid");
2561                 return -1;
2562         }
2563
2564         return child_status(status);
2565 }
2566
2567 int llapi_lsetfacl(int argc, char *argv[])
2568 {
2569         return do_rmtacl(argc, argv, RMT_LSETFACL, NULL);
2570 }
2571
2572 int llapi_lgetfacl(int argc, char *argv[])
2573 {
2574         return do_rmtacl(argc, argv, RMT_LGETFACL, NULL);
2575 }
2576
2577 int llapi_rsetfacl(int argc, char *argv[])
2578 {
2579         return do_rmtacl(argc, argv, RMT_RSETFACL, NULL);
2580 }
2581
2582 int llapi_rgetfacl(int argc, char *argv[])
2583 {
2584         return do_rmtacl(argc, argv, RMT_RGETFACL, rgetfacl_output);
2585 }
2586
2587 int llapi_cp(int argc, char *argv[])
2588 {
2589         int rc;
2590
2591         rc = rmtacl_notify(RMT_RSETFACL);
2592         if (rc < 0)
2593                 return -1;
2594
2595         exit(execvp(argv[0], argv));
2596 }
2597
2598 int llapi_ls(int argc, char *argv[])
2599 {
2600         int rc;
2601
2602         rc = rmtacl_notify(RMT_LGETFACL);
2603         if (rc < 0)
2604                 return -1;
2605
2606         exit(execvp(argv[0], argv));
2607 }
2608
2609 /* Print mdtname 'name' into 'buf' using 'format'.  Add -MDT0000 if needed.
2610  * format must have %s%s, buf must be > 16
2611  */
2612 static int get_mdtname(char *name, char *format, char *buf)
2613 {
2614         char suffix[]="-MDT0000";
2615         int len = strlen(name);
2616
2617         if ((len > 5) && (strncmp(name + len - 5, "_UUID", 5) == 0)) {
2618                 name[len - 5] = '\0';
2619                 len -= 5;
2620         }
2621
2622         if (len > 8) {
2623                 if ((len <= 16) && strncmp(name + len - 8, "-MDT", 4) == 0) {
2624                         suffix[0] = '\0';
2625                 } else {
2626                         /* Not enough room to add suffix */
2627                         llapi_err(LLAPI_MSG_ERROR | LLAPI_MSG_NO_ERRNO,
2628                                   "MDT name too long |%s|", name);
2629                         return -EINVAL;
2630                 }
2631         }
2632
2633         return sprintf(buf, format, name, suffix);
2634 }
2635
2636 /****** Changelog API ********/
2637 #define CHANGELOG_PRIV_MAGIC 0xCA8E1080
2638 struct changelog_private {
2639         int magic;
2640         int fd;
2641         int flags;
2642 };
2643
2644 /** Start reading from a changelog
2645  * @param priv Opaque private control structure
2646  * @param flags Start flags (e.g. follow)
2647  * @param device Report changes recorded on this MDT
2648  * @param startrec Report changes beginning with this record number
2649  */
2650 int llapi_changelog_start(void **priv, int flags, const char *device,
2651                           long long startrec)
2652 {
2653         struct changelog_private *cp;
2654         char path[256];
2655         char mdtname[20];
2656         int rc, fd;
2657
2658         if (device[0] == '/')
2659                 rc = llapi_search_fsname(device, mdtname);
2660         else
2661                 strncpy(mdtname, device, sizeof(mdtname));
2662
2663         /* Use either the mdd changelog (preferred) or a client mdc changelog */
2664         if (get_mdtname(mdtname,
2665                         "/proc/fs/lustre/md[cd]/%s%s{,-mdc-*}/changelog",
2666                         path) < 0)
2667                 return -EINVAL;
2668         rc = first_match(path, path);
2669         if (rc)
2670                 return rc;
2671
2672         if ((fd = open(path, O_RDONLY)) < 0) {
2673                 llapi_err(LLAPI_MSG_ERROR, "error: can't open |%s|\n", path);
2674                 return -errno;
2675         }
2676
2677         rc = lseek(fd, (off_t)startrec, SEEK_SET);
2678         if (rc < 0) {
2679                 llapi_err(LLAPI_MSG_ERROR, "can't seek rc=%d\n", rc);
2680                 return -errno;
2681         }
2682
2683         cp = malloc(sizeof(*cp));
2684         if (cp == NULL) {
2685                 close(fd);
2686                 return -ENOMEM;
2687         }
2688
2689         cp->magic = CHANGELOG_PRIV_MAGIC;
2690         cp->fd = fd;
2691         cp->flags = flags;
2692         *priv = cp;
2693
2694         return 0;
2695 }
2696
2697 /** Finish reading from a changelog */
2698 int llapi_changelog_fini(void **priv)
2699 {
2700         struct changelog_private *cp = (struct changelog_private *)*priv;
2701
2702         if (!cp || (cp->magic != CHANGELOG_PRIV_MAGIC))
2703                 return -EINVAL;
2704
2705         close(cp->fd);
2706         free(cp);
2707         *priv = NULL;
2708         return 0;
2709 }
2710
2711 static int pollwait(int fd) {
2712         struct pollfd pfds[1];
2713         int rc;
2714
2715         pfds[0].fd = fd;
2716         pfds[0].events = POLLIN;
2717         rc = poll(pfds, 1, -1);
2718         return rc < 0 ? -errno : rc;
2719 }
2720
2721 /** Read the next changelog entry
2722  * @param priv Opaque private control structure
2723  * @param rech Changelog record handle; record will be allocated here
2724  * @return 0 valid message received; rec is set
2725  *         <0 error code
2726  *         1 EOF
2727  */
2728 int llapi_changelog_recv(void *priv, struct changelog_rec **rech)
2729 {
2730         struct changelog_private *cp = (struct changelog_private *)priv;
2731         struct changelog_rec rec, *recp;
2732         int rc = 0;
2733
2734         if (!cp || (cp->magic != CHANGELOG_PRIV_MAGIC))
2735                 return -EINVAL;
2736         if (rech == NULL)
2737                 return -EINVAL;
2738
2739 readrec:
2740         /* Read in the rec to get the namelen */
2741         rc = read(cp->fd, &rec, sizeof(rec));
2742         if (rc < 0)
2743                 return -errno;
2744         if (rc == 0) {
2745                 if (cp->flags && CHANGELOG_FLAG_FOLLOW) {
2746                         rc = pollwait(cp->fd);
2747                         if (rc < 0)
2748                                 return rc;
2749                         goto readrec;
2750                 }
2751                 return 1;
2752         }
2753
2754         recp = malloc(sizeof(rec) + rec.cr_namelen);
2755         if (recp == NULL)
2756                 return -ENOMEM;
2757         memcpy(recp, &rec, sizeof(rec));
2758         rc = read(cp->fd, recp->cr_name, rec.cr_namelen);
2759         if (rc < 0) {
2760                 free(recp);
2761                 llapi_err(LLAPI_MSG_ERROR, "Can't read entire filename");
2762                 return -errno;
2763         }
2764
2765         *rech = recp;
2766         return 0;
2767 }
2768
2769 /** Release the changelog record when done with it. */
2770 int llapi_changelog_free(struct changelog_rec **rech)
2771 {
2772         if (*rech)
2773                 free(*rech);
2774         *rech = NULL;
2775         return 0;
2776 }
2777
2778 int llapi_changelog_clear(const char *mdtname, const char *idstr,
2779                           long long endrec)
2780 {
2781         struct ioc_changelog_clear data;
2782         char fsname[17];
2783         char *ptr;
2784         int id, fd, index, rc;
2785
2786         if (endrec < 0) {
2787                 llapi_err(LLAPI_MSG_ERROR | LLAPI_MSG_NO_ERRNO,
2788                           "can't purge negative records\n");
2789                 return -EINVAL;
2790         }
2791
2792         id = strtol(idstr + strlen(CHANGELOG_USER_PREFIX), NULL, 10);
2793         if ((id == 0) || (strncmp(idstr, CHANGELOG_USER_PREFIX,
2794                                   strlen(CHANGELOG_USER_PREFIX)) != 0)) {
2795                 llapi_err(LLAPI_MSG_ERROR | LLAPI_MSG_NO_ERRNO,
2796                           "expecting id of the form '"CHANGELOG_USER_PREFIX
2797                           "<num>'; got '%s'\n", idstr);
2798                 return -EINVAL;
2799         }
2800
2801         /* Take path, fsname, or MDTNAME.  Assume MDT0000 in the former cases */
2802         if (mdtname[0] == '/') {
2803                 index = 0;
2804                 fd = open(mdtname, O_RDONLY | O_DIRECTORY | O_NONBLOCK);
2805                 rc = fd < 0 ? -errno : 0;
2806         } else {
2807                 if (get_mdtname((char *)mdtname, "%s%s", fsname) < 0)
2808                         return -EINVAL;
2809                 ptr = fsname + strlen(fsname) - 8;
2810                 *ptr = '\0';
2811                 index = strtol(ptr + 4, NULL, 10);
2812                 rc = get_root_path(WANT_FD | WANT_ERROR, fsname, &fd, NULL, -1);
2813         }
2814         if (rc < 0) {
2815                 llapi_err(LLAPI_MSG_ERROR | LLAPI_MSG_NO_ERRNO,
2816                           "Can't open %s: %d\n", mdtname, rc);
2817                 return rc;
2818         }
2819
2820         data.icc_mdtindex = index;
2821         data.icc_id = id;
2822         data.icc_recno = endrec;
2823         rc = ioctl(fd, OBD_IOC_CHANGELOG_CLEAR, &data);
2824         if (rc)
2825                 llapi_err(LLAPI_MSG_ERROR, "ioctl err %d", rc);
2826
2827         close(fd);
2828         return rc;
2829 }
2830
2831 int llapi_fid2path(const char *device, const char *fidstr, char *buf,
2832                    int buflen, long long *recno, int *linkno)
2833 {
2834         char path[PATH_MAX];
2835         struct lu_fid fid;
2836         struct getinfo_fid2path *gf;
2837         int fd, rc;
2838
2839         while (*fidstr == '[')
2840                 fidstr++;
2841
2842         sscanf(fidstr, SFID, RFID(&fid));
2843         if (!fid_is_sane(&fid)) {
2844                 llapi_err(LLAPI_MSG_ERROR | LLAPI_MSG_NO_ERRNO,
2845                           "bad FID format [%s], should be "DFID"\n",
2846                           fidstr, (__u64)1, 2, 0);
2847                 return -EINVAL;
2848         }
2849
2850         /* Take path or fsname */
2851         if (device[0] == '/') {
2852                 strcpy(path, device);
2853         } else {
2854                 rc = get_root_path(WANT_PATH | WANT_ERROR, (char *)device,
2855                                    NULL, path, -1);
2856                 if (rc < 0)
2857                         return rc;
2858         }
2859         sprintf(path, "%s/%s/fid/%s", path, dot_lustre_name, fidstr);
2860         fd = open(path, O_RDONLY | O_NONBLOCK);
2861         if (fd < 0)
2862                 return -errno;
2863
2864         gf = malloc(sizeof(*gf) + buflen);
2865         gf->gf_fid = fid;
2866         gf->gf_recno = *recno;
2867         gf->gf_linkno = *linkno;
2868         gf->gf_pathlen = buflen;
2869         rc = ioctl(fd, OBD_IOC_FID2PATH, gf);
2870         if (rc) {
2871                 llapi_err(LLAPI_MSG_ERROR, "ioctl err %d", rc);
2872         } else {
2873                 memcpy(buf, gf->gf_path, gf->gf_pathlen);
2874                 *recno = gf->gf_recno;
2875                 *linkno = gf->gf_linkno;
2876         }
2877
2878         free(gf);
2879         close(fd);
2880         return rc;
2881 }
2882
2883 static int path2fid_from_lma(const char *path, lustre_fid *fid)
2884 {
2885         char buf[512];
2886         struct lustre_mdt_attrs *lma;
2887         int rc;
2888
2889         rc = lgetxattr(path, XATTR_NAME_LMA, buf, sizeof(buf));
2890         if (rc < 0)
2891                 return -errno;
2892         lma = (struct lustre_mdt_attrs *)buf;
2893         fid_be_to_cpu(fid, &lma->lma_self_fid);
2894         return 0;
2895 }
2896
2897 int llapi_path2fid(const char *path, lustre_fid *fid)
2898 {
2899         int fd, rc;
2900
2901         memset(fid, 0, sizeof(*fid));
2902         fd = open(path, O_RDONLY | O_NONBLOCK | O_NOFOLLOW);
2903         if (fd < 0) {
2904                 if (errno == ELOOP) /* symbolic link */
2905                         return path2fid_from_lma(path, fid);
2906                 return -errno;
2907         }
2908
2909         rc = ioctl(fd, LL_IOC_PATH2FID, fid) < 0 ? -errno : 0;
2910         if (rc == -EINVAL) /* char special device */
2911                 rc = path2fid_from_lma(path, fid);
2912
2913         close(fd);
2914         return rc;
2915 }
2916
2917 /****** HSM Copytool API ********/
2918 #define CT_PRIV_MAGIC 0xC0BE2001
2919 struct copytool_private {
2920         int magic;
2921         lustre_netlink lnl;
2922         int archive_num_count;
2923         int archive_nums[0];
2924 };
2925
2926 #include <libcfs/libcfs.h>
2927
2928 /** Register a copytool
2929  * @param priv Opaque private control structure
2930  * @param flags Open flags, currently unused (e.g. O_NONBLOCK)
2931  * @param archive_num_count
2932  * @param archive_nums Which archive numbers this copytool is responsible for
2933  */
2934 int llapi_copytool_start(void **priv, int flags, int archive_num_count,
2935                          int *archive_nums)
2936 {
2937         struct copytool_private *ct;
2938         int rc;
2939
2940         if (archive_num_count > 0 && archive_nums == NULL) {
2941                 llapi_err(LLAPI_MSG_ERROR | LLAPI_MSG_NO_ERRNO,
2942                           "NULL archive numbers");
2943                 return -EINVAL;
2944         }
2945
2946         ct = malloc(sizeof(*ct) +
2947                     archive_num_count * sizeof(ct->archive_nums[0]));
2948         if (ct == NULL)
2949                 return -ENOMEM;
2950
2951         ct->magic = CT_PRIV_MAGIC;
2952         ct->archive_num_count = archive_num_count;
2953         if (ct->archive_num_count > 0)
2954                 memcpy(ct->archive_nums, archive_nums, archive_num_count *
2955                        sizeof(ct->archive_nums[0]));
2956
2957         rc = libcfs_ulnl_start(&ct->lnl, LNL_GRP_HSM);
2958         if (rc < 0)
2959                 goto out_err;
2960
2961         *priv = ct;
2962         return 0;
2963
2964 out_err:
2965         free(ct);
2966         return rc;
2967 }
2968
2969 /** Deregister a copytool */
2970 int llapi_copytool_fini(void **priv)
2971 {
2972         struct copytool_private *ct = (struct copytool_private *)*priv;
2973
2974         if (!ct || (ct->magic != CT_PRIV_MAGIC))
2975                 return -EINVAL;
2976
2977         libcfs_ulnl_stop(&ct->lnl);
2978         free(ct);
2979         *priv = NULL;
2980         return 0;
2981 }
2982
2983 /** Wait for the next hsm_action_list
2984  * @param priv Opaque private control structure
2985  * @param halh Action list handle, will be allocated here
2986  * @param msgsize Number of bytes in the message, will be set here
2987  * @return 0 valid message received; halh and msgsize are set
2988  *         <0 error code
2989  */
2990 int llapi_copytool_recv(void *priv, struct hsm_action_list **halh, int *msgsize)
2991 {
2992         struct copytool_private *ct = (struct copytool_private *)priv;
2993         struct lnl_hdr *lnlh;
2994         struct hsm_action_list *hal;
2995         int rc = 0;
2996
2997         if (!ct || (ct->magic != CT_PRIV_MAGIC))
2998                 return -EINVAL;
2999         if (halh == NULL || msgsize == NULL)
3000                 return -EINVAL;
3001
3002         rc = libcfs_ulnl_msg_get(&ct->lnl, HAL_MAXSIZE,
3003                                  LNL_TRANSPORT_HSM, &lnlh);
3004         if (rc < 0)
3005                 return rc;
3006
3007         /* Handle generic messages */
3008         if (lnlh->lnl_transport == LNL_TRANSPORT_GENERIC &&
3009             lnlh->lnl_msgtype == LNL_MSG_SHUTDOWN) {
3010                 rc = -ESHUTDOWN;
3011                 goto out_free;
3012         }
3013
3014         if (lnlh->lnl_transport != LNL_TRANSPORT_HSM ||
3015             lnlh->lnl_msgtype != HMT_ACTION_LIST) {
3016                 llapi_err(LLAPI_MSG_ERROR | LLAPI_MSG_NO_ERRNO,
3017                           "Unknown HSM message type %d:%d\n",
3018                           lnlh->lnl_transport, lnlh->lnl_msgtype);
3019                 rc = -EPROTO;
3020                 goto out_free;
3021         }
3022
3023         /* Our message is an hsm_action_list */
3024
3025         hal = (struct hsm_action_list *)(lnlh + 1);
3026
3027         /* Check that we have registered for this archive # */
3028         for (rc = 0; rc < ct->archive_num_count; rc++) {
3029                 if (hal->hal_archive_num == ct->archive_nums[rc])
3030                         break;
3031         }
3032         if (rc >= ct->archive_num_count) {
3033                 CDEBUG(D_INFO, "This copytool does not service archive #%d, "
3034                        "ignoring this request.\n", hal->hal_archive_num);
3035                 rc = 0;
3036                 goto out_free;
3037         }
3038
3039         *halh = hal;
3040         *msgsize = lnlh->lnl_msglen - sizeof(*lnlh);
3041         return 0;
3042
3043 out_free:
3044         libcfs_ulnl_msg_free(&lnlh);
3045         *halh = NULL;
3046         *msgsize = 0;
3047         return rc;
3048 }
3049
3050 /** Release the action list when done with it. */
3051 int llapi_copytool_free(struct hsm_action_list **hal)
3052 {
3053         if (*hal) {
3054                 struct lnl_hdr *lnlh = (struct lnl_hdr *)*hal - 1;
3055                 libcfs_ulnl_msg_free(&lnlh);
3056         }
3057         *hal = NULL;
3058         return 0;
3059 }
3060
3061
3062