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