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