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