Whamcloud - gitweb
406c6294e1763284265c9adf4b06dd5862eda44c
[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 #include <fnmatch.h>
44 #ifdef HAVE_ASM_TYPES_H
45 #include <asm/types.h>
46 #endif
47 #ifdef HAVE_LINUX_UNISTD_H
48 #include <linux/unistd.h>
49 #else
50 #include <unistd.h>
51 #endif
52
53 #include <lnet/lnetctl.h>
54
55 #include <liblustre.h>
56 #include <obd.h>
57 #include <lustre_lib.h>
58 #include <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(const char *name, unsigned 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                 rc = -errno;
88                 err_msg("unable to open '%s'", name);
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: bad stripe_size %lu, must be an even "
103                         "multiple of %d bytes", stripe_size, page_size);
104                 goto out;
105         }
106         if (stripe_offset < -1 || stripe_offset > MAX_OBD_DEVICES) {
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 > 0xffffffff){
117                 errno = rc = -EINVAL;
118                 err_msg("error: stripe_size %lu * stripe_count %u "
119                         "exceeds 4GB", stripe_size, stripe_count);
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                 rc = -errno;
133                 if (errno != EEXIST && errno != EALREADY)
134                         errmsg = strerror(errno);
135
136                 rc = -errno;
137                 fprintf(stderr, "error on ioctl "LPX64" for '%s' (%d): %s\n",
138                         (__u64)LL_IOC_LOV_SETSTRIPE, name, fd, errmsg);
139         }
140 out:
141         if (close(fd) < 0) {
142                 if (rc == 0)
143                         rc = -errno;
144                 err_msg("error on close for '%s' (%d)", name, fd);
145         }
146         return rc;
147 }
148
149 typedef int (semantic_func_t)(char *path, DIR *parent, DIR *d, void *data);
150
151 #define MAX_LOV_UUID_COUNT      max(LOV_MAX_STRIPE_COUNT, 1000)
152 #define OBD_NOT_FOUND           (-1)
153
154 static int common_param_init(struct find_param *param)
155 {
156         param->lumlen = lov_mds_md_size(MAX_LOV_UUID_COUNT);
157         if ((param->lmd = malloc(sizeof(lstat_t) + param->lumlen)) == NULL) {
158                 err_msg("error: allocation of %d bytes for ioctl",
159                         sizeof(lstat_t) + param->lumlen);
160                 return -ENOMEM;
161         }
162
163         param->got_uuids = 0;
164         param->obdindex = OBD_NOT_FOUND;
165         return 0;
166 }
167
168 static void find_param_fini(struct find_param *param)
169 {
170         if (param->lmd)
171                 free(param->lmd);
172 }
173
174 int llapi_lov_get_uuids(int fd, struct obd_uuid *uuidp, int *ost_count)
175 {
176         char lov_name[sizeof(struct obd_uuid)];
177         char buf[1024];
178         FILE *fp;
179         int rc = 0, index = 0;
180
181         /* Get the lov name */
182         rc = ioctl(fd, OBD_IOC_GETNAME, (void *) lov_name);
183         if (rc) {
184                 rc = errno;
185                 err_msg("error: can't get lov name.");
186                 return rc;
187         }
188
189         /* Now get the ost uuids from /proc */
190         snprintf(buf, sizeof(buf), "/proc/fs/lustre/lov/%s/target_obd",
191                  lov_name);
192         fp = fopen(buf, "r");
193         if (fp == NULL) {
194                 rc = errno;
195                 err_msg("error: opening '%s'", buf);
196                 return rc;
197         }
198
199         while ((fgets(buf, sizeof(buf), fp) != NULL) && index < *ost_count) {
200                 if (sscanf(buf, "%d: %s", &index, uuidp[index].uuid) < 2)
201                         break;
202                 index++;
203         }
204
205         fclose(fp);
206         *ost_count = index;
207
208         return rc;
209 }
210
211 static int setup_obd_uuids(DIR *dir, char *dname, struct find_param *param)
212 {
213         char uuid[sizeof(struct obd_uuid)];
214         char buf[1024];
215         FILE *fp;
216         int rc = 0, index;
217
218         /* Get the lov name */
219         rc = ioctl(dirfd(dir), OBD_IOC_GETNAME, (void *)uuid);
220         if (rc) {
221                 if (errno != ENOTTY) {
222                         rc = errno;
223                         err_msg("error: can't get lov name: %s", dname);
224                 } else {
225                         rc = 0;
226                 }
227                 return rc;
228         }
229
230         param->got_uuids = 1;
231
232         /* Now get the ost uuids from /proc */
233         snprintf(buf, sizeof(buf), "/proc/fs/lustre/lov/%s/target_obd",
234                  uuid);
235         fp = fopen(buf, "r");
236         if (fp == NULL) {
237                 rc = errno;
238                 err_msg("error: opening '%s'", buf);
239                 return rc;
240         }
241
242         if (!param->obduuid && !param->quiet && !param->obds_printed)
243                 printf("OBDS:\n");
244
245         while (fgets(buf, sizeof(buf), fp) != NULL) {
246                 if (sscanf(buf, "%d: %s", &index, uuid) < 2)
247                         break;
248
249                 if (param->obduuid) {
250                         if (strncmp(param->obduuid->uuid, uuid,
251                                     sizeof(uuid)) == 0) {
252                                 param->obdindex = index;
253                                 break;
254                         }
255                 } else if (!param->quiet && !param->obds_printed) {
256                         /* Print everything */
257                         printf("%s", buf);
258                 }
259         }
260         param->obds_printed = 1;
261
262         fclose(fp);
263
264         if (!param->quiet && param->obduuid &&
265             (param->obdindex == OBD_NOT_FOUND)) {
266                 fprintf(stderr, "error: %s: unknown obduuid: %s\n",
267                         __FUNCTION__, param->obduuid->uuid);
268                 //rc = EINVAL;
269         }
270
271         return (rc);
272 }
273
274 void lov_dump_user_lmm_v1(struct lov_user_md_v1 *lum, char *path, int is_dir,
275                           int obdindex, int quiet, int header, int body)
276 {
277         int i, obdstripe = 0;
278
279         if (obdindex != OBD_NOT_FOUND) {
280                 for (i = 0; !is_dir && i < lum->lmm_stripe_count; i++) {
281                         if (obdindex == lum->lmm_objects[i].l_ost_idx) {
282                                 printf("%s\n", path);
283                                 obdstripe = 1;
284                                 break;
285                         }
286                 }
287         } else if (!quiet) {
288                 printf("%s\n", path);
289                 obdstripe = 1;
290         }
291
292         /* if it's a directory */
293         if (is_dir) {
294                 if (obdstripe == 1) {
295                         printf("default stripe_count: %d stripe_size: %u "
296                                "stripe_offset: %d\n",
297                                lum->lmm_stripe_count == (__u16)-1 ? -1 :
298                                         lum->lmm_stripe_count,
299                                lum->lmm_stripe_size,
300                                lum->lmm_stripe_offset == (__u16)-1 ? -1 :
301                                         lum->lmm_stripe_offset);
302                 }
303                 return;
304         }
305
306         if (header && (obdstripe == 1)) {
307                 printf("lmm_magic:          0x%08X\n",  lum->lmm_magic);
308                 printf("lmm_object_gr:      "LPX64"\n", lum->lmm_object_gr);
309                 printf("lmm_object_id:      "LPX64"\n", lum->lmm_object_id);
310                 printf("lmm_stripe_count:   %u\n", (int)lum->lmm_stripe_count);
311                 printf("lmm_stripe_size:    %u\n",      lum->lmm_stripe_size);
312                 printf("lmm_stripe_pattern: %x\n",      lum->lmm_pattern);
313         }
314
315         if (body) {
316                 if ((!quiet) && (obdstripe == 1))
317                         printf("\tobdidx\t\t objid\t\tobjid\t\t group\n");
318
319                 for (i = 0; i < lum->lmm_stripe_count; i++) {
320                         int idx = lum->lmm_objects[i].l_ost_idx;
321                         long long oid = lum->lmm_objects[i].l_object_id;
322                         long long gr = lum->lmm_objects[i].l_object_gr;
323                         if ((obdindex == OBD_NOT_FOUND) || (obdindex == idx))
324                                 printf("\t%6u\t%14llu\t%#13llx\t%14llu%s\n",
325                                        idx, oid, oid, gr,
326                                        obdindex == idx ? " *" : "");
327                 }
328                 printf("\n");
329         }
330 }
331
332 void lov_dump_user_lmm_join(struct lov_user_md_v1 *lum, char *path,
333                             int is_dir, int obdindex, int quiet,
334                             int header, int body)
335 {
336         struct lov_user_md_join *lumj = (struct lov_user_md_join *)lum;
337         int i, obdstripe = 0;
338
339         if (obdindex != OBD_NOT_FOUND) {
340                 for (i = 0; i < lumj->lmm_stripe_count; i++) {
341                         if (obdindex == lumj->lmm_objects[i].l_ost_idx) {
342                                 printf("%s\n", path);
343                                 obdstripe = 1;
344                                 break;
345                         }
346                 }
347         } else if (!quiet) {
348                 printf("%s\n", path);
349                 obdstripe = 1;
350         }
351
352         if (header && obdstripe == 1) {
353                 printf("lmm_magic:          0x%08X\n",  lumj->lmm_magic);
354                 printf("lmm_object_gr:      "LPX64"\n", lumj->lmm_object_gr);
355                 printf("lmm_object_id:      "LPX64"\n", lumj->lmm_object_id);
356                 printf("lmm_stripe_count:   %u\n", (int)lumj->lmm_stripe_count);
357                 printf("lmm_stripe_size:    %u\n",      lumj->lmm_stripe_size);
358                 printf("lmm_stripe_pattern: %x\n",      lumj->lmm_pattern);
359                 printf("lmm_extent_count:   %x\n",      lumj->lmm_extent_count);
360         }
361
362         if (body) {
363                 unsigned long long start = -1, end = 0;
364                 if (!quiet && obdstripe == 1)
365                         printf("joined\tobdidx\t\t objid\t\tobjid\t\t group"
366                                "\t\tstart\t\tend\n");
367                 for (i = 0; i < lumj->lmm_stripe_count; i++) {
368                         int idx = lumj->lmm_objects[i].l_ost_idx;
369                         long long oid = lumj->lmm_objects[i].l_object_id;
370                         long long gr = lumj->lmm_objects[i].l_object_gr;
371                         if (obdindex == OBD_NOT_FOUND || obdindex == idx)
372                                 printf("\t%6u\t%14llu\t%#13llx\t%14llu%s",
373                                        idx, oid, oid, gr,
374                                        obdindex == idx ? " *" : "");
375                         if (start != lumj->lmm_objects[i].l_extent_start ||
376                             end != lumj->lmm_objects[i].l_extent_end) {
377                                 start = lumj->lmm_objects[i].l_extent_start;
378                                 printf("\t%14llu", start);
379                                 end = lumj->lmm_objects[i].l_extent_end;
380                                 if (end == (unsigned long long)-1)
381                                         printf("\t\tEOF\n");
382                                 else
383                                         printf("\t\t%llu\n", end);
384                         } else {
385                                 printf("\t\t\t\t\n");
386                         }
387                 }
388                 printf("\n");
389         }
390 }
391
392 void llapi_lov_dump_user_lmm(struct find_param *param,
393                              char *path, int is_dir)
394 {
395         switch(*(__u32 *)&param->lmd->lmd_lmm) { /* lum->lmm_magic */
396         case LOV_USER_MAGIC_V1:
397                 lov_dump_user_lmm_v1(&param->lmd->lmd_lmm, path, is_dir,
398                                       param->obdindex, param->quiet,
399                                       param->verbose,
400                                       (param->verbose || !param->obduuid));
401                 break;
402         case LOV_USER_MAGIC_JOIN:
403                 lov_dump_user_lmm_join(&param->lmd->lmd_lmm, path, is_dir,
404                                        param->obdindex, param->quiet,
405                                        param->verbose,
406                                        (param->verbose || !param->obduuid));
407                 break;
408         default:
409                 printf("unknown lmm_magic:  %#x (expecting %#x)\n",
410                        *(__u32 *)&param->lmd->lmd_lmm, LOV_USER_MAGIC_V1);
411                 return;
412         }
413 }
414
415 int llapi_file_get_stripe(const char *path, struct lov_user_md *lum)
416 {
417         const char *fname;
418         char *dname;
419         int fd, rc = 0;
420
421         fname = strrchr(path, '/');
422
423         /* It should be a file (or other non-directory) */
424         if (fname == NULL) {
425                 dname = (char *)malloc(2);
426                 if (dname == NULL)
427                         return ENOMEM;
428                 strcpy(dname, ".");
429                 fname = (char *)path;
430         } else {
431                 dname = (char *)malloc(fname - path + 1);
432                 if (dname == NULL)
433                         return ENOMEM;
434                 strncpy(dname, path, fname - path);
435                 dname[fname - path] = '\0';
436                 fname++;
437         }
438
439         if ((fd = open(dname, O_RDONLY)) == -1) {
440                 rc = errno;
441                 free(dname);
442                 return rc;
443         }
444
445         strcpy((char *)lum, fname);
446         if (ioctl(fd, IOC_MDC_GETFILESTRIPE, (void *)lum) == -1)
447                 rc = errno;
448
449         if (close(fd) == -1 && rc == 0)
450                 rc = errno;
451
452         free(dname);
453
454         return rc;
455 }
456
457 int llapi_file_lookup(int dirfd, const char *name)
458 {
459         struct obd_ioctl_data data = { 0 };
460         char rawbuf[8192];
461         char *buf = rawbuf;
462         int rc;
463
464         if (dirfd < 0 || name == NULL)
465                 return -EINVAL;
466
467         data.ioc_version = OBD_IOCTL_VERSION;
468         data.ioc_len = sizeof(data);
469         data.ioc_inlbuf1 = (char *)name;
470         data.ioc_inllen1 = strlen(name) + 1;
471
472         rc = obd_ioctl_pack(&data, &buf, sizeof(rawbuf));
473         if (rc) {
474                 fprintf(stderr,
475                         "error: IOC_MDC_LOOKUP pack failed for '%s': rc %d\n",
476                         name, rc);
477                 return rc;
478         }
479
480         return ioctl(dirfd, IOC_MDC_LOOKUP, buf);
481 }
482
483 /* some 64bit libcs implement readdir64() by calling sys_getdents().  the
484  * kernel's sys_getdents() doesn't return d_type.  */
485 unsigned char handle_dt_unknown(char *path)
486 {
487         int fd;
488
489         fd = open(path, O_DIRECTORY|O_RDONLY);
490         if (fd < 0) {
491                 if (errno == ENOTDIR)
492                         return DT_REG; /* kind of a lie */
493                 return DT_UNKNOWN;
494         }
495         close(fd);
496         return DT_DIR;
497 }
498
499 static DIR *opendir_parent(char *path)
500 {
501         DIR *parent;
502         char *fname;
503         char c;
504
505         fname = strrchr(path, '/');
506         if (fname == NULL)
507                 return opendir(".");
508
509         c = fname[1];
510         fname[1] = '\0';
511         parent = opendir(path);
512         fname[1] = c;
513         return parent;
514 }
515
516 static int llapi_semantic_traverse(char *path, DIR *parent,
517                                    semantic_func_t sem_init,
518                                    semantic_func_t sem_fini, void *data)
519 {
520         struct dirent64 *dent;
521         int len, ret;
522         DIR *d, *p = NULL;
523
524         ret = 0;
525         len = strlen(path);
526
527         d = opendir(path);
528         if (!d && errno != ENOTDIR) {
529                 fprintf(stderr, "%s: Failed to open '%s': %s.",
530                         __FUNCTION__, path, strerror(errno));
531                 return -EINVAL;
532         } else if (!d && !parent) {
533                 /* ENOTDIR. Open the parent dir. */
534                 p = opendir_parent(path);
535                 if (!p)
536                         GOTO(out, ret = -EINVAL);
537         }
538
539         if (sem_init && (ret = sem_init(path, parent ?: p, d, data)))
540                 goto err;
541
542         if (!d)
543                 GOTO(out, ret = 0);
544
545         while ((dent = readdir64(d)) != NULL) {
546                 if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
547                         continue;
548
549                 path[len] = 0;
550                 strcat(path, "/");
551                 strcat(path, dent->d_name);
552
553                 if (dent->d_type == DT_UNKNOWN)
554                         dent->d_type = handle_dt_unknown(path);
555
556                 switch (dent->d_type) {
557                 case DT_UNKNOWN:
558                         fprintf(stderr, "error: %s: '%s' is UNKNOWN type %d",
559                                 __FUNCTION__, dent->d_name, dent->d_type);
560                         /* If we cared we could stat the file to determine
561                          * type and continue on here, but we don't since we
562                          * know d_type should be valid for lustre and this
563                          * tool only makes sense for lustre filesystems. */
564                         break;
565                 case DT_DIR:
566                         ret = llapi_semantic_traverse(path, d, sem_init,
567                                                       sem_fini, data);
568                         if (ret < 0)
569                                 goto out;
570                         break;
571                 default:
572                         ret = 0;
573                         if (sem_init) {
574                                 ret = sem_init(path, d, NULL, data);
575                                 if (ret < 0)
576                                         goto out;
577                         }
578                         if (sem_fini && ret == 0)
579                                 sem_fini(path, d, NULL, data);
580                 }
581         }
582
583 out:
584         path[len] = 0;
585
586         if (sem_fini)
587                 sem_fini(path, parent, d, data);
588 err:
589         if (d)
590                 closedir(d);
591         if (p)
592                 closedir(p);
593         return ret;
594 }
595
596 /* Check if the file time matches 1 of the given criteria (e.g. --atime +/-N).
597  * @mds indicates if this is MDS timestamps and there are attributes on OSTs.
598  *
599  * The result is -1 if it does not match, 0 if not yet clear, 1 if matches.
600  * The table bolow gives the answers for the specified parameters (time and
601  * sign), 1st column is the answer for the MDS time, the 2nd is for the OST:
602  * --------------------------------------
603  * 1 | file > limit; sign > 0 | -1 / -1 |
604  * 2 | file = limit; sign > 0 |  ? /  1 |
605  * 3 | file < limit; sign > 0 |  ? /  1 |
606  * 4 | file > limit; sign = 0 | -1 / -1 |
607  * 5 | file = limit; sign = 0 |  ? /  1 |  <- (see the Note below)
608  * 6 | file < limit; sign = 0 |  ? / -1 |
609  * 7 | file > limit; sign < 0 |  1 /  1 |
610  * 8 | file = limit; sign < 0 |  ? / -1 |
611  * 9 | file < limit; sign < 0 |  ? / -1 |
612  * --------------------------------------
613  * Note: 5th actually means that the file time stamp is within the interval
614  * (limit - 24hours, limit]. */
615 static int find_time_cmp(time_t file, time_t limit, int sign, int mds) {
616         if (sign > 0) {
617                 if (file <= limit)
618                         return mds ? 0 : 1;
619         }
620
621         if (sign == 0) {
622                 if (file <= limit && file + 24 * 60 * 60 > limit)
623                         return mds ? 0 : 1;
624                 if (file + 24 * 60 * 60 <= limit)
625                         return mds ? 0 : -1;
626         }
627
628         if (sign < 0) {
629                 if (file > limit)
630                         return 1;
631                 if (mds)
632                         return 0;
633         }
634
635         return -1;
636 }
637
638 /* Check if the file time matches all the given criteria (e.g. --atime +/-N).
639  * Return -1 or 1 if file timestamp does not or does match the given criteria
640  * correspondingly. Return 0 if the MDS time is being checked and there are
641  * attributes on OSTs and it is not yet clear if the timespamp matches.
642  *
643  * If 0 is returned, we need to do another RPC to the OSTs to obtain the
644  * updated timestamps. */
645 static int find_time_check(lstat_t *st, struct find_param *param, int mds)
646 {
647         int ret;
648         int rc = 0;
649
650         /* Check if file is accepted. */
651         if (param->atime) {
652                 ret = find_time_cmp(st->st_atime, param->atime,
653                                     param->asign, mds);
654                 if (ret < 0)
655                         return ret;
656                 rc = ret;
657         }
658
659         if (param->mtime) {
660                 ret = find_time_cmp(st->st_mtime, param->mtime,
661                                     param->msign, mds);
662                 if (ret < 0)
663                         return ret;
664
665                 /* If the previous check matches, but this one is not yet clear,
666                  * we should return 0 to do an RPC on OSTs. */
667                 if (rc == 1)
668                         rc = ret;
669         }
670
671         if (param->ctime) {
672                 ret = find_time_cmp(st->st_ctime, param->ctime,
673                                     param->csign, mds);
674                 if (ret < 0)
675                         return ret;
676
677                 /* If the previous check matches, but this one is not yet clear,
678                  * we should return 0 to do an RPC on OSTs. */
679                 if (rc == 1)
680                         rc = ret;
681         }
682
683         return rc;
684 }
685
686 static int cb_find_init(char *path, DIR *parent, DIR *dir, void *data)
687 {
688         struct find_param *param = (struct find_param *)data;
689         int decision = 1; /* 1 is accepted; -1 is rejected. */
690         lstat_t *st = &param->lmd->lmd_st;
691         int lustre_fs = 1;
692         int ret = 0;
693
694         LASSERT(parent != NULL || dir != NULL);
695
696         param->lmd->lmd_lmm.lmm_stripe_count = 0;
697
698         /* If a time or OST should be checked, the decision is not taken yet. */
699         if (param->atime || param->ctime || param->mtime || param->obduuid)
700                 decision = 0;
701
702         /* Request MDS for the stat info. */
703         if (!decision && dir) {
704                 /* retrieve needed file info */
705                 ret = ioctl(dirfd(dir), LL_IOC_MDC_GETINFO,
706                             (void *)param->lmd);
707         } else if (!decision && parent) {
708                 char *fname = strrchr(path, '/');
709                 fname = (fname == NULL ? path : fname + 1);
710
711                 /* retrieve needed file info */
712                 strncpy((char *)param->lmd, fname, param->lumlen);
713                 ret = ioctl(dirfd(parent), IOC_MDC_GETFILEINFO,
714                            (void *)param->lmd);
715         }
716
717         if (ret) {
718                 if (errno == ENOTTY) {
719                         /* ioctl is not supported, it is not a lustre fs.
720                          * Do the regular lstat(2) instead. */
721                         lustre_fs = 0;
722                         ret = lstat_f(path, st);
723                         if (ret) {
724                                 err_msg("error: %s: lstat failed for %s",
725                                         __FUNCTION__, path);
726                                 return ret;
727                         }
728                 } else {
729                         err_msg("error: %s: %s failed for %s", __FUNCTION__,
730                                 dir ? "LL_IOC_MDC_GETINFO" :
731                                 "IOC_MDC_GETFILEINFO", path);
732                         return ret;
733                 }
734         }
735
736         /* Prepare odb. */
737         if (param->obduuid) {
738                 if (lustre_fs && param->got_uuids &&
739                     param->st_dev != st->st_dev) {
740                         /* A lustre/lustre mount point is crossed. */
741                         param->got_uuids = 0;
742                         param->obds_printed = 0;
743                         param->obdindex = OBD_NOT_FOUND;
744                 }
745
746                 if (lustre_fs && !param->got_uuids) {
747                         ret = setup_obd_uuids(dir ? dir : parent, path, param);
748                         if (ret)
749                                 return ret;
750                         param->st_dev = st->st_dev;
751                 } else if (!lustre_fs && param->got_uuids) {
752                         /* A lustre/non-lustre mount point is crossed. */
753                         param->got_uuids = 0;
754                         param->obdindex = OBD_NOT_FOUND;
755                 }
756         }
757
758         /* If a regular expression is presented, make the initial decision */
759         if (param->pattern != NULL) {
760                 char *fname = strrchr(path, '/');
761                 fname = (fname == NULL ? path : fname + 1);
762                 ret = fnmatch(param->pattern, fname, 0);
763                 if ((ret == FNM_NOMATCH && !param->exclude_pattern) ||
764                     (ret == 0 && param->exclude_pattern))
765                         decision = -1;
766         }
767
768         /* If an OBD UUID is specified but no one matches, skip this file. */
769         if (param->obduuid && param->obdindex == OBD_NOT_FOUND)
770                 decision = -1;
771
772         /* If a OST UUID is given, and some OST matches, check it here. */
773         if (decision != -1 && param->obdindex != OBD_NOT_FOUND &&
774             S_ISREG(st->st_mode)) {
775                 /* Only those files should be accepted, which have a strip on
776                  * the specified OST. */
777                 if (!param->lmd->lmd_lmm.lmm_stripe_count) {
778                         decision = -1;
779                 } else {
780                         int i;
781                         for (i = 0;
782                              i < param->lmd->lmd_lmm.lmm_stripe_count; i++) {
783                                if (param->obdindex ==
784                                    param->lmd->lmd_lmm.lmm_objects[i].l_ost_idx)
785                                         break;
786                         }
787
788                         if (i == param->lmd->lmd_lmm.lmm_stripe_count)
789                                 decision = -1;
790                 }
791         }
792
793         /* Check the time on mds. */
794         if (!decision) {
795                 int for_mds;
796
797                 for_mds = lustre_fs ? (S_ISREG(st->st_mode) &&
798                                        param->lmd->lmd_lmm.lmm_stripe_count)
799                                     : 0;
800                 decision = find_time_check(st, param, for_mds);
801         }
802
803         /* If file still fits the request, ask osd for updated info.
804            The regulat stat is almost of the same speed as some new
805            'glimpse-size-ioctl'. */
806         if (!decision && param->lmd->lmd_lmm.lmm_stripe_count &&
807             S_ISREG(st->st_mode)) {
808                 if (param->obdindex != OBD_NOT_FOUND) {
809                         /* Check whether the obd is active or not, if it is
810                          * not active, just print the object affected by this
811                          * failed ost 
812                          * */
813                         struct obd_statfs stat_buf;
814                         struct obd_uuid uuid_buf;
815
816                         memset(&stat_buf, 0, sizeof(struct obd_statfs));
817                         memset(&uuid_buf, 0, sizeof(struct obd_uuid));
818                         ret = llapi_obd_statfs(path, LL_STATFS_LOV,
819                                                param->obdindex, &stat_buf, 
820                                                &uuid_buf);
821                         if (ret) {
822                                 if (ret == -ENODATA || ret == -ENODEV 
823                                     || ret == -EIO)
824                                         errno = EIO;
825                                 printf("obd_uuid: %s failed %s ",
826                                         param->obduuid->uuid, strerror(errno));
827                                 goto print_path;
828                         }
829                 }
830                 if (dir) {
831                         ret = ioctl(dirfd(dir), IOC_LOV_GETINFO,
832                                     (void *)param->lmd);
833                 } else if (parent) {
834                         ret = ioctl(dirfd(parent), IOC_LOV_GETINFO,
835                                     (void *)param->lmd);
836                 }
837
838                 if (ret) {
839                         fprintf(stderr, "%s: IOC_LOV_GETINFO on %s failed: "
840                                 "%s.\n", __FUNCTION__, path, strerror(errno));
841                         return -EINVAL;
842                 }
843
844                 /* Check the time on osc. */
845                 if (!decision)
846                         decision = find_time_check(st, param, 0);
847         }
848
849 print_path:
850         if (decision != -1) {
851                 printf("%s", path);
852                 if (param->zeroend)
853                         printf("%c", '\0');
854                 else
855                         printf("\n");
856         }
857
858         /* Do not get down anymore? */
859         if (param->depth == param->maxdepth)
860                 return 1;
861
862         param->depth++;
863         return 0;
864 }
865
866 static int cb_common_fini(char *path, DIR *parent, DIR *d, void *data)
867 {
868         struct find_param *param = (struct find_param *)data;
869         param->depth--;
870         return 0;
871 }
872
873 int llapi_find(char *path, struct find_param *param)
874 {
875         char buf[PATH_MAX + 1];
876         int ret;
877
878         ret = common_param_init(param);
879         if (ret)
880                 return ret;
881
882         param->depth = 0;
883         strncpy(buf, path, strlen(path));
884         buf[strlen(path)] = '\0';
885
886         ret = llapi_semantic_traverse(buf, NULL, cb_find_init,
887                                       cb_common_fini, param);
888
889         find_param_fini(param);
890         return ret < 0 ? ret : 0;
891 }
892
893 static int cb_getstripe(char *path, DIR *parent, DIR *d, void *data)
894 {
895         struct find_param *param = (struct find_param *)data;
896         int ret = 0;
897
898         LASSERT(parent != NULL || d != NULL);
899
900         /* Prepare odb. */
901         if (!param->got_uuids) {
902                 ret = setup_obd_uuids(d ? d : parent, path, param);
903                 if (ret)
904                         return ret;
905         }
906
907         if (d) {
908                 ret = ioctl(dirfd(d), LL_IOC_LOV_GETSTRIPE,
909                             (void *)&param->lmd->lmd_lmm);
910         } else if (parent) {
911                 char *fname = strrchr(path, '/');
912                 fname = (fname == NULL ? path : fname + 1);
913
914                 strncpy((char *)&param->lmd->lmd_lmm, fname, param->lumlen);
915                 ret = ioctl(dirfd(parent), IOC_MDC_GETFILESTRIPE,
916                             (void *)&param->lmd->lmd_lmm);
917         }
918
919         if (ret) {
920                 if (errno == ENODATA) {
921                         if (!param->obduuid && !param->quiet)
922                                 printf("%s has no stripe info\n", path);
923                         goto out;
924                 } else if (errno == ENOTTY) {
925                         fprintf(stderr, "%s: '%s' not on a Lustre fs?\n",
926                                 __FUNCTION__, path);
927                 } else {
928                         err_msg("error: %s: %s failed for %s", __FUNCTION__,
929                                 d ? "LL_IOC_LOV_GETSTRIPE" :
930                                 "IOC_MDC_GETFILESTRIPE", path);
931                 }
932
933                 return ret;
934         }
935
936         llapi_lov_dump_user_lmm(param, path, d ? 1 : 0);
937 out:
938         /* Do not get down anymore? */
939         if (param->depth == param->maxdepth)
940                 return 1;
941
942         param->depth++;
943         return 0;
944 }
945
946 int llapi_getstripe(char *path, struct find_param *param)
947 {
948         int ret = 0;
949
950         ret = common_param_init(param);
951         if (ret)
952                 return ret;
953
954         param->depth = 0;
955         ret = llapi_semantic_traverse(path, NULL, cb_getstripe,
956                                       cb_common_fini, param);
957         find_param_fini(param);
958         return ret < 0 ? ret : 0;
959 }
960
961 int llapi_obd_statfs(char *path, __u32 type, __u32 index,
962                      struct obd_statfs *stat_buf,
963                      struct obd_uuid *uuid_buf)
964 {
965         int fd;
966         char raw[OBD_MAX_IOCTL_BUFFER] = {'\0'};
967         char *rawbuf = raw;
968         struct obd_ioctl_data data = { 0 };
969         int rc = 0;
970
971         data.ioc_inlbuf1 = (char *)&type;
972         data.ioc_inllen1 = sizeof(__u32);
973         data.ioc_inlbuf2 = (char *)&index;
974         data.ioc_inllen2 = sizeof(__u32);
975         data.ioc_pbuf1 = (char *)stat_buf;
976         data.ioc_plen1 = sizeof(struct obd_statfs);
977         data.ioc_pbuf2 = (char *)uuid_buf;
978         data.ioc_plen2 = sizeof(struct obd_uuid);
979
980         if (obd_ioctl_pack(&data, &rawbuf, sizeof(raw))) {
981                 fprintf(stderr, "llapi_obd_statfs: error packing ioctl data\n");
982                 return -EINVAL;
983         }
984
985         fd = open(path, O_RDONLY);
986         if (errno == EISDIR)
987                 fd = open(path, O_DIRECTORY | O_RDONLY);
988
989         if (fd < 0) {
990                 rc = errno ? -errno : -EBADF;
991                 err_msg("error: %s: opening '%s'", __FUNCTION__, path);
992                 return rc;
993         }
994         rc = ioctl(fd, IOC_OBD_STATFS, (void *)rawbuf);
995         if (rc)
996                 rc = errno ? -errno : -EINVAL;
997
998         close(fd);
999         return rc;
1000 }
1001
1002 #define MAX_STRING_SIZE 128
1003 #define DEVICES_LIST "/proc/fs/lustre/devices"
1004
1005 int llapi_ping(char *obd_type, char *obd_name)
1006 {
1007         char path[MAX_STRING_SIZE];
1008         char buf[1];
1009         int rc, fd;
1010
1011         snprintf(path, MAX_STRING_SIZE, "/proc/fs/lustre/%s/%s/ping",
1012                  obd_type, obd_name);
1013
1014         fd = open(path, O_WRONLY);
1015         if (fd < 0) {
1016                 rc = errno;
1017                 fprintf(stderr, "error opening %s: %s\n", path, strerror(errno));
1018                 return rc;
1019         }
1020
1021         rc = write(fd, buf, 1);
1022         close(fd);
1023
1024         if (rc == 1)
1025                 return 0;
1026         return rc;
1027 }
1028
1029 int llapi_target_iterate(int type_num, char **obd_type, void *args, llapi_cb_t cb)
1030 {
1031         char buf[MAX_STRING_SIZE];
1032         FILE *fp = fopen(DEVICES_LIST, "r");
1033         int i, rc = 0;
1034
1035         if (fp == NULL) {
1036                 rc = errno;
1037                 fprintf(stderr, "error: %s opening "DEVICES_LIST"\n",
1038                         strerror(errno));
1039                 return rc;
1040         }
1041
1042         while (fgets(buf, sizeof(buf), fp) != NULL) {
1043                 char *obd_type_name = NULL;
1044                 char *obd_name = NULL;
1045                 char *obd_uuid = NULL;
1046                 char rawbuf[OBD_MAX_IOCTL_BUFFER];
1047                 char *bufl = rawbuf;
1048                 char *bufp = buf;
1049                 struct obd_ioctl_data datal = { 0, };
1050                 struct obd_statfs osfs_buffer;
1051
1052                 while(bufp[0] == ' ')
1053                         ++bufp;
1054
1055                 for(i = 0; i < 3; i++) {
1056                         obd_type_name = strsep(&bufp, " ");
1057                 }
1058                 obd_name = strsep(&bufp, " ");
1059                 obd_uuid = strsep(&bufp, " ");
1060
1061                 memset(&osfs_buffer, 0, sizeof (osfs_buffer));
1062
1063                 memset(bufl, 0, sizeof(rawbuf));
1064                 datal.ioc_pbuf1 = (char *)&osfs_buffer;
1065                 datal.ioc_plen1 = sizeof(osfs_buffer);
1066
1067                 for (i = 0; i < type_num; i++) {
1068                         if (strcmp(obd_type_name, obd_type[i]) != 0)
1069                                 continue;
1070
1071                         cb(obd_type_name, obd_name, obd_uuid, args);
1072                 }
1073         }
1074         fclose(fp);
1075         return rc;
1076 }
1077
1078 static void do_target_check(char *obd_type_name, char *obd_name,
1079                             char *obd_uuid, void *args)
1080 {
1081         int rc;
1082
1083         rc = llapi_ping(obd_type_name, obd_name);
1084         if (rc) {
1085                 err_msg("error: check '%s'", obd_name);
1086         } else {
1087                 printf("%s active.\n", obd_name);
1088         }
1089 }
1090
1091 int llapi_target_check(int type_num, char **obd_type, char *dir)
1092 {
1093         return llapi_target_iterate(type_num, obd_type, NULL, do_target_check);
1094 }
1095
1096 #undef MAX_STRING_SIZE
1097
1098 int llapi_catinfo(char *dir, char *keyword, char *node_name)
1099 {
1100         char raw[OBD_MAX_IOCTL_BUFFER];
1101         char out[LLOG_CHUNK_SIZE];
1102         char *buf = raw;
1103         struct obd_ioctl_data data = { 0 };
1104         char key[30];
1105         DIR *root;
1106         int rc;
1107
1108         sprintf(key, "%s", keyword);
1109         memset(raw, 0, sizeof(raw));
1110         memset(out, 0, sizeof(out));
1111         data.ioc_inlbuf1 = key;
1112         data.ioc_inllen1 = strlen(key) + 1;
1113         if (node_name) {
1114                 data.ioc_inlbuf2 = node_name;
1115                 data.ioc_inllen2 = strlen(node_name) + 1;
1116         }
1117         data.ioc_pbuf1 = out;
1118         data.ioc_plen1 = sizeof(out);
1119         rc = obd_ioctl_pack(&data, &buf, sizeof(raw));
1120         if (rc)
1121                 return rc;
1122
1123         root = opendir(dir);
1124         if (root == NULL) {
1125                 rc = errno;
1126                 err_msg("open %s failed", dir);
1127                 return rc;
1128         }
1129
1130         rc = ioctl(dirfd(root), OBD_IOC_LLOG_CATINFO, buf);
1131         if (rc)
1132                 err_msg("ioctl OBD_IOC_CATINFO failed");
1133         else
1134                 fprintf(stdout, "%s", data.ioc_pbuf1);
1135
1136         closedir(root);
1137         return rc;
1138 }
1139
1140 /* Is this a lustre fs? */
1141 int llapi_is_lustre_mnttype(const char *type)
1142 {
1143         return (strcmp(type, "lustre") == 0 || strcmp(type,"lustre_lite") == 0);
1144 }
1145
1146 /* Is this a lustre client fs? */
1147 int llapi_is_lustre_mnt(struct mntent *mnt)
1148 {
1149         return (llapi_is_lustre_mnttype(mnt->mnt_type) &&
1150                 strstr(mnt->mnt_fsname, ":/") != NULL);
1151 }
1152
1153 int llapi_quotacheck(char *mnt, int check_type)
1154 {
1155         DIR *root;
1156         int rc;
1157
1158         root = opendir(mnt);
1159         if (!root) {
1160                 err_msg("open %s failed", mnt);
1161                 return -1;
1162         }
1163
1164         rc = ioctl(dirfd(root), LL_IOC_QUOTACHECK, check_type);
1165
1166         closedir(root);
1167         return rc;
1168 }
1169
1170 int llapi_poll_quotacheck(char *mnt, struct if_quotacheck *qchk)
1171 {
1172         DIR *root;
1173         int poll_intvl = 2;
1174         int rc;
1175
1176         root = opendir(mnt);
1177         if (!root) {
1178                 err_msg("open %s failed", mnt);
1179                 return -1;
1180         }
1181
1182         while (1) {
1183                 rc = ioctl(dirfd(root), LL_IOC_POLL_QUOTACHECK, qchk);
1184                 if (!rc)
1185                         break;
1186                 sleep(poll_intvl);
1187                 if (poll_intvl < 30)
1188                         poll_intvl *= 2;
1189         }
1190
1191         closedir(root);
1192         return rc;
1193 }
1194
1195 int llapi_quotactl(char *mnt, struct if_quotactl *qctl)
1196 {
1197         DIR *root;
1198         int rc;
1199
1200         root = opendir(mnt);
1201         if (!root) {
1202                 err_msg("open %s failed", mnt);
1203                 return -1;
1204         }
1205
1206         rc = ioctl(dirfd(root), LL_IOC_QUOTACTL, qctl);
1207
1208         closedir(root);
1209         return rc;
1210 }
1211
1212 static int cb_quotachown(char *path, DIR *parent, DIR *d, void *data)
1213 {
1214         struct find_param *param = (struct find_param *)data;
1215         lstat_t *st;
1216         int rc;
1217
1218         LASSERT(parent != NULL || d != NULL);
1219
1220         if (d) {
1221                 rc = ioctl(dirfd(d), LL_IOC_MDC_GETINFO,
1222                            (void *)param->lmd);
1223         } else if (parent) {
1224                 char *fname = strrchr(path, '/');
1225                 fname = (fname == NULL ? path : fname + 1);
1226
1227                 strncpy((char *)param->lmd, fname, param->lumlen);
1228                 rc = ioctl(dirfd(parent), IOC_MDC_GETFILEINFO,
1229                            (void *)param->lmd);
1230         } else {
1231                 return 0;
1232         }
1233
1234         if (rc) {
1235                 if (errno == ENODATA) {
1236                         if (!param->obduuid && !param->quiet)
1237                                 fprintf(stderr, "%s has no stripe info\n",
1238                                         path);
1239                         rc = 0;
1240                 } else if (errno != EISDIR) {
1241                         rc = errno;
1242                         err_msg("%s ioctl failed for %s.",
1243                                 d ? "LL_IOC_MDC_GETINFO" :
1244                                 "IOC_MDC_GETFILEINFO", path);
1245                 }
1246                 return rc;
1247         }
1248
1249         st = &param->lmd->lmd_st;
1250
1251         /* libc chown() will do extra check, and if the real owner is
1252          * the same as the ones to set, it won't fall into kernel, so
1253          * invoke syscall directly. */
1254         rc = syscall(SYS_chown, path, -1, -1);
1255         if (rc)
1256                 err_msg("error: chown %s (%u,%u)", path);
1257
1258         rc = chmod(path, st->st_mode);
1259         if (rc)
1260                 err_msg("error: chmod %s (%hu)", path, st->st_mode);
1261
1262         return rc;
1263 }
1264
1265 int llapi_quotachown(char *path, int flag)
1266 {
1267         struct find_param param;
1268         int ret = 0;
1269
1270         memset(&param, 0, sizeof(param));
1271         param.recursive = 1;
1272         param.verbose = 0;
1273         param.quiet = 1;
1274
1275         ret = common_param_init(&param);
1276         if (ret)
1277                 goto out;
1278
1279         ret = llapi_semantic_traverse(path, NULL, cb_quotachown,
1280                                       NULL, &param);
1281 out:
1282         find_param_fini(&param);
1283         return ret;
1284 }
1285
1286 int llapi_getfacl(char *fname, char *cmd)
1287 {
1288         struct rmtacl_ioctl_data data;
1289         char out[RMTACL_SIZE_MAX] = "";
1290         int fd, rc;
1291
1292         data.cmd = cmd;
1293         data.cmd_len = strlen(cmd) + 1;
1294         data.res = out;
1295         data.res_len = sizeof(out);
1296
1297         fd = open(fname, 0);
1298         if (fd == -1) {
1299                 err_msg("open %s failed", fname);
1300                 return -1;
1301         }
1302
1303         rc = ioctl(fd, LL_IOC_GETFACL, &data);
1304         close(fd);
1305         if (errno == EBADE) {
1306                 fprintf(stderr, "Please use getfacl directly!\n");
1307                 rc = 1;
1308         } else if (rc) {
1309                 err_msg("getfacl %s failed", fname);
1310         } else {
1311                 printf("%s", out);
1312         }
1313
1314         return rc;
1315 }
1316
1317 int llapi_setfacl(char *fname, char *cmd)
1318 {
1319         struct rmtacl_ioctl_data data;
1320         char out[RMTACL_SIZE_MAX] = "";
1321         int fd, rc;
1322
1323         data.cmd = cmd;
1324         data.cmd_len = strlen(cmd) + 1;
1325         data.res = out;
1326         data.res_len = sizeof(out);
1327
1328         fd = open(fname, 0);
1329         if (fd == -1) {
1330                 err_msg("open %s failed", fname);
1331                 return -1;
1332         }
1333
1334         rc = ioctl(fd, LL_IOC_SETFACL, &data);
1335         close(fd);
1336         if (errno == EBADE) {
1337                 fprintf(stderr, "Please use setfacl directly!\n");
1338                 rc = 1;
1339         } else if (errno == EOPNOTSUPP) {
1340                 fprintf(stderr, "setfacl: %s: %s\n", fname, strerror(errno));
1341                 rc = 1;
1342         } else if (rc) {
1343                 err_msg("setfacl %s failed", fname);
1344         } else {
1345                 printf("%s", out);
1346         }
1347
1348         return rc;
1349 }