Whamcloud - gitweb
Land b_smallfix onto HEAD (20040414_1359)
[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 <linux/types.h>
43 #include <linux/unistd.h>
44
45 #include <liblustre.h>
46 #include <linux/obd.h>
47 #include <linux/lustre_lib.h>
48 #include <lustre/lustre_user.h>
49 #include <linux/obd_lov.h>
50
51 #include <portals/ptlctl.h>
52
53 static void err_msg(char *fmt, ...)
54 {
55         va_list args;
56         int tmp_errno = errno;
57
58         va_start(args, fmt);
59         vfprintf(stderr, fmt, args);
60         va_end(args);
61         fprintf(stderr, ": %s (%d)\n", strerror(tmp_errno), tmp_errno);
62 }
63
64 int op_create_file(char *name, long stripe_size, int stripe_offset,
65                    int stripe_count)
66 {
67         struct lov_user_md lum = { 0 };
68         int fd, rc = 0;
69
70         /*  Initialize IOCTL striping pattern structure  */
71         lum.lmm_magic = LOV_USER_MAGIC;
72         lum.lmm_stripe_size = stripe_size;
73         lum.lmm_stripe_offset = stripe_offset;
74         lum.lmm_stripe_count = stripe_count;
75
76         fd = open(name, O_CREAT | O_RDWR | O_LOV_DELAY_CREATE, 0644);
77         if (errno == EISDIR)
78                 fd = open(name, O_DIRECTORY | O_RDONLY);
79
80         if (fd < 0) {
81                 err_msg("unable to open '%s'",name);
82                 rc = -errno;
83                 return rc;
84         }
85
86         if (ioctl(fd, LL_IOC_LOV_SETSTRIPE, &lum)) {
87                 char *errmsg = "stripe already set";
88                 if (errno != EEXIST && errno != EALREADY)
89                         errmsg = strerror(errno);
90
91                 fprintf(stderr, "error on ioctl for '%s' (%d): %s\n",
92                         name, fd, errmsg);
93                 rc = -errno;
94         }
95         if (close(fd) < 0) {
96                 err_msg("error on close for '%s' (%d)", name, fd);
97                 if (rc == 0)
98                         rc = -errno;
99         }
100         return rc;
101 }
102
103 struct find_param {
104         int     recursive;
105         int     verbose;
106         int     quiet;
107         struct  obd_uuid        *obduuid;
108         struct  obd_ioctl_data  data;
109         struct  lov_desc        desc;
110         int     uuidslen;
111         char    *buf;
112         int     buflen;
113         struct  obd_uuid        *uuids;
114         struct  lov_user_md     *lum;
115         int     got_uuids;
116         int     obdindex;
117         int     max_ost_count;
118 };
119
120 /* XXX Max obds per lov currently hardcoded to 1000 in lov/lov_obd.c */
121 #define MAX_LOV_UUID_COUNT      1000
122 #define OBD_NOT_FOUND           (-1)
123
124 static int prepare_find(struct find_param *param)
125 {
126         int datalen, desclen;
127         int cfglen, lumlen;
128         int max_ost_count = MAX_LOV_UUID_COUNT;
129
130         datalen = size_round(sizeof(param->data));
131         desclen = size_round(sizeof(param->desc));
132         param->uuidslen = size_round(max_ost_count * sizeof(*param->uuids));
133         cfglen = datalen + desclen + param->uuidslen;
134         lumlen = lov_mds_md_size(max_ost_count);
135         if (cfglen > lumlen)
136                 param->buflen = cfglen;
137         else
138                 param->buflen = lumlen;
139
140         /* XXX max ioctl buffer size currently hardcoded to 8192 */
141         if (param->buflen > 8192) {
142                 int nuuids, remaining;
143
144                 param->buflen = 8192;
145                 nuuids = (param->buflen - datalen - desclen) /
146                         sizeof(*param->uuids);
147                 param->uuidslen = size_round(nuuids * sizeof(*param->uuids));
148                 remaining = nuuids * sizeof(*param->uuids);
149                 if (param->uuidslen > remaining)
150                         nuuids--;
151                 max_ost_count = nuuids;
152                 while ((lumlen=lov_mds_md_size(max_ost_count)) > param->buflen)
153                         --max_ost_count;
154
155                 cfglen = datalen + desclen + param->uuidslen;
156         }
157
158         if ((param->buf = malloc(param->buflen)) == NULL) {
159                 err_msg("unable to allocate %d bytes of memory for ioctl's",
160                         param->buflen);
161                 return ENOMEM;
162         }
163
164         param->lum = (struct lov_user_md *)param->buf;
165         param->uuids = (struct obd_uuid *)param->buf;
166         param->got_uuids = 0;
167         param->obdindex = OBD_NOT_FOUND;
168         param->max_ost_count = max_ost_count;
169
170         return 0;
171 }
172
173 static void cleanup_find(struct find_param *param)
174 {
175         if (param->obduuid)
176                 free(param->obduuid);
177         if (param->buf)
178                 free(param->buf);
179 }
180
181 static int get_obd_uuids(DIR *dir, char *dname, struct find_param *param)
182 {
183         int obdcount;
184         struct obd_uuid *uuidp;
185         int rc, i;
186
187         param->got_uuids = 1;
188         memset(&param->data, 0, sizeof(param->data));
189         param->data.ioc_inllen1 = sizeof(struct lov_desc);
190         param->data.ioc_inlbuf1 = (char *)&param->desc;
191         param->data.ioc_inllen2 = param->uuidslen;
192         param->data.ioc_inlbuf2 = (char *)param->uuids;
193
194         memset(&param->desc, 0, sizeof(struct lov_desc));
195         param->desc.ld_tgt_count = param->max_ost_count;
196
197         if (obd_ioctl_pack(&param->data, &param->buf, param->buflen)) {
198                 fprintf(stderr, "internal buffer error from %s\n", dname);
199                 return (param->obduuid ? EINVAL : 0);
200         }
201
202         rc = ioctl(dirfd(dir), OBD_IOC_LOV_GET_CONFIG, param->buf);
203         if (rc) {
204                 err_msg("error getting LOV config from %s", dname);
205                 return (param->obduuid ? errno : 0);
206         }
207
208         if (obd_ioctl_unpack(&param->data, param->buf, param->buflen)) {
209                 err_msg("invalid reply from ioctl from %s", dname);
210                 return (param->obduuid ? EINVAL : 0);
211         }
212
213         obdcount = param->desc.ld_tgt_count;
214         if (obdcount == 0)
215                 return 0;
216
217         if (param->obduuid) {
218                 for (i = 0, uuidp = param->uuids; i < obdcount; i++, uuidp++) {
219                         if (strncmp(param->obduuid->uuid, uuidp->uuid,
220                                     sizeof(*uuidp)) == 0) {
221                                 param->obdindex = i;
222                                 break;
223                         }
224                 }
225                 if (param->obdindex == OBD_NOT_FOUND) {
226                         printf("unknown obduuid: %s\n", param->obduuid->uuid);
227                         return EINVAL;
228                 }
229         } else if (!param->quiet) {
230                 printf("OBDS:\n");
231                 for (i = 0, uuidp = param->uuids; i < obdcount; i++, uuidp++)
232                         printf("%4d: %s\n", i, uuidp->uuid);
233         }
234
235         return 0;
236 }
237
238 void lov_dump_user_lmm_v1(struct lov_user_md_v1 *lum, char *dname, char *fname,
239                           int obdindex, int quiet, int header, int body)
240 {
241         int i, obdstripe = 0;
242
243         if (obdindex != OBD_NOT_FOUND) {
244                 for (i = 0; i < lum->lmm_stripe_count; i++) {
245                         if (obdindex == lum->lmm_objects[i].l_ost_idx) {
246                                 printf("%s/%s\n", dname, fname);
247                                 obdstripe = 1;
248                                 break;
249                         }
250                 }
251         } else if (!quiet) {
252                 printf("%s/%s\n", dname, fname);
253                 obdstripe = 1;
254         }
255
256         /* if it's a directory */
257         if (*fname == '\0') {
258                 if (header && (obdstripe == 1)) {
259                         printf("count: %d, size: %d, offset: %d\n\n",
260                                lum->lmm_stripe_count, lum->lmm_stripe_size,
261                                (short int)lum->lmm_stripe_offset);
262                 }
263                 return;
264         }
265
266         if (header && (obdstripe == 1)) {
267                 printf("lmm_magic:          0x%08X\n",  lum->lmm_magic);
268                 printf("lmm_object_gr:      "LPX64"\n", lum->lmm_object_gr);
269                 printf("lmm_object_id:      "LPX64"\n", lum->lmm_object_id);
270                 printf("lmm_stripe_count:   %u\n", (int)lum->lmm_stripe_count);
271                 printf("lmm_stripe_size:    %u\n",      lum->lmm_stripe_size);
272                 printf("lmm_stripe_pattern: %x\n",      lum->lmm_pattern);
273         }
274
275         if (body) {
276                 if ((!quiet) && (obdstripe == 1))
277                         printf("\tobdidx\t\t objid\t\tobjid\t\t group\n");
278
279                 for (i = 0; i < lum->lmm_stripe_count; i++) {
280                         int idx = lum->lmm_objects[i].l_ost_idx;
281                         long long oid = lum->lmm_objects[i].l_object_id;
282                         long long gr = lum->lmm_objects[i].l_object_gr;
283                         if ((obdindex == OBD_NOT_FOUND) || (obdindex == idx))
284                                 printf("\t%6u\t%14llu\t%#13llx\t%14llu%s\n",
285                                        idx, oid, oid, gr,
286                                        obdindex == idx ? " *" : "");
287                 }
288                 printf("\n");
289         }
290 }
291
292 void lov_dump_user_lmm(struct find_param *param, char *dname, char *fname)
293 {
294         switch(*(__u32 *)param->lum) { /* lum->lmm_magic */
295         case LOV_USER_MAGIC_V1:
296                 lov_dump_user_lmm_v1(param->lum, dname, fname, param->obdindex,
297                                      param->quiet, param->verbose,
298                                      (param->verbose || !param->obduuid));
299                 break;
300         default:
301                 printf("unknown lmm_magic:  0x%08X\n", *(__u32 *)param->lum);
302                 return;
303         }
304 }
305
306 int get_file_stripe(char *path, struct lov_user_md *lum)
307 {
308         char *dname, *fname;
309         int fd, rc = 0;
310
311         fname = strrchr(path, '/');
312
313         /* It should be a file (or other non-directory) */
314         if (fname == NULL) {
315                 dname = (char *)malloc(2);
316                 if (dname == NULL)
317                         return ENOMEM;
318                 strcpy(dname, ".");
319                 fname = path;
320         } else {
321                 dname = (char *)malloc(fname - path + 1);
322                 if (dname == NULL)
323                         return ENOMEM;
324                 strncpy(dname, path, fname - path);
325                 dname[fname - path + 1] = '\0';
326                 fname++;
327         }
328
329         if ((fd = open(dname, O_RDONLY)) == -1) {
330                 free(dname);
331                 return errno;
332         }
333
334         strncpy((char *)lum, fname, sizeof(*lum));
335         if (ioctl(fd, IOC_MDC_GETSTRIPE, (void *)lum) == -1) {
336                 close(fd);
337                 free(dname);
338                 return errno;
339         }
340
341         if (close(fd) == -1)
342                 rc = errno;
343
344         free(dname);
345
346         return rc;
347 }
348
349 static int process_file(DIR *dir, char *dname, char *fname,
350                         struct find_param *param)
351 {
352         int rc;
353
354         strncpy((char *)param->lum, fname, param->buflen);
355
356         rc = ioctl(dirfd(dir), IOC_MDC_GETSTRIPE, (void *)param->lum);
357         if (rc) {
358                 if (errno == ENODATA) {
359                         if (!param->obduuid && !param->quiet)
360                                 fprintf(stderr,
361                                         "%s/%s has no stripe info\n",
362                                         dname, fname);
363                         rc = 0;
364                 } else if (errno == EISDIR) {
365                         fprintf(stderr, "process_file on directory %s/%s!\n",
366                                 dname, fname);
367                         /* add fname to directory list; */
368                         rc = errno;
369                 } else {
370                         err_msg("IOC_MDC_GETSTRIPE ioctl failed");
371                         rc = errno;
372                 }
373                 return rc;
374         }
375
376         lov_dump_user_lmm(param, dname, fname);
377
378         return 0;
379 }
380
381 /* some 64bit libcs implement readdir64() by calling sys_getdents().  the
382  * kernel's sys_getdents() doesn't return d_type.  */
383 unsigned char handle_dt_unknown(char *parent, char *entry)
384 {
385         char path[PATH_MAX + 1];
386         int fd, ret;
387
388         ret = snprintf(path, PATH_MAX, "%s/%s", parent, entry);
389         if (ret >= PATH_MAX)
390                 return DT_UNKNOWN;
391
392         fd = open(path, O_DIRECTORY|O_RDONLY);
393         if (fd < 0) {
394                 if (errno == ENOTDIR)
395                         return DT_REG; /* kind of a lie */
396                 return DT_UNKNOWN;
397         }
398         close(fd);
399         return DT_DIR;
400 }
401
402 static int process_dir(DIR *dir, char *dname, struct find_param *param)
403 {
404         struct dirent64 *dirp;
405         DIR *subdir;
406         char path[1024];
407         int rc;
408
409         if (!param->got_uuids) {
410                 rc = get_obd_uuids(dir, dname, param);
411                 if (rc)
412                         return rc;
413         }
414
415         /* retrieve dir's stripe info */
416         strncpy((char *)param->lum, dname, param->buflen);
417         rc = ioctl(dirfd(dir), LL_IOC_LOV_GETSTRIPE, (void *)param->lum);
418         if (rc) {
419                 if (errno == ENODATA) {
420                         if (!param->obduuid && param->verbose)
421                                 printf("%s/%s has no stripe info\n", dname, "");
422                         rc = 0;
423                 } else {
424                         err_msg("IOC_MDC_GETSTRIPE ioctl failed");
425                         return errno;
426                 }
427         } else {
428                lov_dump_user_lmm(param, dname, "");
429         }
430
431         /* Handle the contents of the directory */
432         while ((dirp = readdir64(dir)) != NULL) {
433                 if (!strcmp(dirp->d_name, ".") || !strcmp(dirp->d_name, ".."))
434                         continue;
435
436                 if (dirp->d_type == DT_UNKNOWN)
437                         dirp->d_type = handle_dt_unknown(dname, dirp->d_name);
438
439                 switch (dirp->d_type) {
440                 case DT_UNKNOWN:
441                         err_msg("\"%s\" is UNKNOWN type %d", dirp->d_name,
442                                 dirp->d_type);
443                         /* If we cared we could stat the file to determine
444                          * type and continue on here, but we don't since we
445                          * know d_type should be valid for lustre and this
446                          * tool only makes sense for lustre filesystems. */
447                         return EINVAL;
448                         break;
449                 case DT_DIR:
450                         if (!param->recursive)
451                                 break;
452                         strcpy(path, dname);
453                         strcat(path, "/");
454                         strcat(path, dirp->d_name);
455                         subdir = opendir(path);
456                         if (subdir == NULL) {
457                                 err_msg("\"%.40s\" opendir failed", path);
458                                 return errno;
459                         }
460                         rc = process_dir(subdir, path, param);
461                         closedir(subdir);
462                         if (rc)
463                                 return rc;
464                         break;
465                 case DT_REG:
466                         rc = process_file(dir, dname, dirp->d_name, param);
467                         if (rc)
468                                 return rc;
469                         break;
470                 default:
471                         break;
472                 }
473         }
474
475         return 0;
476 }
477
478 static int process_path(char *path, struct find_param *param)
479 {
480         char *fname, *dname;
481         DIR *dir;
482         int rc = 0;
483
484         fname = strrchr(path, '/');
485         if (fname != NULL && fname[1] == '\0') {
486                 /* Trailing '/', it must be a dir */
487                 *fname = '\0';
488                 dir = opendir(path);
489                 if (dir == NULL) {
490                         err_msg("\"%.40s\" opendir failed", path);
491                         rc = errno;
492                 } else {
493                         rc = process_dir(dir, path, param);
494                         closedir(dir);
495                 }
496         } else if ((dir = opendir(path)) != NULL) {
497                 /* No trailing '/', but it is still a dir */
498                 rc = process_dir(dir, path, param);
499                 closedir(dir);
500         } else {
501                 /* It must be a file (or other non-directory) */
502                 if (fname == NULL) {
503                         dname = ".";
504                         fname = path;
505                 } else {
506                         *fname = '\0';
507                         fname++;
508                         dname = path;
509                 }
510                 dir = opendir(dname);
511                 if (dir == NULL) {
512                         err_msg("\"%.40s\" opendir failed", dname);
513                         rc = errno;
514                 } else {
515                         if (!param->got_uuids)
516                                 rc = get_obd_uuids(dir, dname, param);
517                         if (rc == 0)
518                                 rc = process_file(dir, dname, fname, param);
519                         closedir(dir);
520                 }
521         }
522
523         return rc;
524 }
525
526
527 int op_find(char *path, struct obd_uuid *obduuid, int recursive,
528             int verbose, int quiet)
529 {
530         struct find_param param;
531         int ret = 0;
532
533         memset(&param, 0, sizeof(param));
534         param.recursive = recursive;
535         param.verbose = verbose;
536         param.quiet = quiet;
537         if (obduuid) {
538                 param.obduuid = malloc(sizeof(*obduuid));
539                 if (param.obduuid == NULL) {
540                         ret = ENOMEM;
541                         goto out;
542                 }
543                 memcpy(param.obduuid, obduuid, sizeof(*obduuid));
544         }
545
546         ret = prepare_find(&param);
547         if (ret)
548                 goto out;
549
550         process_path(path, &param);
551 out:
552         cleanup_find(&param);
553         return ret;
554 }
555
556 #define MAX_STRING_SIZE 128
557 #define DEVICES_LIST "/proc/fs/lustre/devices"
558
559 int op_check(int type_num, char **obd_type, char *dir)
560 {
561         char buf[MAX_STRING_SIZE];
562         FILE *fp = fopen(DEVICES_LIST, "r");
563         int rc = 0;
564         int i;
565
566         if (fp == NULL) {
567                 fprintf(stderr, "error: %s could not open file "
568                         DEVICES_LIST " .\n", strerror(rc =  errno));
569                 return rc;
570         }
571
572         while (fgets(buf, sizeof(buf), fp) != NULL) {
573                 char *obd_type_name = NULL;
574                 char *obd_name = NULL;
575                 char rawbuf[OBD_MAX_IOCTL_BUFFER];
576                 char *bufl = rawbuf;
577                 char *bufp = buf;
578                 int max = sizeof(rawbuf);
579                 struct obd_ioctl_data datal;
580                 struct obd_statfs osfs_buffer;
581
582                 while(bufp[0] == ' ')
583                         ++bufp;
584
585                 for(i = 0; i < 3; i++) {
586                         obd_type_name = strsep(&bufp, " ");
587                 }
588                 obd_name = strsep(&bufp, " ");
589
590                 memset(&osfs_buffer, 0, sizeof (osfs_buffer));
591
592                 memset(bufl, 0, sizeof(rawbuf));
593                 datal.ioc_pbuf1 = (char *)&osfs_buffer;
594                 datal.ioc_plen1 = sizeof(osfs_buffer);
595
596                 for (i = 0; i < type_num; i++)
597                         if (strcmp(obd_type_name, obd_type[i]) == 0) {
598                                 datal.ioc_inlbuf1 = obd_name;
599                                 datal.ioc_inllen1 = strlen(obd_name) + 1;
600
601                                 obd_ioctl_pack(&datal,&bufl,max);
602
603                                 rc = ioctl(dirfd(opendir(dir)), OBD_IOC_PING,
604                                            bufl);
605
606                                 if (rc) {
607                                         fprintf(stderr, "error: check %s: %s\n",
608                                                 obd_name, strerror(rc = errno));
609                                 } else {
610                                         printf("%s active.\n",obd_name);
611                                 }
612                         }
613
614         }
615         fclose(fp);
616         return rc;
617 }
618
619 #undef MAX_STRING_SIZE
620
621 int op_catinfo(char *dir, char *keyword, char *node_name)
622 {
623         char raw[OBD_MAX_IOCTL_BUFFER];
624         char out[LLOG_CHUNK_SIZE];
625         char *buf = raw;
626         struct obd_ioctl_data data;
627         char key[30];
628         DIR *root;
629         int rc;
630
631         sprintf(key, "%s", keyword);
632         memset(raw, 0, sizeof(buf));
633         memset(out, 0, sizeof(out));
634         data.ioc_inlbuf1 = key;
635         data.ioc_inllen1 = strlen(key) + 1;
636         if (node_name) {
637                 data.ioc_inlbuf2 = node_name;
638                 data.ioc_inllen2 = strlen(node_name) + 1;
639         }
640         data.ioc_pbuf1 = out;
641         data.ioc_plen1 = sizeof(out);
642         rc = obd_ioctl_pack(&data, &buf, sizeof(raw));
643         if (rc)
644                 return rc;
645
646         root = opendir(dir);
647         if (root == NULL) {
648                 err_msg("open %s failed", dir);
649                 return errno;
650         }
651
652         rc = ioctl(dirfd(root), OBD_IOC_LLOG_CATINFO, buf);
653         if (rc)
654                 err_msg("ioctl OBD_IOC_CATINFO failed");
655         else
656                 fprintf(stdout, "%s", data.ioc_pbuf1);
657
658         closedir(root);
659         return rc;
660 }
661
662 int llapi_is_lustre_mnttype(char *type)
663 {
664         return (strcmp(type,"lustre") == 0 || strcmp(type,"lustre_lite") == 0);
665 }