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