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