cmdebug-no-zero-pad-output-20060119
[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("    %12d bytes  DV %12d  refcnt %5d\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 #ifdef AFS_NT40_ENV
403         printf("    %12I64d bytes  DV %12d  refcnt %5d\n", centry.Length,
404                centry.DataVersion, centry.refCount);
405 #else
406         printf("    %12llu bytes  DV %12d  refcnt %5d\n", centry.Length,
407                centry.DataVersion, centry.refCount);
408 #endif
409 #else
410         printf("    %12d bytes  DV %12d  refcnt %5d\n", centry.Length,
411                centry.DataVersion, centry.refCount);
412 #endif
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     register 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 int
469 CommandProc(struct cmd_syndesc *as, char *arock)
470 {
471     struct rx_connection *conn;
472     register char *hostName;
473     register struct hostent *thp;
474     afs_int32 port;
475     struct rx_securityClass *secobj;
476     int int32p;
477     afs_int32 addr;
478
479     hostName = as->parms[0].items->data;
480     if (as->parms[1].items)
481         port = atoi(as->parms[1].items->data);
482     else
483         port = 7001;
484     thp = hostutil_GetHostByName(hostName);
485     if (!thp) {
486         printf("cmdebug: can't resolve address for host %s.\n", hostName);
487         exit(1);
488     }
489     memcpy(&addr, thp->h_addr, sizeof(afs_int32));
490     secobj = rxnull_NewServerSecurityObject();
491     conn = rx_NewConnection(addr, htons(port), 1, secobj, 0);
492     if (!conn) {
493         printf("cmdebug: failed to create connection for host %s\n",
494                hostName);
495         exit(1);
496     }
497     if (as->parms[5].items) {
498         /* -addrs */
499         PrintInterfaces(conn);
500         return 0;
501     }
502     if (as->parms[6].items) {
503         /* -cache */
504         PrintCacheConfig(conn);
505         return 0;
506     }
507     if (as->parms[2].items)
508         /* -long */
509         int32p = 1;
510     else if (as->parms[3].items)
511         /* -refcounts */
512         int32p = 2;
513     else if (as->parms[4].items)
514         /* -callbacks */
515         int32p = 4;
516     else
517         int32p = 0;
518
519     if (int32p == 0 || int32p == 1)
520         PrintLocks(conn, int32p);
521     if (int32p >= 0 || int32p <= 4)
522         PrintCacheEntries(conn, int32p);
523     return 0;
524 }
525
526 #ifndef AFS_NT40_ENV
527 #include "AFS_component_version_number.c"
528 #endif
529
530 int
531 main(int argc, char **argv)
532 {
533     register struct cmd_syndesc *ts;
534
535 #ifdef  AFS_AIX32_ENV
536     /*
537      * The following signal action for AIX is necessary so that in case of a 
538      * crash (i.e. core is generated) we can include the user's data section 
539      * in the core dump. Unfortunately, by default, only a partial core is
540      * generated which, in many cases, isn't too useful.
541      */
542     struct sigaction nsa;
543
544     sigemptyset(&nsa.sa_mask);
545     nsa.sa_handler = SIG_DFL;
546     nsa.sa_flags = SA_FULLDUMP;
547     sigaction(SIGSEGV, &nsa, NULL);
548 #endif
549
550 #ifdef AFS_NT40_ENV
551     if (afs_winsockInit() < 0) {
552         printf("%s: Couldn't initialize winsock. Exiting...\n", argv[0]);
553         return 1;
554     }
555 #endif
556
557     rx_Init(0);
558
559     ts = cmd_CreateSyntax(NULL, CommandProc, 0, "probe unik server");
560     cmd_AddParm(ts, "-servers", CMD_SINGLE, CMD_REQUIRED, "server machine");
561     cmd_AddParm(ts, "-port", CMD_SINGLE, CMD_OPTIONAL, "IP port");
562     cmd_AddParm(ts, "-long", CMD_FLAG, CMD_OPTIONAL, "print all info");
563     cmd_AddParm(ts, "-refcounts", CMD_FLAG, CMD_OPTIONAL, 
564                  "print only cache entries with positive reference counts");
565     cmd_AddParm(ts, "-callbacks", CMD_FLAG, CMD_OPTIONAL, 
566                  "print only cache entries with callbacks");
567     cmd_AddParm(ts, "-addrs", CMD_FLAG, CMD_OPTIONAL,
568                 "print only host interfaces");
569     cmd_AddParm(ts, "-cache", CMD_FLAG, CMD_OPTIONAL,
570                 "print only cache configuration");
571
572     cmd_Dispatch(argc, argv);
573     exit(0);
574 }