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