Make cmdebug -addrs work on platforms other than Solaris.
[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("$Header$");
14
15
16 #include <sys/types.h>
17 #include <netinet/in.h>
18 #include <sys/socket.h>
19 #include <netdb.h>
20 #include <stdio.h>
21 #ifdef HAVE_STRING_H
22 #include <string.h>
23 #else
24 #ifdef HAVE_STRINGS_H
25 #include <strings.h>
26 #endif
27 #endif
28 #ifdef  AFS_AIX32_ENV
29 #include <signal.h>
30 #endif
31 #include <afs/afscbint.h>
32 #include <afs/cmd.h>
33 #include <rx/rx.h>
34 #include <lock.h>
35 #include <afs/afs_args.h>
36
37 extern struct hostent *hostutil_GetHostByName();
38
39 static PrintCacheConfig(aconn)
40     struct rx_connection *aconn;
41 {
42     struct cacheConfig c;
43     afs_uint32 srv_ver, conflen;
44     int code;
45
46     c.cacheConfig_len = 0;
47     c.cacheConfig_val = NULL;
48     code = RXAFSCB_GetCacheConfig(aconn, 1, &srv_ver, &conflen, &c);
49     if (code) {
50         printf("cmdebug: error checking cache config: %s\n",
51                error_message(code));
52         return 0;
53     }
54
55     if (srv_ver == AFS_CLIENT_RETRIEVAL_FIRST_EDITION) {
56         struct cm_initparams_v1 *c1;
57
58         if (c.cacheConfig_len != sizeof(*c1) / sizeof(afs_uint32)) {
59             printf("cmdebug: configuration data size mismatch (%d != %d)\n",
60                    c.cacheConfig_len, sizeof(*c1) / sizeof(afs_uint32));
61             return 0;
62         }
63
64         c1 = (struct cm_initparams_v1 *) c.cacheConfig_val;
65         printf("Chunk files:   %d\n", c1->nChunkFiles);
66         printf("Stat caches:   %d\n", c1->nStatCaches);
67         printf("Data caches:   %d\n", c1->nDataCaches);
68         printf("Volume caches: %d\n", c1->nVolumeCaches);
69         printf("Chunk size:    %d", c1->otherChunkSize);
70         if (c1->firstChunkSize != c1->otherChunkSize)
71             printf(" (first: %d)", c1->firstChunkSize);
72         printf("\n");
73         printf("Cache size:    %d kB\n", c1->cacheSize);
74         printf("Set time:      %s\n", c1->setTime ? "yes" : "no");
75         printf("Cache type:    %s\n", c1->memCache ? "memory" : "disk");
76     } else {
77         printf("cmdebug: unsupported server version %d\n", srv_ver);
78     }
79 }
80
81 static PrintInterfaces(aconn)
82     struct rx_connection *aconn;
83 {
84     struct interfaceAddr addr;
85     int i, code;
86
87     code = RXAFSCB_WhoAreYou(aconn, &addr);
88     if (code) {
89         printf("cmdebug: error checking interfaces: %s\n", error_message(code));
90         return 0;
91     }
92
93     printf("Host interfaces:\n");
94     for (i=0; i<addr.numberOfInterfaces; i++) {
95         printf("%s", afs_inet_ntoa(htonl(addr.addr_in[i])));
96         if (addr.subnetmask[i])
97             printf(", netmask %s", afs_inet_ntoa(htonl(addr.subnetmask[i])));
98         if (addr.mtu[i])
99             printf(", MTU %d", addr.mtu[i]);
100         printf("\n");
101     }
102
103     return 0;
104 }
105
106 static IsLocked(alock)
107 register struct AFSDBLockDesc *alock; {
108     if (alock->waitStates || alock->exclLocked
109         || alock->numWaiting || alock->readersReading)
110         return 1;
111     return 0;
112 }
113
114 static PrintLock(alock)
115 register struct AFSDBLockDesc *alock; {
116     printf("(");
117     if (alock->waitStates) {
118         if (alock->waitStates & READ_LOCK)
119             printf("reader_waiting");
120         if (alock->waitStates & WRITE_LOCK)
121             printf("writer_waiting");
122         if (alock->waitStates & SHARED_LOCK)
123             printf("upgrade_waiting");
124     }
125     else
126         printf("none_waiting");
127     if (alock->exclLocked) {
128         if (alock->exclLocked & WRITE_LOCK)
129             printf(", write_locked");
130         if (alock->exclLocked & SHARED_LOCK)
131             printf(", upgrade_locked");
132         printf("(pid:%d at:%d)", alock->pid_writer, alock->src_indicator);
133     }
134     if (alock->readersReading)
135         printf(", %d read_locks(pid:%d)", alock->readersReading,alock->pid_last_reader);
136     if (alock->numWaiting) printf(", %d waiters", alock->numWaiting);
137     printf(")");
138     return 0;
139 }
140
141 static PrintLocks(aconn, aint32)
142 int aint32;
143 register struct rx_connection *aconn; {
144     register int i;
145     struct AFSDBLock lock;
146     afs_int32 code;
147
148     for(i=0;i<1000;i++) {
149         code = RXAFSCB_GetLock(aconn, i, &lock);
150         if (code) {
151             if (code == 1) break;
152             /* otherwise we have an unrecognized error */
153             printf("cmdebug: error checking locks: %s\n", error_message(code));
154             return code;
155         }
156         /* here we have the lock information, so display it, perhaps */
157         if (aint32 || IsLocked(&lock.lock)) {
158             printf("Lock %s status: ", lock.name);
159             PrintLock(&lock.lock);
160             printf("\n");
161         }
162     }
163     return 0;
164 }
165
166 struct cell_cache {
167     afs_int32 cellnum;
168     char *cellname;
169     struct cell_cache *next;
170 };
171
172 static char *GetCellName(struct rx_connection *aconn, afs_int32 cellnum)
173 {
174     static int no_getcellbynum;
175     static struct cell_cache *cache;
176     struct cell_cache *tcp;
177     int code;
178     char *cellname;
179     serverList sl;
180
181     if (no_getcellbynum)
182         return NULL;
183
184     for (tcp = cache; tcp; tcp = tcp->next)
185         if (tcp->cellnum == cellnum)
186             return tcp->cellname;
187
188     cellname = NULL;
189     sl.serverList_len = 0;
190     sl.serverList_val = NULL;
191     code = RXAFSCB_GetCellByNum(aconn, cellnum, &cellname, &sl);
192     if (code) {
193         if (code == RXGEN_OPCODE)
194             no_getcellbynum = 1;
195         return NULL;
196     }
197
198     if (sl.serverList_val)
199         free (sl.serverList_val);
200     tcp = malloc(sizeof(struct cell_cache));
201     tcp->next = cache;
202     tcp->cellnum = cellnum;
203     tcp->cellname = cellname;
204     cache = tcp;
205
206     return cellname;
207 }
208
209 static PrintCacheEntries(struct rx_connection *aconn, int aint32)
210 {
211     register int i;
212     register afs_int32 code;
213     struct AFSDBCacheEntry centry;
214     char *cellname;
215
216     for(i=0;i<10000;i++) {
217         code = RXAFSCB_GetCE(aconn, i, &centry);
218         if (code) {
219             if (code == 1) break;
220             printf("cmdebug: failed to get cache entry %d (%s)\n", i,
221                    error_message(code));
222             return code;
223         }
224
225         if (centry.addr == 0) {
226             /* PS output */
227             printf("Proc %4d sleeping at %08x, pri %3d\n",
228                    centry.netFid.Vnode, centry.netFid.Volume, centry.netFid.Unique-25);
229             continue;
230         }
231
232         if (!aint32 && !IsLocked(&centry.lock)) continue;
233
234         /* otherwise print this entry */
235         printf("** Cache entry @ 0x%08x for %d.%d.%d.%d", centry.addr,
236                centry.cell, centry.netFid.Volume, centry.netFid.Vnode,
237                centry.netFid.Unique);
238
239         cellname = GetCellName(aconn, centry.cell);
240         if (cellname)
241             printf(" [%s]\n", cellname);
242         else
243             printf("\n");
244
245         if (IsLocked(&centry.lock)) {
246             printf("    locks: ");
247             PrintLock(&centry.lock);
248             printf("\n");
249         }
250         printf("    %d bytes\tDV %d refcnt %d\n", centry.Length, centry.DataVersion, centry.refCount);
251         printf("    callback %08x\texpires %u\n", centry.callback, centry.cbExpires);
252         printf("    %d opens\t%d writers\n", centry.opens, centry.writers);
253
254         /* now display states */
255         printf("    ");
256         if (centry.mvstat == 0) printf("normal file");
257         else if (centry.mvstat == 1) printf("mount point");
258         else if (centry.mvstat == 2) printf("volume root");
259         else printf("bogus mvstat %d", centry.mvstat);
260         printf("\n    states (0x%x)", centry.states);
261         if (centry.states & 1) printf(", stat'd");
262         if (centry.states & 2) printf(", backup");
263         if (centry.states & 4) printf(", read-only");
264         if (centry.states & 8) printf(", mt pt valid");
265         if (centry.states & 0x10) printf(", pending core");
266         if (centry.states & 0x40) printf(", wait-for-store");
267         if (centry.states & 0x80) printf(", mapped");
268         printf("\n");
269     }
270     return 0;
271 }
272
273 static CommandProc(as)
274 struct cmd_syndesc *as; {
275     struct rx_connection *conn;
276     register char *hostName;
277     register struct hostent *thp;
278     afs_int32 port;
279     struct rx_securityClass *secobj;
280     int int32p;
281     afs_int32 addr;
282
283     hostName = as->parms[0].items->data;
284     if (as->parms[1].items)
285         port = atoi(as->parms[1].items->data);
286     else
287         port = 7001;
288     thp = hostutil_GetHostByName(hostName);
289     if (!thp) {
290         printf("cmdebug: can't resolve address for host %s.\n", hostName);
291         exit(1);
292     }
293     memcpy(&addr, thp->h_addr, sizeof(afs_int32));
294     secobj = rxnull_NewServerSecurityObject();
295     conn = rx_NewConnection(addr, htons(port), 1, secobj, 0);
296     if (!conn) {
297         printf("cmdebug: failed to create connection for host %s\n", hostName);
298         exit(1);
299     }
300     if (as->parms[3].items) {
301         /* -addrs */
302         PrintInterfaces(conn);
303         return 0;
304     }
305     if (as->parms[4].items) {
306         /* -cache */
307         PrintCacheConfig(conn);
308         return 0;
309     }
310     if (as->parms[2].items) int32p = 1;
311     else int32p = 0;
312     PrintLocks(conn, int32p);
313     PrintCacheEntries(conn, int32p);
314     return 0;
315 }
316
317 #include "AFS_component_version_number.c"
318
319 main(argc, argv)
320 int argc;
321 char **argv; {
322     register struct cmd_syndesc *ts;
323
324 #ifdef  AFS_AIX32_ENV
325     /*
326      * The following signal action for AIX is necessary so that in case of a 
327      * crash (i.e. core is generated) we can include the user's data section 
328      * in the core dump. Unfortunately, by default, only a partial core is
329      * generated which, in many cases, isn't too useful.
330      */
331     struct sigaction nsa;
332     
333     sigemptyset(&nsa.sa_mask);
334     nsa.sa_handler = SIG_DFL;
335     nsa.sa_flags = SA_FULLDUMP;
336     sigaction(SIGSEGV, &nsa, NULL);
337 #endif
338     rx_Init(0);
339
340     ts = cmd_CreateSyntax(NULL, CommandProc, 0, "probe unik server");
341     cmd_AddParm(ts, "-servers", CMD_SINGLE, CMD_REQUIRED, "server machine");
342     cmd_AddParm(ts, "-port", CMD_SINGLE, CMD_OPTIONAL, "IP port");
343     cmd_AddParm(ts, "-long", CMD_FLAG, CMD_OPTIONAL, "print all info");
344     cmd_AddParm(ts, "-addrs", CMD_FLAG, CMD_OPTIONAL, "print only host interfaces");
345     cmd_AddParm(ts, "-cache", CMD_FLAG, CMD_OPTIONAL, "print only cache configuration");
346
347     cmd_Dispatch(argc, argv);
348     exit(0);
349 }