Whamcloud - gitweb
Branch b1_4_mountconf
[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
27 /* for O_DIRECTORY */
28 #define _GNU_SOURCE
29
30 #include <stdlib.h>
31 #include <stdio.h>
32 #include <string.h>
33 #include <stddef.h>
34 #include <sys/ioctl.h>
35 #include <unistd.h>
36 #include <fcntl.h>
37 #include <errno.h>
38 #include <dirent.h>
39 #include <stdarg.h>
40 #include <sys/stat.h>
41 #include <sys/types.h>
42 #include <sys/syscall.h>
43 #ifdef HAVE_LINUX_TYPES_H
44 #include <linux/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 <lnet/lnetctl.h>
53
54 #include <liblustre.h>
55 #include <linux/obd.h>
56 #include <linux/lustre_lib.h>
57 #include <lustre/liblustreapi.h>
58 #include <linux/obd_lov.h>
59 #include <lustre/liblustreapi.h>
60
61 static void err_msg(char *fmt, ...)
62 {
63         va_list args;
64         int tmp_errno = abs(errno);
65
66         va_start(args, fmt);
67         vfprintf(stderr, fmt, args);
68         va_end(args);
69         fprintf(stderr, ": %s (%d)\n", strerror(tmp_errno), tmp_errno);
70 }
71
72 int llapi_file_create(char *name, long stripe_size, int stripe_offset,
73                       int stripe_count, int stripe_pattern)
74 {
75         struct lov_user_md lum = { 0 };
76         int fd, rc = 0;
77         int isdir = 0;
78         int page_size;
79
80         fd = open(name, O_CREAT | O_RDWR | O_LOV_DELAY_CREATE, 0644);
81         if (errno == EISDIR) {
82                 fd = open(name, O_DIRECTORY | O_RDONLY);
83                 isdir++;
84         }
85
86         if (fd < 0) {
87                 err_msg("unable to open '%s'",name);
88                 rc = -errno;
89                 return rc;
90         }
91
92         /* 64 KB is the largest common page size I'm aware of (on ia64), but
93          * check the local page size just in case. */
94         page_size = LOV_MIN_STRIPE_SIZE;
95         if (getpagesize() > page_size) {
96                 page_size = getpagesize();
97                 fprintf(stderr, "warning: your page size (%u) is larger than "
98                         "expected (%u).\n", page_size, LOV_MIN_STRIPE_SIZE);
99         }
100         if (stripe_size < 0 || (stripe_size & (LOV_MIN_STRIPE_SIZE - 1))) {
101                 errno = rc = -EINVAL;
102                 err_msg("error: stripe_size must be an even "
103                         "multiple of %d bytes", page_size);
104                 goto out;
105         }
106         if (stripe_offset < -1 || stripe_offset > 2048) {
107                 errno = rc = -EINVAL;
108                 err_msg("error: bad stripe offset %d", stripe_offset);
109                 goto out;
110         }
111         if (stripe_count < -1 || stripe_count > LOV_MAX_STRIPE_COUNT) {
112                 errno = rc = -EINVAL;
113                 err_msg("error: bad stripe count %d", stripe_count);
114                 goto out;
115         }
116         if (stripe_count > 0 && (__u64)stripe_size * stripe_count > ~0UL) {
117                 errno = rc = -EINVAL;
118                 err_msg("error: stripe_size %ld * stripe_count %d "
119                         "exceeds %lu bytes", ~0UL);
120                 goto out;
121         }
122
123         /*  Initialize IOCTL striping pattern structure */
124         lum.lmm_magic = LOV_USER_MAGIC;
125         lum.lmm_pattern = stripe_pattern;
126         lum.lmm_stripe_size = stripe_size;
127         lum.lmm_stripe_count = stripe_count;
128         lum.lmm_stripe_offset = stripe_offset;
129
130         if (ioctl(fd, LL_IOC_LOV_SETSTRIPE, &lum)) {
131                 char *errmsg = "stripe already set";
132                 if (errno != EEXIST && errno != EALREADY)
133                         errmsg = strerror(errno);
134
135                 fprintf(stderr, "error on ioctl "LPX64" for '%s' (%d): %s\n",
136                         (__u64)LL_IOC_LOV_SETSTRIPE, name, fd, errmsg);
137                 rc = -errno;
138         }
139 out:
140         if (close(fd) < 0) {
141                 err_msg("error on close for '%s' (%d)", name, fd);
142                 if (rc == 0)
143                         rc = -errno;
144         }
145         return rc;
146 }
147
148 /* short term backwards compat only */
149 int op_create_file(char *name, long stripe_size, int stripe_offset,
150                    int stripe_count)
151 {
152         return llapi_file_create(name, stripe_size, stripe_offset,
153                                  stripe_count, 0);
154 }
155
156 struct find_param {
157         int     recursive;
158         int     verbose;
159         int     quiet;
160         struct  obd_uuid        *obduuid;
161         int     lumlen;
162         struct  lov_user_mds_data *lmd;
163 /*        struct  lov_user_md     *lum;*/
164         int     got_uuids;
165         int     obdindex;
166         int     (* process_file)(DIR *dir, char *dname, char *fname,
167                         struct find_param *param);
168 };
169
170 #define MAX_LOV_UUID_COUNT      max(LOV_MAX_STRIPE_COUNT, 1000)
171 #define OBD_NOT_FOUND           (-1)
172
173 static int prepare_find(struct find_param *param)
174 {
175         param->lumlen = lov_mds_md_size(MAX_LOV_UUID_COUNT);
176         if ((param->lmd = malloc(sizeof(lstat_t) + param->lumlen)) == NULL) {
177                 err_msg("unable to allocate %d bytes of memory for ioctl",
178                         sizeof(lstat_t) + param->lumlen);
179                 return ENOMEM;
180         }
181
182         param->got_uuids = 0;
183         param->obdindex = OBD_NOT_FOUND;
184
185         return 0;
186 }
187
188 static void cleanup_find(struct find_param *param)
189 {
190         if (param->obduuid)
191                 free(param->obduuid);
192         if (param->lmd)
193                 free(param->lmd);
194 }
195
196 int llapi_lov_get_uuids(int fd, struct obd_uuid *uuidp, int *ost_count)
197 {
198         struct obd_ioctl_data data = { 0, };
199         struct lov_desc desc = { 0, };
200         char *buf = NULL;
201         int max_ost_count, rc;
202         __u32 *obdgens;
203
204         max_ost_count = (OBD_MAX_IOCTL_BUFFER - size_round(sizeof(data)) -
205                          size_round(sizeof(desc))) /
206                         (sizeof(*uuidp) + sizeof(*obdgens));
207         if (max_ost_count > *ost_count)
208                 max_ost_count = *ost_count;
209
210         obdgens = malloc(size_round(max_ost_count * sizeof(*obdgens)));
211         if (!obdgens) {
212                 err_msg("no memory for %d generation #'s", max_ost_count);
213                 return(-ENOMEM);
214         }
215
216         data.ioc_inllen1 = sizeof(desc);
217         data.ioc_inlbuf1 = (char *)&desc;
218         data.ioc_inllen2 = size_round(max_ost_count * sizeof(*uuidp));
219         data.ioc_inlbuf2 = (char *)uuidp;
220         data.ioc_inllen3 = size_round(max_ost_count * sizeof(*obdgens));
221         data.ioc_inlbuf3 = (char *)obdgens;
222
223         desc.ld_tgt_count = max_ost_count;
224
225         if (obd_ioctl_pack(&data, &buf, OBD_MAX_IOCTL_BUFFER)) {
226                 fprintf(stderr, "internal buffer error packing\n");
227                 rc = EINVAL;
228                 goto out;
229         }
230
231         rc = ioctl(fd, OBD_IOC_LOV_GET_CONFIG, buf);
232         if (rc) {
233                 err_msg("error getting LOV config");
234                 rc = errno;
235                 goto out;
236         }
237
238         if (obd_ioctl_unpack(&data, buf, OBD_MAX_IOCTL_BUFFER)) {
239                 fprintf(stderr, "invalid reply from ioctl");
240                 rc = EINVAL;
241                 goto out;
242         }
243
244         *ost_count = desc.ld_tgt_count;
245 out:
246         free(buf);
247         free(obdgens);
248
249         return rc;
250 }
251
252 static int setup_obd_uuids(DIR *dir, char *dname, struct find_param *param)
253 {
254         char uuid[sizeof(struct obd_uuid)];
255         char buf[1024];
256         FILE *fp;
257         int rc = 0, index;
258
259         param->got_uuids = 1;
260
261         /* Get the lov name */
262         rc = ioctl(dirfd(dir), OBD_IOC_GETNAME, (void *)uuid);
263         if (rc) {
264                 fprintf(stderr, "error: can't get lov name: %s\n",
265                         strerror(rc = errno));
266                 return rc;
267         }
268
269         /* Now get the ost uuids from /proc */
270         snprintf(buf, sizeof(buf), "/proc/fs/lustre/lov/%s/target_obd",
271                  uuid);
272         fp = fopen(buf, "r");
273         if (fp == NULL) {
274                 fprintf(stderr, "error: %s opening %s\n",
275                         strerror(rc = errno), buf);
276                 return rc;
277         }
278
279         if (!param->obduuid && !param->quiet)
280                 printf("OBDS:\n");
281
282         while (fgets(buf, sizeof(buf), fp) != NULL) {
283                 if (sscanf(buf, "%d: %s", &index, uuid) < 2)
284                         break;
285
286                 if (param->obduuid) {
287                         if (strncmp(param->obduuid->uuid, uuid,
288                                     sizeof(uuid)) == 0) {
289                                 param->obdindex = index;
290                                 break;
291                         }
292                 } else if (!param->quiet) {
293                         /* Print everything */
294                         printf("%s", buf);
295                 }
296         }
297
298         fclose(fp);
299
300         if (param->obduuid && (param->obdindex == OBD_NOT_FOUND)) {
301                 printf("unknown obduuid: %s\n", param->obduuid->uuid);
302                 rc =  EINVAL;
303         }
304
305         return (rc);
306 }
307
308 void lov_dump_user_lmm_v1(struct lov_user_md_v1 *lum, char *dname, char *fname,
309                           int obdindex, int quiet, int header, int body)
310 {
311         int i, obdstripe = 0;
312
313         if (obdindex != OBD_NOT_FOUND) {
314                 for (i = 0; fname[0] && i < lum->lmm_stripe_count; i++) {
315                         if (obdindex == lum->lmm_objects[i].l_ost_idx) {
316                                 printf("%s/%s\n", dname, fname);
317                                 obdstripe = 1;
318                                 break;
319                         }
320                 }
321         } else if (!quiet) {
322                 printf("%s/%s\n", dname, fname);
323                 obdstripe = 1;
324         }
325
326         /* if it's a directory */
327         if (*fname == '\0') {
328                 if (obdstripe == 1) {
329                         printf("default stripe_count: %d stripe_size: %u "
330                                "stripe_offset: %d\n",
331                                lum->lmm_stripe_count == (__u16)-1 ? -1 :
332                                         lum->lmm_stripe_count,
333                                lum->lmm_stripe_size,
334                                lum->lmm_stripe_offset == (__u16)-1 ? -1 :
335                                         lum->lmm_stripe_offset);
336                 }
337                 return;
338         }
339
340         if (header && (obdstripe == 1)) {
341                 printf("lmm_magic:          0x%08X\n",  lum->lmm_magic);
342                 printf("lmm_object_gr:      "LPX64"\n", lum->lmm_object_gr);
343                 printf("lmm_object_id:      "LPX64"\n", lum->lmm_object_id);
344                 printf("lmm_stripe_count:   %u\n", (int)lum->lmm_stripe_count);
345                 printf("lmm_stripe_size:    %u\n",      lum->lmm_stripe_size);
346                 printf("lmm_stripe_pattern: %x\n",      lum->lmm_pattern);
347         }
348
349         if (body) {
350                 if ((!quiet) && (obdstripe == 1))
351                         printf("\tobdidx\t\t objid\t\tobjid\t\t group\n");
352
353                 for (i = 0; i < lum->lmm_stripe_count; i++) {
354                         int idx = lum->lmm_objects[i].l_ost_idx;
355                         long long oid = lum->lmm_objects[i].l_object_id;
356                         long long gr = lum->lmm_objects[i].l_object_gr;
357                         if ((obdindex == OBD_NOT_FOUND) || (obdindex == idx))
358                                 printf("\t%6u\t%14llu\t%#13llx\t%14llu%s\n",
359                                        idx, oid, oid, gr,
360                                        obdindex == idx ? " *" : "");
361                 }
362                 printf("\n");
363         }
364 }
365
366 void lov_dump_user_lmm_join(struct lov_user_md_v1 *lum, char *dname,
367                             char *fname, int obdindex, int quiet,
368                             int header, int body)
369 {
370         struct lov_user_md_join *lumj = (struct lov_user_md_join *)lum;
371         int i, obdstripe = 0;
372
373         if (obdindex != OBD_NOT_FOUND) {
374                 for (i = 0; i < lumj->lmm_stripe_count; i++) {
375                         if (obdindex == lumj->lmm_objects[i].l_ost_idx) {
376                                 printf("%s/%s\n", dname, fname);
377                                 obdstripe = 1;
378                                 break;
379                         }
380                 }
381         } else if (!quiet) {
382                 printf("%s/%s\n", dname, fname);
383                 obdstripe = 1;
384         }
385
386         if (header && obdstripe == 1) {
387                 printf("lmm_magic:          0x%08X\n",  lumj->lmm_magic);
388                 printf("lmm_object_gr:      "LPX64"\n", lumj->lmm_object_gr);
389                 printf("lmm_object_id:      "LPX64"\n", lumj->lmm_object_id);
390                 printf("lmm_stripe_count:   %u\n", (int)lumj->lmm_stripe_count);
391                 printf("lmm_stripe_size:    %u\n",      lumj->lmm_stripe_size);
392                 printf("lmm_stripe_pattern: %x\n",      lumj->lmm_pattern);
393                 printf("lmm_extent_count:   %x\n",      lumj->lmm_extent_count);
394         }
395
396         if (body) {
397                 unsigned long long start = -1, end = 0;
398                 if (!quiet && obdstripe == 1)
399                         printf("joined\tobdidx\t\t objid\t\tobjid\t\t group"
400                                "\t\tstart\t\tend\n");
401                 for (i = 0; i < lumj->lmm_stripe_count; i++) {
402                         int idx = lumj->lmm_objects[i].l_ost_idx;
403                         long long oid = lumj->lmm_objects[i].l_object_id;
404                         long long gr = lumj->lmm_objects[i].l_object_gr;
405                         if (obdindex == OBD_NOT_FOUND || obdindex == idx)
406                                 printf("\t%6u\t%14llu\t%#13llx\t%14llu%s",
407                                        idx, oid, oid, gr,
408                                        obdindex == idx ? " *" : "");
409                         if (start != lumj->lmm_objects[i].l_extent_start ||
410                             end != lumj->lmm_objects[i].l_extent_end) {
411                                 start = lumj->lmm_objects[i].l_extent_start;
412                                 printf("\t%14llu", start);
413                                 end = lumj->lmm_objects[i].l_extent_end;
414                                 if (end == (unsigned long long)-1)
415                                         printf("\t\tEOF\n");
416                                 else
417                                         printf("\t\t%llu\n", end);
418                         } else {
419                                 printf("\t\t\t\t\n");
420                         }
421                 }
422                 printf("\n");
423         }
424 }
425
426 void llapi_lov_dump_user_lmm(struct find_param *param, char *dname, char *fname)
427 {
428         switch(*(__u32 *)&param->lmd->lmd_lmm) { /* lum->lmm_magic */
429         case LOV_USER_MAGIC_V1:
430                 lov_dump_user_lmm_v1(&param->lmd->lmd_lmm, dname, fname,
431                                       param->obdindex, param->quiet,
432                                       param->verbose,
433                                       (param->verbose || !param->obduuid));
434                 break;
435         case LOV_USER_MAGIC_JOIN:
436                 lov_dump_user_lmm_join(&param->lmd->lmd_lmm, dname, fname,
437                                        param->obdindex, param->quiet,
438                                        param->verbose,
439                                        (param->verbose || !param->obduuid));
440                 break;
441         default:
442                 printf("unknown lmm_magic:  %#x (expecting %#x)\n",
443                        *(__u32 *)&param->lmd->lmd_lmm, LOV_USER_MAGIC_V1);
444                 return;
445         }
446 }
447
448 int llapi_file_get_stripe(char *path, struct lov_user_md *lum)
449 {
450         char *dname, *fname;
451         int fd, rc = 0;
452
453         fname = strrchr(path, '/');
454
455         /* It should be a file (or other non-directory) */
456         if (fname == NULL) {
457                 dname = (char *)malloc(2);
458                 if (dname == NULL)
459                         return ENOMEM;
460                 strcpy(dname, ".");
461                 fname = path;
462         } else {
463                 dname = (char *)malloc(fname - path + 1);
464                 if (dname == NULL)
465                         return ENOMEM;
466                 strncpy(dname, path, fname - path);
467                 dname[fname - path] = '\0';
468                 fname++;
469         }
470
471         if ((fd = open(dname, O_RDONLY)) == -1) {
472                 free(dname);
473                 return errno;
474         }
475
476         strcpy((char *)lum, fname);
477         if (ioctl(fd, IOC_MDC_GETSTRIPE, (void *)lum) == -1) {
478                 close(fd);
479                 free(dname);
480                 return errno;
481         }
482
483         if (close(fd) == -1)
484                 rc = errno;
485
486         free(dname);
487
488         return rc;
489 }
490
491 /* short term backwards compat only */
492 int op_get_file_stripe(char *path, struct lov_user_md *lum)
493 {
494         return llapi_file_get_stripe(path, lum);
495 }
496
497 static int find_process_file(DIR *dir, char *dname, char *fname,
498                         struct find_param *param)
499 {
500         int rc;
501
502         strncpy((char *)&param->lmd->lmd_lmm, fname, param->lumlen);
503
504         rc = ioctl(dirfd(dir), IOC_MDC_GETSTRIPE, (void *)&param->lmd->lmd_lmm);
505         if (rc) {
506                 if (errno == ENODATA) {
507                         if (!param->obduuid && !param->quiet)
508                                 fprintf(stderr,
509                                         "%s/%s has no stripe info\n",
510                                         dname, fname);
511                         rc = 0;
512                 } else if (errno == EISDIR) {
513                         fprintf(stderr, "process_file on directory %s/%s!\n",
514                                 dname, fname);
515                         /* add fname to directory list; */
516                         rc = errno;
517                 } else {
518                         err_msg("IOC_MDC_GETSTRIPE ioctl failed for '%s/%s'",
519                                 dname, fname);
520                         rc = errno;
521                 }
522                 return rc;
523         }
524
525         llapi_lov_dump_user_lmm(param, dname, fname);
526
527         return 0;
528 }
529
530 /* some 64bit libcs implement readdir64() by calling sys_getdents().  the
531  * kernel's sys_getdents() doesn't return d_type.  */
532 unsigned char handle_dt_unknown(char *parent, char *entry)
533 {
534         char path[PATH_MAX + 1];
535         int fd, ret;
536
537         ret = snprintf(path, PATH_MAX, "%s/%s", parent, entry);
538         if (ret >= PATH_MAX)
539                 return DT_UNKNOWN;
540
541         fd = open(path, O_DIRECTORY|O_RDONLY);
542         if (fd < 0) {
543                 if (errno == ENOTDIR)
544                         return DT_REG; /* kind of a lie */
545                 return DT_UNKNOWN;
546         }
547         close(fd);
548         return DT_DIR;
549 }
550
551 static int process_dir(DIR *dir, char *dname, struct find_param *param)
552 {
553         struct dirent64 *dirp;
554         DIR *subdir;
555         char path[1024];
556         int rc;
557
558         if (!param->got_uuids) {
559                 rc = setup_obd_uuids(dir, dname, param);
560                 if (rc)
561                         return rc;
562         }
563
564         /* retrieve dir's stripe info */
565         strncpy((char *)&param->lmd->lmd_lmm, dname, param->lumlen);
566         rc = ioctl(dirfd(dir), LL_IOC_LOV_GETSTRIPE, (void *)&param->lmd->lmd_lmm);
567         if (rc) {
568                 if (errno == ENODATA) {
569                         if (!param->obduuid && param->verbose)
570                                 printf("%s/%s has no stripe info\n", dname, "");
571                         rc = 0;
572                 } else {
573                         err_msg("GETSTRIPE failed for %s", dname);
574                 }
575         } else {
576                llapi_lov_dump_user_lmm(param, dname, "");
577         }
578
579         /* Handle the contents of the directory */
580         while ((dirp = readdir64(dir)) != NULL) {
581                 if (!strcmp(dirp->d_name, ".") || !strcmp(dirp->d_name, ".."))
582                         continue;
583
584                 if (dirp->d_type == DT_UNKNOWN)
585                         dirp->d_type = handle_dt_unknown(dname, dirp->d_name);
586
587                 switch (dirp->d_type) {
588                 case DT_UNKNOWN:
589                         err_msg("\"%s\" is UNKNOWN type %d", dirp->d_name,
590                                 dirp->d_type);
591                         /* If we cared we could stat the file to determine
592                          * type and continue on here, but we don't since we
593                          * know d_type should be valid for lustre and this
594                          * tool only makes sense for lustre filesystems. */
595                         break;
596                 case DT_DIR:
597                         if (!param->recursive)
598                                 break;
599                         strcpy(path, dname);
600                         strcat(path, "/");
601                         strcat(path, dirp->d_name);
602                         subdir = opendir(path);
603                         if (subdir == NULL) {
604                                 err_msg("\"%.40s\" opendir failed", path);
605                                 return errno;
606                         }
607                         rc = process_dir(subdir, path, param);
608                         closedir(subdir);
609                         break;
610                 case DT_REG:
611                         rc = param->process_file(dir,dname,dirp->d_name,param);
612                         break;
613                 default:
614                         break;
615                 }
616         }
617
618         return 0;
619 }
620
621 static int process_path(char *path, struct find_param *param)
622 {
623         char *fname, *dname;
624         DIR *dir;
625         int rc = 0;
626
627         fname = strrchr(path, '/');
628         if (fname != NULL && fname[1] == '\0') {
629                 /* Trailing '/', it must be a dir */
630                 *fname = '\0';
631                 dir = opendir(path);
632                 if (dir == NULL) {
633                         err_msg("\"%.40s\" opendir failed", path);
634                         rc = errno;
635                 } else {
636                         rc = process_dir(dir, path, param);
637                         closedir(dir);
638                 }
639         } else if ((dir = opendir(path)) != NULL) {
640                 /* No trailing '/', but it is still a dir */
641                 rc = process_dir(dir, path, param);
642                 closedir(dir);
643         } else {
644                 /* It must be a file (or other non-directory) */
645                 if (fname == NULL) {
646                         dname = ".";
647                         fname = path;
648                 } else {
649                         *fname = '\0';
650                         fname++;
651                         dname = path;
652                 }
653                 dir = opendir(dname);
654                 if (dir == NULL) {
655                         err_msg("\"%.40s\" opendir failed", dname);
656                         rc = errno;
657                 } else {
658                         if (!param->got_uuids)
659                                 rc = setup_obd_uuids(dir, dname, param);
660                         if (rc == 0)
661                                 rc = param->process_file(dir, dname, fname, param);
662                         closedir(dir);
663                 }
664         }
665
666         return rc;
667 }
668
669 int llapi_find(char *path, struct obd_uuid *obduuid, int recursive,
670                int verbose, int quiet)
671 {
672         struct find_param param;
673         int ret = 0;
674
675         memset(&param, 0, sizeof(param));
676         param.recursive = recursive;
677         param.verbose = verbose;
678         param.quiet = quiet;
679         param.process_file = find_process_file;
680         if (obduuid) {
681                 param.obduuid = malloc(sizeof(*obduuid));
682                 if (param.obduuid == NULL) {
683                         ret = ENOMEM;
684                         goto out;
685                 }
686                 memcpy(param.obduuid, obduuid, sizeof(*obduuid));
687         }
688
689         ret = prepare_find(&param);
690         if (ret)
691                 goto out;
692
693         process_path(path, &param);
694 out:
695         cleanup_find(&param);
696         return ret;
697 }
698
699 #define MAX_STRING_SIZE 128
700 #define DEVICES_LIST "/proc/fs/lustre/devices"
701
702 int llapi_ping(char *obd_type, char *obd_name)
703 {
704         char path[MAX_STRING_SIZE];
705         char buf[1];
706         int rc, fd;
707
708         snprintf(path, MAX_STRING_SIZE, "/proc/fs/lustre/%s/%s/ping",
709                  obd_type, obd_name);
710
711         fd = open(path, O_WRONLY);
712         if (fd < 0) {
713                 fprintf(stderr, "error opening %s: %s\n", path, strerror(errno));
714                 return errno;
715         }
716
717         rc = write(fd, buf, 1);
718         close(fd);
719
720         if (rc == 1)
721                 return 0;
722         return rc;
723 }
724
725 int llapi_target_iterate(int type_num, char **obd_type, void *args, llapi_cb_t cb)
726 {
727         char buf[MAX_STRING_SIZE];
728         FILE *fp = fopen(DEVICES_LIST, "r");
729         int i, rc = 0;
730
731         if (fp == NULL) {
732                 fprintf(stderr, "error: %s opening "DEVICES_LIST"\n",
733                         strerror(rc =  errno));
734                 return rc;
735         }
736
737         while (fgets(buf, sizeof(buf), fp) != NULL) {
738                 char *obd_type_name = NULL;
739                 char *obd_name = NULL;
740                 char *obd_uuid = NULL;
741                 char rawbuf[OBD_MAX_IOCTL_BUFFER];
742                 char *bufl = rawbuf;
743                 char *bufp = buf;
744                 struct obd_ioctl_data datal = { 0, };
745                 struct obd_statfs osfs_buffer;
746
747                 while(bufp[0] == ' ')
748                         ++bufp;
749
750                 for(i = 0; i < 3; i++) {
751                         obd_type_name = strsep(&bufp, " ");
752                 }
753                 obd_name = strsep(&bufp, " ");
754                 obd_uuid = strsep(&bufp, " ");
755
756                 memset(&osfs_buffer, 0, sizeof (osfs_buffer));
757
758                 memset(bufl, 0, sizeof(rawbuf));
759                 datal.ioc_pbuf1 = (char *)&osfs_buffer;
760                 datal.ioc_plen1 = sizeof(osfs_buffer);
761
762                 for (i = 0; i < type_num; i++) {
763                         if (strcmp(obd_type_name, obd_type[i]) != 0)
764                                 continue;
765
766                         cb(obd_type_name, obd_name, obd_uuid, args);
767                 }
768         }
769         fclose(fp);
770         return rc;
771 }
772
773 static void do_target_check(char *obd_type_name, char *obd_name,
774                             char *obd_uuid, void *args)
775 {
776         int rc;
777
778         rc = llapi_ping(obd_type_name, obd_name);
779         if (rc) {
780                 fprintf(stderr, "error: check %s: %s\n",
781                         obd_name, strerror(rc = errno));
782         } else {
783                 printf("%s active.\n", obd_name);
784         }
785 }
786
787 int llapi_target_check(int type_num, char **obd_type, char *dir)
788 {
789         return llapi_target_iterate(type_num, obd_type, NULL, do_target_check);
790 }
791
792 #undef MAX_STRING_SIZE
793
794 int llapi_catinfo(char *dir, char *keyword, char *node_name)
795 {
796         char raw[OBD_MAX_IOCTL_BUFFER];
797         char out[LLOG_CHUNK_SIZE];
798         char *buf = raw;
799         struct obd_ioctl_data data;
800         char key[30];
801         DIR *root;
802         int rc;
803
804         sprintf(key, "%s", keyword);
805         memset(raw, 0, sizeof(raw));
806         memset(out, 0, sizeof(out));
807         data.ioc_inlbuf1 = key;
808         data.ioc_inllen1 = strlen(key) + 1;
809         if (node_name) {
810                 data.ioc_inlbuf2 = node_name;
811                 data.ioc_inllen2 = strlen(node_name) + 1;
812         }
813         data.ioc_pbuf1 = out;
814         data.ioc_plen1 = sizeof(out);
815         rc = obd_ioctl_pack(&data, &buf, sizeof(raw));
816         if (rc)
817                 return rc;
818
819         root = opendir(dir);
820         if (root == NULL) {
821                 err_msg("open %s failed", dir);
822                 return errno;
823         }
824
825         rc = ioctl(dirfd(root), OBD_IOC_LLOG_CATINFO, buf);
826         if (rc)
827                 err_msg("ioctl OBD_IOC_CATINFO failed");
828         else
829                 fprintf(stdout, "%s", data.ioc_pbuf1);
830
831         closedir(root);
832         return rc;
833 }
834
835 int llapi_is_lustre_mnttype(char *type)
836 {
837         return (strcmp(type,"lustre") == 0 || strcmp(type,"lustre_lite") == 0);
838 }
839
840 int llapi_quotacheck(char *mnt, int check_type)
841 {
842         DIR *root;
843         int rc;
844
845         root = opendir(mnt);
846         if (!root) {
847                 err_msg("open %s failed", mnt);
848                 return -1;
849         }
850
851         rc = ioctl(dirfd(root), LL_IOC_QUOTACHECK, check_type);
852
853         closedir(root);
854         return rc;
855 }
856
857 int llapi_poll_quotacheck(char *mnt, struct if_quotacheck *qchk)
858 {
859         DIR *root;
860         int poll_intvl = 2;
861         int rc;
862
863         root = opendir(mnt);
864         if (!root) {
865                 err_msg("open %s failed", mnt);
866                 return -1;
867         }
868
869         while (1) {
870                 rc = ioctl(dirfd(root), LL_IOC_POLL_QUOTACHECK, qchk);
871                 if (!rc)
872                         break;
873                 sleep(poll_intvl);
874                 if (poll_intvl < 30)
875                         poll_intvl *= 2;
876         }
877
878         closedir(root);
879         return rc;
880 }
881
882 int llapi_quotactl(char *mnt, struct if_quotactl *qctl)
883 {
884         DIR *root;
885         int rc;
886
887         root = opendir(mnt);
888         if (!root) {
889                 err_msg("open %s failed", mnt);
890                 return -1;
891         }
892
893         rc = ioctl(dirfd(root), LL_IOC_QUOTACTL, qctl);
894
895         closedir(root);
896         return rc;
897 }
898
899 static int quotachown_process_file(DIR *dir, char *dname, char *fname,
900                         struct find_param *param)
901 {
902         lstat_t *st;
903         char pathname[PATH_MAX + 1] = "";
904         int rc;
905
906         strncpy((char *)param->lmd, fname, param->lumlen);
907
908         rc = ioctl(dirfd(dir), IOC_MDC_GETFILEINFO, (void *)param->lmd);
909         if (rc) {
910                 if (errno == ENODATA) {
911                         if (!param->obduuid && !param->quiet)
912                                 fprintf(stderr,
913                                         "%s/%s has no stripe info\n",
914                                         dname, fname);
915                         rc = 0;
916                 } else if (errno != EISDIR) {
917                         err_msg("IOC_MDC_GETFILEINFO ioctl failed");
918                         rc = errno;
919                 }
920                 return rc;
921         }
922
923         st = &param->lmd->lmd_st;
924         snprintf(pathname, sizeof(pathname), "%s/%s", dname, fname);
925
926         /* libc chown() will do extra check, and if the real owner is
927          * the same as the ones to set, it won't fall into kernel, so
928          * invoke syscall directly. */
929         rc = syscall(SYS_chown, pathname, st->st_uid, st->st_gid);
930         if (rc)
931                 fprintf(stderr, "chown %s (%u,%u) fail: %s\n",
932                         pathname, st->st_uid, st->st_gid, strerror(errno));
933         return rc;
934 }
935
936 int llapi_quotachown(char *path, int flag)
937 {
938         struct find_param param;
939         int ret = 0;
940
941         memset(&param, 0, sizeof(param));
942         param.recursive = 1;
943         param.verbose = 0;
944         param.quiet = 1;
945         param.process_file = quotachown_process_file;
946
947         ret = prepare_find(&param);
948         if (ret)
949                 goto out;
950
951         process_path(path, &param);
952 out:
953         cleanup_find(&param);
954         return ret;
955 }