Whamcloud - gitweb
66bb5c0775e13bc50528d2c1fae3b6c93899bc2f
[fs/lustre-release.git] / lustre / utils / obdctl.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  *
8  *   This file is part of Lustre, http://www.lustre.org.
9  *
10  *   Lustre is free software; you can redistribute it and/or
11  *   modify it under the terms of version 2 of the GNU General Public
12  *   License as published by the Free Software Foundation.
13  *
14  *   Lustre is distributed in the hope that it will be useful,
15  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
16  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  *   GNU General Public License for more details.
18  *
19  *   You should have received a copy of the GNU General Public License
20  *   along with Lustre; if not, write to the Free Software
21  *   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22  *
23  */
24
25
26 #include <stdlib.h>
27 #include <sys/ioctl.h>
28 #include <fcntl.h>
29 #include <sys/socket.h>
30 #include <sys/types.h>
31 #include <sys/wait.h>
32 #include <sys/stat.h>
33 #include <stdio.h>
34 #include <signal.h>
35 #define printk printf
36
37 #include <linux/lustre_lib.h>
38 #include <linux/lustre_idl.h>
39 #include <linux/lustre_dlm.h>
40
41 #include <libxml/xmlmemory.h>
42 #include <libxml/parser.h>
43
44 #include <unistd.h>
45 #include <sys/un.h>
46 #include <time.h>
47 #include <sys/time.h>
48 #include <netinet/in.h>
49 #include <errno.h>
50 #include <string.h>
51
52 #define __KERNEL__
53 #include <linux/list.h>
54 #undef __KERNEL__
55
56 #include "parser.h"
57 #include <stdio.h>
58
59 static int jt_newdev(int argc, char **argv);
60 static int jt_attach(int argc, char **argv);
61 static int jt_setup(int argc, char **argv);
62
63
64 int fd = -1;
65 int connid = -1;
66 char rawbuf[8192];
67 char *buf = rawbuf;
68 int max = 8192;
69 int thread;
70 int rc = 0;
71
72 #define IOCINIT(data)                                                   \
73 do {                                                                    \
74         memset(&data, 0, sizeof(data));                                 \
75         data.ioc_version = OBD_IOCTL_VERSION;                           \
76         data.ioc_conn1 = connid;                                        \
77         data.ioc_len = sizeof(data);                                    \
78         if (fd < 0) {                                                   \
79                 fprintf(stderr, "No device open, use device\n");        \
80                 return 1;                                               \
81         }                                                               \
82 } while (0)
83
84 /*
85     pack "LL LL LL LL LL LL LL L L L L L L L L L a60 a60 L L L",
86     $obdo->{id}, 0,
87     $obdo->{gr}, 0,
88     $obdo->{atime}, 0,
89     $obdo->{mtime}, 0 ,
90     $obdo->{ctime}, 0,
91     $obdo->{size}, 0,
92     $obdo->{blocks}, 0,
93     $obdo->{blksize},
94     $obdo->{mode},
95     $obdo->{uid},
96     $obdo->{gid},
97     $obdo->{flags},
98     $obdo->{obdflags},
99     $obdo->{nlink},
100     $obdo->{generation},
101     $obdo->{valid},
102     $obdo->{inline},
103     $obdo->{obdmd},
104     0, 0, # struct list_head
105     0;  #  struct obd_ops
106 }
107
108 */
109
110 char * obdo_print(struct obdo *obd)
111 {
112         char buf[1024];
113
114         sprintf(buf, "id: %Ld\ngrp: %Ld\natime: %Ld\nmtime: %Ld\nctime: %Ld\n"
115                 "size: %Ld\nblocks: %Ld\nblksize: %d\nmode: %o\nuid: %d\n"
116                 "gid: %d\nflags: %x\nobdflags: %x\nnlink: %d,\nvalid %x\n",
117                 obd->o_id,
118                 obd->o_gr,
119                 obd->o_atime,
120                 obd->o_mtime,
121                 obd->o_ctime,
122                 obd->o_size,
123                 obd->o_blocks,
124                 obd->o_blksize,
125                 obd->o_mode,
126                 obd->o_uid,
127                 obd->o_gid,
128                 obd->o_flags,
129                 obd->o_obdflags,
130                 obd->o_nlink,
131                 obd->o_valid);
132         return strdup(buf);
133 }
134
135 static char *cmdname(char *func)
136 {
137         static char buf[512];
138
139         if (thread) {
140                 sprintf(buf, "%s-%d", func, thread);
141                 return buf;
142         }
143
144         return func;
145 }
146
147 int getfd(char *func)
148 {
149         if (fd == -1)
150                 fd = open("/dev/obd", O_RDWR);
151         if (fd == -1) {
152                 fprintf(stderr, "error: %s: opening /dev/obd: %s\n",
153                         cmdname(func), strerror(errno));
154                 return -1;
155         }
156         return 0;
157 }
158
159 #if 1
160 #define difftime(a, b)                                          \
161         ((double)(a)->tv_sec - (b)->tv_sec +                    \
162          ((double)((a)->tv_usec - (b)->tv_usec) / 1000000))
163 #else
164
165 #define difftime(a, b)  (((a)->tv_sec - (b)->tv_sec) + \
166                         (((a)->tv_usec - (b)->tv_usec) / 1000000))
167 #endif
168
169 static int be_verbose(int verbose, struct timeval *next_time,
170                       int num, int *next_num, int num_total)
171 {
172         struct timeval now;
173
174         if (!verbose)
175                 return 0;
176
177         if (next_time != NULL)
178                 gettimeofday(&now, NULL);
179
180         /* A positive verbosity means to print every X iterations */
181         if (verbose > 0 &&
182             (next_num == NULL || num >= *next_num || num >= num_total)) {
183                 *next_num += verbose;
184                 if (next_time) {
185                         next_time->tv_sec = now.tv_sec - verbose;
186                         next_time->tv_usec = now.tv_usec;
187                 }
188                 return 1;
189         }
190
191         /* A negative verbosity means to print at most each X seconds */
192         if (verbose < 0 && next_time != NULL && difftime(&now, next_time) >= 0){
193                 next_time->tv_sec = now.tv_sec - verbose;
194                 next_time->tv_usec = now.tv_usec;
195                 if (next_num)
196                         *next_num = num;
197                 return 1;
198         }
199
200         return 0;
201 }
202
203 static int get_verbose(const char *arg)
204 {
205         int verbose;
206
207         if (!arg || arg[0] == 'v')
208                 verbose = 1;
209         else if (arg[0] == 's' || arg[0] == 'q')
210                 verbose = 0;
211         else
212                 verbose = (int) strtoul(arg, NULL, 0);
213
214         if (verbose < 0)
215                 printf("Print status every %d seconds\n", -verbose);
216         else if (verbose == 1)
217                 printf("Print status every operation\n");
218         else if (verbose > 1)
219                 printf("Print status every %d operations\n", verbose);
220
221         return verbose;
222 }
223
224 static int do_disconnect(char *func, int verbose)
225 {
226         struct obd_ioctl_data data;
227
228         if (connid == -1)
229                 return 0;
230
231         IOCINIT(data);
232
233         rc = ioctl(fd, OBD_IOC_DISCONNECT , &data);
234         if (rc < 0) {
235                 fprintf(stderr, "error: %s: %x %s\n", cmdname(func),
236                         OBD_IOC_DISCONNECT, strerror(errno));
237         } else {
238                 if (verbose)
239                         printf("%s: disconnected connid %d\n", cmdname(func),
240                                connid);
241                 connid = -1;
242         }
243
244         return rc;
245 }
246
247 extern command_t cmdlist[];
248
249 /* Given a XML document and the root of a mds branch do the setup */
250 static int xml_mds(xmlDocPtr doc, xmlNodePtr root, 
251                    char *serv_id, char *serv_uuid) {
252         xmlNodePtr cur = root->xmlChildrenNode;
253         char *fstype = NULL, *device = NULL;
254         char *newdev[1] = { "newdev" };
255         char *attach[3] = { "attach", "mds", "MDSDEV" };
256         char *setup[3] = { "setup", NULL, NULL };
257         int rc;
258
259         while (cur != NULL) {
260                 if (!xmlStrcmp(cur->name, "fstype"))
261                         fstype = cur->content;
262
263                 if (!xmlStrcmp(cur->name, "device"))
264                         device = cur->content;
265         } 
266
267         if ((fstype == NULL) || (device == NULL))
268                 return -1;
269
270         /* Invoke commands as if passed interactively */
271         rc = jt_newdev(1, newdev);
272         if (rc != 0)
273                 return rc;
274         
275         rc = jt_attach(3, attach);
276         if (rc != 0)
277                 return rc;
278
279         setup[1] = device;
280         setup[2] = fstype;
281         rc = jt_setup(3, setup);
282         if (rc != 0)
283                 return rc;
284
285         return 0;
286 }
287         
288 /* Given a XML document and the root of a obd branch do the setup */
289 static int xml_obd(xmlDocPtr doc, xmlNodePtr root, 
290                    char *serv_id, char *serv_uuid) {
291         /* FIXME: Fill in the guts... */
292         return 0;
293 }
294
295 /* Given a XML document and the root of a ost branch do the setup */
296 static int xml_ost(xmlDocPtr doc, xmlNodePtr root, 
297                    char *serv_id, char *serv_uuid) {
298         /* FIXME: Fill in the guts... */
299         return 0;
300 }
301
302 /* Given a XML document and the root of a osc branch do the setup */
303 static int xml_osc(xmlDocPtr doc, xmlNodePtr root, 
304                    char *serv_id, char *serv_uuid) {
305         xmlNodePtr cur = root->xmlChildrenNode;
306         char *type = NULL, *address = NULL;
307         char *newdev[1] = { "newdev" };
308         char *attach[3] = { "attach", "osc", "OSCDEV" };
309         char *setup[2] = { "setup", "-1" };
310         int rc;
311
312         while (cur != NULL) {
313                 if (!xmlStrcmp(cur->name, "network")) {
314                         type = xmlGetProp(cur, "type");
315                         if (type == NULL)
316                                 return -1;
317
318                         address = xmlGetProp(cur, "address");
319                         if (address == NULL)
320                                 return -1;
321
322                         /* FIXME: Do the portals setup here as well? */
323                 }
324                         
325                 cur = cur->next;
326         } 
327
328         /* Invoke commands as if passed interactively */
329         rc = jt_newdev(1, newdev);
330         if (rc != 0)
331                 return rc;
332         
333         rc = jt_attach(2, attach);
334         if (rc != 0)
335                 return rc;
336         
337         rc = jt_setup(1, setup);
338         if (rc != 0)
339                 return rc;
340
341         return 0;
342 }
343
344 /* Given a XML document and the root of a lov branch do the setup */
345 static int xml_lov(xmlDocPtr doc, xmlNodePtr root, 
346                    char *serv_id, char *serv_uuid) {
347         /* FIXME: Fill in the guts... */
348         return 0;
349 }
350
351 /* Given a XML document and the root of a router branch do the setup */
352 static int xml_router(xmlDocPtr doc, xmlNodePtr root, 
353                    char *serv_id, char *serv_uuid) {
354         /* FIXME: Fill in the guts... */
355         return 0;
356 }
357
358 /* Given a XML document and service id/uuid setup the service */
359 static int xml_service(xmlDocPtr doc, xmlNodePtr root, 
360                        int serv_num, char *serv_id, char *serv_uuid) {
361         xmlNodePtr cur = root;
362         char *id, *uuid;
363
364         while (cur != NULL) {
365                 id = xmlGetProp(cur, "id");
366                 uuid = xmlGetProp(cur, "uuid");
367
368                 if (xmlStrcmp(id, serv_id) ||
369                     xmlStrcmp(uuid, serv_uuid)) {
370                         cur = cur->next;
371                         continue;
372                 }
373
374                 if (!xmlStrcmp(cur->name, "mds"))
375                         rc = xml_mds(doc, cur, serv_id, serv_uuid);
376                 else if (!xmlStrcmp(cur->name, "obd"))
377                         rc = xml_obd(doc, cur, serv_id, serv_uuid);
378                 else if (!xmlStrcmp(cur->name, "ost"))
379                         rc = xml_ost(doc, cur, serv_id, serv_uuid);
380                 else if (!xmlStrcmp(cur->name, "osc"))
381                         rc = xml_osc(doc, cur, serv_id, serv_uuid);
382                 else if (!xmlStrcmp(cur->name, "lov"))
383                         rc = xml_lov(doc, cur, serv_id, serv_uuid);
384                 else if (!xmlStrcmp(cur->name, "router"))
385                         rc = xml_router(doc, cur, serv_id, serv_uuid);
386                 else
387                         return -1;        
388
389                 cur = cur->next;
390         }
391
392         return rc; 
393 }
394
395 /* Given a XML document and profile id/uuid setup the profile */
396 static int xml_profile(xmlDocPtr doc, xmlNodePtr root, 
397                        int prof_num, char *prof_id, char *prof_uuid) {
398         xmlNodePtr parent, cur = root;
399         char *id, *uuid;
400         int rc = 0, num;
401
402         while (cur != NULL) {
403                 id = xmlGetProp(cur, "id");
404                 uuid = xmlGetProp(cur, "uuid");
405
406                 if (xmlStrcmp(cur->name, "profile") || 
407                     xmlStrcmp(id, prof_id)          ||
408                     xmlStrcmp(uuid, prof_uuid)) {
409                         cur = cur->next;
410                         continue;
411                 }
412
413                 /* FIXME: Doesn't understand mountpoints yet
414                  *        xml_mountpoint(doc, root, ...);
415                  */    
416
417                 /* Setup each service in turn
418                  * FIXME: Should be sorted by "num" attr, we shouldn't
419                  *        assume they're in order in the XML document.
420                  */
421                 parent = cur;
422                 cur = cur->xmlChildrenNode;
423                 while (cur != NULL) {
424                         if (!xmlStrcmp(cur->name, "service_id")) {
425                                 num = atoi(xmlGetProp(cur, "num"));
426                                 rc = xml_service(doc, root, num,
427                                                  xmlGetProp(cur, "id"),
428                                                  xmlGetProp(cur, "uuid"));
429                                 if (rc != 0)
430                                         return rc;
431                         }
432
433                         cur = cur->next;
434                 }
435
436                 cur = parent->next;
437         }
438
439         return rc; 
440 }
441
442 static int xml_node(xmlDocPtr doc, xmlNodePtr root) {
443         xmlNodePtr parent, cur = root;
444         char *id, *uuid;
445         int rc = 0, num;
446         
447         /* Walk the node tags looking for ours */
448         while (cur != NULL) {
449                 if (xmlStrcmp(cur->name, "node")) {
450                         cur = cur->next;
451                         continue;
452                 }
453
454                 id = xmlGetProp(cur, "id");
455                 if (id == NULL)
456                         return -1;
457
458                 uuid = xmlGetProp(cur, "uuid");
459                 if (uuid == NULL)
460                         return -1;
461
462                 /* FIXME: Verify our ID and UUID against /etc/lustre/id
463                  *        so we're sure we are who we think we are.
464                  */
465
466                 /* Setup each profile in turn
467                  * FIXME: Should be sorted by "num" attr, we shouldn't
468                  *        assume they're in order in the XML document.
469                  */
470                 parent = cur;
471                 cur = cur->xmlChildrenNode;
472                 while (cur != NULL) {
473                         if (!xmlStrcmp(cur->name, "profile_id")) {
474                                 num = atoi(xmlGetProp(cur, "num"));
475                                 rc = xml_profile(doc, root, num,
476                                                  xmlGetProp(cur, "id"),
477                                                  xmlGetProp(cur, "uuid"));
478                                 if (rc != 0)
479                                         return rc;
480                         }
481
482                         cur = cur->next;
483                 }
484
485                 cur = parent->next;
486         }
487
488         return rc;
489 }
490
491 static int do_xml(char *func, char *file)
492 {
493         xmlDocPtr doc;
494         xmlNodePtr cur;
495         int rc;
496
497         doc = xmlParseFile(file);
498         if (doc == NULL) {
499                 fprintf(stderr, "error: Unable to parse XML\n");
500                 return -1; 
501         }
502
503         cur = xmlDocGetRootElement(doc);
504         if (cur == NULL) {
505                 fprintf(stderr, "error: Empty XML\n");
506                 xmlFreeDoc(doc);
507                 return -1;
508         }
509         
510         if (xmlStrcmp(cur->name, (const xmlChar *)"lustre")) {
511                 fprintf(stderr, "error: Root node != <lustre>\n");
512                 xmlFreeDoc(doc);
513                 return -1;
514         }
515
516         /* FIXME: Validate the XML against the DTD here */
517     
518         /* FIXME: Merge all the text nodes under each branch and 
519          *        prune empty nodes.  Just to make the parsing more
520          *        tolerant. 
521          */
522         
523         rc = xml_node(doc, cur->xmlChildrenNode);
524         xmlFreeDoc(doc);
525
526         return rc;
527 }
528
529 static int do_device(char *func, int dev)
530 {
531         struct obd_ioctl_data data;
532
533         memset(&data, 0, sizeof(data));
534
535         data.ioc_dev = dev;
536
537         if (getfd(func))
538                 return -1;
539
540         if (obd_ioctl_pack(&data, &buf, max)) {
541                 fprintf(stderr, "error: %s: invalid ioctl\n", cmdname(func));
542                 return -2;
543         }
544
545         return ioctl(fd, OBD_IOC_DEVICE , buf);
546 }
547
548 static int jt_device(int argc, char **argv)
549 {
550         do_disconnect(argv[0], 1);
551
552         if (argc != 2) {
553                 fprintf(stderr, "usage: %s devno\n", cmdname(argv[0]));
554                 return -1;
555         }
556
557         rc = do_device(argv[0], strtoul(argv[1], NULL, 0));
558
559         if (rc < 0)
560                 fprintf(stderr, "error: %s: %s\n", cmdname(argv[0]),
561                         strerror(rc = errno));
562
563         return rc;
564 }
565
566 static int jt_connect(int argc, char **argv)
567 {
568         struct obd_ioctl_data data;
569
570         IOCINIT(data);
571
572         do_disconnect(argv[0], 1);
573
574         if (argc != 1) {
575                 fprintf(stderr, "usage: %s\n", cmdname(argv[0]));
576                 return -1;
577         }
578
579         rc = ioctl(fd, OBD_IOC_CONNECT , &data);
580         if (rc < 0)
581                 fprintf(stderr, "error: %s: %x %s\n", cmdname(argv[0]),
582                         OBD_IOC_CONNECT, strerror(rc = errno));
583         else
584                 connid = data.ioc_conn1;
585
586         return rc;
587 }
588
589 static int jt_disconnect(int argc, char **argv)
590 {
591         if (argc != 1) {
592                 fprintf(stderr, "usage: %s\n", cmdname(argv[0]));
593                 return -1;
594         }
595
596         return do_disconnect(argv[0], 0);
597 }
598
599 static int jt__xml(int argc, char **argv)
600 {
601         if (argc < 2) {
602                 fprintf(stderr, "usage: %s <xml file> <command [args ...]>\n",
603                         cmdname(argv[0]));
604                 return -1;
605         }
606
607         return do_xml("xml", argv[1]);
608 }
609
610 static int jt__device(int argc, char **argv)
611 {
612         char *arg2[3];
613         int ret;
614
615         if (argc < 3) {
616                 fprintf(stderr, "usage: %s devno <command [args ...]>\n",
617                         cmdname(argv[0]));
618                 return -1;
619         }
620
621         rc = do_device("device", strtoul(argv[1], NULL, 0));
622
623         if (!rc) {
624                 arg2[0] = "connect";
625                 arg2[1] = NULL;
626                 rc = jt_connect(1, arg2);
627         }
628
629         if (!rc)
630                 rc = Parser_execarg(argc - 2, argv + 2, cmdlist);
631
632         ret = do_disconnect(argv[0], 0);
633         if (!rc)
634                 rc = ret;
635
636         return rc;
637 }
638
639 static int jt__threads(int argc, char **argv)
640 {
641         int threads, next_thread;
642         int verbose;
643         int i, j;
644
645         if (argc < 5) {
646                 fprintf(stderr,
647                         "usage: %s numthreads verbose devno <cmd [args ...]>\n",
648                         argv[0]);
649                 return -1;
650         }
651
652         threads = strtoul(argv[1], NULL, 0);
653
654         verbose = get_verbose(argv[2]);
655
656         printf("%s: starting %d threads on device %s running %s\n",
657                argv[0], threads, argv[3], argv[4]);
658
659         for (i = 1, next_thread = verbose; i <= threads; i++) {
660                 rc = fork();
661                 if (rc < 0) {
662                         fprintf(stderr, "error: %s: #%d - %s\n", argv[0], i,
663                                 strerror(rc = errno));
664                         break;
665                 } else if (rc == 0) {
666                         thread = i;
667                         argv[2] = "--device";
668                         return jt__device(argc - 2, argv + 2);
669                 } else if (be_verbose(verbose, NULL, i, &next_thread, threads))
670                         printf("%s: thread #%d (PID %d) started\n",
671                                argv[0], i, rc);
672                 rc = 0;
673         }
674
675         if (!thread) { /* parent process */
676                 if (!verbose)
677                         printf("%s: started %d threads\n\n", argv[0], i - 1);
678                 else
679                         printf("\n");
680
681                 for (j = 1; j < i; j++) {
682                         int status;
683                         int ret = wait(&status);
684
685                         if (ret < 0) {
686                                 fprintf(stderr, "error: %s: wait - %s\n",
687                                         argv[0], strerror(errno));
688                                 if (!rc)
689                                         rc = errno;
690                         } else {
691                                 /*
692                                  * This is a hack.  We _should_ be able to use
693                                  * WIFEXITED(status) to see if there was an
694                                  * error, but it appears to be broken and it
695                                  * always returns 1 (OK).  See wait(2).
696                                  */
697                                 int err = WEXITSTATUS(status);
698                                 if (err)
699                                         fprintf(stderr,
700                                                 "%s: PID %d had rc=%d\n",
701                                                 argv[0], ret, err);
702                                 if (!rc)
703                                         rc = err;
704                         }
705                 }
706         }
707
708         return rc;
709 }
710
711 static int jt_detach(int argc, char **argv)
712 {
713         struct obd_ioctl_data data;
714
715         IOCINIT(data);
716
717         if (argc != 1) {
718                 fprintf(stderr, "usage: %s\n", cmdname(argv[0]));
719                 return -1;
720         }
721
722         if (obd_ioctl_pack(&data, &buf, max)) {
723                 fprintf(stderr, "error: %s: invalid ioctl\n", cmdname(argv[0]));
724                 return -2;
725         }
726
727         rc = ioctl(fd, OBD_IOC_DETACH , buf);
728         if (rc < 0)
729                 fprintf(stderr, "error: %s: %s\n", cmdname(argv[0]),
730                         strerror(rc=errno));
731
732         return rc;
733 }
734
735 static int jt_cleanup(int argc, char **argv)
736 {
737         struct obd_ioctl_data data;
738
739         IOCINIT(data);
740
741         if (argc != 1) {
742                 fprintf(stderr, "usage: %s\n", cmdname(argv[0]));
743                 return -1;
744         }
745
746         rc = ioctl(fd, OBD_IOC_CLEANUP , &data);
747         if (rc < 0)
748                 fprintf(stderr, "error: %s: %s\n", cmdname(argv[0]),
749                         strerror(rc=errno));
750
751         return rc;
752 }
753
754 static int jt_newdev(int argc, char **argv)
755 {
756         struct obd_ioctl_data data;
757
758         if (getfd(argv[0]))
759                 return -1;
760
761         IOCINIT(data);
762
763         if (argc != 1) {
764                 fprintf(stderr, "usage: %s\n", cmdname(argv[0]));
765                 return -1;
766         }
767
768         rc = ioctl(fd, OBD_IOC_NEWDEV , &data);
769         if (rc < 0)
770                 fprintf(stderr, "error: %s: %s\n", cmdname(argv[0]),
771                         strerror(rc=errno));
772         else {
773                 printf("Current device set to %d\n", data.ioc_dev);
774         }
775
776         return rc;
777 }
778
779 static int jt_attach(int argc, char **argv)
780 {
781         struct obd_ioctl_data data;
782
783         IOCINIT(data);
784
785         if (argc != 2 && argc != 3) {
786                 fprintf(stderr, "usage: %s type [name [uuid]]\n",
787                         cmdname(argv[0]));
788                 return -1;
789         }
790
791         data.ioc_inllen1 =  strlen(argv[1]) + 1;
792         data.ioc_inlbuf1 = argv[1];
793         if (argc == 3) {
794                 data.ioc_inllen2 = strlen(argv[2]) + 1;
795                 data.ioc_inlbuf2 = argv[2];
796         }
797
798         if (obd_ioctl_pack(&data, &buf, max)) {
799                 fprintf(stderr, "error: %s: invalid ioctl\n", cmdname(argv[0]));
800                 return -2;
801         }
802
803         rc = ioctl(fd, OBD_IOC_ATTACH , buf);
804         if (rc < 0)
805                 fprintf(stderr, "error: %s: %x %s\n", cmdname(argv[0]),
806                         OBD_IOC_ATTACH, strerror(rc = errno));
807         else if (argc == 3) {
808                 char name[1024];
809                 if (strlen(argv[2]) > 128) {
810                         printf("Name too long to set environment\n");
811                         return -EINVAL;
812                 }
813                 snprintf(name, 512, "LUSTRE_DEV_%s", argv[2]);
814                 rc = setenv(name, argv[1], 1);
815                 if (rc) {
816                         printf("error setting env variable %s\n", name);
817                 }
818         }
819
820         return rc;
821 }
822
823 #define N2D_OFF 0x100    /* So we can tell between error codes and devices */
824
825 static int do_name2dev(char *func, char *name)
826 {
827         struct obd_ioctl_data data;
828
829         if (getfd(func))
830                 return -1;
831
832         IOCINIT(data);
833
834         data.ioc_inllen1 = strlen(name) + 1;
835         data.ioc_inlbuf1 = name;
836
837         if (obd_ioctl_pack(&data, &buf, max)) {
838                 fprintf(stderr, "error: %s: invalid ioctl\n", cmdname(func));
839                 return -2;
840         }
841         rc = ioctl(fd, OBD_IOC_NAME2DEV , buf);
842         if (rc < 0) {
843                 fprintf(stderr, "error: %s: %s - %s\n", cmdname(func),
844                         name, strerror(rc = errno));
845                 return rc;
846         }
847
848         memcpy((char *)(&data), buf, sizeof(data));
849
850         return data.ioc_dev + N2D_OFF;
851 }
852
853 static int jt_name2dev(int argc, char **argv)
854 {
855         if (argc != 2) {
856                 fprintf(stderr, "usage: %s name\n", cmdname(argv[0]));
857                 return -1;
858         }
859
860         rc = do_name2dev(argv[0], argv[1]);
861         if (rc >= N2D_OFF) {
862                 int dev = rc - N2D_OFF;
863                 rc = do_device(argv[0], dev);
864                 if (rc == 0)
865                         printf("%d\n", dev);
866         }
867         return rc;
868 }
869
870 static int jt_setup(int argc, char **argv)
871 {
872         struct obd_ioctl_data data;
873
874         IOCINIT(data);
875
876         if ( argc > 3) {
877                 fprintf(stderr, "usage: %s [device] [fstype]\n",
878                         cmdname(argv[0]));
879                 return -1;
880         }
881
882         data.ioc_dev = -1;
883         if (argc > 1) {
884                 if (argv[1][0] == '$') {
885                         rc = do_name2dev(argv[0], argv[1] + 1);
886                         if (rc >= N2D_OFF) {
887                                 printf("%s is device %d\n", argv[1],
888                                        rc - N2D_OFF);
889                                 data.ioc_dev = rc - N2D_OFF;
890                         }
891                 } else
892                         data.ioc_dev = strtoul(argv[1], NULL, 0);
893                 data.ioc_inllen1 = strlen(argv[1]) + 1;
894                 data.ioc_inlbuf1 = argv[1];
895         }
896         if ( argc == 3 ) {
897                 data.ioc_inllen2 = strlen(argv[2]) + 1;
898                 data.ioc_inlbuf2 = argv[2];
899         }
900
901         if (obd_ioctl_pack(&data, &buf, max)) {
902                 fprintf(stderr, "error: %s: invalid ioctl\n", cmdname(argv[0]));
903                 return -2;
904         }
905         rc = ioctl(fd, OBD_IOC_SETUP , buf);
906         if (rc < 0)
907                 fprintf(stderr, "error: %s: %s\n", cmdname(argv[0]),
908                         strerror(rc = errno));
909
910         return rc;
911 }
912
913
914 static int jt_create(int argc, char **argv)
915 {
916         struct obd_ioctl_data data;
917         struct timeval next_time;
918         int count = 1, next_count;
919         int verbose;
920         int i;
921
922         IOCINIT(data);
923         if (argc < 2 || argc > 4) {
924                 fprintf(stderr, "usage: %s num [mode] [verbose]\n",
925                         cmdname(argv[0]));
926                 return -1;
927         }
928         count = strtoul(argv[1], NULL, 0);
929
930         if (argc > 2)
931                 data.ioc_obdo1.o_mode = strtoul(argv[2], NULL, 0);
932         else
933                 data.ioc_obdo1.o_mode = 0100644;
934         data.ioc_obdo1.o_valid = OBD_MD_FLMODE;
935
936         verbose = get_verbose(argv[3]);
937
938         printf("%s: %d obdos\n", cmdname(argv[0]), count);
939         gettimeofday(&next_time, NULL);
940         next_time.tv_sec -= verbose;
941
942         for (i = 1, next_count = verbose; i <= count ; i++) {
943                 rc = ioctl(fd, OBD_IOC_CREATE , &data);
944                 if (rc < 0) {
945                         fprintf(stderr, "error: %s: #%d - %s\n",
946                                 cmdname(argv[0]), i, strerror(rc = errno));
947                         break;
948                 }
949                 if (be_verbose(verbose, &next_time, i, &next_count, count))
950                         printf("%s: #%d is object id %Ld\n", cmdname(argv[0]),
951                                i, data.ioc_obdo1.o_id);
952         }
953         return rc;
954 }
955
956 static int jt_setattr(int argc, char **argv)
957 {
958         struct obd_ioctl_data data;
959
960         IOCINIT(data);
961         if (argc != 2) {
962                 fprintf(stderr, "usage: %s id mode\n", cmdname(argv[0]));
963                 return -1;
964         }
965
966         data.ioc_obdo1.o_id = strtoul(argv[1], NULL, 0);
967         data.ioc_obdo1.o_mode = S_IFREG | strtoul(argv[2], NULL, 0);
968         data.ioc_obdo1.o_valid = OBD_MD_FLMODE;
969
970         rc = ioctl(fd, OBD_IOC_SETATTR , &data);
971         if (rc < 0)
972                 fprintf(stderr, "error: %s: %s\n", cmdname(argv[0]),
973                         strerror(rc = errno));
974
975         return rc;
976 }
977
978 static int jt_destroy(int argc, char **argv)
979 {
980         struct obd_ioctl_data data;
981
982         IOCINIT(data);
983         if (argc != 2) {
984                 fprintf(stderr, "usage: %s id\n", cmdname(argv[0]));
985                 return -1;
986         }
987
988         data.ioc_obdo1.o_id = strtoul(argv[1], NULL, 0);
989         data.ioc_obdo1.o_mode = S_IFREG|0644;
990
991         rc = ioctl(fd, OBD_IOC_DESTROY , &data);
992         if (rc < 0)
993                 fprintf(stderr, "error: %s: %s\n", cmdname(argv[0]),
994                         strerror(rc = errno));
995
996         return rc;
997 }
998
999 static int jt_getattr(int argc, char **argv)
1000 {
1001         struct obd_ioctl_data data;
1002
1003         if (argc != 2) {
1004                 fprintf(stderr, "usage: %s id\n", cmdname(argv[0]));
1005                 return -1;
1006         }
1007
1008         IOCINIT(data);
1009         data.ioc_obdo1.o_id = strtoul(argv[1], NULL, 0);
1010         /* to help obd filter */
1011         data.ioc_obdo1.o_mode = 0100644;
1012         data.ioc_obdo1.o_valid = 0xffffffff;
1013         printf("%s: object id %Ld\n", cmdname(argv[0]), data.ioc_obdo1.o_id);
1014
1015         rc = ioctl(fd, OBD_IOC_GETATTR , &data);
1016         if (rc) {
1017                 fprintf(stderr, "error: %s: %s\n", cmdname(argv[0]),
1018                         strerror(rc=errno));
1019         } else {
1020                 printf("%s: object id %Ld, mode %o\n", cmdname(argv[0]),
1021                        data.ioc_obdo1.o_id, data.ioc_obdo1.o_mode);
1022         }
1023         return rc;
1024 }
1025
1026 static int jt_test_getattr(int argc, char **argv)
1027 {
1028         struct obd_ioctl_data data;
1029         struct timeval start, next_time;
1030         int i, count, next_count;
1031         int verbose;
1032
1033         if (argc != 2 && argc != 3) {
1034                 fprintf(stderr, "usage: %s count [verbose]\n",cmdname(argv[0]));
1035                 return -1;
1036         }
1037
1038         IOCINIT(data);
1039         count = strtoul(argv[1], NULL, 0);
1040
1041         if (argc == 3)
1042                 verbose = get_verbose(argv[2]);
1043         else
1044                 verbose = 1;
1045
1046         data.ioc_obdo1.o_valid = 0xffffffff;
1047         data.ioc_obdo1.o_id = 2;
1048         gettimeofday(&start, NULL);
1049         next_time.tv_sec = start.tv_sec - verbose;
1050         next_time.tv_usec = start.tv_usec;
1051         printf("%s: getting %d attrs (testing only): %s", cmdname(argv[0]),
1052                count, ctime(&start.tv_sec));
1053
1054         for (i = 1, next_count = verbose; i <= count; i++) {
1055                 rc = ioctl(fd, OBD_IOC_GETATTR , &data);
1056                 if (rc < 0) {
1057                         fprintf(stderr, "error: %s: #%d - %s\n",
1058                                 cmdname(argv[0]), i, strerror(rc = errno));
1059                         break;
1060                 } else {
1061                         if (be_verbose(verbose, &next_time, i,&next_count,count))
1062                         printf("%s: got attr #%d\n", cmdname(argv[0]), i);
1063                 }
1064         }
1065
1066         if (!rc) {
1067                 struct timeval end;
1068                 double diff;
1069
1070                 gettimeofday(&end, NULL);
1071
1072                 diff = difftime(&end, &start);
1073
1074                 --i;
1075                 printf("%s: %d attrs in %.4gs (%.4g attr/s): %s",
1076                        cmdname(argv[0]), i, diff, (double)i / diff,
1077                        ctime(&end.tv_sec));
1078         }
1079         return rc;
1080 }
1081
1082 static int jt_test_brw(int argc, char **argv)
1083 {
1084         struct obd_ioctl_data data;
1085         struct timeval start, next_time;
1086         char *bulk, *b;
1087         int pages = 1, obdos = 1, count, next_count;
1088         int verbose = 1, write = 0, rw;
1089         int i, o, p;
1090         int len;
1091
1092         if (argc < 2 || argc > 6) {
1093                 fprintf(stderr,
1094                         "usage: %s count [write [verbose [pages [obdos]]]]\n",
1095                         cmdname(argv[0]));
1096                 return -1;
1097         }
1098
1099         count = strtoul(argv[1], NULL, 0);
1100
1101         if (argc >= 3) {
1102                 if (argv[2][0] == 'w' || argv[2][0] == '1')
1103                         write = 1;
1104                 else if (argv[2][0] == 'r' || argv[2][0] == '0')
1105                         write = 0;
1106
1107                 verbose = get_verbose(argv[3]);
1108         }
1109
1110         if (argc >= 5)
1111                 pages = strtoul(argv[4], NULL, 0);
1112         if (argc >= 6)
1113                 obdos = strtoul(argv[5], NULL, 0);
1114
1115         if (obdos != 1 && obdos != 2) {
1116                 fprintf(stderr, "error: %s: only 1 or 2 obdos supported\n",
1117                         cmdname(argv[0]));
1118                 return -2;
1119         }
1120
1121         len = pages * PAGE_SIZE;
1122
1123         bulk = calloc(obdos, len);
1124         if (!bulk) {
1125                 fprintf(stderr, "error: %s: no memory allocating %dx%d pages\n",
1126                         cmdname(argv[0]), obdos, pages);
1127                 return -2;
1128         }
1129         IOCINIT(data);
1130         data.ioc_conn2 = connid;
1131         data.ioc_obdo1.o_id = 2;
1132         data.ioc_count = len;
1133         data.ioc_offset = 0;
1134         data.ioc_plen1 = len;
1135         data.ioc_pbuf1 = bulk;
1136         if (obdos > 1) {
1137                 data.ioc_obdo2.o_id = 3;
1138                 data.ioc_plen2 = len;
1139                 data.ioc_pbuf2 = bulk + len;
1140         }
1141
1142         gettimeofday(&start, NULL);
1143         next_time.tv_sec = start.tv_sec - verbose;
1144         next_time.tv_usec = start.tv_usec;
1145
1146         printf("%s: %s %d (%dx%d pages) (testing only): %s",
1147                cmdname(argv[0]), write ? "writing" : "reading",
1148                count, obdos, pages, ctime(&start.tv_sec));
1149
1150         /*
1151          * We will put in the start time (and loop count inside the loop)
1152          * at the beginning of each page so that we will be able to validate
1153          * (at some later time) whether the data actually made it or not.
1154          *
1155          * XXX we do not currently use any of this memory in OBD_IOC_BRW_*
1156          *     just to avoid the overhead of the copy_{to,from}_user.  It
1157          *     can be fixed if we ever need to send real data around.
1158          */
1159         for (o = 0, b = bulk; o < obdos; o++)
1160                 for (p = 0; p < pages; p++, b += PAGE_SIZE)
1161                         memcpy(b, &start, sizeof(start));
1162
1163         rw = write ? OBD_IOC_BRW_WRITE : OBD_IOC_BRW_READ;
1164         for (i = 1, next_count = verbose; i <= count; i++) {
1165                 if (write) {
1166                         b = bulk + sizeof(struct timeval);
1167                         for (o = 0; o < obdos; o++)
1168                                 for (p = 0; p < pages; p++, b += PAGE_SIZE)
1169                                         memcpy(b, &count, sizeof(count));
1170                 }
1171
1172                 rc = ioctl(fd, rw, &data);
1173                 if (rc) {
1174                         fprintf(stderr, "error: %s: #%d - %s on %s\n",
1175                                 cmdname(argv[0]), i, strerror(rc = errno),
1176                                 write ? "write" : "read");
1177                         break;
1178                 } else if (be_verbose(verbose, &next_time, i,&next_count,count))
1179                         printf("%s: %s number %d\n", cmdname(argv[0]),
1180                                write ? "write" : "read", i);
1181         }
1182
1183         free(bulk);
1184
1185         if (!rc) {
1186                 struct timeval end;
1187                 double diff;
1188
1189                 gettimeofday(&end, NULL);
1190
1191                 diff = difftime(&end, &start);
1192
1193                 --i;
1194                 printf("%s: %s %dx%dx%d pages in %.4gs (%.4g pg/s): %s",
1195                        cmdname(argv[0]), write ? "wrote" : "read", obdos,
1196                        pages, i, diff, (double)obdos * i * pages / diff,
1197                        ctime(&end.tv_sec));
1198         }
1199         return rc;
1200 }
1201
1202 static int jt_test_ldlm(int argc, char **argv)
1203 {
1204         struct obd_ioctl_data data;
1205
1206         IOCINIT(data);
1207         if (argc != 1) {
1208                 fprintf(stderr, "usage: %s\n", cmdname(argv[0]));
1209                 return 1;
1210         }
1211
1212         rc = ioctl(fd, IOC_LDLM_TEST, &data);
1213         if (rc)
1214                 fprintf(stderr, "error: %s: test failed: %s\n",
1215                         cmdname(argv[0]), strerror(rc = errno));
1216         return rc;
1217 }
1218
1219 static int jt_newconn(int argc, char **argv)
1220 {
1221         struct obd_ioctl_data data;
1222
1223         IOCINIT(data);
1224         if (argc != 1) {
1225                 fprintf(stderr, "usage: %s\n", cmdname(argv[0]));
1226                 return -1;
1227         }
1228
1229         rc = ioctl(fd, OBD_IOC_RECOVD_NEWCONN , &data);
1230         if (rc < 0)
1231                 fprintf(stderr, "error: %s: %s\n", cmdname(argv[0]),
1232                         strerror(rc = errno));
1233
1234         return rc;
1235 }
1236
1237 static int jt_quit(int argc, char **argv)
1238 {
1239         Parser_quit(argc, argv);
1240
1241         return rc;
1242 }
1243
1244 command_t cmdlist[] = {
1245         /* Metacommands */
1246         {"--xml", jt__xml, 0, "--xml <xml file> <command [args ...]>"},
1247         {"--device", jt__device, 0, "--device <devno> <command [args ...]>"},
1248         {"--threads", jt__threads, 0,
1249                 "--threads <threads> <devno> <command [args ...]>"},
1250
1251         /* Device configuration commands */
1252         {"newdev", jt_newdev, 0, "set device to a new unused obd (no args)"},
1253         {"device", jt_device, 0, "set current device (args device_no name)"},
1254         {"name2dev", jt_name2dev, 0, "set device by name (args name)"},
1255         {"attach", jt_attach, 0, "name the type of device (args: type data"},
1256         {"setup", jt_setup, 0, "setup device (args: <blkdev> [data]"},
1257         {"detach", jt_detach, 0, "detach the current device (arg: )"},
1258         {"cleanup", jt_cleanup, 0, "cleanup the current device (arg: )"},
1259
1260         /* Session commands */
1261         {"connect", jt_connect, 0, "connect - get a connection to device"},
1262         {"disconnect", jt_disconnect, 0,
1263                 "disconnect - break connection to device"},
1264
1265         /* Session operations */
1266         {"create", jt_create, 0, "create [count [mode [verbose]]]"},
1267         {"destroy", jt_destroy, 0, "destroy <id>"},
1268         {"getattr", jt_getattr, 0, "getattr <id>"},
1269         {"setattr", jt_setattr, 0, "setattr <id> <mode>"},
1270         {"newconn", jt_newconn, 0, "newconn [newuuid]"},
1271         {"test_getattr", jt_test_getattr, 0, "test_getattr <count> [verbose]"},
1272         {"test_brw", jt_test_brw, 0, "test_brw <count> [write [verbose]]"},
1273         {"test_ldlm", jt_test_ldlm, 0, "test lock manager (no args)"},
1274
1275         /* User interface commands */
1276         {"help", Parser_help, 0, "help"},
1277         {"exit", jt_quit, 0, "quit"},
1278         {"quit", jt_quit, 0, "quit"},
1279         { 0, 0, 0, NULL }
1280 };
1281
1282
1283 static void signal_server(int sig)
1284 {
1285         if (sig == SIGINT) {
1286                 do_disconnect("sigint", 1);
1287                 exit(1);
1288         } else {
1289                 fprintf(stderr, "%s: got signal %d\n", cmdname("sigint"), sig);
1290         }
1291 }
1292
1293 int main(int argc, char **argv)
1294 {
1295         struct sigaction sigact;
1296
1297         sigact.sa_handler = signal_server;
1298         sigfillset(&sigact.sa_mask);
1299         sigact.sa_flags = SA_RESTART;
1300         sigaction(SIGINT, &sigact, NULL);
1301
1302
1303         if (argc > 1) {
1304                 rc = Parser_execarg(argc - 1, argv + 1, cmdlist);
1305         } else {
1306                 Parser_init("obdctl > ", cmdlist);
1307                 rc = Parser_commands();
1308         }
1309
1310         do_disconnect(argv[0], 1);
1311         return rc;
1312 }
1313