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