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