Commit | Line | Data |
---|---|---|
1b69205a | 1 | /* |
8b8a47ba | 2 | * Copyright (c) 1985 Regents of the University of California. |
26b5a830 KB |
3 | * All rights reserved. |
4 | * | |
5 | * Redistribution and use in source and binary forms are permitted | |
b8c620d6 KB |
6 | * provided that the above copyright notice and this paragraph are |
7 | * duplicated in all such forms and that any documentation, | |
8 | * advertising materials, and other materials related to such | |
9 | * distribution and use acknowledge that the software was developed | |
10 | * by the University of California, Berkeley. The name of the | |
11 | * University may not be used to endorse or promote products derived | |
12 | * from this software without specific prior written permission. | |
13 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR | |
14 | * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED | |
15 | * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. | |
1b69205a RG |
16 | */ |
17 | ||
18 | #ifndef lint | |
19 | char copyright[] = | |
8b8a47ba | 20 | "@(#) Copyright (c) 1985 Regents of the University of California.\n\ |
1b69205a | 21 | All rights reserved.\n"; |
26b5a830 | 22 | #endif /* not lint */ |
1b69205a RG |
23 | |
24 | #ifndef lint | |
7abf8d65 | 25 | static char sccsid[] = "@(#)timed.c 2.16 (Berkeley) %G%"; |
26b5a830 | 26 | #endif /* not lint */ |
1b69205a RG |
27 | |
28 | #include "globals.h" | |
29 | #define TSPTYPES | |
30 | #include <protocols/timed.h> | |
31 | #include <net/if.h> | |
32 | #include <sys/file.h> | |
33 | #include <sys/ioctl.h> | |
34 | #include <setjmp.h> | |
383be14d | 35 | #include "pathnames.h" |
1b69205a | 36 | |
1b69205a RG |
37 | int id; |
38 | int trace; | |
19f1ff0f | 39 | int sock, sock_raw = -1; |
75d5ce8a | 40 | int status = 0; |
1b69205a RG |
41 | int backoff; |
42 | int slvcount; /* no. of slaves controlled by master */ | |
43 | int machup; | |
44 | u_short sequence; /* sequence number */ | |
45 | long delay1; | |
46 | long delay2; | |
77491c98 | 47 | long random(); |
964c88f5 | 48 | char hostname[MAXHOSTNAMELEN]; |
1b69205a | 49 | struct host hp[NHOSTS]; |
383be14d | 50 | char tracefile[] = _PATH_TIMEDLOG; |
1b69205a RG |
51 | FILE *fd; |
52 | jmp_buf jmpenv; | |
75d5ce8a | 53 | struct netinfo *nettab = NULL; |
9a957f87 JB |
54 | int nslavenets; /* Number of networks were I could be a slave */ |
55 | int nmasternets; /* Number of networks were I could be a master */ | |
56 | int nignorednets; /* Number of ignored networks */ | |
57 | int nnets; /* Number of networks I am connected to */ | |
58 | struct netinfo *slavenet; | |
59 | struct netinfo *firstslavenet(); | |
60 | int Mflag; | |
a3f2fd3a JB |
61 | int justquit = 0; |
62 | ||
5c0a9ec2 JB |
63 | struct nets { |
64 | char *name; | |
65 | long net; | |
66 | struct nets *next; | |
67 | } *nets = (struct nets *)0; | |
1b69205a RG |
68 | |
69 | /* | |
70 | * The timedaemons synchronize the clocks of hosts in a local area network. | |
71 | * One daemon runs as master, all the others as slaves. The master | |
72 | * performs the task of computing clock differences and sends correction | |
73 | * values to the slaves. | |
74 | * Slaves start an election to choose a new master when the latter disappears | |
75 | * because of a machine crash, network partition, or when killed. | |
76 | * A resolution protocol is used to kill all but one of the masters | |
77 | * that happen to exist in segments of a partitioned network when the | |
78 | * network partition is fixed. | |
79 | * | |
80 | * Authors: Riccardo Gusella & Stefano Zatti | |
1b69205a RG |
81 | */ |
82 | ||
83 | main(argc, argv) | |
84 | int argc; | |
85 | char **argv; | |
86 | { | |
87 | int on; | |
88 | int ret; | |
89 | long seed; | |
5c0a9ec2 | 90 | int nflag, iflag; |
1b69205a RG |
91 | struct timeval time; |
92 | struct servent *srvp; | |
1b69205a | 93 | long casual(); |
1b69205a | 94 | char *date(); |
964c88f5 | 95 | int n; |
75d5ce8a | 96 | int flag; |
964c88f5 JB |
97 | char buf[BUFSIZ]; |
98 | struct ifconf ifc; | |
99 | struct ifreq ifreq, *ifr; | |
75d5ce8a JB |
100 | register struct netinfo *ntp; |
101 | struct netinfo *ntip; | |
9a957f87 | 102 | struct netinfo *savefromnet; |
75d5ce8a JB |
103 | struct sockaddr_in server; |
104 | u_short port; | |
77491c98 | 105 | uid_t getuid(); |
9a957f87 | 106 | |
75d5ce8a JB |
107 | #ifdef lint |
108 | ntip = NULL; | |
109 | #endif | |
1b69205a | 110 | |
319813b5 | 111 | Mflag = 0; |
1b69205a RG |
112 | on = 1; |
113 | backoff = 1; | |
1b69205a RG |
114 | trace = OFF; |
115 | nflag = OFF; | |
5c0a9ec2 | 116 | iflag = OFF; |
a3f2fd3a | 117 | openlog("timed", LOG_CONS|LOG_PID, LOG_DAEMON); |
1b69205a RG |
118 | |
119 | if (getuid() != 0) { | |
964c88f5 | 120 | fprintf(stderr, "Timed: not superuser\n"); |
1b69205a RG |
121 | exit(1); |
122 | } | |
123 | ||
124 | while (--argc > 0 && **++argv == '-') { | |
125 | (*argv)++; | |
126 | do { | |
127 | switch (**argv) { | |
128 | ||
129 | case 'M': | |
319813b5 | 130 | Mflag = 1; |
1b69205a RG |
131 | break; |
132 | case 't': | |
133 | trace = ON; | |
1b69205a RG |
134 | break; |
135 | case 'n': | |
136 | argc--, argv++; | |
5c0a9ec2 JB |
137 | if (iflag) { |
138 | fprintf(stderr, | |
139 | "timed: -i and -n make no sense together\n"); | |
140 | } else { | |
141 | nflag = ON; | |
77491c98 | 142 | addnetname(*argv); |
5c0a9ec2 JB |
143 | } |
144 | while (*(++(*argv)+1)) ; | |
145 | break; | |
146 | case 'i': | |
147 | argc--, argv++; | |
148 | if (nflag) { | |
149 | fprintf(stderr, | |
150 | "timed: -i and -n make no sense together\n"); | |
151 | } else { | |
152 | iflag = ON; | |
77491c98 | 153 | addnetname(*argv); |
5c0a9ec2 | 154 | } |
1b69205a RG |
155 | while (*(++(*argv)+1)) ; |
156 | break; | |
157 | default: | |
158 | fprintf(stderr, "timed: -%c: unknown option\n", | |
159 | **argv); | |
160 | break; | |
161 | } | |
162 | } while (*++(*argv)); | |
163 | } | |
164 | ||
964c88f5 | 165 | if (trace == ON) { |
75d5ce8a JB |
166 | fd = fopen(tracefile, "w"); |
167 | setlinebuf(fd); | |
964c88f5 JB |
168 | fprintf(fd, "Tracing started on: %s\n\n", |
169 | date()); | |
964c88f5 | 170 | } |
964c88f5 | 171 | |
1b69205a RG |
172 | srvp = getservbyname("timed", "udp"); |
173 | if (srvp == 0) { | |
964c88f5 | 174 | syslog(LOG_CRIT, "unknown service 'timed/udp'"); |
1b69205a RG |
175 | exit(1); |
176 | } | |
75d5ce8a | 177 | port = srvp->s_port; |
1b69205a RG |
178 | server.sin_port = srvp->s_port; |
179 | server.sin_family = AF_INET; | |
180 | sock = socket(AF_INET, SOCK_DGRAM, 0); | |
181 | if (sock < 0) { | |
964c88f5 | 182 | syslog(LOG_ERR, "socket: %m"); |
1b69205a RG |
183 | exit(1); |
184 | } | |
185 | if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char *)&on, | |
186 | sizeof(on)) < 0) { | |
964c88f5 | 187 | syslog(LOG_ERR, "setsockopt: %m"); |
1b69205a RG |
188 | exit(1); |
189 | } | |
190 | if (bind(sock, &server, sizeof(server))) { | |
191 | if (errno == EADDRINUSE) | |
964c88f5 | 192 | syslog(LOG_ERR, "server already running"); |
1b69205a | 193 | else |
964c88f5 | 194 | syslog(LOG_ERR, "bind: %m"); |
1b69205a RG |
195 | exit(1); |
196 | } | |
197 | ||
198 | /* choose a unique seed for random number generation */ | |
199 | (void)gettimeofday(&time, (struct timezone *)0); | |
200 | seed = time.tv_sec + time.tv_usec; | |
201 | srandom(seed); | |
202 | ||
03b1f474 | 203 | sequence = random(); /* initial seq number */ |
1b69205a RG |
204 | |
205 | /* rounds kernel variable time to multiple of 5 ms. */ | |
206 | time.tv_sec = 0; | |
207 | time.tv_usec = -((time.tv_usec/1000) % 5) * 1000; | |
208 | (void)adjtime(&time, (struct timeval *)0); | |
209 | ||
210 | id = getpid(); | |
211 | ||
212 | if (gethostname(hostname, sizeof(hostname) - 1) < 0) { | |
964c88f5 | 213 | syslog(LOG_ERR, "gethostname: %m"); |
1b69205a RG |
214 | exit(1); |
215 | } | |
216 | hp[0].name = hostname; | |
217 | ||
5c0a9ec2 JB |
218 | if (nflag || iflag) { |
219 | struct netent *getnetent(); | |
220 | struct netent *n; | |
221 | struct nets *np; | |
222 | for ( np = nets ; np ; np = np->next) { | |
223 | n = getnetbyname(np->name); | |
224 | if (n == NULL) { | |
225 | syslog(LOG_ERR, "getnetbyname: unknown net %s", | |
226 | np->name); | |
227 | exit(1); | |
228 | } | |
229 | np->net = n->n_net; | |
1b69205a | 230 | } |
964c88f5 JB |
231 | } |
232 | ifc.ifc_len = sizeof(buf); | |
233 | ifc.ifc_buf = buf; | |
77491c98 | 234 | if (ioctl(sock, SIOCGIFCONF, (char *)&ifc) < 0) { |
964c88f5 JB |
235 | syslog(LOG_ERR, "get interface configuration: %m"); |
236 | exit(1); | |
237 | } | |
75d5ce8a JB |
238 | n = ifc.ifc_len/sizeof(struct ifreq); |
239 | ntp = NULL; | |
240 | for (ifr = ifc.ifc_req; n > 0; n--, ifr++) { | |
241 | if (ifr->ifr_addr.sa_family != AF_INET) | |
242 | continue; | |
964c88f5 | 243 | ifreq = *ifr; |
75d5ce8a JB |
244 | if (ntp == NULL) |
245 | ntp = (struct netinfo *)malloc(sizeof(struct netinfo)); | |
246 | ntp->my_addr = | |
247 | ((struct sockaddr_in *)&ifreq.ifr_addr)->sin_addr; | |
77491c98 | 248 | if (ioctl(sock, SIOCGIFFLAGS, |
964c88f5 JB |
249 | (char *)&ifreq) < 0) { |
250 | syslog(LOG_ERR, "get interface flags: %m"); | |
251 | continue; | |
1b69205a | 252 | } |
964c88f5 | 253 | if ((ifreq.ifr_flags & IFF_UP) == 0 || |
75d5ce8a JB |
254 | ((ifreq.ifr_flags & IFF_BROADCAST) == 0 && |
255 | (ifreq.ifr_flags & IFF_POINTOPOINT) == 0)) { | |
964c88f5 | 256 | continue; |
1b69205a | 257 | } |
75d5ce8a JB |
258 | if (ifreq.ifr_flags & IFF_BROADCAST) |
259 | flag = 1; | |
260 | else | |
261 | flag = 0; | |
77491c98 | 262 | if (ioctl(sock, SIOCGIFNETMASK, |
964c88f5 | 263 | (char *)&ifreq) < 0) { |
75d5ce8a | 264 | syslog(LOG_ERR, "get netmask: %m"); |
964c88f5 JB |
265 | continue; |
266 | } | |
75d5ce8a | 267 | ntp->mask = ((struct sockaddr_in *) |
964c88f5 | 268 | &ifreq.ifr_addr)->sin_addr.s_addr; |
75d5ce8a | 269 | if (flag) { |
77491c98 | 270 | if (ioctl(sock, SIOCGIFBRDADDR, |
75d5ce8a JB |
271 | (char *)&ifreq) < 0) { |
272 | syslog(LOG_ERR, "get broadaddr: %m"); | |
273 | continue; | |
274 | } | |
275 | ntp->dest_addr = *(struct sockaddr_in *)&ifreq.ifr_broadaddr; | |
276 | } else { | |
77491c98 | 277 | if (ioctl(sock, SIOCGIFDSTADDR, |
75d5ce8a JB |
278 | (char *)&ifreq) < 0) { |
279 | syslog(LOG_ERR, "get destaddr: %m"); | |
280 | continue; | |
281 | } | |
282 | ntp->dest_addr = *(struct sockaddr_in *)&ifreq.ifr_dstaddr; | |
964c88f5 | 283 | } |
75d5ce8a | 284 | ntp->dest_addr.sin_port = port; |
5c0a9ec2 | 285 | if (nflag || iflag) { |
964c88f5 | 286 | u_long addr, mask; |
5c0a9ec2 | 287 | struct nets *n; |
964c88f5 | 288 | |
75d5ce8a JB |
289 | addr = ntohl(ntp->dest_addr.sin_addr.s_addr); |
290 | mask = ntohl(ntp->mask); | |
964c88f5 JB |
291 | while ((mask & 1) == 0) { |
292 | addr >>= 1; | |
293 | mask >>= 1; | |
1b69205a | 294 | } |
5c0a9ec2 JB |
295 | for (n = nets ; n ; n = n->next) |
296 | if (addr == n->net) | |
297 | break; | |
298 | if (nflag && !n || iflag && n) | |
1b69205a | 299 | continue; |
1b69205a | 300 | } |
75d5ce8a JB |
301 | ntp->net = ntp->mask & ntp->dest_addr.sin_addr.s_addr; |
302 | ntp->next = NULL; | |
303 | if (nettab == NULL) { | |
304 | nettab = ntp; | |
305 | } else { | |
306 | ntip->next = ntp; | |
307 | } | |
308 | ntip = ntp; | |
309 | ntp = NULL; | |
964c88f5 | 310 | } |
75d5ce8a JB |
311 | if (ntp) |
312 | (void) free((char *)ntp); | |
313 | if (nettab == NULL) { | |
964c88f5 JB |
314 | syslog(LOG_ERR, "No network usable"); |
315 | exit(1); | |
1b69205a RG |
316 | } |
317 | ||
9a957f87 JB |
318 | for (ntp = nettab; ntp != NULL; ntp = ntp->next) |
319 | lookformaster(ntp); | |
320 | setstatus(); | |
321 | /* | |
322 | * Take care of some basic initialization. | |
323 | */ | |
1b69205a RG |
324 | /* us. delay to be used in response to broadcast */ |
325 | delay1 = casual((long)10000, 200000); | |
326 | ||
327 | /* election timer delay in secs. */ | |
328 | delay2 = casual((long)MINTOUT, (long)MAXTOUT); | |
8b8a47ba MK |
329 | #ifndef DEBUG |
330 | if (fork()) | |
331 | exit(0); | |
332 | { int s; | |
333 | for (s = getdtablesize(); s >= 0; --s) | |
334 | (void) close(s); | |
335 | (void) open("/dev/null", 0); | |
336 | (void) dup2(0, 1); | |
337 | (void) dup2(0, 2); | |
338 | s = open("/dev/tty", 2); | |
339 | if (s >= 0) { | |
8b8a47ba MK |
340 | (void) close(s); |
341 | } | |
342 | } | |
343 | #endif | |
344 | ||
1b69205a | 345 | |
1b69205a | 346 | if (Mflag) { |
1b69205a RG |
347 | /* |
348 | * number (increased by 1) of slaves controlled by master: | |
349 | * used in master.c, candidate.c, networkdelta.c, and | |
350 | * correct.c | |
351 | */ | |
352 | slvcount = 1; | |
1b69205a | 353 | ret = setjmp(jmpenv); |
9a957f87 | 354 | |
1b69205a RG |
355 | switch (ret) { |
356 | ||
357 | case 0: | |
9a957f87 JB |
358 | makeslave(firstslavenet()); |
359 | setstatus(); | |
1b69205a RG |
360 | break; |
361 | case 1: | |
9a957f87 JB |
362 | /* Just lost our master */ |
363 | setstatus(); | |
364 | slavenet->status = election(slavenet); | |
365 | checkignorednets(); | |
366 | setstatus(); | |
367 | if (slavenet->status == MASTER) | |
368 | makeslave(firstslavenet()); | |
369 | else | |
370 | makeslave(slavenet); | |
371 | setstatus(); | |
1b69205a RG |
372 | break; |
373 | case 2: | |
9a957f87 JB |
374 | /* Just been told to quit */ |
375 | fromnet->status = SLAVE; | |
376 | setstatus(); | |
377 | savefromnet = fromnet; | |
378 | rmnetmachs(fromnet); | |
379 | checkignorednets(); | |
380 | if (slavenet) | |
381 | makeslave(slavenet); | |
382 | else | |
383 | makeslave(savefromnet); | |
384 | setstatus(); | |
a3f2fd3a | 385 | justquit = 1; |
1b69205a | 386 | break; |
9a957f87 | 387 | |
1b69205a RG |
388 | default: |
389 | /* this should not happen */ | |
964c88f5 | 390 | syslog(LOG_ERR, "Attempt to enter invalid state"); |
1b69205a RG |
391 | break; |
392 | } | |
393 | ||
19f1ff0f MK |
394 | if (status & MASTER) { |
395 | /* open raw socket used to measure time differences */ | |
396 | if (sock_raw == -1) { | |
397 | sock_raw = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); | |
398 | if (sock_raw < 0) { | |
399 | syslog(LOG_ERR, "opening raw socket: %m"); | |
400 | exit (1); | |
401 | } | |
402 | } | |
403 | } else { | |
404 | /* sock_raw is not being used now */ | |
405 | if (sock_raw != -1) { | |
406 | (void)close(sock_raw); | |
407 | sock_raw = -1; | |
408 | } | |
409 | } | |
410 | ||
964c88f5 | 411 | if (status == MASTER) |
1b69205a RG |
412 | master(); |
413 | else | |
414 | slave(); | |
415 | } else { | |
416 | /* if Mflag is not set timedaemon is forced to act as a slave */ | |
75d5ce8a | 417 | status = SLAVE; |
1b69205a | 418 | if (setjmp(jmpenv)) { |
9a957f87 JB |
419 | setstatus(); |
420 | checkignorednets(); | |
9a957f87 | 421 | } |
8b8a47ba | 422 | makeslave(firstslavenet()); |
cefa40d1 | 423 | makeslave(firstslavenet()); |
9a957f87 JB |
424 | for (ntp = nettab; ntp != NULL; ntp = ntp->next) |
425 | if (ntp->status == MASTER) | |
426 | ntp->status = IGNORE; | |
427 | setstatus(); | |
428 | slave(); | |
429 | } | |
430 | } | |
431 | ||
432 | /* | |
433 | * Try to become master over ignored nets.. | |
434 | */ | |
435 | checkignorednets() | |
436 | { | |
437 | register struct netinfo *ntp; | |
438 | for (ntp = nettab; ntp != NULL; ntp = ntp->next) | |
439 | if (ntp->status == IGNORE) | |
440 | lookformaster(ntp); | |
441 | } | |
442 | ||
443 | lookformaster(ntp) | |
444 | register struct netinfo *ntp; | |
445 | { | |
446 | struct tsp resp, conflict, *answer, *readmsg(), *acksend(); | |
447 | struct timeval time; | |
448 | char mastername[MAXHOSTNAMELEN]; | |
449 | struct sockaddr_in masteraddr; | |
450 | ||
451 | ntp->status = SLAVE; | |
452 | /* look for master */ | |
453 | resp.tsp_type = TSP_MASTERREQ; | |
454 | (void)strcpy(resp.tsp_name, hostname); | |
455 | answer = acksend(&resp, &ntp->dest_addr, (char *)ANYADDR, | |
456 | TSP_MASTERACK, ntp); | |
457 | if (answer == NULL) { | |
458 | /* | |
459 | * Various conditions can cause conflict: race between | |
460 | * two just started timedaemons when no master is | |
461 | * present, or timedaemon started during an election. | |
462 | * Conservative approach is taken: give up and became a | |
463 | * slave postponing election of a master until first | |
464 | * timer expires. | |
465 | */ | |
466 | time.tv_sec = time.tv_usec = 0; | |
467 | answer = readmsg(TSP_MASTERREQ, (char *)ANYADDR, | |
468 | &time, ntp); | |
469 | if (answer != NULL) { | |
470 | ntp->status = SLAVE; | |
471 | return; | |
472 | } | |
473 | ||
474 | time.tv_sec = time.tv_usec = 0; | |
475 | answer = readmsg(TSP_MASTERUP, (char *)ANYADDR, | |
476 | &time, ntp); | |
477 | if (answer != NULL) { | |
478 | ntp->status = SLAVE; | |
479 | return; | |
480 | } | |
481 | ||
482 | time.tv_sec = time.tv_usec = 0; | |
483 | answer = readmsg(TSP_ELECTION, (char *)ANYADDR, | |
484 | &time, ntp); | |
485 | if (answer != NULL) { | |
486 | ntp->status = SLAVE; | |
487 | return; | |
488 | } | |
489 | ntp->status = MASTER; | |
490 | } else { | |
491 | (void)strcpy(mastername, answer->tsp_name); | |
492 | masteraddr = from; | |
493 | ||
494 | /* | |
495 | * If network has been partitioned, there might be other | |
496 | * masters; tell the one we have just acknowledged that | |
497 | * it has to gain control over the others. | |
498 | */ | |
499 | time.tv_sec = 0; | |
500 | time.tv_usec = 300000; | |
501 | answer = readmsg(TSP_MASTERACK, (char *)ANYADDR, &time, | |
502 | ntp); | |
503 | /* | |
504 | * checking also not to send CONFLICT to ack'ed master | |
505 | * due to duplicated MASTERACKs | |
506 | */ | |
507 | if (answer != NULL && | |
508 | strcmp(answer->tsp_name, mastername) != 0) { | |
509 | conflict.tsp_type = TSP_CONFLICT; | |
510 | (void)strcpy(conflict.tsp_name, hostname); | |
511 | if (acksend(&conflict, &masteraddr, mastername, | |
512 | TSP_ACK, (struct netinfo *)NULL) == NULL) { | |
513 | syslog(LOG_ERR, | |
514 | "error on sending TSP_CONFLICT"); | |
75d5ce8a JB |
515 | exit(1); |
516 | } | |
1b69205a | 517 | } |
1b69205a RG |
518 | } |
519 | } | |
9a957f87 JB |
520 | /* |
521 | * based on the current network configuration, set the status, and count | |
522 | * networks; | |
523 | */ | |
524 | setstatus() | |
525 | { | |
526 | register struct netinfo *ntp; | |
527 | ||
528 | status = 0; | |
529 | nmasternets = nslavenets = nnets = nignorednets = 0; | |
530 | if (trace) | |
531 | fprintf(fd, "Net status:\n"); | |
532 | for (ntp = nettab; ntp != NULL; ntp = ntp->next) { | |
77491c98 | 533 | switch ((int)ntp->status) { |
9a957f87 JB |
534 | case MASTER: |
535 | nmasternets++; | |
536 | break; | |
537 | case SLAVE: | |
538 | nslavenets++; | |
539 | break; | |
540 | case IGNORE: | |
541 | nignorednets++; | |
542 | break; | |
543 | } | |
544 | if (trace) { | |
545 | fprintf(fd, "\t%-16s", inet_ntoa(ntp->net)); | |
77491c98 | 546 | switch ((int)ntp->status) { |
9a957f87 JB |
547 | case MASTER: |
548 | fprintf(fd, "MASTER\n"); | |
549 | break; | |
550 | case SLAVE: | |
551 | fprintf(fd, "SLAVE\n"); | |
552 | break; | |
553 | case IGNORE: | |
554 | fprintf(fd, "IGNORE\n"); | |
555 | break; | |
556 | default: | |
ff8002b1 | 557 | fprintf(fd, "invalid state %d\n",(int)ntp->status); |
9a957f87 JB |
558 | break; |
559 | } | |
560 | } | |
561 | nnets++; | |
562 | status |= ntp->status; | |
563 | } | |
564 | status &= ~IGNORE; | |
565 | if (trace) | |
566 | fprintf(fd, | |
567 | "\tnets = %d, masters = %d, slaves = %d, ignored = %d\n", | |
568 | nnets, nmasternets, nslavenets, nignorednets); | |
569 | } | |
570 | ||
571 | makeslave(net) | |
572 | struct netinfo *net; | |
573 | { | |
574 | register struct netinfo *ntp; | |
575 | ||
576 | for (ntp = nettab; ntp != NULL; ntp = ntp->next) | |
577 | if (ntp->status == SLAVE && ntp != net) | |
578 | ntp->status = IGNORE; | |
579 | slavenet = net; | |
580 | } | |
581 | ||
582 | struct netinfo * | |
583 | firstslavenet() | |
584 | { | |
585 | register struct netinfo *ntp; | |
586 | ||
587 | for (ntp = nettab; ntp != NULL; ntp = ntp->next) | |
588 | if (ntp->status == SLAVE) | |
589 | return (ntp); | |
590 | return ((struct netinfo *)0); | |
591 | } | |
1b69205a | 592 | |
8b8a47ba | 593 | /* |
1b69205a RG |
594 | * `casual' returns a random number in the range [inf, sup] |
595 | */ | |
596 | ||
75d5ce8a JB |
597 | long |
598 | casual(inf, sup) | |
1b69205a RG |
599 | long inf; |
600 | long sup; | |
601 | { | |
602 | float value; | |
1b69205a | 603 | |
964c88f5 | 604 | value = (float)(random() & 0x7fffffff) / 0x7fffffff; |
1b69205a RG |
605 | return(inf + (sup - inf) * value); |
606 | } | |
607 | ||
964c88f5 JB |
608 | char * |
609 | date() | |
1b69205a | 610 | { |
2b79715d | 611 | char *ctime(); |
1b69205a | 612 | struct timeval tv; |
1b69205a RG |
613 | |
614 | (void)gettimeofday(&tv, (struct timezone *)0); | |
03b1f474 | 615 | return (ctime(&tv.tv_sec)); |
1b69205a | 616 | } |
5c0a9ec2 JB |
617 | |
618 | addnetname(name) | |
619 | char *name; | |
620 | { | |
03b1f474 MK |
621 | register struct nets **netlist = &nets; |
622 | ||
5c0a9ec2 JB |
623 | while (*netlist) |
624 | netlist = &((*netlist)->next); | |
625 | *netlist = (struct nets *)malloc(sizeof **netlist); | |
626 | if (*netlist == (struct nets *)0) { | |
627 | syslog(LOG_ERR, "malloc failed"); | |
628 | exit(1); | |
629 | } | |
77491c98 | 630 | bzero((char *)*netlist, sizeof(**netlist)); |
5c0a9ec2 JB |
631 | (*netlist)->name = name; |
632 | } |