e1f19f54098e2aa7f7ace686aefd4534f1dece6f
[openafs.git] / src / venus / cmdebug.c
1 /*
2  * Copyright 2000, International Business Machines Corporation and others.
3  * All Rights Reserved.
4  * 
5  * This software has been released under the terms of the IBM Public
6  * License.  For details, see the LICENSE file in the top-level source
7  * directory or online at http://www.openafs.org/dl/license10.html
8  */
9
10 #include <afsconfig.h>
11 #include <afs/param.h>
12
13
14
15 #include <sys/types.h>
16 #ifdef AFS_NT40_ENV
17 #include <winsock2.h>
18 #include <rpc.h>
19 #else
20 #ifdef HAVE_NETINET_IN_H
21 #include <netinet/in.h>
22 #endif
23 #include <sys/socket.h>
24 #include <netdb.h>
25 #endif
26 #include <stdio.h>
27 #include <string.h>
28 #ifdef  AFS_AIX32_ENV
29 #include <signal.h>
30 #endif
31 #include <afs/afscbint.h>
32 #include <afs/cmd.h>
33 #include <rx/rx.h>
34 #include <lock.h>
35 #include <afs/afs_args.h>
36 #include <afs/afsutil.h>
37 #include <afs/com_err.h>
38
39 static int print_ctime = 0;
40
41 static int
42 PrintCacheConfig(struct rx_connection *aconn)
43 {
44     struct cacheConfig c;
45     afs_uint32 srv_ver, conflen;
46     int code;
47
48     c.cacheConfig_len = 0;
49     c.cacheConfig_val = NULL;
50     code = RXAFSCB_GetCacheConfig(aconn, 1, &srv_ver, &conflen, &c);
51     if (code) {
52         printf("cmdebug: error checking cache config: %s\n",
53                afs_error_message(code));
54         return 0;
55     }
56
57     if (srv_ver == AFS_CLIENT_RETRIEVAL_FIRST_EDITION) {
58         struct cm_initparams_v1 *c1;
59
60         if (c.cacheConfig_len != sizeof(*c1) / sizeof(afs_uint32)) {
61             printf("cmdebug: configuration data size mismatch (%d != %lu)\n",
62                    c.cacheConfig_len, sizeof(*c1) / sizeof(afs_uint32));
63             return 0;
64         }
65
66         c1 = (struct cm_initparams_v1 *)c.cacheConfig_val;
67         printf("Chunk files:   %d\n", c1->nChunkFiles);
68         printf("Stat caches:   %d\n", c1->nStatCaches);
69         printf("Data caches:   %d\n", c1->nDataCaches);
70         printf("Volume caches: %d\n", c1->nVolumeCaches);
71         printf("Chunk size:    %d", c1->otherChunkSize);
72         if (c1->firstChunkSize != c1->otherChunkSize)
73             printf(" (first: %d)", c1->firstChunkSize);
74         printf("\n");
75         printf("Cache size:    %d kB\n", c1->cacheSize);
76         printf("Set time:      %s\n", c1->setTime ? "yes" : "no");
77         printf("Cache type:    %s\n", c1->memCache ? "memory" : "disk");
78     } else {
79         printf("cmdebug: unsupported server version %d\n", srv_ver);
80     }
81     return 0;
82 }
83
84 #ifndef CAPABILITY_BITS
85 #define CAPABILITY_ERRORTRANS (1<<0)
86 #define CAPABILITY_BITS 1
87 #endif
88
89 static int
90 PrintInterfaces(struct rx_connection *aconn)
91 {
92     Capabilities caps;
93     struct interfaceAddr addr;
94 #ifdef AFS_NT40_ENV
95     char * p;
96 #else
97     char uuidstr[128];
98 #endif
99     int i, code;
100
101     caps.Capabilities_val = NULL;
102     caps.Capabilities_len = 0;
103
104     code = RXAFSCB_TellMeAboutYourself(aconn, &addr, &caps);
105     if (code == RXGEN_OPCODE)
106         code = RXAFSCB_WhoAreYou(aconn, &addr);
107     if (code) {
108         printf("cmdebug: error checking interfaces: %s\n",
109                afs_error_message(code));
110         return 0;
111     }
112
113 #ifdef AFS_NT40_ENV
114     UuidToString((UUID *)&addr.uuid, &p);
115     printf("UUID: %s\n",p);
116     RpcStringFree(&p);
117 #else
118     afsUUID_to_string(&addr.uuid, uuidstr, sizeof(uuidstr));
119     printf("UUID: %s\n",uuidstr);
120 #endif
121
122     printf("Host interfaces:\n");
123     for (i = 0; i < addr.numberOfInterfaces; i++) {
124         printf("%s", afs_inet_ntoa(htonl(addr.addr_in[i])));
125         if (addr.subnetmask[i])
126             printf(", netmask %s", afs_inet_ntoa(htonl(addr.subnetmask[i])));
127         if (addr.mtu[i])
128             printf(", MTU %d", addr.mtu[i]);
129         printf("\n");
130     }
131
132     if (caps.Capabilities_val) {
133         printf("Capabilities:\n");
134         if (caps.Capabilities_val[0] & CAPABILITY_ERRORTRANS) {
135             printf("Error Translation\n");  
136         }
137         printf("\n");
138     }
139
140     if (caps.Capabilities_val)
141         free(caps.Capabilities_val);
142     caps.Capabilities_val = NULL;
143     caps.Capabilities_len = 0;
144
145     return 0;
146 }
147
148 static int
149 IsLocked(register struct AFSDBLockDesc *alock)
150 {
151     if (alock->waitStates || alock->exclLocked || alock->numWaiting
152         || alock->readersReading)
153         return 1;
154     return 0;
155 }
156
157 static int
158 PrintLock(register struct AFSDBLockDesc *alock)
159 {
160     printf("(");
161     if (alock->waitStates) {
162         if (alock->waitStates & READ_LOCK)
163             printf("reader_waiting");
164         if (alock->waitStates & WRITE_LOCK)
165             printf("writer_waiting");
166         if (alock->waitStates & SHARED_LOCK)
167             printf("upgrade_waiting");
168     } else
169         printf("none_waiting");
170     if (alock->exclLocked) {
171         if (alock->exclLocked & WRITE_LOCK)
172             printf(", write_locked");
173         if (alock->exclLocked & SHARED_LOCK)
174             printf(", upgrade_locked");
175         printf("(pid:%d at:%d)", alock->pid_writer, alock->src_indicator);
176     }
177     if (alock->readersReading)
178         printf(", %d read_locks(pid:%d)", alock->readersReading,
179                alock->pid_last_reader);
180     if (alock->numWaiting)
181         printf(", %d waiters", alock->numWaiting);
182     printf(")");
183     return 0;
184 }
185
186 static int
187 PrintLocks(register struct rx_connection *aconn, int aint32)
188 {
189     register int i;
190     struct AFSDBLock lock;
191     afs_int32 code;
192
193     for (i = 0; i < 1000; i++) {
194         code = RXAFSCB_GetLock(aconn, i, &lock);
195         if (code) {
196             if (code == 1)
197                 break;
198             /* otherwise we have an unrecognized error */
199             printf("cmdebug: error checking locks: %s\n",
200                    afs_error_message(code));
201             return code;
202         }
203         /* here we have the lock information, so display it, perhaps */
204         if (aint32 || IsLocked(&lock.lock)) {
205             printf("Lock %s status: ", lock.name);
206             PrintLock(&lock.lock);
207             printf("\n");
208         }
209     }
210     return 0;
211 }
212
213 struct cell_cache {
214     afs_int32 cellnum;
215     char *cellname;
216     struct cell_cache *next;
217 };
218
219 static char *
220 GetCellName(struct rx_connection *aconn, afs_int32 cellnum)
221 {
222     static int no_getcellbynum;
223     static struct cell_cache *cache;
224     struct cell_cache *tcp;
225     int code;
226     char *cellname;
227     serverList sl;
228
229     if (no_getcellbynum)
230         return NULL;
231
232     for (tcp = cache; tcp; tcp = tcp->next)
233         if (tcp->cellnum == cellnum)
234             return tcp->cellname;
235
236     cellname = NULL;
237     sl.serverList_len = 0;
238     sl.serverList_val = NULL;
239     code = RXAFSCB_GetCellByNum(aconn, cellnum, &cellname, &sl);
240     if (code) {
241         if (code == RXGEN_OPCODE)
242             no_getcellbynum = 1;
243         return NULL;
244     }
245
246     if (sl.serverList_val)
247         free(sl.serverList_val);
248     tcp = malloc(sizeof(struct cell_cache));
249     tcp->next = cache;
250     tcp->cellnum = cellnum;
251     tcp->cellname = cellname;
252     cache = tcp;
253
254     return cellname;
255 }
256
257 static int
258 PrintCacheEntries32(struct rx_connection *aconn, int aint32)
259 {
260     register int i;
261     register afs_int32 code;
262     struct AFSDBCacheEntry centry;
263     char *cellname;
264
265     for (i = 0; i < 1000000; i++) {
266         code = RXAFSCB_GetCE(aconn, i, &centry);
267         if (code) {
268             if (code == 1)
269                 break;
270             printf("cmdebug: failed to get cache entry %d (%s)\n", i,
271                    afs_error_message(code));
272             return code;
273         }
274
275         if (centry.addr == 0) {
276             /* PS output */
277             printf("Proc %4d sleeping at %08x, pri %3d\n",
278                    centry.netFid.Vnode, centry.netFid.Volume,
279                    centry.netFid.Unique - 25);
280             continue;
281         }
282
283         if ((aint32 == 0 && !IsLocked(&centry.lock)) ||
284             (aint32 == 2 && centry.refCount == 0) ||
285             (aint32 == 4 && centry.callback == 0))
286             continue;
287
288         /* otherwise print this entry */
289         printf("** Cache entry @ 0x%08x for %d.%d.%d.%d", centry.addr,
290                centry.cell, centry.netFid.Volume, centry.netFid.Vnode,
291                centry.netFid.Unique);
292
293         cellname = GetCellName(aconn, centry.cell);
294         if (cellname)
295             printf(" [%s]\n", cellname);
296         else
297             printf("\n");
298
299         if (IsLocked(&centry.lock)) {
300             printf("    locks: ");
301             PrintLock(&centry.lock);
302             printf("\n");
303         }
304         printf("    %12d bytes  DV %12d  refcnt %5d\n", centry.Length,
305                centry.DataVersion, centry.refCount);
306         if (print_ctime) {
307             time_t t = centry.cbExpires;
308             printf("    callback %08x\texpires %s\n", centry.callback,
309                     ctime(&t));
310         } else
311             printf("    callback %08x\texpires %u\n", centry.callback,
312                    centry.cbExpires);
313         printf("    %d opens\t%d writers\n", centry.opens, centry.writers);
314
315         /* now display states */
316         printf("    ");
317         if (centry.mvstat == 0)
318             printf("normal file");
319         else if (centry.mvstat == 1)
320             printf("mount point");
321         else if (centry.mvstat == 2)
322             printf("volume root");
323         else if (centry.mvstat == 3)    /* windows */
324             printf("directory");
325         else if (centry.mvstat == 4)    /* windows */
326             printf("symlink");
327         else if (centry.mvstat == 5)    /* windows */
328             printf("microsoft dfs link");
329         else if (centry.mvstat == 6)    /* windows */
330             printf("invalid link");
331         else
332             printf("bogus mvstat %d", centry.mvstat);
333         printf("\n    states (0x%x)", centry.states);
334         if (centry.states & 1)
335             printf(", stat'd");
336         if (centry.states & 2)
337             printf(", backup");
338         if (centry.states & 4)
339             printf(", read-only");
340         if (centry.states & 8)
341             printf(", mt pt valid");
342         if (centry.states & 0x10)
343             printf(", pending core");
344         if (centry.states & 0x40)
345             printf(", wait-for-store");
346         if (centry.states & 0x80)
347             printf(", mapped");
348         printf("\n");
349     }
350     return 0;
351 }
352
353 static int
354 PrintCacheEntries64(struct rx_connection *aconn, int aint32)
355 {
356     register int i;
357     register afs_int32 code;
358     struct AFSDBCacheEntry64 centry;
359     char *cellname;
360
361     for (i = 0; i < 1000000; i++) {
362         code = RXAFSCB_GetCE64(aconn, i, &centry);
363         if (code) {
364             if (code == 1)
365                 break;
366             printf("cmdebug: failed to get cache entry %d (%s)\n", i,
367                    afs_error_message(code));
368             return code;
369         }
370
371         if (centry.addr == 0) {
372             /* PS output */
373             printf("Proc %4d sleeping at %08x, pri %3d\n",
374                    centry.netFid.Vnode, centry.netFid.Volume,
375                    centry.netFid.Unique - 25);
376             continue;
377         }
378
379         if ((aint32 == 0 && !IsLocked(&centry.lock)) ||
380             (aint32 == 2 && centry.refCount == 0) ||
381             (aint32 == 4 && centry.callback == 0))
382             continue;
383
384         /* otherwise print this entry */
385         printf("** Cache entry @ 0x%08x for %d.%d.%d.%d", centry.addr,
386                centry.cell, centry.netFid.Volume, centry.netFid.Vnode,
387                centry.netFid.Unique);
388
389         cellname = GetCellName(aconn, centry.cell);
390         if (cellname)
391             printf(" [%s]\n", cellname);
392         else
393             printf("\n");
394
395         if (IsLocked(&centry.lock)) {
396             printf("    locks: ");
397             PrintLock(&centry.lock);
398             printf("\n");
399         }
400 #ifdef AFS_64BIT_ENV
401 #ifdef AFS_NT40_ENV
402         printf("    %12I64d bytes  DV %12d  refcnt %5d\n", centry.Length,
403                centry.DataVersion, centry.refCount);
404 #else
405         printf("    %12llu bytes  DV %12d  refcnt %5d\n", centry.Length,
406                centry.DataVersion, centry.refCount);
407 #endif
408 #else
409         printf("    %12d bytes  DV %12d  refcnt %5d\n", centry.Length,
410                centry.DataVersion, centry.refCount);
411 #endif
412         if (print_ctime) {
413             time_t t = centry.cbExpires;
414             printf("    callback %08x\texpires %s\n", centry.callback,
415                     ctime(&t));
416         } else
417             printf("    callback %08x\texpires %u\n", centry.callback,
418                    centry.cbExpires);
419         printf("    %d opens\t%d writers\n", centry.opens, centry.writers);
420
421         /* now display states */
422         printf("    ");
423         if (centry.mvstat == 0)
424             printf("normal file");
425         else if (centry.mvstat == 1)
426             printf("mount point");
427         else if (centry.mvstat == 2)
428             printf("volume root");
429         else if (centry.mvstat == 3)
430             printf("directory");
431         else if (centry.mvstat == 4)
432             printf("symlink");
433         else if (centry.mvstat == 5)
434             printf("microsoft dfs link");
435         else if (centry.mvstat == 6)
436             printf("invalid link");
437         else
438             printf("bogus mvstat %d", centry.mvstat);
439         printf("\n    states (0x%x)", centry.states);
440         if (centry.states & 1)
441             printf(", stat'd");
442         if (centry.states & 2)
443             printf(", backup");
444         if (centry.states & 4)
445             printf(", read-only");
446         if (centry.states & 8)
447             printf(", mt pt valid");
448         if (centry.states & 0x10)
449             printf(", pending core");
450         if (centry.states & 0x40)
451             printf(", wait-for-store");
452         if (centry.states & 0x80)
453             printf(", mapped");
454         printf("\n");
455     }
456     return 0;
457 }
458
459 static int
460 PrintCacheEntries(struct rx_connection *aconn, int aint32)
461 {
462     register afs_int32 code;
463     struct AFSDBCacheEntry64 centry64;
464
465     code = RXAFSCB_GetCE64(aconn, 0, &centry64);
466     if (code != RXGEN_OPCODE)
467         return PrintCacheEntries64(aconn, aint32);
468     else
469         return PrintCacheEntries32(aconn, aint32);
470 }
471
472 static int
473 PrintCellServDBEntry(struct rx_connection *aconn, afs_int32 cellnum)
474 {
475     int code;
476     char *cellname;
477     serverList sl;
478     unsigned int n;
479     int rc = 0;
480
481     cellname = NULL;
482     sl.serverList_len = 0;
483     sl.serverList_val = NULL;
484     code = RXAFSCB_GetCellServDB(aconn, cellnum, &cellname, &sl);
485     if (code)
486         return 0;
487
488     if ( !cellname || !cellname[0] )
489         goto done;
490
491     rc = 1;
492     printf(">%-23s#%s\n", cellname, cellname);
493
494     if (sl.serverList_val) {
495         for ( n=0; n<sl.serverList_len; n++) {
496             struct hostent *host;
497             afs_uint32      addr = ntohl(sl.serverList_val[n]);
498
499             host = gethostbyaddr((const char *)&addr, sizeof(afs_uint32), AF_INET);
500             printf("%-28s#%s\n", afs_inet_ntoa(addr), 
501                     host ? host->h_name : "");
502         }
503     }
504
505   done:
506     if (cellname)
507         free(cellname);
508
509     if (sl.serverList_val)
510         free(sl.serverList_val);
511
512     return rc;
513 }
514
515 static void
516 PrintCellServDB(struct rx_connection *aconn) 
517 {
518     afs_int32 index;
519
520     for ( index = 0 ; PrintCellServDBEntry(aconn, index); index++ );
521 }
522
523 int
524 CommandProc(struct cmd_syndesc *as, void *arock)
525 {
526     struct rx_connection *conn;
527     register char *hostName;
528     register struct hostent *thp;
529     afs_int32 port;
530     struct rx_securityClass *secobj;
531     int int32p;
532     afs_int32 addr;
533
534     hostName = as->parms[0].items->data;
535     if (as->parms[1].items)
536         port = atoi(as->parms[1].items->data);
537     else
538         port = 7001;
539     thp = hostutil_GetHostByName(hostName);
540     if (!thp) {
541         printf("cmdebug: can't resolve address for host %s.\n", hostName);
542         exit(1);
543     }
544     memcpy(&addr, thp->h_addr, sizeof(afs_int32));
545     secobj = rxnull_NewServerSecurityObject();
546     conn = rx_NewConnection(addr, htons(port), 1, secobj, 0);
547     if (!conn) {
548         printf("cmdebug: failed to create connection for host %s\n",
549                hostName);
550         exit(1);
551     }
552
553     if (as->parms[6].items) {
554         /* -addrs */
555         PrintInterfaces(conn);
556         return 0;
557     }
558     if (as->parms[7].items) {
559         /* -cache */
560         PrintCacheConfig(conn);
561         return 0;
562     }
563
564     if (as->parms[8].items) {
565         /* -cellservdb */
566         PrintCellServDB(conn);
567         return 0;
568     }
569
570     if (as->parms[5].items)
571         print_ctime = 1;
572
573     if (as->parms[2].items)
574         /* -long */
575         int32p = 1;
576     else if (as->parms[3].items)
577         /* -refcounts */
578         int32p = 2;
579     else if (as->parms[4].items)
580         /* -callbacks */
581         int32p = 4;
582     else
583         int32p = 0;
584
585     if (int32p == 0 || int32p == 1)
586         PrintLocks(conn, int32p);
587     if (int32p >= 0 || int32p <= 4)
588         PrintCacheEntries(conn, int32p);
589     return 0;
590 }
591
592 #ifndef AFS_NT40_ENV
593 #include "AFS_component_version_number.c"
594 #endif
595
596 int
597 main(int argc, char **argv)
598 {
599     register struct cmd_syndesc *ts;
600
601 #ifdef  AFS_AIX32_ENV
602     /*
603      * The following signal action for AIX is necessary so that in case of a 
604      * crash (i.e. core is generated) we can include the user's data section 
605      * in the core dump. Unfortunately, by default, only a partial core is
606      * generated which, in many cases, isn't too useful.
607      */
608     struct sigaction nsa;
609
610     sigemptyset(&nsa.sa_mask);
611     nsa.sa_handler = SIG_DFL;
612     nsa.sa_flags = SA_FULLDUMP;
613     sigaction(SIGSEGV, &nsa, NULL);
614 #endif
615
616 #ifdef AFS_NT40_ENV
617     if (afs_winsockInit() < 0) {
618         printf("%s: Couldn't initialize winsock. Exiting...\n", argv[0]);
619         return 1;
620     }
621 #endif
622
623     rx_Init(0);
624
625     ts = cmd_CreateSyntax(NULL, CommandProc, NULL, "query afs cache manager");
626     cmd_AddParm(ts, "-servers", CMD_SINGLE, CMD_REQUIRED, "server machine");
627     cmd_AddParm(ts, "-port", CMD_SINGLE, CMD_OPTIONAL, "IP port");
628     cmd_AddParm(ts, "-long", CMD_FLAG, CMD_OPTIONAL, "print all info");
629     cmd_AddParm(ts, "-refcounts", CMD_FLAG, CMD_OPTIONAL, 
630                  "print only cache entries with positive reference counts");
631     cmd_AddParm(ts, "-callbacks", CMD_FLAG, CMD_OPTIONAL, 
632                  "print only cache entries with callbacks");
633     cmd_AddParm(ts, "-ctime", CMD_FLAG, CMD_OPTIONAL, 
634                 "print human readable expiration time");
635
636     
637     cmd_AddParm(ts, "-addrs", CMD_FLAG, CMD_OPTIONAL,
638                 "print only host interfaces");
639     cmd_AddParm(ts, "-cache", CMD_FLAG, CMD_OPTIONAL,
640                 "print only cache configuration");
641     cmd_AddParm(ts, "-cellservdb", CMD_FLAG, CMD_OPTIONAL, 
642                 "print only cellservdb info");
643
644     cmd_Dispatch(argc, argv);
645     exit(0);
646 }