Whamcloud - gitweb
b=16893
[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/param.h>
62 #include <fnmatch.h>
63 #include <glob.h>
64 #ifdef HAVE_ASM_TYPES_H
65 #include <asm/types.h>
66 #endif
67 #ifdef HAVE_LINUX_UNISTD_H
68 #include <linux/unistd.h>
69 #else
70 #include <unistd.h>
71 #endif
72
73 #include <liblustre.h>
74 #include <lnet/lnetctl.h>
75 #include <obd.h>
76 #include <lustre_lib.h>
77 #include <lustre/liblustreapi.h>
78 #include <obd_lov.h>
79
80 static unsigned llapi_dir_filetype_table[] = {
81         [DT_UNKNOWN]= 0,
82         [DT_FIFO]= S_IFIFO,
83         [DT_CHR] = S_IFCHR,
84         [DT_DIR] = S_IFDIR,
85         [DT_BLK] = S_IFBLK,
86         [DT_REG] = S_IFREG,
87         [DT_LNK] = S_IFLNK,
88         [DT_SOCK]= S_IFSOCK,
89 #if defined(DT_DOOR) && defined(S_IFDOOR)
90         [DT_DOOR]= S_IFDOOR,
91 #endif
92 };
93
94 #if defined(DT_DOOR) && defined(S_IFDOOR)
95 static const int DT_MAX = DT_DOOR;
96 #else
97 static const int DT_MAX = DT_SOCK;
98 #endif
99
100 static unsigned llapi_filetype_dir_table[] = {
101         [0]= DT_UNKNOWN,
102         [S_IFIFO]= DT_FIFO,
103         [S_IFCHR] = DT_CHR,
104         [S_IFDIR] = DT_DIR,
105         [S_IFBLK] = DT_BLK,
106         [S_IFREG] = DT_REG,
107         [S_IFLNK] = DT_LNK,
108         [S_IFSOCK]= DT_SOCK,
109 #if defined(DT_DOOR) && defined(S_IFDOOR)
110         [S_IFDOOR]= DT_DOOR,
111 #endif
112 };
113
114 #if defined(DT_DOOR) && defined(S_IFDOOR)
115 static const int S_IFMAX = DT_DOOR;
116 #else
117 static const int S_IFMAX = DT_SOCK;
118 #endif
119
120 /* liblustreapi message level */
121 static int llapi_msg_level = LLAPI_MSG_MAX;
122
123 void llapi_msg_set_level(int level)
124 {
125         /* ensure level is in the good range */
126         if (level < LLAPI_MSG_OFF)
127                 llapi_msg_level = LLAPI_MSG_OFF;
128         else if (level > LLAPI_MSG_MAX)
129                 llapi_msg_level = LLAPI_MSG_MAX;
130         else
131                 llapi_msg_level = level;
132 }
133
134 void llapi_err(int level, char *fmt, ...)
135 {
136         va_list args;
137         int tmp_errno = abs(errno);
138
139         if ((level & LLAPI_MSG_MASK) > llapi_msg_level)
140                 return;
141
142         va_start(args, fmt);
143         vfprintf(stderr, fmt, args);
144         va_end(args);
145
146         if (level & LLAPI_MSG_NO_ERRNO)
147                 fprintf(stderr, "\n");
148         else
149                 fprintf(stderr, ": %s (%d)\n", strerror(tmp_errno), tmp_errno);
150 }
151
152 #define llapi_err_noerrno(level, fmt, a...)                             \
153         llapi_err((level) | LLAPI_MSG_NO_ERRNO, fmt, ## a)
154
155 void llapi_printf(int level, char *fmt, ...)
156 {
157         va_list args;
158
159         if ((level & LLAPI_MSG_MASK) > llapi_msg_level)
160                 return;
161
162         va_start(args, fmt);
163         vfprintf(stdout, fmt, args);
164         va_end(args);
165 }
166
167 /* size_units is unchanged if no specifier used */
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                 errno = -EINVAL;
239                 llapi_err(LLAPI_MSG_ERROR, "error: bad stripe_size %lu, "
240                           "must be an even multiple of %d bytes",
241                           stripe_size, page_size);
242                 return errno;
243         }
244         if (stripe_offset < -1 || stripe_offset > MAX_OBD_DEVICES) {
245                 errno = -EINVAL;
246                 llapi_err(LLAPI_MSG_ERROR, "error: bad stripe offset %d",
247                           stripe_offset);
248                 return errno;
249         }
250         if (stripe_count < -1 || stripe_count > LOV_MAX_STRIPE_COUNT) {
251                 errno = -EINVAL;
252                 llapi_err(LLAPI_MSG_ERROR, "error: bad stripe count %d",
253                           stripe_count);
254                 return errno;
255         }
256         if (stripe_size >= (1ULL << 32)) {
257                 errno = -EINVAL;
258                 llapi_err(LLAPI_MSG_ERROR, "warning: stripe size larger than 4G"
259                           " is not currently supported and would wrap");
260                 return errno;
261         }
262         return 0;
263 }
264
265 static int poolpath(char *fsname, char *pathname, char *pool_pathname);
266
267 int llapi_file_open_pool(const char *name, int flags, int mode,
268                          unsigned long long stripe_size, int stripe_offset,
269                          int stripe_count, int stripe_pattern, char *pool_name)
270 {
271         struct lov_user_md_v3 lum = { 0 };
272         int fd, rc = 0;
273         int isdir = 0;
274         char fsname[MAX_OBD_NAME + 1], *ptr;
275
276         fd = open(name, flags | O_LOV_DELAY_CREATE, mode);
277         if (fd < 0 && errno == EISDIR) {
278                 fd = open(name, O_DIRECTORY | O_RDONLY);
279                 isdir++;
280         }
281
282         if (fd < 0) {
283                 rc = -errno;
284                 llapi_err(LLAPI_MSG_ERROR, "unable to open '%s'", name);
285                 return rc;
286         }
287
288         if ((rc = llapi_stripe_limit_check(stripe_size, stripe_offset,
289                                            stripe_count, stripe_pattern)) != 0){
290                 errno = rc;
291                 goto out;
292         }
293
294         /*  Initialize IOCTL striping pattern structure */
295         lum.lmm_magic = LOV_USER_MAGIC_V3;
296         lum.lmm_pattern = stripe_pattern;
297         lum.lmm_stripe_size = stripe_size;
298         lum.lmm_stripe_count = stripe_count;
299         lum.lmm_stripe_offset = stripe_offset;
300
301         /* in case user give the full pool name <fsname>.<poolname>, skip
302          * the fsname */
303         if (pool_name != NULL) {
304                 ptr = strchr(pool_name, '.');
305                 if (ptr != NULL) {
306                         strncpy(fsname, pool_name, ptr - pool_name);
307                         fsname[ptr - pool_name] = '\0';
308                         /* if fsname matches a filesystem skip it
309                          * if not keep the poolname as is */
310                         if (poolpath(fsname, NULL, NULL) == 0)
311                                 pool_name = ptr + 1;
312                 }
313                 strncpy(lum.lmm_pool_name, pool_name, LOV_MAXPOOLNAME);
314         } else {
315                 /* If no pool is specified at all, use V1 request */
316                 lum.lmm_magic = LOV_USER_MAGIC_V1;
317         }
318
319         if (ioctl(fd, LL_IOC_LOV_SETSTRIPE, &lum)) {
320                 char *errmsg = "stripe already set";
321                 rc = -errno;
322                 if (errno != EEXIST && errno != EALREADY)
323                         errmsg = strerror(errno);
324
325                 llapi_err_noerrno(LLAPI_MSG_ERROR,
326                                   "error on ioctl "LPX64" for '%s' (%d): %s",
327                                   (__u64)LL_IOC_LOV_SETSTRIPE, name, fd,errmsg);
328         }
329 out:
330         if (rc) {
331                 close(fd);
332                 fd = rc;
333         }
334
335         return fd;
336 }
337
338 int llapi_file_open(const char *name, int flags, int mode,
339                     unsigned long long stripe_size, int stripe_offset,
340                     int stripe_count, int stripe_pattern)
341 {
342         return llapi_file_open_pool(name, flags, mode, stripe_size,
343                                     stripe_offset, stripe_count,
344                                     stripe_pattern, NULL);
345 }
346
347 int llapi_file_create(const char *name, unsigned long long stripe_size,
348                       int stripe_offset, int stripe_count, int stripe_pattern)
349 {
350         int fd;
351
352         fd = llapi_file_open_pool(name, O_CREAT | O_WRONLY, 0644, stripe_size,
353                                   stripe_offset, stripe_count, stripe_pattern,
354                                   NULL);
355         if (fd < 0)
356                 return fd;
357
358         close(fd);
359         return 0;
360 }
361
362 int llapi_file_create_pool(const char *name, unsigned long long stripe_size,
363                            int stripe_offset, int stripe_count,
364                            int stripe_pattern, char *pool_name)
365 {
366         int fd;
367
368         fd = llapi_file_open_pool(name, O_CREAT | O_WRONLY, 0644, stripe_size,
369                                   stripe_offset, stripe_count, stripe_pattern,
370                                   pool_name);
371         if (fd < 0)
372                 return fd;
373
374         close(fd);
375         return 0;
376 }
377
378
379 static int print_pool_members(char *fs, char *pool_dir, char *pool_file)
380 {
381         char path[MAXPATHLEN + 1];
382         char buf[1024];
383         FILE *fd;
384
385         llapi_printf(LLAPI_MSG_NORMAL, "Pool: %s.%s\n", fs, pool_file);
386         sprintf(path, "%s/%s", pool_dir, pool_file);
387         if ((fd = fopen(path, "r")) == NULL) {
388                 llapi_err(LLAPI_MSG_ERROR, "Cannot open %s\n", path);
389                 return -EINVAL;
390         }
391         while (fgets(buf, sizeof(buf), fd) != NULL)
392                llapi_printf(LLAPI_MSG_NORMAL, buf);
393
394         fclose(fd);
395         return 0;
396 }
397
398 /*
399  * search lustre fsname from pathname
400  *
401  */
402 static int search_fsname(char *pathname, char *fsname)
403 {
404         char *ptr;
405         FILE *fp;
406         struct mntent *mnt = NULL;
407
408         /* get the mount point */
409         fp = setmntent(MOUNTED, "r");
410         if (fp == NULL) {
411                  llapi_err(LLAPI_MSG_ERROR,
412                            "setmntent(%s) failed: %s:", MOUNTED,
413                            strerror (errno));
414                  return -EIO;
415         }
416         mnt = getmntent(fp);
417         while ((feof(fp) == 0) && ferror(fp) == 0) {
418                 if (llapi_is_lustre_mnt(mnt)) {
419                         /* search by pathname */
420                         if (strncmp(mnt->mnt_dir, pathname,
421                                     strlen(mnt->mnt_dir)) == 0) {
422                                 ptr = strchr(mnt->mnt_fsname, '/');
423                                 if (ptr == NULL)
424                                         return -EINVAL;
425                                 ptr++;
426                                 strcpy(fsname, ptr);
427                                 return 0;
428                         }
429                 }
430                 mnt = getmntent(fp);
431         }
432         endmntent(fp);
433         return -ENOENT;
434
435 }
436
437 /*
438  * find the pool directory path under /proc
439  * (can be also used to test if a fsname is known)
440  */
441 static int poolpath(char *fsname, char *pathname, char *pool_pathname)
442 {
443         int rc = 0;
444         glob_t glob_info;
445         char pattern[MAXPATHLEN + 1];
446         char buffer[MAXPATHLEN];
447
448         if (fsname == NULL) {
449                 rc = search_fsname(pathname, buffer);
450                 if (rc != 0)
451                         return rc;
452                 fsname = buffer;
453                 strcpy(pathname, fsname);
454         }
455
456         snprintf(pattern, MAXPATHLEN,
457                  "/proc/fs/lustre/lov/%s-*/pools",
458                  fsname);
459         rc = glob(pattern, GLOB_BRACE, NULL, &glob_info);
460         if (rc)
461                 return -ENOENT;
462
463         if (glob_info.gl_pathc == 0) {
464                 globfree(&glob_info);
465                 return -ENOENT;
466         }
467
468         /* in fsname test mode, pool_pathname is NULL */
469         if (pool_pathname != NULL)
470                 strcpy(pool_pathname, glob_info.gl_pathv[0]);
471
472         return 0;
473 }
474
475 int llapi_poollist(char *name)
476 {
477         char *poolname;
478         char *fsname;
479         char rname[MAXPATHLEN + 1], pathname[MAXPATHLEN + 1];
480         char *ptr;
481         int rc = 0;
482
483         /* is name a pathname ? */
484         ptr = strchr(name, '/');
485         if (ptr != NULL) {
486                 /* only absolute pathname is supported */
487                 if (*name != '/')
488                         return -EINVAL;
489                 if (!realpath(name, rname)) {
490                         rc = -errno;
491                         llapi_err(LLAPI_MSG_ERROR,
492                                   "llapi_poollist: invalid path '%s'",
493                                   name);
494                         return rc;
495                 }
496
497                 rc = poolpath(NULL, rname, pathname);
498                 if (rc != 0) {
499                         errno = -rc;
500                         llapi_err(LLAPI_MSG_ERROR,
501                                   "llapi_poollist: '%s' is not"
502                                   " a Lustre filesystem",
503                                   name);
504                         return rc;
505                 }
506                 fsname = rname;
507                 poolname = NULL;
508         } else {
509                 /* name is FSNAME[.POOLNAME] */
510                 fsname = name;
511                 poolname = strchr(name, '.');
512                 if (poolname != NULL) {
513                         *poolname = '\0';
514                         poolname++;
515                 }
516                 rc = poolpath(fsname, NULL, pathname);
517                 if (rc != 0) {
518                         errno = -rc;
519                         llapi_err(LLAPI_MSG_ERROR,
520                                   "llapi_poollist: Lustre filesystem '%s'"
521                                   " not found", name);
522                         return rc;
523                 }
524         }
525         if (rc != 0) {
526                 errno = -rc;
527                 llapi_err(LLAPI_MSG_ERROR,
528                           "llapi_poollist: Lustre filesystem '%s' not found",
529                           name);
530                 return rc;
531         }
532
533         if (poolname != NULL) {
534                 rc = print_pool_members(fsname, pathname, poolname);
535                 poolname--;
536                 *poolname = '.';
537         } else {
538                 DIR *dir;
539                 struct dirent *pool;
540
541                 llapi_printf(LLAPI_MSG_NORMAL, "Pools from %s:\n", fsname);
542                 if ((dir = opendir(pathname)) == NULL) {
543                         return -EINVAL;
544                 }
545                 while ((pool = readdir(dir)) != NULL) {
546                         if (!((pool->d_name[0] == '.') &&
547                               (pool->d_name[1] == '\0')) &&
548                             !((pool->d_name[0] == '.') &&
549                               (pool->d_name[1] == '.') &&
550                               (pool->d_name[2] == '\0')))
551                         llapi_printf(LLAPI_MSG_NORMAL, " %s.%s\n",
552                                      fsname, pool->d_name);
553                 }
554                 closedir(dir);
555         }
556         return rc;
557 }
558
559 typedef int (semantic_func_t)(char *path, DIR *parent, DIR *d,
560                               void *data, struct dirent64 *de);
561
562 #define MAX_LOV_UUID_COUNT      max(LOV_MAX_STRIPE_COUNT, 1000)
563 #define OBD_NOT_FOUND           (-1)
564
565 static int common_param_init(struct find_param *param)
566 {
567         param->lumlen = lov_mds_md_size(MAX_LOV_UUID_COUNT, LOV_MAGIC_V3);
568         if ((param->lmd = malloc(sizeof(lstat_t) + param->lumlen)) == NULL) {
569                 llapi_err(LLAPI_MSG_ERROR,
570                           "error: allocation of %d bytes for ioctl",
571                           sizeof(lstat_t) + param->lumlen);
572                 return -ENOMEM;
573         }
574
575         param->got_uuids = 0;
576         param->obdindexes = NULL;
577         param->obdindex = OBD_NOT_FOUND;
578         return 0;
579 }
580
581 static void find_param_fini(struct find_param *param)
582 {
583         if (param->obdindexes)
584                 free(param->obdindexes);
585
586         if (param->lmd)
587                 free(param->lmd);
588 }
589
590 int llapi_file_fget_lov_uuid(int fd, struct obd_uuid *lov_name)
591 {
592         int rc = ioctl(fd, OBD_IOC_GETNAME, lov_name);
593         if (rc) {
594                 rc = errno;
595                 llapi_err(LLAPI_MSG_ERROR, "error: can't get lov name.");
596         }
597         return rc;
598 }
599
600 int llapi_file_get_lov_uuid(const char *path, struct obd_uuid *lov_uuid)
601 {
602         int fd, rc;
603
604         fd = open(path, O_RDONLY);
605         if (fd < 0) {
606                 rc = errno;
607                 llapi_err(LLAPI_MSG_ERROR, "error opening %s", path);
608                 return rc;
609         }
610
611         rc = llapi_file_fget_lov_uuid(fd, lov_uuid);
612
613         close(fd);
614
615         return rc;
616 }
617
618 /*
619  * If uuidp is NULL, return the number of available obd uuids.
620  * If uuidp is non-NULL, then it will return the uuids of the obds. If
621  * there are more OSTs then allocated to uuidp, then an error is returned with
622  * the ost_count set to number of available obd uuids.
623  */
624 int llapi_lov_get_uuids(int fd, struct obd_uuid *uuidp, int *ost_count)
625 {
626         struct obd_uuid lov_name;
627         char buf[1024];
628         FILE *fp;
629         int rc = 0, index = 0;
630
631         /* Get the lov name */
632         rc = llapi_file_fget_lov_uuid(fd, &lov_name);
633         if (rc)
634                 return rc;
635
636         /* Now get the ost uuids from /proc */
637         snprintf(buf, sizeof(buf), "/proc/fs/lustre/lov/%s/target_obd",
638                  lov_name.uuid);
639         fp = fopen(buf, "r");
640         if (fp == NULL) {
641                 rc = errno;
642                 llapi_err(LLAPI_MSG_ERROR, "error: opening '%s'", buf);
643                 return rc;
644         }
645
646         while (fgets(buf, sizeof(buf), fp) != NULL) {
647                 if (uuidp && (index < *ost_count)) {
648                         if (sscanf(buf, "%d: %s", &index, uuidp[index].uuid) <2)
649                                 break;
650                 }
651                 index++;
652         }
653
654         fclose(fp);
655
656         if (uuidp && (index >= *ost_count))
657                 return -EOVERFLOW;
658
659         *ost_count = index;
660         return rc;
661 }
662
663 /* Here, param->obduuid points to a single obduuid, the index of which is
664  * returned in param->obdindex */
665 static int setup_obd_uuid(DIR *dir, char *dname, struct find_param *param)
666 {
667         struct obd_uuid lov_uuid;
668         char uuid[sizeof(struct obd_uuid)];
669         char buf[1024];
670         FILE *fp;
671         int rc = 0, index;
672
673         /* Get the lov name */
674         rc = llapi_file_fget_lov_uuid(dirfd(dir), &lov_uuid);
675         if (rc) {
676                 if (errno != ENOTTY) {
677                         rc = errno;
678                         llapi_err(LLAPI_MSG_ERROR,
679                                   "error: can't get lov name: %s", dname);
680                 } else {
681                         rc = 0;
682                 }
683                 return rc;
684         }
685
686         param->got_uuids = 1;
687
688         /* Now get the ost uuids from /proc */
689         snprintf(buf, sizeof(buf), "/proc/fs/lustre/lov/%s/target_obd",
690                  lov_uuid.uuid);
691         fp = fopen(buf, "r");
692         if (fp == NULL) {
693                 rc = errno;
694                 llapi_err(LLAPI_MSG_ERROR, "error: opening '%s'", buf);
695                 return rc;
696         }
697
698         if (!param->obduuid && !param->quiet && !param->obds_printed)
699                 llapi_printf(LLAPI_MSG_NORMAL, "OBDS:\n");
700
701         while (fgets(buf, sizeof(buf), fp) != NULL) {
702                 if (sscanf(buf, "%d: %s", &index, uuid) < 2)
703                         break;
704
705                 if (param->obduuid) {
706                         if (strncmp((char *)param->obduuid->uuid, uuid,
707                                     sizeof(uuid)) == 0) {
708                                 param->obdindex = index;
709                                 break;
710                         }
711                 } else if (!param->quiet && !param->obds_printed) {
712                         /* Print everything */
713                         llapi_printf(LLAPI_MSG_NORMAL, "%s", buf);
714                 }
715         }
716         param->obds_printed = 1;
717
718         fclose(fp);
719
720         if (!param->quiet && param->obduuid &&
721             (param->obdindex == OBD_NOT_FOUND)) {
722                 llapi_err_noerrno(LLAPI_MSG_ERROR, 
723                                   "error: %s: unknown obduuid: %s",
724                                   __FUNCTION__, param->obduuid->uuid);
725                 //rc = EINVAL;
726         }
727
728         return (rc);
729 }
730
731 /* In this case, param->obduuid will be an array of obduuids and
732  * obd index for all these obduuids will be returned in
733  * param->obdindexes */
734 static int setup_obd_indexes(DIR *dir, struct find_param *param)
735 {
736         struct obd_uuid *uuids = NULL;
737         int obdcount = INIT_ALLOC_NUM_OSTS;
738         int ret, obd_valid = 0, obdnum, i;
739
740         uuids = (struct obd_uuid *)malloc(INIT_ALLOC_NUM_OSTS *
741                                           sizeof(struct obd_uuid));
742         if (uuids == NULL)
743                 return -ENOMEM;
744
745 retry_get_uuids:
746         ret = llapi_lov_get_uuids(dirfd(dir), uuids,
747                                   &obdcount);
748         if (ret) {
749                 struct obd_uuid *uuids_temp;
750
751                 if (ret == -EOVERFLOW) {
752                         uuids_temp = realloc(uuids, obdcount *
753                                              sizeof(struct obd_uuid));
754                         if (uuids_temp != NULL)
755                                 goto retry_get_uuids;
756                         else
757                                 ret = -ENOMEM;
758                 }
759
760                 llapi_err(LLAPI_MSG_ERROR, "get ost uuid failed");
761                 return ret;
762         }
763
764         param->obdindexes = malloc(param->num_obds * sizeof(param->obdindex));
765         if (param->obdindexes == NULL)
766                 return -ENOMEM;
767
768         for (obdnum = 0; obdnum < param->num_obds; obdnum++) {
769                 for (i = 0; i <= obdcount; i++) {
770                         if (strcmp((char *)&param->obduuid[obdnum].uuid,
771                                    (char *)&uuids[i]) == 0) {
772                                 param->obdindexes[obdnum] = i;
773                                 obd_valid++;
774                                 break;
775                         }
776                 }
777                 if (i == obdcount)
778                         param->obdindexes[obdnum] = OBD_NOT_FOUND;
779         }
780
781         if (obd_valid == 0)
782                 param->obdindex = OBD_NOT_FOUND;
783         else
784                 param->obdindex = obd_valid;
785
786         param->got_uuids = 1;
787
788         return 0;
789 }
790
791 static void lov_dump_user_lmm_join(struct lov_user_md_v1 *lum, char *path,
792                                    int is_dir, int obdindex, int quiet,
793                                    int header, int body)
794 {
795         struct lov_user_md_join *lumj = (struct lov_user_md_join *)lum;
796         int i, obdstripe = 0;
797
798         if (obdindex != OBD_NOT_FOUND) {
799                 for (i = 0; i < lumj->lmm_stripe_count; i++) {
800                         if (obdindex == lumj->lmm_objects[i].l_ost_idx) {
801                                 llapi_printf(LLAPI_MSG_NORMAL, "%s\n", path);
802                                 obdstripe = 1;
803                                 break;
804                         }
805                 }
806         } else if (!quiet) {
807                 llapi_printf(LLAPI_MSG_NORMAL, "%s\n", path);
808                 obdstripe = 1;
809         }
810
811         if (header && obdstripe == 1) {
812                 llapi_printf(LLAPI_MSG_NORMAL, "lmm_magic:          0x%08X\n",
813                              lumj->lmm_magic);
814                 llapi_printf(LLAPI_MSG_NORMAL, "lmm_object_gr:      "LPX64"\n",
815                              lumj->lmm_object_gr);
816                 llapi_printf(LLAPI_MSG_NORMAL, "lmm_object_id:      "LPX64"\n",
817                              lumj->lmm_object_id);
818                 llapi_printf(LLAPI_MSG_NORMAL, "lmm_stripe_count:   %u\n",
819                              (int)lumj->lmm_stripe_count);
820                 llapi_printf(LLAPI_MSG_NORMAL, "lmm_stripe_size:    %u\n",
821                              lumj->lmm_stripe_size);
822                 llapi_printf(LLAPI_MSG_NORMAL, "lmm_stripe_pattern: %x\n",
823                              lumj->lmm_pattern);
824                 llapi_printf(LLAPI_MSG_NORMAL, "lmm_extent_count:   %x\n",
825                              lumj->lmm_extent_count);
826         }
827
828         if (body) {
829                 unsigned long long start = -1, end = 0;
830                 if (!quiet && obdstripe == 1)
831                         llapi_printf(LLAPI_MSG_NORMAL,
832                                      "joined\tobdidx\t\t objid\t\tobjid\t\t "
833                                      "group\t\tstart\t\tend\n");
834                 for (i = 0; i < lumj->lmm_stripe_count; i++) {
835                         int idx = lumj->lmm_objects[i].l_ost_idx;
836                         long long oid = lumj->lmm_objects[i].l_object_id;
837                         long long gr = lumj->lmm_objects[i].l_object_gr;
838                         if (obdindex == OBD_NOT_FOUND || obdindex == idx)
839                                 llapi_printf(LLAPI_MSG_NORMAL,
840                                              "\t%6u\t%14llu\t%#13llx\t%14llu%s",
841                                              idx, oid, oid, gr,
842                                              obdindex == idx ? " *" : "");
843                         if (start != lumj->lmm_objects[i].l_extent_start ||
844                             end != lumj->lmm_objects[i].l_extent_end) {
845                                 start = lumj->lmm_objects[i].l_extent_start;
846                                 llapi_printf(LLAPI_MSG_NORMAL, "\t%14llu",
847                                              start);
848                                 end = lumj->lmm_objects[i].l_extent_end;
849                                 if (end == (unsigned long long)-1)
850                                         llapi_printf(LLAPI_MSG_NORMAL,
851                                                      "\t\tEOF\n");
852                                 else
853                                         llapi_printf(LLAPI_MSG_NORMAL,
854                                                      "\t\t%llu\n", end);
855                         } else {
856                                 llapi_printf(LLAPI_MSG_NORMAL, "\t\t\t\t\n");
857                         }
858                 }
859                 llapi_printf(LLAPI_MSG_NORMAL, "\n");
860         }
861 }
862
863 static void lov_dump_user_lmm_v1v3(struct lov_user_md *lum, char *pool_name,
864                                    struct lov_user_ost_data_v1 *objects,
865                                    char *path,
866                                    int is_dir, int obdindex, int quiet,
867                                    int header, int body)
868 {
869         int i, obdstripe = 0;
870
871         if (obdindex != OBD_NOT_FOUND) {
872                 for (i = 0; !is_dir && i < lum->lmm_stripe_count; i++) {
873                         if (obdindex == objects[i].l_ost_idx) {
874                                 llapi_printf(LLAPI_MSG_NORMAL, "%s\n", path);
875                                 obdstripe = 1;
876                                 break;
877                         }
878                 }
879         } else if (!quiet) {
880                 llapi_printf(LLAPI_MSG_NORMAL, "%s\n", path);
881                 obdstripe = 1;
882         }
883
884         /* if it's a directory */
885         if (is_dir) {
886                 if (obdstripe == 1) {
887                         if (lum->lmm_object_gr == LOV_OBJECT_GROUP_DEFAULT) {
888                                 llapi_printf(LLAPI_MSG_NORMAL, "(Default) ");
889                                 lum->lmm_object_gr = LOV_OBJECT_GROUP_CLEAR;
890                         }
891                         llapi_printf(LLAPI_MSG_NORMAL,
892                                      "stripe_count: %d stripe_size: %u "
893                                      "stripe_offset: %d%s%s\n",
894                                      lum->lmm_stripe_count == (__u16)-1 ? -1 :
895                                                         lum->lmm_stripe_count,
896                                      lum->lmm_stripe_size,
897                                      lum->lmm_stripe_offset == (__u16)-1 ? -1 :
898                                                         lum->lmm_stripe_offset,
899                                      pool_name != NULL ? " pool: " : "",
900                                      pool_name != NULL ? pool_name : "");
901                 }
902                 return;
903         }
904
905         if (header && (obdstripe == 1)) {
906                 llapi_printf(LLAPI_MSG_NORMAL, "lmm_magic:          0x%08X\n",
907                              lum->lmm_magic);
908                 llapi_printf(LLAPI_MSG_NORMAL, "lmm_object_gr:      "LPX64"\n",
909                              lum->lmm_object_gr);
910                 llapi_printf(LLAPI_MSG_NORMAL, "lmm_object_id:      "LPX64"\n",
911                              lum->lmm_object_id);
912                 llapi_printf(LLAPI_MSG_NORMAL, "lmm_stripe_count:   %u\n",
913                              lum->lmm_stripe_count);
914                 llapi_printf(LLAPI_MSG_NORMAL, "lmm_stripe_size:    %u\n",
915                              lum->lmm_stripe_size);
916                 llapi_printf(LLAPI_MSG_NORMAL, "lmm_stripe_pattern: %x\n",
917                              lum->lmm_pattern);
918                 if (pool_name != NULL)
919                         llapi_printf(LLAPI_MSG_NORMAL,
920                                      "lmm_pool_name:      %s\n", pool_name);
921         }
922
923         if (body) {
924                 if ((!quiet) && (obdstripe == 1))
925                         llapi_printf(LLAPI_MSG_NORMAL,
926                                      "\tobdidx\t\t objid\t\tobjid\t\t group\n");
927
928                 for (i = 0; i < lum->lmm_stripe_count; i++) {
929                         int idx = objects[i].l_ost_idx;
930                         long long oid = objects[i].l_object_id;
931                         long long gr = objects[i].l_object_gr;
932                         if ((obdindex == OBD_NOT_FOUND) || (obdindex == idx))
933                                 llapi_printf(LLAPI_MSG_NORMAL,
934                                            "\t%6u\t%14llu\t%#13llx\t%14llu%s\n",
935                                            idx, oid, oid, gr,
936                                            obdindex == idx ? " *" : "");
937                 }
938                 llapi_printf(LLAPI_MSG_NORMAL, "\n");
939         }
940 }
941
942
943 void llapi_lov_dump_user_lmm(struct find_param *param,
944                              char *path, int is_dir)
945 {
946         switch(*(__u32 *)&param->lmd->lmd_lmm) { /* lum->lmm_magic */
947         case LOV_USER_MAGIC_V1:
948                 lov_dump_user_lmm_v1v3(&param->lmd->lmd_lmm, NULL,
949                                        param->lmd->lmd_lmm.lmm_objects,
950                                        path, is_dir,
951                                        param->obdindex, param->quiet,
952                                        param->verbose,
953                                        (param->verbose || !param->obduuid));
954                 break;
955         case LOV_USER_MAGIC_JOIN:
956                 lov_dump_user_lmm_join(&param->lmd->lmd_lmm, path, is_dir,
957                                        param->obdindex, param->quiet,
958                                        param->verbose,
959                                        (param->verbose || !param->obduuid));
960                 break;
961         case LOV_USER_MAGIC_V3: {
962                 char pool_name[LOV_MAXPOOLNAME + 1];
963                 struct lov_user_ost_data_v1 *objects;
964                 struct lov_user_md_v3 *lmmv3 = (void *)&param->lmd->lmd_lmm;
965
966                 strncpy(pool_name, lmmv3->lmm_pool_name, LOV_MAXPOOLNAME);
967                 pool_name[LOV_MAXPOOLNAME] = '\0';
968                 objects = lmmv3->lmm_objects;
969                 lov_dump_user_lmm_v1v3(&param->lmd->lmd_lmm, pool_name,
970                                        objects, path, is_dir,
971                                        param->obdindex, param->quiet,
972                                        param->verbose,
973                                        (param->verbose || !param->obduuid));
974                 break;
975         }
976         default:
977                 llapi_printf(LLAPI_MSG_NORMAL, "unknown lmm_magic:  %#x "
978                              "(expecting one of %#x %#x %#x)\n",
979                              param->lmd->lmd_lmm.lmm_magic,
980                              LOV_USER_MAGIC_V1, LOV_USER_MAGIC_JOIN,
981                              LOV_USER_MAGIC_V3);
982                 return;
983         }
984 }
985
986 int llapi_file_get_stripe(const char *path, struct lov_user_md *lum)
987 {
988         const char *fname;
989         char *dname;
990         int fd, rc = 0;
991
992         fname = strrchr(path, '/');
993
994         /* It should be a file (or other non-directory) */
995         if (fname == NULL) {
996                 dname = (char *)malloc(2);
997                 if (dname == NULL)
998                         return ENOMEM;
999                 strcpy(dname, ".");
1000                 fname = (char *)path;
1001         } else {
1002                 dname = (char *)malloc(fname - path + 1);
1003                 if (dname == NULL)
1004                         return ENOMEM;
1005                 strncpy(dname, path, fname - path);
1006                 dname[fname - path] = '\0';
1007                 fname++;
1008         }
1009
1010         if ((fd = open(dname, O_RDONLY)) == -1) {
1011                 rc = errno;
1012                 free(dname);
1013                 return rc;
1014         }
1015
1016         strcpy((char *)lum, fname);
1017         if (ioctl(fd, IOC_MDC_GETFILESTRIPE, (void *)lum) == -1)
1018                 rc = errno;
1019
1020         if (close(fd) == -1 && rc == 0)
1021                 rc = errno;
1022
1023         free(dname);
1024
1025         return rc;
1026 }
1027
1028 int llapi_file_lookup(int dirfd, const char *name)
1029 {
1030         struct obd_ioctl_data data = { 0 };
1031         char rawbuf[8192];
1032         char *buf = rawbuf;
1033         int rc;
1034
1035         if (dirfd < 0 || name == NULL)
1036                 return -EINVAL;
1037
1038         data.ioc_version = OBD_IOCTL_VERSION;
1039         data.ioc_len = sizeof(data);
1040         data.ioc_inlbuf1 = (char *)name;
1041         data.ioc_inllen1 = strlen(name) + 1;
1042
1043         rc = obd_ioctl_pack(&data, &buf, sizeof(rawbuf));
1044         if (rc) {
1045                 llapi_err(LLAPI_MSG_ERROR,
1046                           "error: IOC_MDC_LOOKUP pack failed for '%s': rc %d",
1047                           name, rc);
1048                 return rc;
1049         }
1050
1051         return ioctl(dirfd, IOC_MDC_LOOKUP, buf);
1052 }
1053
1054 int llapi_mds_getfileinfo(char *path, DIR *parent,
1055                           struct lov_user_mds_data *lmd)
1056 {
1057         lstat_t *st = &lmd->lmd_st;
1058         char *fname = strrchr(path, '/');
1059         int ret = 0;
1060
1061         if (parent == NULL)
1062                 return -EINVAL;
1063
1064         fname = (fname == NULL ? path : fname + 1);
1065         /* retrieve needed file info */
1066         strncpy((char *)lmd, fname, lov_mds_md_size(MAX_LOV_UUID_COUNT,
1067                 LOV_MAGIC));
1068         ret = ioctl(dirfd(parent), IOC_MDC_GETFILEINFO, (void *)lmd);
1069
1070         if (ret) {
1071                 if (errno == ENOTTY) {
1072                         /* ioctl is not supported, it is not a lustre fs.
1073                          * Do the regular lstat(2) instead. */
1074                         ret = lstat_f(path, st);
1075                         if (ret) {
1076                                 llapi_err(LLAPI_MSG_ERROR,
1077                                           "error: %s: lstat failed for %s",
1078                                           __FUNCTION__, path);
1079                                 return ret;
1080                         }
1081                 } else if (errno == ENOENT) {
1082                         llapi_err(LLAPI_MSG_WARN,
1083                                   "warning: %s: %s does not exist",
1084                                   __FUNCTION__, path);
1085                         return -ENOENT;
1086                 } else {
1087                         llapi_err(LLAPI_MSG_ERROR,
1088                                  "error: %s: IOC_MDC_GETFILEINFO failed for %s",
1089                                  __FUNCTION__, path);
1090                         return ret;
1091                 }
1092         }
1093
1094         return 0;
1095 }
1096
1097 static DIR *opendir_parent(char *path)
1098 {
1099         DIR *parent;
1100         char *fname;
1101         char c;
1102
1103         fname = strrchr(path, '/');
1104         if (fname == NULL)
1105                 return opendir(".");
1106
1107         c = fname[1];
1108         fname[1] = '\0';
1109         parent = opendir(path);
1110         fname[1] = c;
1111         return parent;
1112 }
1113
1114 static int llapi_semantic_traverse(char *path, int size, DIR *parent,
1115                                    semantic_func_t sem_init,
1116                                    semantic_func_t sem_fini, void *data,
1117                                    struct dirent64 *de)
1118 {
1119         struct dirent64 *dent;
1120         int len, ret;
1121         DIR *d, *p = NULL;
1122
1123         ret = 0;
1124         len = strlen(path);
1125
1126         d = opendir(path);
1127         if (!d && errno != ENOTDIR) {
1128                 llapi_err(LLAPI_MSG_ERROR, "%s: Failed to open '%s'",
1129                           __FUNCTION__, path);
1130                 return -EINVAL;
1131         } else if (!d && !parent) {
1132                 /* ENOTDIR. Open the parent dir. */
1133                 p = opendir_parent(path);
1134                 if (!p)
1135                         GOTO(out, ret = -EINVAL);
1136         }
1137
1138         if (sem_init && (ret = sem_init(path, parent ?: p, d, data, de)))
1139                 goto err;
1140
1141         if (!d)
1142                 GOTO(out, ret = 0);
1143
1144         while ((dent = readdir64(d)) != NULL) {
1145                 ((struct find_param *)data)->have_fileinfo = 0;
1146
1147                 if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
1148                         continue;
1149
1150                 path[len] = 0;
1151                 if ((len + dent->d_reclen + 2) > size) {
1152                         llapi_err(LLAPI_MSG_ERROR,
1153                                   "error: %s: string buffer is too small",
1154                                   __FUNCTION__);
1155                         break;
1156                 }
1157                 strcat(path, "/");
1158                 strcat(path, dent->d_name);
1159
1160                 if (dent->d_type == DT_UNKNOWN) {
1161                         lstat_t *st = &((struct find_param *)data)->lmd->lmd_st;
1162
1163                         ret = llapi_mds_getfileinfo(path, d,
1164                                              ((struct find_param *)data)->lmd);
1165                         if (ret == 0) {
1166                                 ((struct find_param *)data)->have_fileinfo = 1;
1167                                 dent->d_type =
1168                                         llapi_filetype_dir_table[st->st_mode &
1169                                                                  S_IFMT];
1170                         }
1171                         if (ret == -ENOENT)
1172                                 continue;
1173                 }
1174
1175                 switch (dent->d_type) {
1176                 case DT_UNKNOWN:
1177                         llapi_err(LLAPI_MSG_ERROR,
1178                                   "error: %s: '%s' is UNKNOWN type %d",
1179                                   __FUNCTION__, dent->d_name, dent->d_type);
1180                         break;
1181                 case DT_DIR:
1182                         ret = llapi_semantic_traverse(path, size, d, sem_init,
1183                                                       sem_fini, data, dent);
1184                         if (ret < 0)
1185                                 goto out;
1186                         break;
1187                 default:
1188                         ret = 0;
1189                         if (sem_init) {
1190                                 ret = sem_init(path, d, NULL, data, dent);
1191                                 if (ret < 0)
1192                                         goto out;
1193                         }
1194                         if (sem_fini && ret == 0)
1195                                 sem_fini(path, d, NULL, data, dent);
1196                 }
1197         }
1198
1199 out:
1200         path[len] = 0;
1201
1202         if (sem_fini)
1203                 sem_fini(path, parent, d, data, de);
1204 err:
1205         if (d)
1206                 closedir(d);
1207         if (p)
1208                 closedir(p);
1209         return ret;
1210 }
1211
1212 /* Check if the value matches 1 of the given criteria (e.g. --atime +/-N).
1213  * @mds indicates if this is MDS timestamps and there are attributes on OSTs.
1214  *
1215  * The result is -1 if it does not match, 0 if not yet clear, 1 if matches.
1216  * The table below gives the answers for the specified parameters (value and
1217  * sign), 1st column is the answer for the MDS value, the 2nd is for the OST:
1218  * --------------------------------------
1219  * 1 | file > limit; sign > 0 | -1 / -1 |
1220  * 2 | file = limit; sign > 0 |  ? /  1 |
1221  * 3 | file < limit; sign > 0 |  ? /  1 |
1222  * 4 | file > limit; sign = 0 | -1 / -1 |
1223  * 5 | file = limit; sign = 0 |  ? /  1 |  <- (see the Note below)
1224  * 6 | file < limit; sign = 0 |  ? / -1 |
1225  * 7 | file > limit; sign < 0 |  1 /  1 |
1226  * 8 | file = limit; sign < 0 |  ? / -1 |
1227  * 9 | file < limit; sign < 0 |  ? / -1 |
1228  * --------------------------------------
1229  * Note: 5th actually means that the value is within the interval
1230  * (limit - margin, limit]. */
1231 static int find_value_cmp(unsigned int file, unsigned int limit, int sign,
1232                           unsigned long long margin, int mds)
1233 {
1234         if (sign > 0) {
1235                 if (file < limit)
1236                         return mds ? 0 : 1;
1237         }
1238
1239         if (sign == 0) {
1240                 if (file <= limit && file + margin > limit)
1241                         return mds ? 0 : 1;
1242                 if (file + margin <= limit)
1243                         return mds ? 0 : -1;
1244         }
1245
1246         if (sign < 0) {
1247                 if (file > limit)
1248                         return 1;
1249                 if (mds)
1250                         return 0;
1251         }
1252
1253         return -1;
1254 }
1255
1256 /* Check if the file time matches all the given criteria (e.g. --atime +/-N).
1257  * Return -1 or 1 if file timestamp does not or does match the given criteria
1258  * correspondingly. Return 0 if the MDS time is being checked and there are
1259  * attributes on OSTs and it is not yet clear if the timespamp matches.
1260  *
1261  * If 0 is returned, we need to do another RPC to the OSTs to obtain the
1262  * updated timestamps. */
1263 static int find_time_check(lstat_t *st, struct find_param *param, int mds)
1264 {
1265         int ret;
1266         int rc = 0;
1267
1268         /* Check if file is accepted. */
1269         if (param->atime) {
1270                 ret = find_value_cmp(st->st_atime, param->atime,
1271                                      param->asign, 24 * 60 * 60, mds);
1272                 if (ret < 0)
1273                         return ret;
1274                 rc = ret;
1275         }
1276
1277         if (param->mtime) {
1278                 ret = find_value_cmp(st->st_mtime, param->mtime,
1279                                      param->msign, 24 * 60 * 60, mds);
1280                 if (ret < 0)
1281                         return ret;
1282
1283                 /* If the previous check matches, but this one is not yet clear,
1284                  * we should return 0 to do an RPC on OSTs. */
1285                 if (rc == 1)
1286                         rc = ret;
1287         }
1288
1289         if (param->ctime) {
1290                 ret = find_value_cmp(st->st_ctime, param->ctime,
1291                                      param->csign, 24 * 60 * 60, mds);
1292                 if (ret < 0)
1293                         return ret;
1294
1295                 /* If the previous check matches, but this one is not yet clear,
1296                  * we should return 0 to do an RPC on OSTs. */
1297                 if (rc == 1)
1298                         rc = ret;
1299         }
1300
1301         return rc;
1302 }
1303
1304 static int cb_find_init(char *path, DIR *parent, DIR *dir,
1305                         void *data, struct dirent64 *de)
1306 {
1307         struct find_param *param = (struct find_param *)data;
1308         struct lov_user_md_v3 *lmmv3 = (void *)&param->lmd->lmd_lmm;
1309         int decision = 1; /* 1 is accepted; -1 is rejected. */
1310         lstat_t *st = &param->lmd->lmd_st;
1311         int lustre_fs = 1;
1312         int checked_type = 0;
1313         int ret = 0;
1314
1315         LASSERT(parent != NULL || dir != NULL);
1316
1317         param->lmd->lmd_lmm.lmm_stripe_count = 0;
1318
1319         /* If a regular expression is presented, make the initial decision */
1320         if (param->pattern != NULL) {
1321                 char *fname = strrchr(path, '/');
1322                 fname = (fname == NULL ? path : fname + 1);
1323                 ret = fnmatch(param->pattern, fname, 0);
1324                 if ((ret == FNM_NOMATCH && !param->exclude_pattern) ||
1325                     (ret == 0 && param->exclude_pattern))
1326                         goto decided;
1327         }
1328
1329         /* See if we can check the file type from the dirent. */
1330         if (param->type && de != NULL && de->d_type != DT_UNKNOWN &&
1331             de->d_type <= DT_MAX) {
1332                 checked_type = 1;
1333                 if (llapi_dir_filetype_table[de->d_type] == param->type) {
1334                         if (param->exclude_type)
1335                                 goto decided;
1336                 } else {
1337                         if (!param->exclude_type)
1338                                 goto decided;
1339                 }
1340         }
1341
1342
1343         /* If a time or OST should be checked, the decision is not taken yet. */
1344         if (param->atime || param->ctime || param->mtime || param->obduuid ||
1345             param->size_check)
1346                 decision = 0;
1347
1348         ret = 0;
1349         /* Request MDS for the stat info. */
1350         if (param->have_fileinfo == 0) {
1351                 if (dir) {
1352                         /* retrieve needed file info */
1353                         ret = ioctl(dirfd(dir), LL_IOC_MDC_GETINFO,
1354                                     (void *)param->lmd);
1355                 } else {
1356                         char *fname = strrchr(path, '/');
1357                         fname = (fname == NULL ? path : fname + 1);
1358
1359                         /* retrieve needed file info */
1360                         strncpy((char *)param->lmd, fname, param->lumlen);
1361                         ret = ioctl(dirfd(parent), IOC_MDC_GETFILEINFO,
1362                                    (void *)param->lmd);
1363                 }
1364         }
1365
1366         if (ret) {
1367                 if (errno == ENOTTY) {
1368                         /* ioctl is not supported, it is not a lustre fs.
1369                          * Do the regular lstat(2) instead. */
1370                         lustre_fs = 0;
1371                         ret = lstat_f(path, st);
1372                         if (ret) {
1373                                 llapi_err(LLAPI_MSG_ERROR,
1374                                           "error: %s: lstat failed for %s",
1375                                           __FUNCTION__, path);
1376                                 return ret;
1377                         }
1378                 } else if (errno == ENOENT) {
1379                         llapi_err(LLAPI_MSG_WARN,
1380                                   "warning: %s: %s does not exist",
1381                                   __FUNCTION__, path);
1382                         goto decided;
1383                 } else {
1384                         llapi_err(LLAPI_MSG_ERROR,"error: %s: %s failed for %s",
1385                                   __FUNCTION__, dir ? "LL_IOC_MDC_GETINFO" :
1386                                   "IOC_MDC_GETFILEINFO", path);
1387                         return ret;
1388                 }
1389         }
1390
1391         if (param->check_uid) {
1392                 if (st->st_uid == param->uid) {
1393                         if (param->exclude_uid)
1394                                 goto decided;
1395                 } else {
1396                         if (!param->exclude_uid)
1397                                 goto decided;
1398                 }
1399         }
1400
1401         if (param->check_gid) {
1402                 if (st->st_gid == param->gid) {
1403                         if (param->exclude_gid)
1404                                 goto decided;
1405                 } else {
1406                         if (!param->exclude_gid)
1407                                 goto decided;
1408                 }
1409         }
1410
1411         if (param->check_pool) {
1412                 /* empty requested pool is taken as no pool search => V1 */
1413                 if ((param->lmd->lmd_lmm.lmm_magic == LOV_USER_MAGIC_V1 &&
1414                      param->poolname[0] == '\0') ||
1415                     (param->lmd->lmd_lmm.lmm_magic == LOV_USER_MAGIC_V3 &&
1416                      (strncmp(lmmv3->lmm_pool_name, param->poolname,
1417                               LOV_MAXPOOLNAME) == 0 ||
1418                       strcmp(param->poolname, "*") == 0))) {
1419                         if (param->exclude_pool)
1420                                 goto decided;
1421                 } else {
1422                         if (!param->exclude_pool)
1423                                 goto decided;
1424                 }
1425         }
1426
1427         /* Check the time on mds. */
1428         if (!decision) {
1429                 int for_mds;
1430
1431                 for_mds = lustre_fs ? (S_ISREG(st->st_mode) &&
1432                                        param->lmd->lmd_lmm.lmm_stripe_count)
1433                                     : 0;
1434                 decision = find_time_check(st, param, for_mds);
1435                 if (decision == -1)
1436                         goto decided;
1437         }
1438
1439         if (param->type && !checked_type) {
1440                 if ((st->st_mode & S_IFMT) == param->type) {
1441                         if (param->exclude_type)
1442                                 goto decided;
1443                 } else {
1444                         if (!param->exclude_type)
1445                                 goto decided;
1446                 }
1447         }
1448
1449         /* Prepare odb. */
1450         if (param->obduuid) {
1451                 if (lustre_fs && param->got_uuids &&
1452                     param->st_dev != st->st_dev) {
1453                         /* A lustre/lustre mount point is crossed. */
1454                         param->got_uuids = 0;
1455                         param->obds_printed = 0;
1456                         param->obdindex = OBD_NOT_FOUND;
1457                 }
1458
1459                 if (lustre_fs && !param->got_uuids) {
1460                         ret = setup_obd_indexes(dir ? dir : parent, param);
1461                         if (ret)
1462                                 return ret;
1463
1464                         param->st_dev = st->st_dev;
1465                 } else if (!lustre_fs && param->got_uuids) {
1466                         /* A lustre/non-lustre mount point is crossed. */
1467                         param->got_uuids = 0;
1468                         param->obdindex = OBD_NOT_FOUND;
1469                 }
1470         }
1471
1472         /* If an OBD UUID is specified but no one matches, skip this file. */
1473         if (param->obduuid && param->obdindex == OBD_NOT_FOUND)
1474                 goto decided;
1475
1476         /* If a OST UUID is given, and some OST matches, check it here. */
1477         if (param->obdindex != OBD_NOT_FOUND) {
1478                 if (!S_ISREG(st->st_mode))
1479                         goto decided;
1480
1481                 /* Only those files should be accepted, which have a
1482                  * stripe on the specified OST. */
1483                 if (!param->lmd->lmd_lmm.lmm_stripe_count) {
1484                         goto decided;
1485                 } else {
1486                         int i, j;
1487                         struct lov_user_ost_data_v1 *lmm_objects;
1488
1489                         if (param->lmd->lmd_lmm.lmm_magic == LOV_USER_MAGIC_V3)
1490                                 lmm_objects = lmmv3->lmm_objects;
1491                         else
1492                                 lmm_objects = param->lmd->lmd_lmm.lmm_objects;
1493
1494                         for (i = 0;
1495                              i < param->lmd->lmd_lmm.lmm_stripe_count; i++) {
1496                                 for (j = 0; j < param->num_obds; j++) {
1497                                         if (param->obdindexes[j] ==
1498                                             lmm_objects[i].l_ost_idx)
1499                                                 goto obd_matches;
1500                                 }
1501                         }
1502
1503                         if (i == param->lmd->lmd_lmm.lmm_stripe_count)
1504                                 goto decided;
1505                 }
1506         }
1507
1508 obd_matches:
1509
1510         /* If file still fits the request, ask osd for updated info.
1511            The regulat stat is almost of the same speed as some new
1512            'glimpse-size-ioctl'. */
1513         if (!decision && S_ISREG(st->st_mode) &&
1514             (param->lmd->lmd_lmm.lmm_stripe_count || param->size_check)) {
1515                 if (dir) {
1516                         ret = ioctl(dirfd(dir), IOC_LOV_GETINFO,
1517                                     (void *)param->lmd);
1518                 } else if (parent) {
1519                         ret = ioctl(dirfd(parent), IOC_LOV_GETINFO,
1520                                     (void *)param->lmd);
1521                 }
1522
1523                 if (ret) {
1524                         if (errno == ENOENT) {
1525                                 llapi_err(LLAPI_MSG_ERROR,
1526                                           "warning: %s: %s does not exist",
1527                                           __FUNCTION__, path);
1528                                 goto decided;
1529                         } else {
1530                                 llapi_err(LLAPI_MSG_ERROR,
1531                                           "%s: IOC_LOV_GETINFO on %s failed",
1532                                           __FUNCTION__, path);
1533                                 return ret;
1534                         }
1535                 }
1536
1537                 /* Check the time on osc. */
1538                 decision = find_time_check(st, param, 0);
1539                 if (decision == -1)
1540                         goto decided;
1541         }
1542
1543         if (param->size_check)
1544                 decision = find_value_cmp(st->st_size, param->size,
1545                                           param->size_sign, param->size_units,
1546                                           0);
1547
1548         if (decision != -1) {
1549                 llapi_printf(LLAPI_MSG_NORMAL, "%s", path);
1550                 if (param->zeroend)
1551                         llapi_printf(LLAPI_MSG_NORMAL, "%c", '\0');
1552                 else
1553                         llapi_printf(LLAPI_MSG_NORMAL, "\n");
1554         }
1555
1556 decided:
1557         /* Do not get down anymore? */
1558         if (param->depth == param->maxdepth)
1559                 return 1;
1560
1561         param->depth++;
1562         return 0;
1563 }
1564
1565 static int cb_common_fini(char *path, DIR *parent, DIR *d, void *data,
1566                           struct dirent64 *de)
1567 {
1568         struct find_param *param = (struct find_param *)data;
1569         param->depth--;
1570         return 0;
1571 }
1572
1573 int llapi_find(char *path, struct find_param *param)
1574 {
1575         char *buf;
1576         int ret, len = strlen(path);
1577
1578         if (len > PATH_MAX) {
1579                 llapi_err(LLAPI_MSG_ERROR, "%s: Path name '%s' is too long",
1580                           __FUNCTION__, path);
1581                 return -EINVAL;
1582         }
1583
1584         buf = (char *)malloc(PATH_MAX + 1);
1585         if (!buf)
1586                 return -ENOMEM;
1587
1588         ret = common_param_init(param);
1589         if (ret) {
1590                 free(buf);
1591                 return ret;
1592         }
1593
1594         param->depth = 0;
1595
1596         strncpy(buf, path, PATH_MAX + 1);
1597         ret = llapi_semantic_traverse(buf, PATH_MAX + 1, NULL, cb_find_init,
1598                                       cb_common_fini, param, NULL);
1599
1600         find_param_fini(param);
1601         free(buf);
1602         return ret < 0 ? ret : 0;
1603 }
1604
1605 static int cb_getstripe(char *path, DIR *parent, DIR *d, void *data,
1606                         struct dirent64 *de)
1607 {
1608         struct find_param *param = (struct find_param *)data;
1609         int ret = 0;
1610
1611         LASSERT(parent != NULL || d != NULL);
1612
1613         /* Prepare odb. */
1614         if (!param->got_uuids) {
1615                 ret = setup_obd_uuid(d ? d : parent, path, param);
1616                 if (ret)
1617                         return ret;
1618         }
1619
1620         if (d) {
1621                 ret = ioctl(dirfd(d), LL_IOC_LOV_GETSTRIPE,
1622                             (void *)&param->lmd->lmd_lmm);
1623         } else if (parent) {
1624                 char *fname = strrchr(path, '/');
1625                 fname = (fname == NULL ? path : fname + 1);
1626
1627                 strncpy((char *)&param->lmd->lmd_lmm, fname, param->lumlen);
1628                 ret = ioctl(dirfd(parent), IOC_MDC_GETFILESTRIPE,
1629                             (void *)&param->lmd->lmd_lmm);
1630         }
1631
1632         if (ret) {
1633                 if (errno == ENODATA) {
1634                         if (!param->obduuid && !param->quiet)
1635                                 llapi_printf(LLAPI_MSG_NORMAL,
1636                                              "%s has no stripe info\n", path);
1637                         goto out;
1638                 } else if (errno == ENOTTY) {
1639                         llapi_err(LLAPI_MSG_ERROR,
1640                                   "%s: '%s' not on a Lustre fs?",
1641                                   __FUNCTION__, path);
1642                 } else if (errno == ENOENT) {
1643                         llapi_err(LLAPI_MSG_WARN,
1644                                   "warning: %s: %s does not exist",
1645                                   __FUNCTION__, path);
1646                         goto out;
1647                 } else {
1648                         llapi_err(LLAPI_MSG_ERROR,
1649                                   "error: %s: %s failed for %s",
1650                                    __FUNCTION__, d ? "LL_IOC_LOV_GETSTRIPE" :
1651                                   "IOC_MDC_GETFILESTRIPE", path);
1652                 }
1653
1654                 return ret;
1655         }
1656
1657         llapi_lov_dump_user_lmm(param, path, d ? 1 : 0);
1658 out:
1659         /* Do not get down anymore? */
1660         if (param->depth == param->maxdepth)
1661                 return 1;
1662
1663         param->depth++;
1664         return 0;
1665 }
1666
1667 int llapi_getstripe(char *path, struct find_param *param)
1668 {
1669         char *buf;
1670         int ret = 0, len = strlen(path);
1671
1672         if (len > PATH_MAX) {
1673                 llapi_err(LLAPI_MSG_ERROR,
1674                           "%s: Path name '%s' is too long",
1675                           __FUNCTION__, path);
1676                 return -EINVAL;
1677         }
1678
1679         buf = (char *)malloc(PATH_MAX + 1);
1680         if (!buf)
1681                 return -ENOMEM;
1682
1683         ret = common_param_init(param);
1684         if (ret) {
1685                 free(buf);
1686                 return ret;
1687         }
1688
1689         param->depth = 0;
1690
1691         strncpy(buf, path, PATH_MAX + 1);
1692         ret = llapi_semantic_traverse(buf, PATH_MAX + 1, NULL, cb_getstripe,
1693                                       cb_common_fini, param, NULL);
1694         find_param_fini(param);
1695         free(buf);
1696         return ret < 0 ? ret : 0;
1697 }
1698
1699 int llapi_obd_statfs(char *path, __u32 type, __u32 index,
1700                      struct obd_statfs *stat_buf,
1701                      struct obd_uuid *uuid_buf)
1702 {
1703         int fd;
1704         char raw[OBD_MAX_IOCTL_BUFFER] = {'\0'};
1705         char *rawbuf = raw;
1706         struct obd_ioctl_data data = { 0 };
1707         int rc = 0;
1708
1709         data.ioc_inlbuf1 = (char *)&type;
1710         data.ioc_inllen1 = sizeof(__u32);
1711         data.ioc_inlbuf2 = (char *)&index;
1712         data.ioc_inllen2 = sizeof(__u32);
1713         data.ioc_pbuf1 = (char *)stat_buf;
1714         data.ioc_plen1 = sizeof(struct obd_statfs);
1715         data.ioc_pbuf2 = (char *)uuid_buf;
1716         data.ioc_plen2 = sizeof(struct obd_uuid);
1717
1718         if ((rc = obd_ioctl_pack(&data, &rawbuf, sizeof(raw))) != 0) {
1719                 llapi_err(LLAPI_MSG_ERROR,
1720                           "llapi_obd_statfs: error packing ioctl data");
1721                 return rc;
1722         }
1723
1724         fd = open(path, O_RDONLY);
1725         if (errno == EISDIR)
1726                 fd = open(path, O_DIRECTORY | O_RDONLY);
1727
1728         if (fd < 0) {
1729                 rc = errno ? -errno : -EBADF;
1730                 llapi_err(LLAPI_MSG_ERROR, "error: %s: opening '%s'",
1731                           __FUNCTION__, path);
1732                 return rc;
1733         }
1734         rc = ioctl(fd, IOC_OBD_STATFS, (void *)rawbuf);
1735         if (rc)
1736                 rc = errno ? -errno : -EINVAL;
1737
1738         close(fd);
1739         return rc;
1740 }
1741
1742 #define MAX_STRING_SIZE 128
1743 #define DEVICES_LIST "/proc/fs/lustre/devices"
1744
1745 int llapi_ping(char *obd_type, char *obd_name)
1746 {
1747         char path[MAX_STRING_SIZE];
1748         char buf[1];
1749         int rc, fd;
1750
1751         snprintf(path, MAX_STRING_SIZE, "/proc/fs/lustre/%s/%s/ping",
1752                  obd_type, obd_name);
1753
1754         fd = open(path, O_WRONLY);
1755         if (fd < 0) {
1756                 rc = errno;
1757                 llapi_err(LLAPI_MSG_ERROR, "error opening %s", path);
1758                 return rc;
1759         }
1760
1761         rc = write(fd, buf, 1);
1762         close(fd);
1763
1764         if (rc == 1)
1765                 return 0;
1766         return rc;
1767 }
1768
1769 int llapi_target_iterate(int type_num, char **obd_type,void *args,llapi_cb_t cb)
1770 {
1771         char buf[MAX_STRING_SIZE];
1772         FILE *fp = fopen(DEVICES_LIST, "r");
1773         int i, rc = 0;
1774
1775         if (fp == NULL) {
1776                 rc = errno;
1777                 llapi_err(LLAPI_MSG_ERROR, "error: opening "DEVICES_LIST);
1778                 return rc;
1779         }
1780
1781         while (fgets(buf, sizeof(buf), fp) != NULL) {
1782                 char *obd_type_name = NULL;
1783                 char *obd_name = NULL;
1784                 char *obd_uuid = NULL;
1785                 char rawbuf[OBD_MAX_IOCTL_BUFFER];
1786                 char *bufl = rawbuf;
1787                 char *bufp = buf;
1788                 struct obd_ioctl_data datal = { 0, };
1789                 struct obd_statfs osfs_buffer;
1790
1791                 while(bufp[0] == ' ')
1792                         ++bufp;
1793
1794                 for(i = 0; i < 3; i++) {
1795                         obd_type_name = strsep(&bufp, " ");
1796                 }
1797                 obd_name = strsep(&bufp, " ");
1798                 obd_uuid = strsep(&bufp, " ");
1799
1800                 memset(&osfs_buffer, 0, sizeof (osfs_buffer));
1801
1802                 memset(bufl, 0, sizeof(rawbuf));
1803                 datal.ioc_pbuf1 = (char *)&osfs_buffer;
1804                 datal.ioc_plen1 = sizeof(osfs_buffer);
1805
1806                 for (i = 0; i < type_num; i++) {
1807                         if (strcmp(obd_type_name, obd_type[i]) != 0)
1808                                 continue;
1809
1810                         cb(obd_type_name, obd_name, obd_uuid, args);
1811                 }
1812         }
1813         fclose(fp);
1814         return rc;
1815 }
1816
1817 static void do_target_check(char *obd_type_name, char *obd_name,
1818                             char *obd_uuid, void *args)
1819 {
1820         int rc;
1821
1822         rc = llapi_ping(obd_type_name, obd_name);
1823         if (rc) {
1824                 llapi_err(LLAPI_MSG_ERROR, "error: check '%s'", obd_name);
1825         } else {
1826                 llapi_printf(LLAPI_MSG_NORMAL, "%s active.\n", obd_name);
1827         }
1828 }
1829
1830 int llapi_target_check(int type_num, char **obd_type, char *dir)
1831 {
1832         return llapi_target_iterate(type_num, obd_type, NULL, do_target_check);
1833 }
1834
1835 #undef MAX_STRING_SIZE
1836
1837 int llapi_catinfo(char *dir, char *keyword, char *node_name)
1838 {
1839         char raw[OBD_MAX_IOCTL_BUFFER];
1840         char out[LLOG_CHUNK_SIZE];
1841         char *buf = raw;
1842         struct obd_ioctl_data data = { 0 };
1843         char key[30];
1844         DIR *root;
1845         int rc;
1846
1847         sprintf(key, "%s", keyword);
1848         memset(raw, 0, sizeof(raw));
1849         memset(out, 0, sizeof(out));
1850         data.ioc_inlbuf1 = key;
1851         data.ioc_inllen1 = strlen(key) + 1;
1852         if (node_name) {
1853                 data.ioc_inlbuf2 = node_name;
1854                 data.ioc_inllen2 = strlen(node_name) + 1;
1855         }
1856         data.ioc_pbuf1 = out;
1857         data.ioc_plen1 = sizeof(out);
1858         rc = obd_ioctl_pack(&data, &buf, sizeof(raw));
1859         if (rc)
1860                 return rc;
1861
1862         root = opendir(dir);
1863         if (root == NULL) {
1864                 rc = errno;
1865                 llapi_err(LLAPI_MSG_ERROR, "open %s failed", dir);
1866                 return rc;
1867         }
1868
1869         rc = ioctl(dirfd(root), OBD_IOC_LLOG_CATINFO, buf);
1870         if (rc)
1871                 llapi_err(LLAPI_MSG_ERROR, "ioctl OBD_IOC_CATINFO failed");
1872         else
1873                 llapi_printf(LLAPI_MSG_NORMAL, "%s", data.ioc_pbuf1);
1874
1875         closedir(root);
1876         return rc;
1877 }
1878
1879 /* Is this a lustre fs? */
1880 int llapi_is_lustre_mnttype(const char *type)
1881 {
1882         return (strcmp(type, "lustre") == 0 || strcmp(type,"lustre_lite") == 0);
1883 }
1884
1885 /* Is this a lustre client fs? */
1886 int llapi_is_lustre_mnt(struct mntent *mnt)
1887 {
1888         return (llapi_is_lustre_mnttype(mnt->mnt_type) &&
1889                 strstr(mnt->mnt_fsname, ":/") != NULL);
1890 }
1891
1892 int llapi_quotacheck(char *mnt, int check_type)
1893 {
1894         DIR *root;
1895         int rc;
1896
1897         root = opendir(mnt);
1898         if (!root) {
1899                 llapi_err(LLAPI_MSG_ERROR, "open %s failed", mnt);
1900                 return -1;
1901         }
1902
1903         rc = ioctl(dirfd(root), LL_IOC_QUOTACHECK, check_type);
1904
1905         closedir(root);
1906         return rc;
1907 }
1908
1909 int llapi_poll_quotacheck(char *mnt, struct if_quotacheck *qchk)
1910 {
1911         DIR *root;
1912         int poll_intvl = 2;
1913         int rc;
1914
1915         root = opendir(mnt);
1916         if (!root) {
1917                 llapi_err(LLAPI_MSG_ERROR, "open %s failed", mnt);
1918                 return -1;
1919         }
1920
1921         while (1) {
1922                 rc = ioctl(dirfd(root), LL_IOC_POLL_QUOTACHECK, qchk);
1923                 if (!rc)
1924                         break;
1925                 sleep(poll_intvl);
1926                 if (poll_intvl < 30)
1927                         poll_intvl *= 2;
1928         }
1929
1930         closedir(root);
1931         return rc;
1932 }
1933
1934 int llapi_quotactl(char *mnt, struct if_quotactl *qctl)
1935 {
1936         DIR *root;
1937         int rc;
1938
1939         root = opendir(mnt);
1940         if (!root) {
1941                 llapi_err(LLAPI_MSG_ERROR, "open %s failed", mnt);
1942                 return -1;
1943         }
1944
1945         rc = ioctl(dirfd(root), LL_IOC_QUOTACTL, qctl);
1946
1947         closedir(root);
1948         return rc;
1949 }
1950
1951 static int cb_quotachown(char *path, DIR *parent, DIR *d, void *data,
1952                          struct dirent64 *de)
1953 {
1954         struct find_param *param = (struct find_param *)data;
1955         lstat_t *st;
1956         int rc;
1957
1958         LASSERT(parent != NULL || d != NULL);
1959
1960         if (d) {
1961                 rc = ioctl(dirfd(d), LL_IOC_MDC_GETINFO,
1962                            (void *)param->lmd);
1963         } else if (parent) {
1964                 char *fname = strrchr(path, '/');
1965                 fname = (fname == NULL ? path : fname + 1);
1966
1967                 strncpy((char *)param->lmd, fname, param->lumlen);
1968                 rc = ioctl(dirfd(parent), IOC_MDC_GETFILEINFO,
1969                            (void *)param->lmd);
1970         } else {
1971                 return 0;
1972         }
1973
1974         if (rc) {
1975                 if (errno == ENODATA) {
1976                         if (!param->obduuid && !param->quiet)
1977                                 llapi_err(LLAPI_MSG_ERROR,
1978                                           "%s has no stripe info", path);
1979                         rc = 0;
1980                 } else if (errno == ENOENT) {
1981                         llapi_err(LLAPI_MSG_ERROR,
1982                                   "warning: %s: %s does not exist",
1983                                   __FUNCTION__, path);
1984                         rc = 0;
1985                 } else if (errno != EISDIR) {
1986                         rc = errno;
1987                         llapi_err(LLAPI_MSG_ERROR, "%s ioctl failed for %s.",
1988                                   d ? "LL_IOC_MDC_GETINFO" :
1989                                   "IOC_MDC_GETFILEINFO", path);
1990                 }
1991                 return rc;
1992         }
1993
1994         st = &param->lmd->lmd_st;
1995
1996         /* libc chown() will do extra check, and if the real owner is
1997          * the same as the ones to set, it won't fall into kernel, so
1998          * invoke syscall directly. */
1999         rc = syscall(SYS_chown, path, -1, -1);
2000         if (rc)
2001                 llapi_err(LLAPI_MSG_ERROR, "error: chown %s", path);
2002
2003         rc = chmod(path, st->st_mode);
2004         if (rc)
2005                 llapi_err(LLAPI_MSG_ERROR, "error: chmod %s (%hu)",
2006                           path, st->st_mode);
2007
2008         return rc;
2009 }
2010
2011 int llapi_quotachown(char *path, int flag)
2012 {
2013         struct find_param param;
2014         char *buf;
2015         int ret = 0, len = strlen(path);
2016
2017         if (len > PATH_MAX) {
2018                 llapi_err(LLAPI_MSG_ERROR, "%s: Path name '%s' is too long",
2019                           __FUNCTION__, path);
2020                 return -EINVAL;
2021         }
2022
2023         buf = (char *)malloc(PATH_MAX + 1);
2024         if (!buf)
2025                 return -ENOMEM;
2026
2027         memset(&param, 0, sizeof(param));
2028         param.recursive = 1;
2029         param.verbose = 0;
2030         param.quiet = 1;
2031
2032         ret = common_param_init(&param);
2033         if (ret)
2034                 goto out;
2035
2036         strncpy(buf, path, PATH_MAX + 1);
2037         ret = llapi_semantic_traverse(buf, PATH_MAX + 1, NULL, cb_quotachown,
2038                                       NULL, &param, NULL);
2039 out:
2040         find_param_fini(&param);
2041         free(buf);
2042         return ret;
2043 }