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