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