Whamcloud - gitweb
b=13919
[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  *  Copyright (C) 2002 Cluster File Systems, Inc.
5  *   Author: Peter J. Braam <braam@clusterfs.com>
6  *   Author: Phil Schwan <phil@clusterfs.com>
7  *   Author: Robert Read <rread@clusterfs.com>
8  *
9  *   This file is part of Lustre, http://www.lustre.org.
10  *
11  *   Lustre is free software; you can redistribute it and/or
12  *   modify it under the terms of version 2 of the GNU General Public
13  *   License as published by the Free Software Foundation.
14  *
15  *   Lustre is distributed in the hope that it will be useful,
16  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
17  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  *   GNU General Public License for more details.
19  *
20  *   You should have received a copy of the GNU General Public License
21  *   along with Lustre; if not, write to the Free Software
22  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23  *
24  */
25
26 /* for O_DIRECTORY */
27 #define _GNU_SOURCE
28
29 #include <stdlib.h>
30 #include <stdio.h>
31 #include <string.h>
32 #include <stddef.h>
33 #include <sys/ioctl.h>
34 #include <unistd.h>
35 #include <fcntl.h>
36 #include <errno.h>
37 #include <dirent.h>
38 #include <stdarg.h>
39 #include <sys/stat.h>
40 #include <sys/types.h>
41 #include <sys/syscall.h>
42 #include <fnmatch.h>
43 #ifdef HAVE_ASM_TYPES_H
44 #include <asm/types.h>
45 #endif
46 #ifdef HAVE_LINUX_UNISTD_H
47 #include <linux/unistd.h>
48 #else
49 #include <unistd.h>
50 #endif
51
52 #include <liblustre.h>
53 #include <lnet/lnetctl.h>
54 #include <obd.h>
55 #include <lustre_lib.h>
56 #include <obd_lov.h>
57 #include <lustre/liblustreapi.h>
58
59 static unsigned llapi_dir_filetype_table[] = {
60         [DT_UNKNOWN]= 0,
61         [DT_FIFO]= S_IFIFO,
62         [DT_CHR] = S_IFCHR,
63         [DT_DIR] = S_IFDIR,
64         [DT_BLK] = S_IFBLK,
65         [DT_REG] = S_IFREG,
66         [DT_LNK] = S_IFLNK,
67         [DT_SOCK]= S_IFSOCK,
68 #if defined(DT_DOOR) && defined(S_IFDOOR)
69         [DT_DOOR]= S_IFDOOR,
70 #endif
71 };
72
73 #if defined(DT_DOOR) && defined(S_IFDOOR)
74 static const int DT_MAX = DT_DOOR;
75 #else
76 static const int DT_MAX = DT_SOCK;
77 #endif
78
79 static unsigned llapi_filetype_dir_table[] = {
80         [0]= DT_UNKNOWN,
81         [S_IFIFO]= DT_FIFO,
82         [S_IFCHR] = DT_CHR,
83         [S_IFDIR] = DT_DIR,
84         [S_IFBLK] = DT_BLK,
85         [S_IFREG] = DT_REG,
86         [S_IFLNK] = DT_LNK,
87         [S_IFSOCK]= DT_SOCK,
88 #if defined(DT_DOOR) && defined(S_IFDOOR)
89         [S_IFDOOR]= DT_DOOR,
90 #endif
91 };
92
93 #if defined(DT_DOOR) && defined(S_IFDOOR)
94 static const int S_IFMAX = DT_DOOR;
95 #else
96 static const int S_IFMAX = DT_SOCK;
97 #endif
98
99 static void err_msg(char *fmt, ...)
100 {
101         va_list args;
102         int tmp_errno = abs(errno);
103
104         va_start(args, fmt);
105         vfprintf(stderr, fmt, args);
106         va_end(args);
107         fprintf(stderr, ": %s (%d)\n", strerror(tmp_errno), tmp_errno);
108 }
109
110 int parse_size(char *optarg, unsigned long long *size,
111                unsigned long long *size_units)
112 {
113         char *end;
114
115         *size = strtoul(optarg, &end, 0);
116
117         if (*end != '\0') {
118                 if ((*end == 'b') && *(end+1) == '\0' &&
119                     (*size & (~0ULL << (64 - 9))) == 0) {
120                         *size <<= 9;
121                         *size_units = 1 << 9;
122                 } else if ((*end == 'k' || *end == 'K') &&
123                            *(end+1) == '\0' && (*size &
124                            (~0ULL << (64 - 10))) == 0) {
125                         *size <<= 10;
126                         *size_units = 1 << 10;
127                 } else if ((*end == 'm' || *end == 'M') &&
128                            *(end+1) == '\0' && (*size &
129                            (~0ULL << (64 - 20))) == 0) {
130                         *size <<= 20;
131                         *size_units = 1 << 20;
132                 } else if ((*end == 'g' || *end == 'G') &&
133                            *(end+1) == '\0' && (*size &
134                            (~0ULL << (64 - 30))) == 0) {
135                         *size <<= 30;
136                         *size_units = 1 << 30;
137                 } else if ((*end == 't' || *end == 'T') &&
138                            *(end+1) == '\0' && (*size &
139                            (~0ULL << (64 - 40))) == 0) {
140                         *size <<= 40;
141                         *size_units = 1ULL << 40;
142                 } else if ((*end == 'p' || *end == 'P') &&
143                            *(end+1) == '\0' && (*size &
144                            (~0ULL << (64 - 50))) == 0) {
145                         *size <<= 50;
146                         *size_units = 1ULL << 50;
147                 } else if ((*end == 'e' || *end == 'E') &&
148                            *(end+1) == '\0' && (*size &
149                            (~0ULL << (64 - 60))) == 0) {
150                         *size <<= 60;
151                         *size_units = 1ULL << 60;
152                 } else {
153                         return -1;
154                 }
155         }
156
157         return 0;
158 }
159
160 int llapi_file_open(const char *name, int flags, int mode,
161                     unsigned long stripe_size, int stripe_offset,
162                     int stripe_count, int stripe_pattern)
163 {
164         struct lov_user_md lum = { 0 };
165         int fd, rc = 0;
166         int isdir = 0;
167         int page_size;
168
169         fd = open(name, flags | O_LOV_DELAY_CREATE, mode);
170         if (fd < 0 && errno == EISDIR) {
171                 fd = open(name, O_DIRECTORY | O_RDONLY);
172                 isdir++;
173         }
174
175         if (fd < 0) {
176                 rc = -errno;
177                 err_msg("unable to open '%s'", name);
178                 return rc;
179         }
180
181         /* 64 KB is the largest common page size I'm aware of (on ia64), but
182          * check the local page size just in case. */
183         page_size = LOV_MIN_STRIPE_SIZE;
184         if (getpagesize() > page_size) {
185                 page_size = getpagesize();
186                 fprintf(stderr, "warning: your page size (%u) is larger than "
187                         "expected (%u).\n", page_size, LOV_MIN_STRIPE_SIZE);
188         }
189         if (stripe_size < 0 || (stripe_size & (LOV_MIN_STRIPE_SIZE - 1))) {
190                 errno = rc = -EINVAL;
191                 err_msg("error: bad stripe_size %lu, must be an even "
192                         "multiple of %d bytes", stripe_size, page_size);
193                 goto out;
194         }
195         if (stripe_offset < -1 || stripe_offset > MAX_OBD_DEVICES) {
196                 errno = rc = -EINVAL;
197                 err_msg("error: bad stripe offset %d", stripe_offset);
198                 goto out;
199         }
200         if (stripe_count < -1 || stripe_count > LOV_MAX_STRIPE_COUNT) {
201                 errno = rc = -EINVAL;
202                 err_msg("error: bad stripe count %d", stripe_count);
203                 goto out;
204         }
205         if (stripe_count > 0 && (__u64)stripe_size * stripe_count > 0xffffffff){
206                 errno = rc = -EINVAL;
207                 err_msg("error: stripe_size %lu * stripe_count %u "
208                         "exceeds 4GB", stripe_size, stripe_count);
209                 goto out;
210         }
211
212         /*  Initialize IOCTL striping pattern structure */
213         lum.lmm_magic = LOV_USER_MAGIC;
214         lum.lmm_pattern = stripe_pattern;
215         lum.lmm_stripe_size = stripe_size;
216         lum.lmm_stripe_count = stripe_count;
217         lum.lmm_stripe_offset = stripe_offset;
218
219         if (ioctl(fd, LL_IOC_LOV_SETSTRIPE, &lum)) {
220                 char *errmsg = "stripe already set";
221                 rc = -errno;
222                 if (errno != EEXIST && errno != EALREADY)
223                         errmsg = strerror(errno);
224
225                 fprintf(stderr, "error on ioctl "LPX64" for '%s' (%d): %s\n",
226                         (__u64)LL_IOC_LOV_SETSTRIPE, name, fd, errmsg);
227         }
228 out:
229         if (rc) {
230                 close(fd);
231                 fd = rc;
232         }
233
234         return fd;
235 }
236
237 int llapi_file_create(const char *name, unsigned long stripe_size,
238                       int stripe_offset, int stripe_count, int stripe_pattern)
239 {
240         int fd;
241
242         fd = llapi_file_open(name, O_CREAT | O_WRONLY, 0644, stripe_size,
243                              stripe_offset, stripe_count, stripe_pattern);
244         if (fd < 0)
245                 return fd;
246
247         close(fd);
248         return 0;
249 }
250
251 typedef int (semantic_func_t)(char *path, DIR *parent, DIR *d,
252                               void *data, struct dirent64 *de);
253
254 #define MAX_LOV_UUID_COUNT      max(LOV_MAX_STRIPE_COUNT, 1000)
255 #define OBD_NOT_FOUND           (-1)
256
257 static int common_param_init(struct find_param *param)
258 {
259         param->lumlen = lov_mds_md_size(MAX_LOV_UUID_COUNT);
260         if ((param->lmd = malloc(sizeof(lstat_t) + param->lumlen)) == NULL) {
261                 err_msg("error: allocation of %d bytes for ioctl",
262                         sizeof(lstat_t) + param->lumlen);
263                 return -ENOMEM;
264         }
265
266         param->got_uuids = 0;
267         param->obdindexes = NULL;
268         param->obdindex = OBD_NOT_FOUND;
269         return 0;
270 }
271
272 static void find_param_fini(struct find_param *param)
273 {
274         if (param->obdindexes)
275                 free(param->obdindexes);
276
277         if (param->lmd)
278                 free(param->lmd);
279 }
280
281 /*
282  * If uuidp is NULL, return the number of available obd uuids.
283  * If uuidp is non-NULL, then it will return the uuids of the obds. If
284  * there are more OSTs then allocated to uuidp, then an error is returned with
285  * the ost_count set to number of available obd uuids.
286  */
287 int llapi_lov_get_uuids(int fd, struct obd_uuid *uuidp, int *ost_count)
288 {
289         char lov_name[sizeof(struct obd_uuid)];
290         char buf[1024];
291         FILE *fp;
292         int rc = 0, index = 0;
293
294         /* Get the lov name */
295         rc = ioctl(fd, OBD_IOC_GETNAME, (void *) lov_name);
296         if (rc) {
297                 rc = errno;
298                 err_msg("error: can't get lov name.");
299                 return rc;
300         }
301
302         /* Now get the ost uuids from /proc */
303         snprintf(buf, sizeof(buf), "/proc/fs/lustre/lov/%s/target_obd",
304                  lov_name);
305         fp = fopen(buf, "r");
306         if (fp == NULL) {
307                 rc = errno;
308                 err_msg("error: opening '%s'", buf);
309                 return rc;
310         }
311
312         while (fgets(buf, sizeof(buf), fp) != NULL) {
313                 if (uuidp && (index < *ost_count)) {
314                         if (sscanf(buf, "%d: %s", &index, uuidp[index].uuid) <2)
315                                 break;
316                 }
317                 index++;
318         }
319
320         fclose(fp);
321
322         if (uuidp && (index >= *ost_count))
323                 return -EOVERFLOW;
324
325         *ost_count = index;
326         return rc;
327 }
328
329 /* Here, param->obduuid points to a single obduuid, the index of which is
330  * returned in param->obdindex */
331 static int setup_obd_uuid(DIR *dir, char *dname, struct find_param *param)
332 {
333         char uuid[sizeof(struct obd_uuid)];
334         char buf[1024];
335         FILE *fp;
336         int rc = 0, index;
337
338         /* Get the lov name */
339         rc = ioctl(dirfd(dir), OBD_IOC_GETNAME, (void *)uuid);
340         if (rc) {
341                 if (errno != ENOTTY) {
342                         rc = errno;
343                         err_msg("error: can't get lov name: %s", dname);
344                 } else {
345                         rc = 0;
346                 }
347                 return rc;
348         }
349
350         param->got_uuids = 1;
351
352         /* Now get the ost uuids from /proc */
353         snprintf(buf, sizeof(buf), "/proc/fs/lustre/lov/%s/target_obd",
354                  uuid);
355         fp = fopen(buf, "r");
356         if (fp == NULL) {
357                 rc = errno;
358                 err_msg("error: opening '%s'", buf);
359                 return rc;
360         }
361
362         if (!param->obduuid && !param->quiet && !param->obds_printed)
363                 printf("OBDS:\n");
364
365         while (fgets(buf, sizeof(buf), fp) != NULL) {
366                 if (sscanf(buf, "%d: %s", &index, uuid) < 2)
367                         break;
368
369                 if (param->obduuid) {
370                         if (strncmp(param->obduuid->uuid, uuid,
371                                     sizeof(uuid)) == 0) {
372                                 param->obdindex = index;
373                                 break;
374                         }
375                 } else if (!param->quiet && !param->obds_printed) {
376                         /* Print everything */
377                         printf("%s", buf);
378                 }
379         }
380         param->obds_printed = 1;
381
382         fclose(fp);
383
384         if (!param->quiet && param->obduuid &&
385             (param->obdindex == OBD_NOT_FOUND)) {
386                 fprintf(stderr, "error: %s: unknown obduuid: %s\n",
387                         __FUNCTION__, param->obduuid->uuid);
388                 //rc = EINVAL;
389         }
390
391         return (rc);
392 }
393
394 /* In this case, param->obduuid will be an array of obduuids and
395  * obd index for all these obduuids will be returned in
396  * param->obdindexes */
397 static int setup_obd_indexes(DIR *dir, struct find_param *param)
398 {
399         struct obd_uuid *uuids = NULL;
400         int obdcount = INIT_ALLOC_NUM_OSTS;
401         int ret, obd_valid = 0, obdnum, i;
402
403         uuids = (struct obd_uuid *)malloc(INIT_ALLOC_NUM_OSTS *
404                                           sizeof(struct obd_uuid));
405         if (uuids == NULL)
406                 return -ENOMEM;
407
408 retry_get_uuids:
409         ret = llapi_lov_get_uuids(dirfd(dir), uuids,
410                                   &obdcount);
411         if (ret) {
412                 struct obd_uuid *uuids_temp;
413
414                 if (ret == -EOVERFLOW) {
415                         uuids_temp = realloc(uuids, obdcount *
416                                              sizeof(struct obd_uuid));
417                         if (uuids_temp != NULL)
418                                 goto retry_get_uuids;
419                         else
420                                 ret = -ENOMEM;
421                 }
422
423                 fprintf(stderr, "get ost uuid failed: %s\n", strerror(errno));
424                 return ret;
425         }
426
427         param->obdindexes = malloc(param->num_obds * sizeof(param->obdindex));
428         if (param->obdindexes == NULL)
429                 return -ENOMEM;
430
431         for (obdnum = 0; obdnum < param->num_obds; obdnum++) {
432                 for (i = 0; i <= obdcount; i++) {
433                         if (strcmp((char *)&param->obduuid[obdnum].uuid,
434                                    (char *)&uuids[i]) == 0) {
435                                 param->obdindexes[obdnum] = i;
436                                 obd_valid++;
437                                 break;
438                         }
439                 }
440                 if (i == obdcount)
441                         param->obdindexes[obdnum] = OBD_NOT_FOUND;
442         }
443
444         if (obd_valid == 0)
445                 param->obdindex = OBD_NOT_FOUND;
446         else
447                 param->obdindex = obd_valid;
448
449         param->got_uuids = 1;
450
451         return 0;
452 }
453
454 void lov_dump_user_lmm_v1(struct lov_user_md_v1 *lum, char *path, int is_dir,
455                           int obdindex, int quiet, int header, int body)
456 {
457         int i, obdstripe = 0;
458
459         if (obdindex != OBD_NOT_FOUND) {
460                 for (i = 0; !is_dir && i < lum->lmm_stripe_count; i++) {
461                         if (obdindex == lum->lmm_objects[i].l_ost_idx) {
462                                 printf("%s\n", path);
463                                 obdstripe = 1;
464                                 break;
465                         }
466                 }
467         } else if (!quiet) {
468                 printf("%s\n", path);
469                 obdstripe = 1;
470         }
471
472         /* if it's a directory */
473         if (is_dir) {
474                 if (obdstripe == 1) {
475                         printf("default stripe_count: %d stripe_size: %u "
476                                "stripe_offset: %d\n",
477                                lum->lmm_stripe_count == (__u16)-1 ? -1 :
478                                         lum->lmm_stripe_count,
479                                lum->lmm_stripe_size,
480                                lum->lmm_stripe_offset == (__u16)-1 ? -1 :
481                                         lum->lmm_stripe_offset);
482                 }
483                 return;
484         }
485
486         if (header && (obdstripe == 1)) {
487                 printf("lmm_magic:          0x%08X\n",  lum->lmm_magic);
488                 printf("lmm_object_gr:      "LPX64"\n", lum->lmm_object_gr);
489                 printf("lmm_object_id:      "LPX64"\n", lum->lmm_object_id);
490                 printf("lmm_stripe_count:   %u\n", (int)lum->lmm_stripe_count);
491                 printf("lmm_stripe_size:    %u\n",      lum->lmm_stripe_size);
492                 printf("lmm_stripe_pattern: %x\n",      lum->lmm_pattern);
493         }
494
495         if (body) {
496                 if ((!quiet) && (obdstripe == 1))
497                         printf("\tobdidx\t\t objid\t\tobjid\t\t group\n");
498
499                 for (i = 0; i < lum->lmm_stripe_count; i++) {
500                         int idx = lum->lmm_objects[i].l_ost_idx;
501                         long long oid = lum->lmm_objects[i].l_object_id;
502                         long long gr = lum->lmm_objects[i].l_object_gr;
503                         if ((obdindex == OBD_NOT_FOUND) || (obdindex == idx))
504                                 printf("\t%6u\t%14llu\t%#13llx\t%14llu%s\n",
505                                        idx, oid, oid, gr,
506                                        obdindex == idx ? " *" : "");
507                 }
508                 printf("\n");
509         }
510 }
511
512 void lov_dump_user_lmm_join(struct lov_user_md_v1 *lum, char *path,
513                             int is_dir, int obdindex, int quiet,
514                             int header, int body)
515 {
516         struct lov_user_md_join *lumj = (struct lov_user_md_join *)lum;
517         int i, obdstripe = 0;
518
519         if (obdindex != OBD_NOT_FOUND) {
520                 for (i = 0; i < lumj->lmm_stripe_count; i++) {
521                         if (obdindex == lumj->lmm_objects[i].l_ost_idx) {
522                                 printf("%s\n", path);
523                                 obdstripe = 1;
524                                 break;
525                         }
526                 }
527         } else if (!quiet) {
528                 printf("%s\n", path);
529                 obdstripe = 1;
530         }
531
532         if (header && obdstripe == 1) {
533                 printf("lmm_magic:          0x%08X\n",  lumj->lmm_magic);
534                 printf("lmm_object_gr:      "LPX64"\n", lumj->lmm_object_gr);
535                 printf("lmm_object_id:      "LPX64"\n", lumj->lmm_object_id);
536                 printf("lmm_stripe_count:   %u\n", (int)lumj->lmm_stripe_count);
537                 printf("lmm_stripe_size:    %u\n",      lumj->lmm_stripe_size);
538                 printf("lmm_stripe_pattern: %x\n",      lumj->lmm_pattern);
539                 printf("lmm_extent_count:   %x\n",      lumj->lmm_extent_count);
540         }
541
542         if (body) {
543                 unsigned long long start = -1, end = 0;
544                 if (!quiet && obdstripe == 1)
545                         printf("joined\tobdidx\t\t objid\t\tobjid\t\t group"
546                                "\t\tstart\t\tend\n");
547                 for (i = 0; i < lumj->lmm_stripe_count; i++) {
548                         int idx = lumj->lmm_objects[i].l_ost_idx;
549                         long long oid = lumj->lmm_objects[i].l_object_id;
550                         long long gr = lumj->lmm_objects[i].l_object_gr;
551                         if (obdindex == OBD_NOT_FOUND || obdindex == idx)
552                                 printf("\t%6u\t%14llu\t%#13llx\t%14llu%s",
553                                        idx, oid, oid, gr,
554                                        obdindex == idx ? " *" : "");
555                         if (start != lumj->lmm_objects[i].l_extent_start ||
556                             end != lumj->lmm_objects[i].l_extent_end) {
557                                 start = lumj->lmm_objects[i].l_extent_start;
558                                 printf("\t%14llu", start);
559                                 end = lumj->lmm_objects[i].l_extent_end;
560                                 if (end == (unsigned long long)-1)
561                                         printf("\t\tEOF\n");
562                                 else
563                                         printf("\t\t%llu\n", end);
564                         } else {
565                                 printf("\t\t\t\t\n");
566                         }
567                 }
568                 printf("\n");
569         }
570 }
571
572 void llapi_lov_dump_user_lmm(struct find_param *param,
573                              char *path, int is_dir)
574 {
575         switch(*(__u32 *)&param->lmd->lmd_lmm) { /* lum->lmm_magic */
576         case LOV_USER_MAGIC_V1:
577                 lov_dump_user_lmm_v1(&param->lmd->lmd_lmm, path, is_dir,
578                                       param->obdindex, param->quiet,
579                                       param->verbose,
580                                       (param->verbose || !param->obduuid));
581                 break;
582         case LOV_USER_MAGIC_JOIN:
583                 lov_dump_user_lmm_join(&param->lmd->lmd_lmm, path, is_dir,
584                                        param->obdindex, param->quiet,
585                                        param->verbose,
586                                        (param->verbose || !param->obduuid));
587                 break;
588         default:
589                 printf("unknown lmm_magic:  %#x (expecting %#x)\n",
590                        *(__u32 *)&param->lmd->lmd_lmm, LOV_USER_MAGIC_V1);
591                 return;
592         }
593 }
594
595 int llapi_file_get_stripe(const char *path, struct lov_user_md *lum)
596 {
597         const char *fname;
598         char *dname;
599         int fd, rc = 0;
600
601         fname = strrchr(path, '/');
602
603         /* It should be a file (or other non-directory) */
604         if (fname == NULL) {
605                 dname = (char *)malloc(2);
606                 if (dname == NULL)
607                         return ENOMEM;
608                 strcpy(dname, ".");
609                 fname = (char *)path;
610         } else {
611                 dname = (char *)malloc(fname - path + 1);
612                 if (dname == NULL)
613                         return ENOMEM;
614                 strncpy(dname, path, fname - path);
615                 dname[fname - path] = '\0';
616                 fname++;
617         }
618
619         if ((fd = open(dname, O_RDONLY)) == -1) {
620                 rc = errno;
621                 free(dname);
622                 return rc;
623         }
624
625         strcpy((char *)lum, fname);
626         if (ioctl(fd, IOC_MDC_GETFILESTRIPE, (void *)lum) == -1)
627                 rc = errno;
628
629         if (close(fd) == -1 && rc == 0)
630                 rc = errno;
631
632         free(dname);
633
634         return rc;
635 }
636
637 int llapi_file_lookup(int dirfd, const char *name)
638 {
639         struct obd_ioctl_data data = { 0 };
640         char rawbuf[8192];
641         char *buf = rawbuf;
642         int rc;
643
644         if (dirfd < 0 || name == NULL)
645                 return -EINVAL;
646
647         data.ioc_version = OBD_IOCTL_VERSION;
648         data.ioc_len = sizeof(data);
649         data.ioc_inlbuf1 = (char *)name;
650         data.ioc_inllen1 = strlen(name) + 1;
651
652         rc = obd_ioctl_pack(&data, &buf, sizeof(rawbuf));
653         if (rc) {
654                 fprintf(stderr,
655                         "error: IOC_MDC_LOOKUP pack failed for '%s': rc %d\n",
656                         name, rc);
657                 return rc;
658         }
659
660         return ioctl(dirfd, IOC_MDC_LOOKUP, buf);
661 }
662
663 int llapi_mds_getfileinfo(char *path, DIR *parent,
664                           struct lov_user_mds_data *lmd)
665 {
666         lstat_t *st = &lmd->lmd_st;
667         char *fname = strrchr(path, '/');
668         int ret = 0;
669
670         if (parent == NULL)
671                 return -EINVAL;
672
673         fname = (fname == NULL ? path : fname + 1);
674         /* retrieve needed file info */
675         strncpy((char *)lmd, fname, lov_mds_md_size(MAX_LOV_UUID_COUNT));
676         ret = ioctl(dirfd(parent), IOC_MDC_GETFILEINFO, (void *)lmd);
677
678         if (ret) {
679                 if (errno == ENOTTY) {
680                         /* ioctl is not supported, it is not a lustre fs.
681                          * Do the regular lstat(2) instead. */
682                         ret = lstat_f(path, st);
683                         if (ret) {
684                                 err_msg("error: %s: lstat failed for %s",
685                                         __FUNCTION__, path);
686                                 return ret;
687                         }
688                 } else if (errno == ENOENT) {
689                         err_msg("warning: %s: %s does not exist", __FUNCTION__,
690                                 path);
691                         return -ENOENT;
692                 } else {
693                         err_msg("error: %s: IOC_MDC_GETFILEINFO failed for %s",
694                                 __FUNCTION__, path);
695                         return ret;
696                 }
697         }
698
699         return 0;
700 }
701
702 static DIR *opendir_parent(char *path)
703 {
704         DIR *parent;
705         char *fname;
706         char c;
707
708         fname = strrchr(path, '/');
709         if (fname == NULL)
710                 return opendir(".");
711
712         c = fname[1];
713         fname[1] = '\0';
714         parent = opendir(path);
715         fname[1] = c;
716         return parent;
717 }
718
719 static int llapi_semantic_traverse(char *path, int size, DIR *parent,
720                                    semantic_func_t sem_init,
721                                    semantic_func_t sem_fini, void *data,
722                                    struct dirent64 *de)
723 {
724         struct dirent64 *dent;
725         int len, ret;
726         DIR *d, *p = NULL;
727
728         ret = 0;
729         len = strlen(path);
730
731         d = opendir(path);
732         if (!d && errno != ENOTDIR) {
733                 fprintf(stderr, "%s: Failed to open '%s': %s.",
734                         __FUNCTION__, path, strerror(errno));
735                 return -EINVAL;
736         } else if (!d && !parent) {
737                 /* ENOTDIR. Open the parent dir. */
738                 p = opendir_parent(path);
739                 if (!p)
740                         GOTO(out, ret = -EINVAL);
741         }
742
743         if (sem_init && (ret = sem_init(path, parent ?: p, d, data, de)))
744                 goto err;
745
746         if (!d)
747                 GOTO(out, ret = 0);
748
749         while ((dent = readdir64(d)) != NULL) {
750                 ((struct find_param *)data)->have_fileinfo = 0;
751
752                 if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
753                         continue;
754
755                 path[len] = 0;
756                 if ((len + dent->d_reclen + 2) > size) {
757                         fprintf(stderr,
758                                 "error: %s: string buffer is too small\n",
759                                 __FUNCTION__);
760                         break;
761                 }
762                 strcat(path, "/");
763                 strcat(path, dent->d_name);
764
765                 if (dent->d_type == DT_UNKNOWN) {
766                         lstat_t *st = &((struct find_param *)data)->lmd->lmd_st;
767
768                         ret = llapi_mds_getfileinfo(path, d,
769                                              ((struct find_param *)data)->lmd);
770                         if (ret == 0) {
771                                 ((struct find_param *)data)->have_fileinfo = 1;
772                                 dent->d_type = llapi_filetype_dir_table[st->st_mode &
773                                                                         S_IFMT];
774                         }
775                         if (ret == -ENOENT)
776                                 continue;
777                 }
778
779                 switch (dent->d_type) {
780                 case DT_UNKNOWN:
781                         fprintf(stderr, "error: %s: '%s' is UNKNOWN type %d",
782                                 __FUNCTION__, dent->d_name, dent->d_type);
783                         break;
784                 case DT_DIR:
785                         ret = llapi_semantic_traverse(path, size, d, sem_init,
786                                                       sem_fini, data, dent);
787                         if (ret < 0)
788                                 goto out;
789                         break;
790                 default:
791                         ret = 0;
792                         if (sem_init) {
793                                 ret = sem_init(path, d, NULL, data, dent);
794                                 if (ret < 0)
795                                         goto out;
796                         }
797                         if (sem_fini && ret == 0)
798                                 sem_fini(path, d, NULL, data, dent);
799                 }
800         }
801
802 out:
803         path[len] = 0;
804
805         if (sem_fini)
806                 sem_fini(path, parent, d, data, de);
807 err:
808         if (d)
809                 closedir(d);
810         if (p)
811                 closedir(p);
812         return ret;
813 }
814
815 /* Check if the value matches 1 of the given criteria (e.g. --atime +/-N).
816  * @mds indicates if this is MDS timestamps and there are attributes on OSTs.
817  *
818  * The result is -1 if it does not match, 0 if not yet clear, 1 if matches.
819  * The table bolow gives the answers for the specified parameters (value and
820  * sign), 1st column is the answer for the MDS value, the 2nd is for the OST:
821  * --------------------------------------
822  * 1 | file > limit; sign > 0 | -1 / -1 |
823  * 2 | file = limit; sign > 0 |  ? /  1 |
824  * 3 | file < limit; sign > 0 |  ? /  1 |
825  * 4 | file > limit; sign = 0 | -1 / -1 |
826  * 5 | file = limit; sign = 0 |  ? /  1 |  <- (see the Note below)
827  * 6 | file < limit; sign = 0 |  ? / -1 |
828  * 7 | file > limit; sign < 0 |  1 /  1 |
829  * 8 | file = limit; sign < 0 |  ? / -1 |
830  * 9 | file < limit; sign < 0 |  ? / -1 |
831  * --------------------------------------
832  * Note: 5th actually means that the value is within the interval
833  * (limit - margin, limit]. */
834 static int find_value_cmp(unsigned int file, unsigned int limit, int sign,
835                           unsigned long long margin, int mds)
836 {
837         if (sign > 0) {
838                 if (file < limit)
839                         return mds ? 0 : 1;
840         }
841
842         if (sign == 0) {
843                 if (file <= limit && file + margin > limit)
844                         return mds ? 0 : 1;
845                 if (file + margin <= limit)
846                         return mds ? 0 : -1;
847         }
848
849         if (sign < 0) {
850                 if (file > limit)
851                         return 1;
852                 if (mds)
853                         return 0;
854         }
855
856         return -1;
857 }
858
859 /* Check if the file time matches all the given criteria (e.g. --atime +/-N).
860  * Return -1 or 1 if file timestamp does not or does match the given criteria
861  * correspondingly. Return 0 if the MDS time is being checked and there are
862  * attributes on OSTs and it is not yet clear if the timespamp matches.
863  *
864  * If 0 is returned, we need to do another RPC to the OSTs to obtain the
865  * updated timestamps. */
866 static int find_time_check(lstat_t *st, struct find_param *param, int mds)
867 {
868         int ret;
869         int rc = 0;
870
871         /* Check if file is accepted. */
872         if (param->atime) {
873                 ret = find_value_cmp(st->st_atime, param->atime,
874                                      param->asign, 24 * 60 * 60, mds);
875                 if (ret < 0)
876                         return ret;
877                 rc = ret;
878         }
879
880         if (param->mtime) {
881                 ret = find_value_cmp(st->st_mtime, param->mtime,
882                                      param->msign, 24 * 60 * 60, mds);
883                 if (ret < 0)
884                         return ret;
885
886                 /* If the previous check matches, but this one is not yet clear,
887                  * we should return 0 to do an RPC on OSTs. */
888                 if (rc == 1)
889                         rc = ret;
890         }
891
892         if (param->ctime) {
893                 ret = find_value_cmp(st->st_ctime, param->ctime,
894                                      param->csign, 24 * 60 * 60, mds);
895                 if (ret < 0)
896                         return ret;
897
898                 /* If the previous check matches, but this one is not yet clear,
899                  * we should return 0 to do an RPC on OSTs. */
900                 if (rc == 1)
901                         rc = ret;
902         }
903
904         return rc;
905 }
906
907 static int cb_find_init(char *path, DIR *parent, DIR *dir,
908                         void *data, struct dirent64 *de)
909 {
910         struct find_param *param = (struct find_param *)data;
911         int decision = 1; /* 1 is accepted; -1 is rejected. */
912         lstat_t *st = &param->lmd->lmd_st;
913         int lustre_fs = 1;
914         int checked_type = 0;
915         int ret = 0;
916
917         LASSERT(parent != NULL || dir != NULL);
918
919         param->lmd->lmd_lmm.lmm_stripe_count = 0;
920
921         /* If a regular expression is presented, make the initial decision */
922         if (param->pattern != NULL) {
923                 char *fname = strrchr(path, '/');
924                 fname = (fname == NULL ? path : fname + 1);
925                 ret = fnmatch(param->pattern, fname, 0);
926                 if ((ret == FNM_NOMATCH && !param->exclude_pattern) ||
927                     (ret == 0 && param->exclude_pattern))
928                         goto decided;
929         }
930
931         /* See if we can check the file type from the dirent. */
932         if (param->type && de != NULL && de->d_type != DT_UNKNOWN &&
933             de->d_type < DT_MAX) {
934                 checked_type = 1;
935                 if (llapi_dir_filetype_table[de->d_type] == param->type) {
936                         if (param->exclude_type)
937                                 goto decided;
938                 } else {
939                         if (!param->exclude_type)
940                                 goto decided;
941                 }
942         }
943
944
945         /* If a time or OST should be checked, the decision is not taken yet. */
946         if (param->atime || param->ctime || param->mtime || param->obduuid ||
947             param->size)
948                 decision = 0;
949
950         ret = 0;
951         /* Request MDS for the stat info. */
952         if (param->have_fileinfo == 0) {
953                 if (dir) {
954                         /* retrieve needed file info */
955                         ret = ioctl(dirfd(dir), LL_IOC_MDC_GETINFO,
956                                     (void *)param->lmd);
957                 } else {
958                         char *fname = strrchr(path, '/');
959                         fname = (fname == NULL ? path : fname + 1);
960
961                         /* retrieve needed file info */
962                         strncpy((char *)param->lmd, fname, param->lumlen);
963                         ret = ioctl(dirfd(parent), IOC_MDC_GETFILEINFO,
964                                    (void *)param->lmd);
965                 }
966         }
967
968         if (ret) {
969                 if (errno == ENOTTY) {
970                         /* ioctl is not supported, it is not a lustre fs.
971                          * Do the regular lstat(2) instead. */
972                         lustre_fs = 0;
973                         ret = lstat_f(path, st);
974                         if (ret) {
975                                 err_msg("error: %s: lstat failed for %s",
976                                         __FUNCTION__, path);
977                                 return ret;
978                         }
979                 } else if (errno == ENOENT) {
980                         err_msg("warning: %s: %s does not exist",
981                                 __FUNCTION__, path);
982                         goto decided;
983                 } else {
984                         err_msg("error: %s: %s failed for %s", __FUNCTION__,
985                                 dir ? "LL_IOC_MDC_GETINFO" :
986                                 "IOC_MDC_GETFILEINFO", path);
987                         return ret;
988                 }
989         }
990
991         if (param->type && !checked_type) {
992                 if ((st->st_mode & S_IFMT) == param->type) {
993                         if (param->exclude_type)
994                                 goto decided;
995                 } else {
996                         if (!param->exclude_type)
997                                 goto decided;
998                 }
999         }
1000
1001         /* Prepare odb. */
1002         if (param->obduuid) {
1003                 if (lustre_fs && param->got_uuids &&
1004                     param->st_dev != st->st_dev) {
1005                         /* A lustre/lustre mount point is crossed. */
1006                         param->got_uuids = 0;
1007                         param->obds_printed = 0;
1008                         param->obdindex = OBD_NOT_FOUND;
1009                 }
1010
1011                 if (lustre_fs && !param->got_uuids) {
1012                         ret = setup_obd_indexes(dir ? dir : parent, param);
1013                         if (ret)
1014                                 return ret;
1015
1016                         param->st_dev = st->st_dev;
1017                 } else if (!lustre_fs && param->got_uuids) {
1018                         /* A lustre/non-lustre mount point is crossed. */
1019                         param->got_uuids = 0;
1020                         param->obdindex = OBD_NOT_FOUND;
1021                 }
1022         }
1023
1024         /* If an OBD UUID is specified but no one matches, skip this file. */
1025         if (param->obduuid && param->obdindex == OBD_NOT_FOUND)
1026                 goto decided;
1027
1028         /* If a OST UUID is given, and some OST matches, check it here. */
1029         if (param->obdindex != OBD_NOT_FOUND) {
1030                 if (!S_ISREG(st->st_mode))
1031                         goto decided;
1032
1033                 /* Only those files should be accepted, which have a
1034                  * stripe on the specified OST. */
1035                 if (!param->lmd->lmd_lmm.lmm_stripe_count) {
1036                         goto decided;
1037                 } else {
1038                         int i, j;
1039                         for (i = 0;
1040                              i < param->lmd->lmd_lmm.lmm_stripe_count; i++) {
1041                                 for (j = 0; j < param->num_obds; j++) {
1042                                         if (param->obdindexes[j] ==
1043                                             param->lmd->lmd_lmm.lmm_objects[i].l_ost_idx)
1044                                                 goto obd_matches;
1045                                 }
1046                         }
1047
1048                         if (i == param->lmd->lmd_lmm.lmm_stripe_count)
1049                                 goto decided;
1050                 }
1051         }
1052
1053         /* Check the time on mds. */
1054         if (!decision) {
1055                 int for_mds;
1056
1057                 for_mds = lustre_fs ? (S_ISREG(st->st_mode) &&
1058                                        param->lmd->lmd_lmm.lmm_stripe_count)
1059                                     : 0;
1060                 decision = find_time_check(st, param, for_mds);
1061         }
1062
1063 obd_matches:
1064         /* If file still fits the request, ask osd for updated info.
1065            The regulat stat is almost of the same speed as some new
1066            'glimpse-size-ioctl'. */
1067         if (!decision && S_ISREG(st->st_mode) &&
1068             (param->lmd->lmd_lmm.lmm_stripe_count || param->size)) {
1069                 if (param->obdindex != OBD_NOT_FOUND) {
1070                         /* Check whether the obd is active or not, if it is
1071                          * not active, just print the object affected by this
1072                          * failed ost 
1073                          * */
1074                         struct obd_statfs stat_buf;
1075                         struct obd_uuid uuid_buf;
1076
1077                         memset(&stat_buf, 0, sizeof(struct obd_statfs));
1078                         memset(&uuid_buf, 0, sizeof(struct obd_uuid));
1079                         ret = llapi_obd_statfs(path, LL_STATFS_LOV,
1080                                                param->obdindex, &stat_buf, 
1081                                                &uuid_buf);
1082                         if (ret) {
1083                                 if (ret == -ENODATA || ret == -ENODEV 
1084                                     || ret == -EIO)
1085                                         errno = EIO;
1086                                 printf("obd_uuid: %s failed %s ",
1087                                         param->obduuid->uuid, strerror(errno));
1088                                 goto print_path;
1089                         }
1090                 }
1091                 if (dir) {
1092                         ret = ioctl(dirfd(dir), IOC_LOV_GETINFO,
1093                                     (void *)param->lmd);
1094                 } else if (parent) {
1095                         ret = ioctl(dirfd(parent), IOC_LOV_GETINFO,
1096                                     (void *)param->lmd);
1097                 }
1098
1099                 if (ret) {
1100                         if (errno == ENOENT) {
1101                                 err_msg("warning: %s: %s does not exist",
1102                                         __FUNCTION__, path);
1103                                 goto decided;
1104                         } else {
1105                                 fprintf(stderr, "%s: IOC_LOV_GETINFO on %s failed: "
1106                                         "%s.\n", __FUNCTION__, path, strerror(errno));
1107                                 return ret;
1108                         }
1109                 }
1110
1111                 /* Check the time on osc. */
1112                 decision = find_time_check(st, param, 0);
1113                 if (decision == -1)
1114                         goto decided;
1115         }
1116
1117         if (param->size)
1118                 decision = find_value_cmp(st->st_size, param->size,
1119                                           param->size_sign, param->size_units,
1120                                           0);
1121
1122 print_path:
1123         if (decision != -1) {
1124                 printf("%s", path);
1125                 if (param->zeroend)
1126                         printf("%c", '\0');
1127                 else
1128                         printf("\n");
1129         }
1130
1131 decided:
1132         /* Do not get down anymore? */
1133         if (param->depth == param->maxdepth)
1134                 return 1;
1135
1136         param->depth++;
1137         return 0;
1138 }
1139
1140 static int cb_common_fini(char *path, DIR *parent, DIR *d, void *data,
1141                           struct dirent64 *de)
1142 {
1143         struct find_param *param = (struct find_param *)data;
1144         param->depth--;
1145         return 0;
1146 }
1147
1148 int llapi_find(char *path, struct find_param *param)
1149 {
1150         char *buf;
1151         int ret, len = strlen(path);
1152
1153         if (len > PATH_MAX) {
1154                 fprintf(stderr, "%s: Path name '%s' is too long.\n",
1155                         __FUNCTION__, path);
1156                 return -EINVAL;
1157         }
1158
1159         buf = (char *)malloc(PATH_MAX + 1);
1160         if (!buf)
1161                 return -ENOMEM;
1162
1163         ret = common_param_init(param);
1164         if (ret) {
1165                 free(buf);
1166                 return ret;
1167         }
1168
1169         param->depth = 0;
1170
1171         strncpy(buf, path, PATH_MAX + 1);
1172         ret = llapi_semantic_traverse(buf, PATH_MAX + 1, NULL, cb_find_init,
1173                                       cb_common_fini, param, NULL);
1174
1175         find_param_fini(param);
1176         free(buf);
1177         return ret < 0 ? ret : 0;
1178 }
1179
1180 static int cb_getstripe(char *path, DIR *parent, DIR *d, void *data,
1181                         struct dirent64 *de)
1182 {
1183         struct find_param *param = (struct find_param *)data;
1184         int ret = 0;
1185
1186         LASSERT(parent != NULL || d != NULL);
1187
1188         /* Prepare odb. */
1189         if (!param->got_uuids) {
1190                 ret = setup_obd_uuid(d ? d : parent, path, param);
1191                 if (ret)
1192                         return ret;
1193         }
1194
1195         if (d) {
1196                 ret = ioctl(dirfd(d), LL_IOC_LOV_GETSTRIPE,
1197                             (void *)&param->lmd->lmd_lmm);
1198         } else if (parent) {
1199                 char *fname = strrchr(path, '/');
1200                 fname = (fname == NULL ? path : fname + 1);
1201
1202                 strncpy((char *)&param->lmd->lmd_lmm, fname, param->lumlen);
1203                 ret = ioctl(dirfd(parent), IOC_MDC_GETFILESTRIPE,
1204                             (void *)&param->lmd->lmd_lmm);
1205         }
1206
1207         if (ret) {
1208                 if (errno == ENODATA) {
1209                         if (!param->obduuid && !param->quiet)
1210                                 printf("%s has no stripe info\n", path);
1211                         goto out;
1212                 } else if (errno == ENOTTY) {
1213                         fprintf(stderr, "%s: '%s' not on a Lustre fs?\n",
1214                                 __FUNCTION__, path);
1215                 } else if (errno == ENOENT) {
1216                         err_msg("warning: %s: %s does not exist",
1217                                 __FUNCTION__, path);
1218                         goto out;
1219                 } else {
1220                         err_msg("error: %s: %s failed for %s", __FUNCTION__,
1221                                 d ? "LL_IOC_LOV_GETSTRIPE" :
1222                                 "IOC_MDC_GETFILESTRIPE", path);
1223                 }
1224
1225                 return ret;
1226         }
1227
1228         llapi_lov_dump_user_lmm(param, path, d ? 1 : 0);
1229 out:
1230         /* Do not get down anymore? */
1231         if (param->depth == param->maxdepth)
1232                 return 1;
1233
1234         param->depth++;
1235         return 0;
1236 }
1237
1238 int llapi_getstripe(char *path, struct find_param *param)
1239 {
1240         char *buf;
1241         int ret = 0, len = strlen(path);
1242
1243         if (len > PATH_MAX) {
1244                 fprintf(stderr, "%s: Path name '%s' is too long.\n",
1245                         __FUNCTION__, path);
1246                 return -EINVAL;
1247         }
1248
1249         buf = (char *)malloc(PATH_MAX + 1);
1250         if (!buf)
1251                 return -ENOMEM;
1252
1253         ret = common_param_init(param);
1254         if (ret) {
1255                 free(buf);
1256                 return ret;
1257         }
1258
1259         param->depth = 0;
1260
1261         strncpy(buf, path, PATH_MAX + 1);
1262         ret = llapi_semantic_traverse(buf, PATH_MAX + 1, NULL, cb_getstripe,
1263                                       cb_common_fini, param, NULL);
1264         find_param_fini(param);
1265         free(buf);
1266         return ret < 0 ? ret : 0;
1267 }
1268
1269 int llapi_obd_statfs(char *path, __u32 type, __u32 index,
1270                      struct obd_statfs *stat_buf,
1271                      struct obd_uuid *uuid_buf)
1272 {
1273         int fd;
1274         char raw[OBD_MAX_IOCTL_BUFFER] = {'\0'};
1275         char *rawbuf = raw;
1276         struct obd_ioctl_data data = { 0 };
1277         int rc = 0;
1278
1279         data.ioc_inlbuf1 = (char *)&type;
1280         data.ioc_inllen1 = sizeof(__u32);
1281         data.ioc_inlbuf2 = (char *)&index;
1282         data.ioc_inllen2 = sizeof(__u32);
1283         data.ioc_pbuf1 = (char *)stat_buf;
1284         data.ioc_plen1 = sizeof(struct obd_statfs);
1285         data.ioc_pbuf2 = (char *)uuid_buf;
1286         data.ioc_plen2 = sizeof(struct obd_uuid);
1287
1288         if ((rc = obd_ioctl_pack(&data, &rawbuf, sizeof(raw))) != 0) {
1289                 fprintf(stderr, "llapi_obd_statfs: error packing ioctl data\n");
1290                 return rc;
1291         }
1292
1293         fd = open(path, O_RDONLY);
1294         if (errno == EISDIR)
1295                 fd = open(path, O_DIRECTORY | O_RDONLY);
1296
1297         if (fd < 0) {
1298                 rc = errno ? -errno : -EBADF;
1299                 err_msg("error: %s: opening '%s'", __FUNCTION__, path);
1300                 return rc;
1301         }
1302         rc = ioctl(fd, IOC_OBD_STATFS, (void *)rawbuf);
1303         if (rc)
1304                 rc = errno ? -errno : -EINVAL;
1305
1306         close(fd);
1307         return rc;
1308 }
1309
1310 #define MAX_STRING_SIZE 128
1311 #define DEVICES_LIST "/proc/fs/lustre/devices"
1312
1313 int llapi_ping(char *obd_type, char *obd_name)
1314 {
1315         char path[MAX_STRING_SIZE];
1316         char buf[1];
1317         int rc, fd;
1318
1319         snprintf(path, MAX_STRING_SIZE, "/proc/fs/lustre/%s/%s/ping",
1320                  obd_type, obd_name);
1321
1322         fd = open(path, O_WRONLY);
1323         if (fd < 0) {
1324                 rc = errno;
1325                 fprintf(stderr, "error opening %s: %s\n", path, strerror(errno));
1326                 return rc;
1327         }
1328
1329         rc = write(fd, buf, 1);
1330         close(fd);
1331
1332         if (rc == 1)
1333                 return 0;
1334         return rc;
1335 }
1336
1337 int llapi_target_iterate(int type_num, char **obd_type, void *args, llapi_cb_t cb)
1338 {
1339         char buf[MAX_STRING_SIZE];
1340         FILE *fp = fopen(DEVICES_LIST, "r");
1341         int i, rc = 0;
1342
1343         if (fp == NULL) {
1344                 rc = errno;
1345                 fprintf(stderr, "error: %s opening "DEVICES_LIST"\n",
1346                         strerror(errno));
1347                 return rc;
1348         }
1349
1350         while (fgets(buf, sizeof(buf), fp) != NULL) {
1351                 char *obd_type_name = NULL;
1352                 char *obd_name = NULL;
1353                 char *obd_uuid = NULL;
1354                 char rawbuf[OBD_MAX_IOCTL_BUFFER];
1355                 char *bufl = rawbuf;
1356                 char *bufp = buf;
1357                 struct obd_ioctl_data datal = { 0, };
1358                 struct obd_statfs osfs_buffer;
1359
1360                 while(bufp[0] == ' ')
1361                         ++bufp;
1362
1363                 for(i = 0; i < 3; i++) {
1364                         obd_type_name = strsep(&bufp, " ");
1365                 }
1366                 obd_name = strsep(&bufp, " ");
1367                 obd_uuid = strsep(&bufp, " ");
1368
1369                 memset(&osfs_buffer, 0, sizeof (osfs_buffer));
1370
1371                 memset(bufl, 0, sizeof(rawbuf));
1372                 datal.ioc_pbuf1 = (char *)&osfs_buffer;
1373                 datal.ioc_plen1 = sizeof(osfs_buffer);
1374
1375                 for (i = 0; i < type_num; i++) {
1376                         if (strcmp(obd_type_name, obd_type[i]) != 0)
1377                                 continue;
1378
1379                         cb(obd_type_name, obd_name, obd_uuid, args);
1380                 }
1381         }
1382         fclose(fp);
1383         return rc;
1384 }
1385
1386 static void do_target_check(char *obd_type_name, char *obd_name,
1387                             char *obd_uuid, void *args)
1388 {
1389         int rc;
1390
1391         rc = llapi_ping(obd_type_name, obd_name);
1392         if (rc) {
1393                 err_msg("error: check '%s'", obd_name);
1394         } else {
1395                 printf("%s active.\n", obd_name);
1396         }
1397 }
1398
1399 int llapi_target_check(int type_num, char **obd_type, char *dir)
1400 {
1401         return llapi_target_iterate(type_num, obd_type, NULL, do_target_check);
1402 }
1403
1404 #undef MAX_STRING_SIZE
1405
1406 int llapi_catinfo(char *dir, char *keyword, char *node_name)
1407 {
1408         char raw[OBD_MAX_IOCTL_BUFFER];
1409         char out[LLOG_CHUNK_SIZE];
1410         char *buf = raw;
1411         struct obd_ioctl_data data = { 0 };
1412         char key[30];
1413         DIR *root;
1414         int rc;
1415
1416         sprintf(key, "%s", keyword);
1417         memset(raw, 0, sizeof(raw));
1418         memset(out, 0, sizeof(out));
1419         data.ioc_inlbuf1 = key;
1420         data.ioc_inllen1 = strlen(key) + 1;
1421         if (node_name) {
1422                 data.ioc_inlbuf2 = node_name;
1423                 data.ioc_inllen2 = strlen(node_name) + 1;
1424         }
1425         data.ioc_pbuf1 = out;
1426         data.ioc_plen1 = sizeof(out);
1427         rc = obd_ioctl_pack(&data, &buf, sizeof(raw));
1428         if (rc)
1429                 return rc;
1430
1431         root = opendir(dir);
1432         if (root == NULL) {
1433                 rc = errno;
1434                 err_msg("open %s failed", dir);
1435                 return rc;
1436         }
1437
1438         rc = ioctl(dirfd(root), OBD_IOC_LLOG_CATINFO, buf);
1439         if (rc)
1440                 err_msg("ioctl OBD_IOC_CATINFO failed");
1441         else
1442                 fprintf(stdout, "%s", data.ioc_pbuf1);
1443
1444         closedir(root);
1445         return rc;
1446 }
1447
1448 /* Is this a lustre fs? */
1449 int llapi_is_lustre_mnttype(const char *type)
1450 {
1451         return (strcmp(type, "lustre") == 0 || strcmp(type,"lustre_lite") == 0);
1452 }
1453
1454 /* Is this a lustre client fs? */
1455 int llapi_is_lustre_mnt(struct mntent *mnt)
1456 {
1457         return (llapi_is_lustre_mnttype(mnt->mnt_type) &&
1458                 strstr(mnt->mnt_fsname, ":/") != NULL);
1459 }
1460
1461 int llapi_quotacheck(char *mnt, int check_type)
1462 {
1463         DIR *root;
1464         int rc;
1465
1466         root = opendir(mnt);
1467         if (!root) {
1468                 err_msg("open %s failed", mnt);
1469                 return -1;
1470         }
1471
1472         rc = ioctl(dirfd(root), LL_IOC_QUOTACHECK, check_type);
1473
1474         closedir(root);
1475         return rc;
1476 }
1477
1478 int llapi_poll_quotacheck(char *mnt, struct if_quotacheck *qchk)
1479 {
1480         DIR *root;
1481         int poll_intvl = 2;
1482         int rc;
1483
1484         root = opendir(mnt);
1485         if (!root) {
1486                 err_msg("open %s failed", mnt);
1487                 return -1;
1488         }
1489
1490         while (1) {
1491                 rc = ioctl(dirfd(root), LL_IOC_POLL_QUOTACHECK, qchk);
1492                 if (!rc)
1493                         break;
1494                 sleep(poll_intvl);
1495                 if (poll_intvl < 30)
1496                         poll_intvl *= 2;
1497         }
1498
1499         closedir(root);
1500         return rc;
1501 }
1502
1503 int llapi_quotactl(char *mnt, struct if_quotactl *qctl)
1504 {
1505         DIR *root;
1506         int rc;
1507
1508         root = opendir(mnt);
1509         if (!root) {
1510                 err_msg("open %s failed", mnt);
1511                 return -1;
1512         }
1513
1514         rc = ioctl(dirfd(root), LL_IOC_QUOTACTL, qctl);
1515
1516         closedir(root);
1517         return rc;
1518 }
1519
1520 static int cb_quotachown(char *path, DIR *parent, DIR *d, void *data,
1521                          struct dirent64 *de)
1522 {
1523         struct find_param *param = (struct find_param *)data;
1524         lstat_t *st;
1525         int rc;
1526
1527         LASSERT(parent != NULL || d != NULL);
1528
1529         if (d) {
1530                 rc = ioctl(dirfd(d), LL_IOC_MDC_GETINFO,
1531                            (void *)param->lmd);
1532         } else if (parent) {
1533                 char *fname = strrchr(path, '/');
1534                 fname = (fname == NULL ? path : fname + 1);
1535
1536                 strncpy((char *)param->lmd, fname, param->lumlen);
1537                 rc = ioctl(dirfd(parent), IOC_MDC_GETFILEINFO,
1538                            (void *)param->lmd);
1539         } else {
1540                 return 0;
1541         }
1542
1543         if (rc) {
1544                 if (errno == ENODATA) {
1545                         if (!param->obduuid && !param->quiet)
1546                                 fprintf(stderr, "%s has no stripe info\n",
1547                                         path);
1548                         rc = 0;
1549                 } else if (errno == ENOENT) {
1550                         err_msg("warning: %s: %s does not exist",
1551                                 __FUNCTION__, path);
1552                         rc = 0;
1553                 } else if (errno != EISDIR) {
1554                         rc = errno;
1555                         err_msg("%s ioctl failed for %s.",
1556                                 d ? "LL_IOC_MDC_GETINFO" :
1557                                 "IOC_MDC_GETFILEINFO", path);
1558                 }
1559                 return rc;
1560         }
1561
1562         st = &param->lmd->lmd_st;
1563
1564         /* libc chown() will do extra check, and if the real owner is
1565          * the same as the ones to set, it won't fall into kernel, so
1566          * invoke syscall directly. */
1567         rc = syscall(SYS_chown, path, -1, -1);
1568         if (rc)
1569                 err_msg("error: chown %s (%u,%u)", path);
1570
1571         rc = chmod(path, st->st_mode);
1572         if (rc)
1573                 err_msg("error: chmod %s (%hu)", path, st->st_mode);
1574
1575         return rc;
1576 }
1577
1578 int llapi_quotachown(char *path, int flag)
1579 {
1580         struct find_param param;
1581         char *buf;
1582         int ret = 0, len = strlen(path);
1583
1584         if (len > PATH_MAX) {
1585                 fprintf(stderr, "%s: Path name '%s' is too long.\n",
1586                         __FUNCTION__, path);
1587                 return -EINVAL;
1588         }
1589
1590         buf = (char *)malloc(PATH_MAX + 1);
1591         if (!buf)
1592                 return -ENOMEM;
1593
1594         memset(&param, 0, sizeof(param));
1595         param.recursive = 1;
1596         param.verbose = 0;
1597         param.quiet = 1;
1598
1599         ret = common_param_init(&param);
1600         if (ret)
1601                 goto out;
1602
1603         strncpy(buf, path, PATH_MAX + 1);
1604         ret = llapi_semantic_traverse(buf, PATH_MAX + 1, NULL, cb_quotachown,
1605                                       NULL, &param, NULL);
1606 out:
1607         find_param_fini(&param);
1608         free(buf);
1609         return ret;
1610 }
1611
1612 int llapi_getfacl(char *fname, char *cmd)
1613 {
1614         struct rmtacl_ioctl_data data;
1615         char out[RMTACL_SIZE_MAX] = "";
1616         int fd, rc;
1617
1618         data.cmd = cmd;
1619         data.cmd_len = strlen(cmd) + 1;
1620         data.res = out;
1621         data.res_len = sizeof(out);
1622
1623         fd = open(fname, 0);
1624         if (fd == -1) {
1625                 err_msg("open %s failed", fname);
1626                 return -1;
1627         }
1628
1629         rc = ioctl(fd, LL_IOC_GETFACL, &data);
1630         close(fd);
1631         if (errno == EBADE) {
1632                 fprintf(stderr, "Please use getfacl directly!\n");
1633                 rc = 1;
1634         } else if (rc) {
1635                 err_msg("getfacl %s failed", fname);
1636         } else {
1637                 printf("%s", out);
1638         }
1639
1640         return rc;
1641 }
1642
1643 int llapi_setfacl(char *fname, char *cmd)
1644 {
1645         struct rmtacl_ioctl_data data;
1646         char out[RMTACL_SIZE_MAX] = "";
1647         int fd, rc;
1648
1649         data.cmd = cmd;
1650         data.cmd_len = strlen(cmd) + 1;
1651         data.res = out;
1652         data.res_len = sizeof(out);
1653
1654         fd = open(fname, 0);
1655         if (fd == -1) {
1656                 err_msg("open %s failed", fname);
1657                 return -1;
1658         }
1659
1660         rc = ioctl(fd, LL_IOC_SETFACL, &data);
1661         close(fd);
1662         if (errno == EBADE) {
1663                 fprintf(stderr, "Please use setfacl directly!\n");
1664                 rc = 1;
1665         } else if (errno == EOPNOTSUPP) {
1666                 fprintf(stderr, "setfacl: %s: %s\n", fname, strerror(errno));
1667                 rc = 1;
1668         } else if (rc) {
1669                 err_msg("setfacl %s failed", fname);
1670         } else {
1671                 printf("%s", out);
1672         }
1673
1674         return rc;
1675 }