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