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