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