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