85c0beabbc863457d8a64c9522dd6cbc42bb4a6d
[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 #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_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         if (print_ctime) {
409             time_t t = centry.cbExpires;
410             printf("    callback %08x\texpires %s\n", centry.callback,
411                     ctime(&t));
412         } else
413             printf("    callback %08x\texpires %u\n", centry.callback,
414                    centry.cbExpires);
415         printf("    %d opens\t%d writers\n", centry.opens, centry.writers);
416
417         /* now display states */
418         printf("    ");
419         if (centry.mvstat == 0)
420             printf("normal file");
421         else if (centry.mvstat == 1)
422             printf("mount point");
423         else if (centry.mvstat == 2)
424             printf("volume root");
425         else if (centry.mvstat == 3)
426             printf("directory");
427         else if (centry.mvstat == 4)
428             printf("symlink");
429         else if (centry.mvstat == 5)
430             printf("microsoft dfs link");
431         else if (centry.mvstat == 6)
432             printf("invalid link");
433         else
434             printf("bogus mvstat %d", centry.mvstat);
435         printf("\n    states (0x%x)", centry.states);
436         if (centry.states & 1)
437             printf(", stat'd");
438         if (centry.states & 2)
439             printf(", backup");
440         if (centry.states & 4)
441             printf(", read-only");
442         if (centry.states & 8)
443             printf(", mt pt valid");
444         if (centry.states & 0x10)
445             printf(", pending core");
446         if (centry.states & 0x40)
447             printf(", wait-for-store");
448         if (centry.states & 0x80)
449             printf(", mapped");
450         printf("\n");
451     }
452     return 0;
453 }
454
455 static int
456 PrintCacheEntries(struct rx_connection *aconn, int aint32)
457 {
458     afs_int32 code;
459     struct AFSDBCacheEntry64 centry64;
460
461     code = RXAFSCB_GetCE64(aconn, 0, &centry64);
462     if (code != RXGEN_OPCODE)
463         return PrintCacheEntries64(aconn, aint32);
464     else
465         return PrintCacheEntries32(aconn, aint32);
466 }
467
468 static int
469 PrintCellServDBEntry(struct rx_connection *aconn, afs_int32 cellnum)
470 {
471     int code;
472     char *cellname;
473     serverList sl;
474     unsigned int n;
475     int rc = 0;
476
477     cellname = NULL;
478     sl.serverList_len = 0;
479     sl.serverList_val = NULL;
480     code = RXAFSCB_GetCellServDB(aconn, cellnum, &cellname, &sl);
481     if (code)
482         return 0;
483
484     if ( !cellname || !cellname[0] )
485         goto done;
486
487     rc = 1;
488     printf(">%-23s#%s\n", cellname, cellname);
489
490     if (sl.serverList_val) {
491         char hoststr[16];
492         for ( n=0; n<sl.serverList_len; n++) {
493             struct hostent *host;
494             afs_uint32      addr = ntohl(sl.serverList_val[n]);
495
496             host = gethostbyaddr((const char *)&addr, sizeof(afs_uint32), AF_INET);
497             printf("%-28s#%s\n", afs_inet_ntoa_r(addr, hoststr),
498                     host ? host->h_name : "");
499         }
500     }
501
502   done:
503     if (cellname)
504         free(cellname);
505
506     if (sl.serverList_val)
507         free(sl.serverList_val);
508
509     return rc;
510 }
511
512 static void
513 PrintCellServDB(struct rx_connection *aconn)
514 {
515     afs_int32 index;
516
517     for ( index = 0 ; PrintCellServDBEntry(aconn, index); index++ );
518 }
519
520 int
521 CommandProc(struct cmd_syndesc *as, void *arock)
522 {
523     struct rx_connection *conn;
524     char *hostName;
525     struct hostent *thp;
526     afs_int32 port;
527     struct rx_securityClass *secobj;
528     int int32p;
529     afs_int32 addr;
530
531     hostName = as->parms[0].items->data;
532     if (as->parms[1].items)
533         port = atoi(as->parms[1].items->data);
534     else
535         port = 7001;
536     thp = hostutil_GetHostByName(hostName);
537     if (!thp) {
538         printf("cmdebug: can't resolve address for host %s.\n", hostName);
539         exit(1);
540     }
541     memcpy(&addr, thp->h_addr, sizeof(afs_int32));
542     secobj = rxnull_NewServerSecurityObject();
543     conn = rx_NewConnection(addr, htons(port), 1, secobj, 0);
544     if (!conn) {
545         printf("cmdebug: failed to create connection for host %s\n",
546                hostName);
547         exit(1);
548     }
549
550     if (as->parms[6].items) {
551         /* -addrs */
552         PrintInterfaces(conn);
553         return 0;
554     }
555     if (as->parms[7].items) {
556         /* -cache */
557         PrintCacheConfig(conn);
558         return 0;
559     }
560
561     if (as->parms[8].items) {
562         /* -cellservdb */
563         PrintCellServDB(conn);
564         return 0;
565     }
566
567     if (as->parms[5].items)
568         print_ctime = 1;
569
570     if (as->parms[2].items)
571         /* -long */
572         int32p = 1;
573     else if (as->parms[3].items)
574         /* -refcounts */
575         int32p = 2;
576     else if (as->parms[4].items)
577         /* -callbacks */
578         int32p = 4;
579     else
580         int32p = 0;
581
582     if (int32p == 0 || int32p == 1)
583         PrintLocks(conn, int32p);
584     if (int32p >= 0 || int32p <= 4)
585         PrintCacheEntries(conn, int32p);
586     return 0;
587 }
588
589 #ifndef AFS_NT40_ENV
590 #include "AFS_component_version_number.c"
591 #endif
592
593 int
594 main(int argc, char **argv)
595 {
596     struct cmd_syndesc *ts;
597
598 #ifdef  AFS_AIX32_ENV
599     /*
600      * The following signal action for AIX is necessary so that in case of a
601      * crash (i.e. core is generated) we can include the user's data section
602      * in the core dump. Unfortunately, by default, only a partial core is
603      * generated which, in many cases, isn't too useful.
604      */
605     struct sigaction nsa;
606
607     sigemptyset(&nsa.sa_mask);
608     nsa.sa_handler = SIG_DFL;
609     nsa.sa_flags = SA_FULLDUMP;
610     sigaction(SIGSEGV, &nsa, NULL);
611 #endif
612
613 #ifdef AFS_NT40_ENV
614     if (afs_winsockInit() < 0) {
615         printf("%s: Couldn't initialize winsock. Exiting...\n", argv[0]);
616         return 1;
617     }
618 #endif
619
620     rx_Init(0);
621
622     ts = cmd_CreateSyntax(NULL, CommandProc, NULL, "query afs cache manager");
623     cmd_AddParm(ts, "-servers", CMD_SINGLE, CMD_REQUIRED, "server machine");
624     cmd_AddParm(ts, "-port", CMD_SINGLE, CMD_OPTIONAL, "IP port");
625     cmd_AddParm(ts, "-long", CMD_FLAG, CMD_OPTIONAL, "print all info");
626     cmd_AddParm(ts, "-refcounts", CMD_FLAG, CMD_OPTIONAL,
627                  "print only cache entries with positive reference counts");
628     cmd_AddParm(ts, "-callbacks", CMD_FLAG, CMD_OPTIONAL,
629                  "print only cache entries with callbacks");
630     cmd_AddParm(ts, "-ctime", CMD_FLAG, CMD_OPTIONAL,
631                 "print human readable expiration time");
632
633
634     cmd_AddParm(ts, "-addrs", CMD_FLAG, CMD_OPTIONAL,
635                 "print only host interfaces");
636     cmd_AddParm(ts, "-cache", CMD_FLAG, CMD_OPTIONAL,
637                 "print only cache configuration");
638     cmd_AddParm(ts, "-cellservdb", CMD_FLAG, CMD_OPTIONAL,
639                 "print only cellservdb info");
640
641     cmd_Dispatch(argc, argv);
642     exit(0);
643 }