b72ad85cfa238c03a2a9f5d0346b56d05e57b4d6
[openafs.git] / src / ubik / udebug.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 #include <sys/types.h>
17 #include <stdlib.h>
18 #ifdef HAVE_STRING_H
19 #include <string.h>
20 #else
21 #ifdef HAVE_STRINGS_H
22 #include <strings.h>
23 #endif
24 #endif
25 #ifdef AFS_NT40_ENV
26 #include <winsock2.h>
27 #else
28 #include <sys/file.h>
29 #include <sys/param.h>
30 #include <netinet/in.h>
31 #include <netdb.h>
32 #endif
33 #ifdef HAVE_UNISTD_H
34 #include <unistd.h>
35 #endif
36 #include <signal.h>
37 #include <time.h>
38
39 #include <lock.h>
40 #include <rx/xdr.h>
41 #include <rx/rx.h>
42 #include <afs/cmd.h>
43
44 #define UBIK_INTERNALS
45 #include "ubik.h"
46 #include "ubik_int.h"
47
48 /* needed by Irix. Include a header to get it, or leave it alone. */
49 extern struct hostent *hostutil_GetHostByName();
50
51 static short
52 PortNumber(register char *aport)
53 {
54     register int tc;
55     register afs_int32 total;
56
57     total = 0;
58     while ((tc = *aport++)) {
59         if (tc < '0' || tc > '9')
60             return -1;          /* bad port number */
61         total *= 10;
62         total += tc - (int)'0';
63     }
64     return (total);
65 }
66
67 static short
68 PortName(char *aname)
69 {
70     struct servent *ts;
71     int len;
72
73     ts = getservbyname(aname, NULL);
74
75     if (ts)
76         return ntohs(ts->s_port);       /* returns it in host byte order */
77
78     len = strlen(aname);
79     if (strncmp(aname, "vlserver", len) == 0) {
80         return 7003;
81     } else if (strncmp(aname, "ptserver", len) == 0) {
82         return 7002;
83     } else if (strncmp(aname, "kaserver", len) == 0) {
84         return 7004;
85     } else if (strncmp(aname, "buserver", len) == 0) {
86         return 7021;
87     }
88     return (-1);
89 }
90
91 static int
92 CommandProc(struct cmd_syndesc *as, char *arock)
93 {
94     char *hostName, *portName, *times;
95     afs_int32 hostAddr;
96     struct in_addr inhostAddr;
97     register afs_int32 i, j, code;
98     short port;
99     int int32p;
100     time_t now, diff, newtime;
101     struct hostent *th;
102     struct rx_connection *tconn;
103     struct rx_securityClass *sc;
104     struct ubik_debug udebug;
105     struct ubik_sdebug usdebug;
106     int oldServer = 0;          /* are we talking to a pre 3.5 server? */
107     afs_int32 isClone = 0;
108
109     int32p = (as->parms[2].items ? 1 : 0);
110
111     if (as->parms[0].items)
112         hostName = as->parms[0].items->data;
113     else
114         hostName = NULL;
115
116     if (as->parms[1].items)
117         portName = as->parms[1].items->data;
118     else
119         portName = NULL;
120
121     /* lookup host */
122     if (hostName) {
123         th = hostutil_GetHostByName(hostName);
124         if (!th) {
125             printf("udebug: host %s not found in host table\n", hostName);
126             exit(1);
127         }
128         memcpy(&hostAddr, th->h_addr, sizeof(afs_int32));
129     } else
130         hostAddr = htonl(0x7f000001);   /* IP localhost */
131
132     if (!portName)
133         port = htons(3000);     /* default */
134     else {
135         port = PortNumber(portName);
136         if (port < 0)
137             port = PortName(portName);
138         if (port < 0) {
139             printf("udebug: can't resolve port name %s\n", portName);
140             exit(1);
141         }
142         port = htons(port);
143     }
144
145     rx_Init(0);
146     sc = rxnull_NewClientSecurityObject();
147     tconn = rx_NewConnection(hostAddr, port, VOTE_SERVICE_ID, sc, 0);
148
149     /* now do the main call */
150     code = VOTE_XDebug(tconn, &udebug, &isClone);
151     if (code)
152         code = VOTE_Debug(tconn, &udebug);
153     if (code == RXGEN_OPCODE) {
154         oldServer = 1;          /* talking to a pre 3.5 server */
155         memset(&udebug, 0, sizeof(udebug));
156         code = VOTE_DebugOld(tconn, &udebug);
157     }
158
159     if (code) {
160         printf("return code %d from VOTE_Debug\n", code);
161         exit(0);
162     }
163     now = time(0);
164
165     /* now print the main info */
166     times = ctime((time_t *) & udebug.now);
167     times[24] = 0;
168     inhostAddr.s_addr = hostAddr;
169     if (!oldServer) {
170         printf("Host's addresses are: ");
171         for (j = 0; udebug.interfaceAddr[j] && (j < UBIK_MAX_INTERFACE_ADDR);
172              j++)
173             printf("%s ", afs_inet_ntoa(htonl(udebug.interfaceAddr[j])));
174         printf("\n");
175     }
176     printf("Host's %s time is %s\n", inet_ntoa(inhostAddr), times);
177
178     times = ctime(&now);
179     times[24] = 0;
180     diff = now - udebug.now;
181     printf("Local time is %s (time differential %d secs)\n", times, diff);
182     if (abs(diff) >= MAXSKEW)
183         printf("****clock may be bad\n");
184
185     /* UBIK skips the voting if 1 server - so we fudge it here */
186     if (udebug.amSyncSite && (udebug.nServers == 1)) {
187         udebug.lastYesHost = hostAddr;
188         udebug.lastYesTime = udebug.now;
189         udebug.lastYesState = 1;
190         udebug.lastYesClaim = udebug.now;
191         udebug.syncVersion.epoch = udebug.localVersion.epoch;
192         udebug.syncVersion.counter = udebug.localVersion.counter;
193     }
194
195     /* sockaddr is always in net-order */
196     if (udebug.lastYesHost == 0xffffffff) {
197         printf("Last yes vote not cast yet \n");
198     } else {
199         inhostAddr.s_addr = htonl(udebug.lastYesHost);
200         diff = udebug.now - udebug.lastYesTime;
201         printf("Last yes vote for %s was %d secs ago (%ssync site); \n",
202                inet_ntoa(inhostAddr), diff,
203                ((udebug.lastYesState) ? "" : "not "));
204
205         diff = udebug.now - udebug.lastYesClaim;
206         newtime = now - diff;
207         times = ctime(&newtime);
208         times[24] = 0;
209         printf("Last vote started %d secs ago (at %s)\n", diff, times);
210     }
211
212     printf("Local db version is %d.%d\n", udebug.localVersion.epoch,
213            udebug.localVersion.counter);
214
215     if (udebug.amSyncSite) {
216         if (udebug.syncSiteUntil == 0x7fffffff) {
217             printf("I am sync site forever (%d server%s)\n", udebug.nServers,
218                    ((udebug.nServers > 1) ? "s" : ""));
219         } else {
220             diff = udebug.syncSiteUntil - udebug.now;
221             newtime = now + diff;
222             times = ctime(&newtime);
223             times[24] = 0;
224             printf
225                 ("I am sync site until %d secs from now (at %s) (%d server%s)\n",
226                  diff, times, udebug.nServers,
227                  ((udebug.nServers > 1) ? "s" : ""));
228         }
229         printf("Recovery state %x\n", udebug.recoveryState);
230         if (udebug.activeWrite) {
231             printf("I am currently managing write trans %d.%d\n",
232                    udebug.epochTime, udebug.tidCounter);
233         }
234     } else {
235         if (isClone)
236             printf("I am a clone and never can become sync site\n");
237         else
238             printf("I am not sync site\n");
239         inhostAddr.s_addr = htonl(udebug.lowestHost);
240         diff = udebug.now - udebug.lowestTime;
241         printf("Lowest host %s was set %d secs ago\n", inet_ntoa(inhostAddr),
242                diff);
243
244         inhostAddr.s_addr = htonl(udebug.syncHost);
245         diff = udebug.now - udebug.syncTime;
246         printf("Sync host %s was set %d secs ago\n", inet_ntoa(inhostAddr),
247                diff);
248     }
249
250     printf("Sync site's db version is %d.%d\n", udebug.syncVersion.epoch,
251            udebug.syncVersion.counter);
252     printf("%d locked pages, %d of them for write\n", udebug.lockedPages,
253            udebug.writeLockedPages);
254
255     if (udebug.anyReadLocks)
256         printf("There are read locks held\n");
257     if (udebug.anyWriteLocks)
258         printf("There are write locks held\n");
259
260     if (udebug.currentTrans) {
261         if (udebug.writeTrans)
262             printf("There is an active write transaction\n");
263         else
264             printf("There is at least one active read transaction\n");
265         printf("Transaction tid is %d.%d\n", udebug.syncTid.epoch,
266                udebug.syncTid.counter);
267     }
268     if (udebug.epochTime) {
269         diff = udebug.now - udebug.epochTime;
270         newtime = now - diff;
271         times = ctime(&newtime);
272         times[24] = 0;
273         printf
274             ("Last time a new db version was labelled was:\n\t %d secs ago (at %s)\n",
275              diff, times);
276     }
277
278     if (int32p || udebug.amSyncSite) {
279         /* now do the subcalls */
280         for (i = 0;; i++) {
281             isClone = 0;
282             code = VOTE_XSDebug(tconn, i, &usdebug, &isClone);
283             if (code < 0) {
284                 if (oldServer) {        /* pre 3.5 server */
285                     memset(&usdebug, 0, sizeof(usdebug));
286                     code = VOTE_SDebugOld(tconn, i, &usdebug);
287                 } else
288                     code = VOTE_SDebug(tconn, i, &usdebug);
289             }
290             if (code > 0)
291                 break;          /* done */
292             if (code < 0) {
293                 printf("error code %d from VOTE_SDebug\n", code);
294                 break;
295             }
296             inhostAddr.s_addr = htonl(usdebug.addr);
297             /* otherwise print the structure */
298             printf("\nServer (%s", afs_inet_ntoa(htonl(usdebug.addr)));
299             for (j = 0;
300                  ((usdebug.altAddr[j]) && (j < UBIK_MAX_INTERFACE_ADDR - 1));
301                  j++)
302                 printf(" %s", afs_inet_ntoa(htonl(usdebug.altAddr[j])));
303             printf("): (db %d.%d)", usdebug.remoteVersion.epoch,
304                    usdebug.remoteVersion.counter);
305             if (isClone)
306                 printf("    is only a clone!");
307             printf("\n");
308
309             if (usdebug.lastVoteTime == 0) {
310                 printf("    last vote never rcvd \n");
311             } else {
312                 diff = udebug.now - usdebug.lastVoteTime;
313                 newtime = now - diff;
314                 times = ctime(&newtime);
315                 times[24] = 0;
316                 printf("    last vote rcvd %d secs ago (at %s),\n", diff,
317                        times);
318             }
319
320             if (usdebug.lastBeaconSent == 0) {
321                 printf("    last beacon never sent \n");
322             } else {
323                 diff = udebug.now - usdebug.lastBeaconSent;
324                 newtime = now - diff;
325                 times = ctime(&newtime);
326                 times[24] = 0;
327                 printf
328                     ("    last beacon sent %d secs ago (at %s), last vote was %s\n",
329                      diff, times, ((usdebug.lastVote) ? "yes" : "no"));
330             }
331
332             printf("    dbcurrent=%d, up=%d beaconSince=%d\n",
333                    usdebug.currentDB, usdebug.up, usdebug.beaconSinceDown);
334         }
335     }
336     return (0);
337 }
338
339 #include "AFS_component_version_number.c"
340
341 int
342 main(int argc, char **argv)
343 {
344     struct cmd_syndesc *ts;
345
346 #ifdef  AFS_AIX32_ENV
347     /*
348      * The following signal action for AIX is necessary so that in case of a 
349      * crash (i.e. core is generated) we can include the user's data section 
350      * in the core dump. Unfortunately, by default, only a partial core is
351      * generated which, in many cases, isn't too useful.
352      */
353     struct sigaction nsa;
354
355     sigemptyset(&nsa.sa_mask);
356     nsa.sa_handler = SIG_DFL;
357     nsa.sa_flags = SA_FULLDUMP;
358     sigaction(SIGSEGV, &nsa, NULL);
359 #endif
360     ts = cmd_CreateSyntax(NULL, CommandProc, 0, "probe ubik server");
361     cmd_AddParm(ts, "-server", CMD_SINGLE, CMD_REQUIRED, "server machine");
362     cmd_AddParm(ts, "-port", CMD_SINGLE, CMD_OPTIONAL, "IP port");
363     cmd_AddParm(ts, "-long", CMD_FLAG, CMD_OPTIONAL, "print all info");
364
365     cmd_Dispatch(argc, argv);
366     exit(0);
367 }