*** empty log message ***
[arla.git] / rx / rxdebug.c
blob82277ef38e5ca8b29b27b2c97365c07bf7ee95f6
1 /*
2 ****************************************************************************
3 * Copyright IBM Corporation 1988, 1989 - All Rights Reserved *
4 * *
5 * Permission to use, copy, modify, and distribute this software and its *
6 * documentation for any purpose and without fee is hereby granted, *
7 * provided that the above copyright notice appear in all copies and *
8 * that both that copyright notice and this permission notice appear in *
9 * supporting documentation, and that the name of IBM not be used in *
10 * advertising or publicity pertaining to distribution of the software *
11 * without specific, written prior permission. *
12 * *
13 * IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL *
14 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL IBM *
15 * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY *
16 * DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER *
17 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING *
18 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. *
19 ****************************************************************************
21 #include <sys/types.h>
22 #include <sys/time.h>
23 #include <sys/socket.h>
24 #include <sys/file.h>
25 #include <sys/stat.h>
26 #include <netinet/in.h>
27 #include <arpa/inet.h>
28 #include <netdb.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <errno.h>
32 #include <string.h>
33 #include <unistd.h>
34 #include <agetarg.h>
36 #include <stdio.h>
37 #include <err.h>
39 #include "rx_user.h"
40 #include "rx_clock.h"
41 #include "rx_queue.h"
42 #include "rx.h"
44 #include "config.h"
45 #include "roken.h"
47 RCSID ("$Id$");
49 #define TIMEOUT 20
51 static uint16_t
52 PortNumber(char *aport)
54 uint16_t port = atoi(aport);
55 return htons(port);
58 static uint16_t
59 PortName(char *aname)
61 struct servent *ts = getservbyname(aname, NULL);
62 if (ts == NULL)
63 return 0;
64 return ts->s_port; /* returns it in network byte order */
67 static int
68 MakeCall (int asocket, uint32_t ahost, uint16_t aport, char *adata,
69 long alen, char *aresult, long aresultLen)
71 static long counter = 100;
72 long endTime;
73 struct rx_header theader;
74 char tbuffer[1500];
75 int code;
76 struct timeval tv;
77 struct sockaddr_in taddr, faddr;
78 fd_set imask;
79 char *tp;
81 endTime = time(0) + TIMEOUT; /* try for N seconds */
82 counter++;
83 tp = &tbuffer[sizeof(struct rx_header)];
84 taddr.sin_family = AF_INET;
85 taddr.sin_port = aport;
86 taddr.sin_addr.s_addr = ahost;
87 while(1) {
88 memset(&theader, 0, sizeof(theader));
89 theader.epoch = htonl(999);
90 theader.cid = 0;
91 theader.callNumber = htonl(counter);
92 theader.seq = 0;
93 theader.serial = 0;
94 theader.type = RX_PACKET_TYPE_DEBUG;
95 theader.flags = RX_CLIENT_INITIATED | RX_LAST_PACKET;
96 theader.serviceId = 0;
98 if (sizeof(theader) + alen > sizeof(tbuffer))
99 errx(1, "message to large");
101 memcpy(tbuffer, &theader, sizeof(theader));
102 memcpy(tp, adata, alen);
103 code = sendto(asocket, tbuffer, alen+sizeof(struct rx_header), 0,
104 (struct sockaddr *)&taddr, sizeof(struct sockaddr_in));
105 if (code == -1) {
106 err(1, "sendto");
108 /* see if there's a packet available */
110 if (asocket >= FD_SETSIZE) {
111 printf("rxdebug: socket fd too large\n");
112 exit (1);
115 FD_ZERO(&imask);
116 FD_SET(asocket,&imask);
117 tv.tv_sec = 1;
118 tv.tv_usec = 0;
119 code = select(asocket + 1, &imask, NULL, NULL, &tv);
120 if (code == -1) {
121 err(1, "select");
123 if (code > 0) {
124 /* now receive a packet */
125 socklen_t faddrLen = sizeof(struct sockaddr_in);
127 code = recvfrom(asocket, tbuffer, sizeof(tbuffer), 0,
128 (struct sockaddr *)&faddr, &faddrLen);
129 if (code == -1) {
130 err(1, "recvfrom");
132 memcpy(&theader, tbuffer, sizeof(struct rx_header));
133 if (counter == ntohl(theader.callNumber))
134 break;
137 /* see if we've timed out */
138 if (endTime < time(0)) return -1;
140 code -= sizeof(struct rx_header);
141 if (code > aresultLen) code = aresultLen;
142 memcpy(aresult, tp, code);
143 return code;
146 static int
147 GetVersion(int asocket, uint32_t ahost, uint16_t aport,
148 void *adata, long alen,
149 char *aresult, long aresultLen)
151 static long counter = 100;
152 long endTime;
153 struct rx_header theader;
154 char tbuffer[1500];
155 int code;
156 struct timeval tv;
157 struct sockaddr_in taddr, faddr;
158 fd_set imask;
159 char *tp;
161 endTime = time(0) + TIMEOUT; /* try for N seconds */
162 counter++;
163 tp = &tbuffer[sizeof(struct rx_header)];
164 taddr.sin_family = AF_INET;
165 taddr.sin_port = aport;
166 taddr.sin_addr.s_addr = ahost;
167 while(1) {
168 memset(&theader, 0, sizeof(theader));
169 theader.epoch = htonl(999);
170 theader.cid = 0;
171 theader.callNumber = htonl(counter);
172 theader.seq = 0;
173 theader.serial = 0;
174 theader.type = RX_PACKET_TYPE_VERSION;
175 theader.flags = RX_CLIENT_INITIATED | RX_LAST_PACKET;
176 theader.serviceId = 0;
178 if (sizeof(theader) + alen > sizeof(tbuffer))
179 errx(1, "message to large");
181 memcpy(tbuffer, &theader, sizeof(theader));
182 memcpy(tp, adata, alen);
184 code = sendto(asocket, tbuffer, alen+sizeof(struct rx_header), 0,
185 (struct sockaddr *)&taddr, sizeof(struct sockaddr_in));
186 if (code == -1) {
187 err(1, "sendto");
190 if (asocket >= FD_SETSIZE) {
191 printf("rxdebug: socket fd too large\n");
192 exit (1);
195 /* see if there's a packet available */
196 FD_ZERO(&imask);
197 FD_SET(asocket, &imask);
199 /* should be 1 */
201 tv.tv_sec = 10;
202 tv.tv_usec = 0;
204 code = select(asocket + 1, &imask, 0, 0, &tv);
205 if (code == -1) {
206 err(1, "select");
208 if (code > 0) {
209 /* now receive a packet */
210 socklen_t faddrLen = sizeof(struct sockaddr_in);
212 code = recvfrom(asocket, tbuffer, sizeof(tbuffer), 0,
213 (struct sockaddr *)&faddr, &faddrLen);
214 if (code == -1) {
215 err(1, "recvfrom");
218 memcpy(&theader, tbuffer, sizeof(struct rx_header));
220 if (counter == ntohl(theader.callNumber))
221 break;
224 /* see if we've timed out */
225 if (endTime < time(0)) return -1;
227 code -= sizeof(struct rx_header);
228 if (code > aresultLen)
229 code = aresultLen;
230 memcpy(aresult, tp, code);
231 return code;
234 static int
235 MapOldConn (char version, struct rx_debugConn *tconn)
237 int i;
238 struct rx_debugConn_vL *vL = (struct rx_debugConn_vL *)tconn;
239 #define MOVEvL(a) (tconn->a = vL->a)
241 if ((version <= RX_DEBUGI_VERSION_W_UNALIGNED_CONN) ||
242 (version > RX_DEBUGI_VERSION)) {
243 /* any old or unrecognized version... */
244 for (i=0;i<RX_MAXCALLS;i++) {
245 MOVEvL(callState[i]);
246 MOVEvL(callMode[i]);
247 MOVEvL(callFlags[i]);
248 MOVEvL(callOther[i]);
250 if (version == RX_DEBUGI_VERSION_W_SECSTATS) {
251 MOVEvL(secStats.type);
252 MOVEvL(secStats.level);
253 MOVEvL(secStats.flags);
254 MOVEvL(secStats.expires);
255 MOVEvL(secStats.packetsReceived);
256 MOVEvL(secStats.packetsSent);
257 MOVEvL(secStats.bytesReceived);
258 MOVEvL(secStats.bytesSent);
261 return 0;
264 static int nodally_flag;
265 static int allconns_flag;
266 static int rxstats_flag;
267 static int onlyServer_flag;
268 static int onlyClient_flag;
269 static int version_flag;
270 static int noConns_flag;
271 static int help_flag;
272 static char *hostName;
273 static char *portName;
274 static char *onlyAuthName;
275 static char *onlyPortName;
276 static char *onlyHostName;
278 static int
279 MainCommand (void)
281 int i;
282 int s;
283 int j;
284 struct sockaddr_in taddr;
285 uint32_t host;
286 struct in_addr hostAddr;
287 uint16_t port;
288 struct rx_debugIn tin;
289 int code;
290 uint32_t onlyHost;
291 uint16_t onlyPort;
292 int onlyAuth;
293 int flag;
294 int dallyCounter;
295 int withSecStats;
296 int withAllConn;
297 int withRxStats;
298 int withWaiters;
299 struct rx_debugStats tstats;
300 struct rx_debugConn tconn;
302 char version[64];
303 char nada[64];
304 long length=64;
306 if (onlyPortName) {
307 char *name = onlyPortName;
308 if ((onlyPort = PortNumber(name)) == 0)
309 onlyPort = PortName(name);
310 if (onlyPort == 0) {
311 printf("rxdebug: can't resolve port name %s\n", name);
312 exit(1);
314 } else
315 onlyPort = 0xffff;
317 if (onlyHostName) {
318 char *name = onlyHostName;
319 struct hostent *th;
321 th = gethostbyname(name);
322 if (!th) {
323 printf("rxdebug: host %s not found in host table\n", name);
324 exit(1);
326 memcpy(&onlyHost, th->h_addr, sizeof(onlyHost));
327 } else
328 onlyHost = 0xffffffff;
330 if (onlyAuthName) {
331 char *name = onlyAuthName;
332 if (strcmp (name, "clear") == 0) onlyAuth = 0;
333 else if (strcmp (name, "auth") == 0) onlyAuth = 1;
334 else if (strcmp (name, "crypt") == 0) onlyAuth = 2;
335 else if ((strcmp (name, "null") == 0) ||
336 (strcmp (name, "none") == 0) ||
337 (strncmp (name, "noauth", 6) == 0) ||
338 (strncmp (name, "unauth", 6) == 0)) onlyAuth = -1;
339 else {
340 fprintf (stderr, "Unknown authentication level: %s\n", name);
341 exit (1);
343 } else onlyAuth = 999;
345 /* lookup host */
346 if (hostName) {
347 struct hostent *th;
349 th = gethostbyname(hostName);
350 if (!th) {
351 printf("rxdebug: host %s not found in host table\n", hostName);
352 exit(1);
354 memcpy(&host, th->h_addr, sizeof(host));
356 else host = htonl(0x7f000001); /* IP localhost */
358 if (!portName)
359 port = htons(7000); /* default is fileserver */
360 else {
361 if ((port = PortNumber(portName)) == 0)
362 port = PortName(portName);
363 if (port == 0) {
364 printf("rxdebug: can't resolve port name %s\n", portName);
365 exit(1);
369 dallyCounter = 0;
371 hostAddr.s_addr = host;
372 printf("Trying %s (port %d):\n", inet_ntoa(hostAddr), ntohs(port));
373 s = socket(AF_INET, SOCK_DGRAM, 0);
375 memset(&taddr, 0, sizeof(taddr));
376 taddr.sin_family = AF_INET;
377 taddr.sin_port = 0;
378 taddr.sin_addr.s_addr = 0;
380 code = bind(s, (struct sockaddr *)&taddr, sizeof(struct sockaddr_in));
381 if (code) {
382 perror("bind");
383 exit(1);
386 if(version_flag)
388 nada[0] = '\0';
390 code = GetVersion(s, host, port, nada, length,
391 version, length);
392 if (code < 0)
394 printf("get version call failed with code %d, errno %d\n",
395 code,errno);
396 exit(1);
398 printf("AFS version: %s\n",version);fflush(stdout);
400 exit(0);
405 tin.type = htonl(RX_DEBUGI_GETSTATS);
406 tin.index = 0;
407 code = MakeCall(s, host, port, (char *) &tin, sizeof(tin),
408 (char *) &tstats, sizeof(tstats));
409 if (code < 0) {
410 printf("getstats call failed with code %d\n", code);
411 exit(1);
414 withSecStats = (tstats.version >= RX_DEBUGI_VERSION_W_SECSTATS);
415 withAllConn = (tstats.version >= RX_DEBUGI_VERSION_W_GETALLCONN);
416 withRxStats = (tstats.version >= RX_DEBUGI_VERSION_W_RXSTATS);
417 withWaiters = (tstats.version >= RX_DEBUGI_VERSION_W_WAITERS);
419 printf("Free packets: %ld, packet reclaims: %ld, calls: %ld, "
420 "used FDs: %d\n",
421 (long)ntohl(tstats.nFreePackets),
422 (long)ntohl(tstats.packetReclaims),
423 (long)ntohl(tstats.callsExecuted),
424 tstats.usedFDs);
425 if (!tstats.waitingForPackets) printf("not ");
426 printf("waiting for packets.\n");
427 if (withWaiters)
428 printf("%ld calls waiting for a thread\n",
429 (long)ntohl(tstats.nWaiting));
431 if (rxstats_flag && withRxStats) {
432 if(!withRxStats) {
433 fprintf (stderr, "WARNING: Server doens't support "
434 "retrieval of Rx statistics\n");
435 } else {
436 struct rx_stats rxstats;
437 uint32_t *lp;
439 memset (&rxstats, 0, sizeof(rxstats));
440 tin.type = htonl(RX_DEBUGI_RXSTATS);
441 tin.index = 0;
442 /* should gracefully handle the case where rx_stats grows */
443 code = MakeCall(s, host, port, (char *) &tin, sizeof(tin),
444 (char *) &rxstats, sizeof(rxstats));
445 if (code < 0) {
446 printf("rxstats call failed with code %d\n", code);
447 exit(1);
450 if ((code == sizeof(tin)) &&
451 (ntohl(((struct rx_debugIn *)(void*)&rxstats)->type) ==
452 RX_DEBUGI_BADTYPE)) {
453 fprintf (stderr, "WARNING: Server doens't support "
454 "retrieval of Rx statistics\n");
455 } else {
456 if (code != sizeof(rxstats)) {
457 /* handle other versions?... */
458 fprintf (stderr, "WARNING: returned Rx statistics of "
459 "unexpected size (got %d)\n",
460 code);
462 /* Since its all int32's, convert to host order with a loop. */
463 lp = (uint32_t*)&rxstats;
464 for (i=0; i< sizeof(rxstats)/sizeof(uint32_t); i++)
465 lp[i] = ntohl(lp[i]);
467 rx_PrintTheseStats (stdout, &rxstats, sizeof(rxstats));
472 if (noConns_flag)
473 return 0;
475 tin.type = htonl(RX_DEBUGI_GETCONN);
476 if (allconns_flag)
477 tin.type = htonl(RX_DEBUGI_GETALLCONN);
479 if (onlyServer_flag) printf ("Showing only server connections\n");
480 if (onlyClient_flag) printf ("Showing only client connections\n");
481 if (onlyAuth != 999) {
482 static char *name[] =
483 {"unauthenticated", "rxkad_clear", "rxkad_auth", "rxkad_crypt"};
484 printf ("Showing only %s connections\n", name[onlyAuth+1]);
486 if (onlyHost != 0xffffffff) {
487 hostAddr.s_addr = onlyHost;
488 printf ("Showing only connections from host %s\n",
489 inet_ntoa(hostAddr));
491 if (onlyPort != 0xffff)
492 printf ("Showing only connections on port %u\n", ntohs(onlyPort));
494 for(i=0;;i++) {
495 tin.index = htonl(i);
496 memset (&tconn, 0, sizeof(tconn));
497 code = MakeCall(s, host, port, (char *)&tin, sizeof(tin),
498 (char *) &tconn, sizeof(tconn));
499 if (code < 0) {
500 printf("getconn call failed with code %d\n", code);
501 break;
503 MapOldConn (tstats.version, &tconn);
504 if (tconn.cid == htonl(0xffffffff)) {
505 printf("Done.\n");
506 break;
509 /* see if we're in nodally mode and all calls are dallying */
510 if (nodally_flag) {
511 flag = 0;
512 for(j=0;j<RX_MAXCALLS;j++) {
513 if (tconn.callState[j] != RX_STATE_NOTINIT &&
514 tconn.callState[j] != RX_STATE_DALLY) {
515 flag = 1;
516 break;
519 if (flag == 0) {
521 * this call looks too ordinary, bump skipped count and go
522 * around again
524 dallyCounter++;
525 continue;
528 if ((onlyHost != -1) && (onlyHost != tconn.host)) continue;
529 if ((onlyPort != 0) && (onlyPort != tconn.port)) continue;
530 if (onlyServer_flag && (tconn.type != RX_SERVER_CONNECTION)) continue;
531 if (onlyClient_flag && (tconn.type != RX_CLIENT_CONNECTION)) continue;
532 if (onlyAuth != 999) {
533 if (onlyAuth == -1) {
534 if (tconn.securityIndex != 0) continue;
535 } else {
536 if (tconn.securityIndex != 2) continue;
537 if (withSecStats && (tconn.secStats.type == 3) &&
538 (tconn.secStats.level != onlyAuth)) continue;
542 /* now display the connection */
543 hostAddr.s_addr = tconn.host;
544 printf("Connection from host %s, port %d, ",
545 inet_ntoa(hostAddr), ntohs(tconn.port));
546 if (tconn.epoch)
547 printf ("Cuid %lx/%lx", (unsigned long)ntohl(tconn.epoch),
548 (unsigned long)ntohl(tconn.cid));
549 else
550 printf ("cid %lx", (unsigned long)ntohl(tconn.cid));
551 if (tconn.error)
552 printf (", error %ld", (long)ntohl(tconn.error));
553 printf("\n serial %ld, ", (long)ntohl(tconn.serial));
554 printf(" maxPacketSize %ld, ", (long)ntohl(tconn.maxPacketSize));
556 if (tconn.flags) {
557 printf ("flags");
558 if (tconn.flags & RX_CONN_MAKECALL_WAITING)
559 printf(" MAKECALL_WAITING");
560 if (tconn.flags & RX_CONN_DESTROY_ME) printf(" DESTROYED");
561 if (tconn.flags & RX_CONN_USING_PACKET_CKSUM) printf(" pktCksum");
562 printf (", ");
564 printf("security index %d, ", tconn.securityIndex);
565 if (tconn.type == RX_CLIENT_CONNECTION) printf("client conn\n");
566 else printf("server conn\n");
568 if (withSecStats) {
569 switch ((int)tconn.secStats.type) {
570 case 0:
571 if (tconn.securityIndex == 2)
572 printf (" no GetStats procedure for security object\n");
573 break;
574 case 1:
575 printf (" rxnull level=%d, flags=%d\n",
576 tconn.secStats.level, (int)tconn.secStats.flags);
577 break;
578 case 2:
579 printf (" rxvab level=%d, flags=%d\n",
580 tconn.secStats.level, (int)tconn.secStats.flags);
581 break;
582 case 3: {
583 char *level;
584 char flags = ntohl(tconn.secStats.flags);
585 if (tconn.secStats.level == 0) level = "clear";
586 else if (tconn.secStats.level == 1) level = "auth";
587 else if (tconn.secStats.level == 2) level = "crypt";
588 else level = "unknown";
589 printf (" rxkad: level %s", level);
590 if (flags) printf (", flags");
591 if (flags & 1) printf (" unalloc");
592 if (flags & 2) printf (" authenticated");
593 if (flags & 4) printf (" expired");
594 if (flags & 8) printf (" pktCksum");
595 if (tconn.secStats.expires)
596 /* Apparently due to a bug in the RT compiler that
597 * prevents (u_long)0xffffffff => (double) from working,
598 * this code produces negative lifetimes when run on the
599 * RT. */
600 printf (", expires in %.1f hours",
601 ((u_long)ntohl(tconn.secStats.expires) -
602 time(0)) / 3600.0);
603 if (!(flags & 1)) {
604 printf ("\n Received %lu bytes in %lu packets\n",
605 (long)ntohl(tconn.secStats.bytesReceived),
606 (long)ntohl(tconn.secStats.packetsReceived));
607 printf (" Sent %lu bytes in %lu packets\n",
608 (long)ntohl(tconn.secStats.bytesSent),
609 (long)ntohl(tconn.secStats.packetsSent));
610 } else
611 printf ("\n");
612 break;
615 default: printf(" unknown\n");
619 for(j=0;j<RX_MAXCALLS;j++) {
620 printf(" call %d: # %ld, state ", j,
621 (long)ntohl(tconn.callNumber[j]));
622 if (tconn.callState[j]==RX_STATE_NOTINIT) {
623 printf("not initialized\n");
624 continue;
626 else if (tconn.callState[j]==RX_STATE_PRECALL)
627 printf("precall, ");
628 else if (tconn.callState[j] == RX_STATE_ACTIVE)
629 printf("active, ");
630 else if (tconn.callState[j] == RX_STATE_DALLY)
631 printf("dally, ");
632 printf("mode: ");
633 if (tconn.callMode[j]==RX_MODE_SENDING)
634 printf("sending");
635 else if (tconn.callMode[j]==RX_MODE_RECEIVING)
636 printf("receiving");
637 else if (tconn.callMode[j]==RX_MODE_ERROR)
638 printf("error");
639 else if (tconn.callMode[j] == RX_MODE_EOF)
640 printf("eof");
641 else printf("unknown");
642 if (tconn.callFlags[j]) {
643 printf(", flags:");
644 if (tconn.callFlags[j]&RX_CALL_READER_WAIT)
645 printf(" reader_wait");
646 if (tconn.callFlags[j]&RX_CALL_WAIT_WINDOW_ALLOC)
647 printf(" window_alloc");
648 if (tconn.callFlags[j]&RX_CALL_WAIT_WINDOW_SEND)
649 printf(" window_send");
650 if (tconn.callFlags[j]&RX_CALL_WAIT_PACKETS)
651 printf(" wait_packets");
652 if (tconn.callFlags[j]&RX_CALL_WAIT_PROC)
653 printf(" waiting_for_process");
654 if (tconn.callFlags[j]&RX_CALL_RECEIVE_DONE)
655 printf(" receive_done");
656 if (tconn.callFlags[j]&RX_CALL_CLEARED)
657 printf(" call_cleared");
659 if (tconn.callOther[j] & RX_OTHER_IN)
660 printf(", has_input_packets");
661 if (tconn.callOther[j] & RX_OTHER_OUT)
662 printf(", has_output_packets");
663 printf("\n");
666 if (nodally_flag)
667 printf("Skipped %d dallying connections.\n", dallyCounter);
668 return 0;
671 static struct agetargs args[] = {
672 {"servers", 0, aarg_string, &hostName,
673 "server machine", NULL, aarg_mandatory},
674 {"port", 0, aarg_string, &portName,
675 "IP port", NULL, aarg_optional_swless },
676 {"nodally", 0, aarg_flag, &nodally_flag,
677 "don't show dallying conns", NULL },
678 {"allconnections", 0, aarg_flag, &allconns_flag,
679 "don't filter out uninteresting connections on server"},
680 {"rxstats", 0, aarg_flag, &rxstats_flag,
681 "show Rx statistics", NULL },
682 {"onlyserver", 0, aarg_flag, &onlyServer_flag,
683 "only show server conns", NULL },
684 {"onlyclient", 0, aarg_flag, &onlyClient_flag,
685 "only show client conns", NULL},
686 {"onlyport", 0, aarg_integer, &onlyPortName,
687 "show only <port>", NULL },
688 {"onlyhost", 0, aarg_string, &onlyHostName,
689 "show only <host>", NULL },
690 {"onlyauth", 0, aarg_string, &onlyAuthName,
691 "show only <auth level>", NULL },
692 {"version", 0, aarg_flag, &version_flag,
693 "show AFS version id", NULL },
694 {"noconns", 0, aarg_flag, &noConns_flag,
695 "show no connections", NULL },
696 {"help", 0, aarg_flag, &help_flag,
697 "show help", NULL },
698 {NULL}
701 static void
702 usage(void)
704 aarg_printusage (args, "rxdebug", "", AARG_AFSSTYLE);
708 /* simple main program */
711 main(int argc, char **argv)
714 int o = 0;
716 if (agetarg (args, argc, argv, &o, AARG_AFSSTYLE)) {
717 usage();
718 return 0;
721 if(help_flag) {
722 usage();
723 return 0;
726 argc -= o;
727 argv += o;
729 if (argc > 0) {
730 fprintf (stderr, "create volume: unparsed arguments\n");
731 return 0;
734 return MainCommand();