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