f6b7b44bcf07bab92d5c2c92334bab5d15234f13
[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
44 PrintCacheConfig(struct rx_connection *aconn)
45 {
46     struct cacheConfig c;
47     afs_uint32 srv_ver, conflen;
48     int code;
49
50     c.cacheConfig_len = 0;
51     c.cacheConfig_val = NULL;
52     code = RXAFSCB_GetCacheConfig(aconn, 1, &srv_ver, &conflen, &c);
53     if (code) {
54         printf("cmdebug: error checking cache config: %s\n",
55                afs_error_message(code));
56         return 0;
57     }
58
59     if (srv_ver == AFS_CLIENT_RETRIEVAL_FIRST_EDITION) {
60         struct cm_initparams_v1 *c1;
61
62         if (c.cacheConfig_len != sizeof(*c1) / sizeof(afs_uint32)) {
63             printf("cmdebug: configuration data size mismatch (%d != %d)\n",
64                    c.cacheConfig_len, sizeof(*c1) / sizeof(afs_uint32));
65             return 0;
66         }
67
68         c1 = (struct cm_initparams_v1 *)c.cacheConfig_val;
69         printf("Chunk files:   %d\n", c1->nChunkFiles);
70         printf("Stat caches:   %d\n", c1->nStatCaches);
71         printf("Data caches:   %d\n", c1->nDataCaches);
72         printf("Volume caches: %d\n", c1->nVolumeCaches);
73         printf("Chunk size:    %d", c1->otherChunkSize);
74         if (c1->firstChunkSize != c1->otherChunkSize)
75             printf(" (first: %d)", c1->firstChunkSize);
76         printf("\n");
77         printf("Cache size:    %d kB\n", c1->cacheSize);
78         printf("Set time:      %s\n", c1->setTime ? "yes" : "no");
79         printf("Cache type:    %s\n", c1->memCache ? "memory" : "disk");
80     } else {
81         printf("cmdebug: unsupported server version %d\n", srv_ver);
82     }
83 }
84
85 #ifndef CAPABILITY_BITS
86 #define CAPABILITY_ERRORTRANS (1<<0)
87 #define CAPABILITY_BITS 1
88 #endif
89
90 static int
91 PrintInterfaces(struct rx_connection *aconn)
92 {
93     Capabilities caps;
94     struct interfaceAddr addr;
95 #ifdef AFS_NT40_ENV
96     char * p;
97 #else
98     char uuidstr[128];
99 #endif
100     int i, code;
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(htonl(addr.addr_in[i])));
126         if (addr.subnetmask[i])
127             printf(", netmask %s", afs_inet_ntoa(htonl(addr.subnetmask[i])));
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(register 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(register 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(register struct rx_connection *aconn, int aint32)
189 {
190     register 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     register int i;
262     register afs_int32 code;
263     struct AFSDBCacheEntry centry;
264     char *cellname;
265
266     for (i = 0; i < 10000; 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         printf("    callback %08x\texpires %u\n", centry.callback,
308                centry.cbExpires);
309         printf("    %d opens\t%d writers\n", centry.opens, centry.writers);
310
311         /* now display states */
312         printf("    ");
313         if (centry.mvstat == 0)
314             printf("normal file");
315         else if (centry.mvstat == 1)
316             printf("mount point");
317         else if (centry.mvstat == 2)
318             printf("volume root");
319         else if (centry.mvstat == 3)    /* windows */
320             printf("directory");
321         else if (centry.mvstat == 4)    /* windows */
322             printf("symlink");
323         else if (centry.mvstat == 5)    /* windows */
324             printf("microsoft dfs link");
325         else if (centry.mvstat == 6)    /* windows */
326             printf("invalid link");
327         else
328             printf("bogus mvstat %d", centry.mvstat);
329         printf("\n    states (0x%x)", centry.states);
330         if (centry.states & 1)
331             printf(", stat'd");
332         if (centry.states & 2)
333             printf(", backup");
334         if (centry.states & 4)
335             printf(", read-only");
336         if (centry.states & 8)
337             printf(", mt pt valid");
338         if (centry.states & 0x10)
339             printf(", pending core");
340         if (centry.states & 0x40)
341             printf(", wait-for-store");
342         if (centry.states & 0x80)
343             printf(", mapped");
344         printf("\n");
345     }
346     return 0;
347 }
348
349 static int
350 PrintCacheEntries64(struct rx_connection *aconn, int aint32)
351 {
352     register int i;
353     register afs_int32 code;
354     struct AFSDBCacheEntry64 centry;
355     char *cellname;
356     int ce64 = 0;
357
358     for (i = 0; i < 10000; i++) {
359         code = RXAFSCB_GetCE64(aconn, i, &centry);
360         if (code) {
361             if (code == 1)
362                 break;
363             printf("cmdebug: failed to get cache entry %d (%s)\n", i,
364                    afs_error_message(code));
365             return code;
366         }
367
368         if (centry.addr == 0) {
369             /* PS output */
370             printf("Proc %4d sleeping at %08x, pri %3d\n",
371                    centry.netFid.Vnode, centry.netFid.Volume,
372                    centry.netFid.Unique - 25);
373             continue;
374         }
375
376         if (aint32 == 0 && !IsLocked(&centry.lock) ||
377             aint32 == 2 && centry.refCount == 0 ||
378             aint32 == 4 && centry.callback == 0)
379             continue;
380
381         /* otherwise print this entry */
382         printf("** Cache entry @ 0x%08x for %d.%d.%d.%d", centry.addr,
383                centry.cell, centry.netFid.Volume, centry.netFid.Vnode,
384                centry.netFid.Unique);
385
386         cellname = GetCellName(aconn, centry.cell);
387         if (cellname)
388             printf(" [%s]\n", cellname);
389         else
390             printf("\n");
391
392         if (IsLocked(&centry.lock)) {
393             printf("    locks: ");
394             PrintLock(&centry.lock);
395             printf("\n");
396         }
397 #ifdef AFS_64BIT_ENV
398 #ifdef AFS_NT40_ENV
399         printf("    %12I64d bytes  DV %12d  refcnt %5d\n", centry.Length,
400                centry.DataVersion, centry.refCount);
401 #else
402         printf("    %12llu bytes  DV %12d  refcnt %5d\n", centry.Length,
403                centry.DataVersion, centry.refCount);
404 #endif
405 #else
406         printf("    %12d bytes  DV %12d  refcnt %5d\n", centry.Length,
407                centry.DataVersion, centry.refCount);
408 #endif
409         printf("    callback %08x\texpires %u\n", centry.callback,
410                centry.cbExpires);
411         printf("    %d opens\t%d writers\n", centry.opens, centry.writers);
412
413         /* now display states */
414         printf("    ");
415         if (centry.mvstat == 0)
416             printf("normal file");
417         else if (centry.mvstat == 1)
418             printf("mount point");
419         else if (centry.mvstat == 2)
420             printf("volume root");
421         else if (centry.mvstat == 3)
422             printf("directory");
423         else if (centry.mvstat == 4)
424             printf("symlink");
425         else if (centry.mvstat == 5)
426             printf("microsoft dfs link");
427         else if (centry.mvstat == 6)
428             printf("invalid link");
429         else
430             printf("bogus mvstat %d", centry.mvstat);
431         printf("\n    states (0x%x)", centry.states);
432         if (centry.states & 1)
433             printf(", stat'd");
434         if (centry.states & 2)
435             printf(", backup");
436         if (centry.states & 4)
437             printf(", read-only");
438         if (centry.states & 8)
439             printf(", mt pt valid");
440         if (centry.states & 0x10)
441             printf(", pending core");
442         if (centry.states & 0x40)
443             printf(", wait-for-store");
444         if (centry.states & 0x80)
445             printf(", mapped");
446         printf("\n");
447     }
448     return 0;
449 }
450
451 static int
452 PrintCacheEntries(struct rx_connection *aconn, int aint32)
453 {
454     register afs_int32 code;
455     struct AFSDBCacheEntry64 centry64;
456
457     code = RXAFSCB_GetCE64(aconn, 0, &centry64);
458     if (code != RXGEN_OPCODE)
459         return PrintCacheEntries64(aconn, aint32);
460     else
461         return PrintCacheEntries32(aconn, aint32);
462 }
463
464 int
465 CommandProc(struct cmd_syndesc *as, char *arock)
466 {
467     struct rx_connection *conn;
468     register char *hostName;
469     register struct hostent *thp;
470     afs_int32 port;
471     struct rx_securityClass *secobj;
472     int int32p;
473     afs_int32 addr;
474
475     hostName = as->parms[0].items->data;
476     if (as->parms[1].items)
477         port = atoi(as->parms[1].items->data);
478     else
479         port = 7001;
480     thp = hostutil_GetHostByName(hostName);
481     if (!thp) {
482         printf("cmdebug: can't resolve address for host %s.\n", hostName);
483         exit(1);
484     }
485     memcpy(&addr, thp->h_addr, sizeof(afs_int32));
486     secobj = rxnull_NewServerSecurityObject();
487     conn = rx_NewConnection(addr, htons(port), 1, secobj, 0);
488     if (!conn) {
489         printf("cmdebug: failed to create connection for host %s\n",
490                hostName);
491         exit(1);
492     }
493     if (as->parms[5].items) {
494         /* -addrs */
495         PrintInterfaces(conn);
496         return 0;
497     }
498     if (as->parms[6].items) {
499         /* -cache */
500         PrintCacheConfig(conn);
501         return 0;
502     }
503     if (as->parms[2].items)
504         /* -long */
505         int32p = 1;
506     else if (as->parms[3].items)
507         /* -refcounts */
508         int32p = 2;
509     else if (as->parms[4].items)
510         /* -callbacks */
511         int32p = 4;
512     else
513         int32p = 0;
514
515     if (int32p == 0 || int32p == 1)
516         PrintLocks(conn, int32p);
517     if (int32p >= 0 || int32p <= 4)
518         PrintCacheEntries(conn, int32p);
519     return 0;
520 }
521
522 #ifndef AFS_NT40_ENV
523 #include "AFS_component_version_number.c"
524 #endif
525
526 int
527 main(int argc, char **argv)
528 {
529     register struct cmd_syndesc *ts;
530
531 #ifdef  AFS_AIX32_ENV
532     /*
533      * The following signal action for AIX is necessary so that in case of a 
534      * crash (i.e. core is generated) we can include the user's data section 
535      * in the core dump. Unfortunately, by default, only a partial core is
536      * generated which, in many cases, isn't too useful.
537      */
538     struct sigaction nsa;
539
540     sigemptyset(&nsa.sa_mask);
541     nsa.sa_handler = SIG_DFL;
542     nsa.sa_flags = SA_FULLDUMP;
543     sigaction(SIGSEGV, &nsa, NULL);
544 #endif
545
546 #ifdef AFS_NT40_ENV
547     if (afs_winsockInit() < 0) {
548         printf("%s: Couldn't initialize winsock. Exiting...\n", argv[0]);
549         return 1;
550     }
551 #endif
552
553     rx_Init(0);
554
555     ts = cmd_CreateSyntax(NULL, CommandProc, 0, "probe unik server");
556     cmd_AddParm(ts, "-servers", CMD_SINGLE, CMD_REQUIRED, "server machine");
557     cmd_AddParm(ts, "-port", CMD_SINGLE, CMD_OPTIONAL, "IP port");
558     cmd_AddParm(ts, "-long", CMD_FLAG, CMD_OPTIONAL, "print all info");
559     cmd_AddParm(ts, "-refcounts", CMD_FLAG, CMD_OPTIONAL, 
560                  "print only cache entries with positive reference counts");
561     cmd_AddParm(ts, "-callbacks", CMD_FLAG, CMD_OPTIONAL, 
562                  "print only cache entries with callbacks");
563     cmd_AddParm(ts, "-addrs", CMD_FLAG, CMD_OPTIONAL,
564                 "print only host interfaces");
565     cmd_AddParm(ts, "-cache", CMD_FLAG, CMD_OPTIONAL,
566                 "print only cache configuration");
567
568     cmd_Dispatch(argc, argv);
569     exit(0);
570 }