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