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