BSD 4_3_Reno release
[unix-history] / usr / src / usr.sbin / timed / timed / timed.c
index 34d5403..2ba21a8 100644 (file)
@@ -1,18 +1,31 @@
 /*
 /*
- * Copyright (c) 1983 Regents of the University of California.
- * All rights reserved.  The Berkeley software License Agreement
- * specifies the terms and conditions for redistribution.
+ * Copyright (c) 1985 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms are permitted provided
+ * that: (1) source distributions retain this entire copyright notice and
+ * comment, and (2) distributions including binaries display the following
+ * acknowledgement:  ``This product includes software developed by the
+ * University of California, Berkeley and its contributors'' in the
+ * documentation or other materials provided with the distribution and in
+ * all advertising materials mentioning features or use of this software.
+ * Neither the name of the University nor the names of its contributors may
+ * be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  */
 
 #ifndef lint
 char copyright[] =
  */
 
 #ifndef lint
 char copyright[] =
-"@(#) Copyright (c) 1983 Regents of the University of California.\n\
+"@(#) Copyright (c) 1985 Regents of the University of California.\n\
  All rights reserved.\n";
  All rights reserved.\n";
-#endif not lint
+#endif /* not lint */
 
 #ifndef lint
 
 #ifndef lint
-static char sccsid[] = "@(#)timed.c    1.4 (Berkeley) %G%";
-#endif not lint
+static char sccsid[] = "@(#)timed.c    2.20 (Berkeley) 6/29/90";
+#endif /* not lint */
 
 #include "globals.h"
 #define TSPTYPES
 
 #include "globals.h"
 #define TSPTYPES
@@ -21,27 +34,39 @@ static char sccsid[] = "@(#)timed.c 1.4 (Berkeley) %G%";
 #include <sys/file.h>
 #include <sys/ioctl.h>
 #include <setjmp.h>
 #include <sys/file.h>
 #include <sys/ioctl.h>
 #include <setjmp.h>
+#include "pathnames.h"
 
 int id;
 int trace;
 
 int id;
 int trace;
-int sock, sock_raw;
-int status;                            /* either MASTER or SLAVE */
+int sock, sock_raw = -1;
+int status = 0;
 int backoff;
 int slvcount;                          /* no. of slaves controlled by master */
 int machup;
 u_short sequence;                      /* sequence number */
 long delay1;
 long delay2;
 int backoff;
 int slvcount;                          /* no. of slaves controlled by master */
 int machup;
 u_short sequence;                      /* sequence number */
 long delay1;
 long delay2;
+long random();
 char hostname[MAXHOSTNAMELEN];
 char hostname[MAXHOSTNAMELEN];
-struct in_addr broadcastaddr;          /* local net broadcast address */
-u_long netmask, mynet = 0;             /* my network number & netmask */
-struct sockaddr_in server;
 struct host hp[NHOSTS];
 struct host hp[NHOSTS];
-char *fj;
+char tracefile[] = _PATH_TIMEDLOG;
 FILE *fd;
 jmp_buf jmpenv;
 FILE *fd;
 jmp_buf jmpenv;
-
-extern struct sockaddr_in from;
+struct netinfo *nettab = NULL;
+int nslavenets;                /* Number of networks were I could be a slave */
+int nmasternets;       /* Number of networks were I could be a master */
+int nignorednets;      /* Number of ignored networks */
+int nnets;             /* Number of networks I am connected to */
+struct netinfo *slavenet;
+struct netinfo *firstslavenet();
+int Mflag;
+int justquit = 0;
+
+struct nets {
+       char *name;
+       long net;
+       struct nets *next;
+} *nets = (struct nets *)0;
 
 /*
  * The timedaemons synchronize the clocks of hosts in a local area network.
 
 /*
  * The timedaemons synchronize the clocks of hosts in a local area network.
@@ -55,8 +80,6 @@ extern struct sockaddr_in from;
  * network partition is fixed.
  *
  * Authors: Riccardo Gusella & Stefano Zatti
  * network partition is fixed.
  *
  * Authors: Riccardo Gusella & Stefano Zatti
- *
- * For problems and suggestions, please send mail to gusella@BERKELEY
  */
 
 main(argc, argv)
  */
 
 main(argc, argv)
@@ -66,35 +89,34 @@ char **argv;
        int on;
        int ret;
        long seed;
        int on;
        int ret;
        long seed;
-       int Mflag;
-       int nflag;
-       char mastername[MAXHOSTNAMELEN];
-       char *netname;
+       int nflag, iflag;
        struct timeval time;
        struct servent *srvp;
        struct timeval time;
        struct servent *srvp;
-       struct netent *getnetent();
-       struct netent *localnet;
-       struct sockaddr_in masteraddr;
-       struct tsp resp, conflict, *answer, *readmsg(), *acksend();
        long casual();
        long casual();
-       char *malloc(), *strcpy();
        char *date();
        int n;
        char *date();
        int n;
-       int n_addrlen;
-       char *n_addr;
-       char buf[BUFSIZ];
+       int flag;
+       char buf[BUFSIZ], *cp, *cplim;
        struct ifconf ifc;
        struct ifreq ifreq, *ifr;
        struct ifconf ifc;
        struct ifreq ifreq, *ifr;
-       struct sockaddr_in *sin;
-       
+       register struct netinfo *ntp;
+       struct netinfo *ntip;
+       struct netinfo *savefromnet;
+       struct sockaddr_in server;
+       u_short port;
+       uid_t getuid();
+
+#ifdef lint
+       ntip = NULL;
+#endif
 
        Mflag = 0;
        on = 1;
        backoff = 1;
 
        Mflag = 0;
        on = 1;
        backoff = 1;
-       fj = "/usr/adm/timed.log";
        trace = OFF;
        nflag = OFF;
        trace = OFF;
        nflag = OFF;
-       openlog("timed", LOG_ODELAY, LOG_DAEMON);
+       iflag = OFF;
+       openlog("timed", LOG_CONS|LOG_PID, LOG_DAEMON);
 
        if (getuid() != 0) {
                fprintf(stderr, "Timed: not superuser\n");
 
        if (getuid() != 0) {
                fprintf(stderr, "Timed: not superuser\n");
@@ -114,8 +136,24 @@ char **argv;
                                break;
                        case 'n':
                                argc--, argv++;
                                break;
                        case 'n':
                                argc--, argv++;
-                               nflag = ON;
-                               netname = *argv;
+                               if (iflag) {
+                                       fprintf(stderr,
+                                   "timed: -i and -n make no sense together\n");
+                               } else {
+                                       nflag = ON;
+                                       addnetname(*argv);
+                               }
+                               while (*(++(*argv)+1)) ;
+                               break;
+                       case 'i':
+                               argc--, argv++;
+                               if (nflag) {
+                                       fprintf(stderr,
+                                   "timed: -i and -n make no sense together\n");
+                               } else {
+                                       iflag = ON;
+                                       addnetname(*argv);
+                               }
                                while (*(++(*argv)+1)) ;
                                break;
                        default:
                                while (*(++(*argv)+1)) ;
                                break;
                        default:
@@ -127,35 +165,22 @@ char **argv;
        }
 
 #ifndef DEBUG
        }
 
 #ifndef DEBUG
-       if (fork())
-               exit(0);
-       { int s;
-         for (s = 0; s < 10; s++)
-               (void) close(s);
-         (void) open("/", 0);
-         (void) dup2(0, 1);
-         (void) dup2(0, 2);
-         s = open("/dev/tty", 2);
-         if (s >= 0) {
-               (void) ioctl(s, (int)TIOCNOTTY, (char *)0);
-               (void) close(s);
-         }
-       }
+       daemon(0, 0);
 #endif
 
        if (trace == ON) {
 #endif
 
        if (trace == ON) {
-               fd = fopen(fj, "w");
+               fd = fopen(tracefile, "w");
+               setlinebuf(fd);
                fprintf(fd, "Tracing started on: %s\n\n", 
                                        date());
                fprintf(fd, "Tracing started on: %s\n\n", 
                                        date());
-               (void)fflush(fd);
        }
        }
-       openlog("timed", LOG_ODELAY|LOG_CONS, LOG_DAEMON);
 
        srvp = getservbyname("timed", "udp");
        if (srvp == 0) {
                syslog(LOG_CRIT, "unknown service 'timed/udp'");
                exit(1);
        }
 
        srvp = getservbyname("timed", "udp");
        if (srvp == 0) {
                syslog(LOG_CRIT, "unknown service 'timed/udp'");
                exit(1);
        }
+       port = srvp->s_port;
        server.sin_port = srvp->s_port;
        server.sin_family = AF_INET;
        sock = socket(AF_INET, SOCK_DGRAM, 0);
        server.sin_port = srvp->s_port;
        server.sin_family = AF_INET;
        sock = socket(AF_INET, SOCK_DGRAM, 0);
@@ -181,7 +206,7 @@ char **argv;
        seed = time.tv_sec + time.tv_usec;
        srandom(seed);
 
        seed = time.tv_sec + time.tv_usec;
        srandom(seed);
 
-       sequence = casual((long)1, (long)MAXSEQ);     /* initial seq number */
+       sequence = random();     /* initial seq number */
 
        /* rounds kernel variable time to multiple of 5 ms. */
        time.tv_sec = 0;
 
        /* rounds kernel variable time to multiple of 5 ms. */
        time.tv_sec = 0;
@@ -196,199 +221,378 @@ char **argv;
        }
        hp[0].name = hostname;
 
        }
        hp[0].name = hostname;
 
-       if (nflag) {
-               localnet = getnetbyname(netname);
-               if (localnet == NULL) {
-                       syslog(LOG_ERR, "getnetbyname: unknown net %s",
-                               netname);
-                       exit(1);
+       if (nflag || iflag) {
+               struct netent *getnetent();
+               struct netent *n;
+               struct nets *np;
+               for ( np = nets ; np ; np = np->next) {
+                       n = getnetbyname(np->name);
+                       if (n == NULL) {
+                               syslog(LOG_ERR, "getnetbyname: unknown net %s",
+                                       np->name);
+                               exit(1);
+                       }
+                       np->net = n->n_net;
                }
        }
        ifc.ifc_len = sizeof(buf);
        ifc.ifc_buf = buf;
                }
        }
        ifc.ifc_len = sizeof(buf);
        ifc.ifc_buf = buf;
-       if (ioctl(sock, (int)SIOCGIFCONF, (char *)&ifc) < 0) {
+       if (ioctl(sock, SIOCGIFCONF, (char *)&ifc) < 0) {
                syslog(LOG_ERR, "get interface configuration: %m");
                exit(1);
        }
                syslog(LOG_ERR, "get interface configuration: %m");
                exit(1);
        }
-       ifr = ifc.ifc_req;
-       for (n = ifc.ifc_len/sizeof(struct ifreq); n > 0; n--, ifr++) {
+       ntp = NULL;
+#define max(a, b) (a > b ? a : b)
+#define size(p)        max((p).sa_len, sizeof(p))
+       cplim = buf + ifc.ifc_len; /*skip over if's with big ifr_addr's */
+       for (cp = buf; cp < cplim;
+                       cp += sizeof (ifr->ifr_name) + size(ifr->ifr_addr)) {
+               ifr = (struct ifreq *)cp;
+               if (ifr->ifr_addr.sa_family != AF_INET)
+                       continue;
                ifreq = *ifr;
                ifreq = *ifr;
-               if (ioctl(sock, (int)SIOCGIFFLAGS, 
+               if (ntp == NULL)
+                       ntp = (struct netinfo *)malloc(sizeof(struct netinfo));
+               ntp->my_addr = 
+                       ((struct sockaddr_in *)&ifreq.ifr_addr)->sin_addr;
+               if (ioctl(sock, SIOCGIFFLAGS, 
                                        (char *)&ifreq) < 0) {
                        syslog(LOG_ERR, "get interface flags: %m");
                        continue;
                }
                if ((ifreq.ifr_flags & IFF_UP) == 0 ||
                                        (char *)&ifreq) < 0) {
                        syslog(LOG_ERR, "get interface flags: %m");
                        continue;
                }
                if ((ifreq.ifr_flags & IFF_UP) == 0 ||
-                       (ifreq.ifr_flags & IFF_BROADCAST) == 0) {
+                       ((ifreq.ifr_flags & IFF_BROADCAST) == 0 &&
+                       (ifreq.ifr_flags & IFF_POINTOPOINT) == 0)) {
                        continue;
                }
                        continue;
                }
-               if (ioctl(sock, (int)SIOCGIFNETMASK, 
+               if (ifreq.ifr_flags & IFF_BROADCAST)
+                       flag = 1;
+               else
+                       flag = 0;
+               if (ioctl(sock, SIOCGIFNETMASK, 
                                        (char *)&ifreq) < 0) {
                                        (char *)&ifreq) < 0) {
-                       syslog(LOG_ERR, "get broadaddr: %m");
+                       syslog(LOG_ERR, "get netmask: %m");
                        continue;
                }
                        continue;
                }
-               netmask = ((struct sockaddr_in *)
+               ntp->mask = ((struct sockaddr_in *)
                        &ifreq.ifr_addr)->sin_addr.s_addr;
                        &ifreq.ifr_addr)->sin_addr.s_addr;
-               if (ioctl(sock, (int)SIOCGIFBRDADDR, 
-                                       (char *)&ifreq) < 0) {
-                       syslog(LOG_ERR, "get broadaddr: %m");
-                       continue;
+               if (flag) {
+                       if (ioctl(sock, SIOCGIFBRDADDR, 
+                                               (char *)&ifreq) < 0) {
+                               syslog(LOG_ERR, "get broadaddr: %m");
+                               continue;
+                       }
+                       ntp->dest_addr = *(struct sockaddr_in *)&ifreq.ifr_broadaddr;
+               } else {
+                       if (ioctl(sock, SIOCGIFDSTADDR, 
+                                               (char *)&ifreq) < 0) {
+                               syslog(LOG_ERR, "get destaddr: %m");
+                               continue;
+                       }
+                       ntp->dest_addr = *(struct sockaddr_in *)&ifreq.ifr_dstaddr;
                }
                }
-               n_addrlen = sizeof(ifr->ifr_addr);
-               n_addr = (char *)malloc((unsigned)n_addrlen);
-               bcopy((char *)&ifreq.ifr_broadaddr, n_addr, n_addrlen);
-               sin = (struct sockaddr_in *)n_addr;
-               broadcastaddr = sin->sin_addr;
-               if (nflag) {
+               ntp->dest_addr.sin_port = port;
+               if (nflag || iflag) {
                        u_long addr, mask;
                        u_long addr, mask;
+                       struct nets *n;
 
 
-                       addr = ntohl(broadcastaddr.s_addr);
-                       mask = ntohl(netmask);
+                       addr = ntohl(ntp->dest_addr.sin_addr.s_addr);
+                       mask = ntohl(ntp->mask);
                        while ((mask & 1) == 0) {
                                addr >>= 1;
                                mask >>= 1;
                        }
                        while ((mask & 1) == 0) {
                                addr >>= 1;
                                mask >>= 1;
                        }
-                       if (addr != localnet->n_net)
+                       for (n = nets ; n ; n = n->next)
+                               if (addr == n->net)
+                                       break;
+                       if (nflag && !n || iflag && n)
                                continue;
                }
                                continue;
                }
-               mynet = netmask & broadcastaddr.s_addr;
-               break;
+               ntp->net = ntp->mask & ntp->dest_addr.sin_addr.s_addr;
+               ntp->next = NULL;
+               if (nettab == NULL) {
+                       nettab = ntp;
+               } else {
+                       ntip->next = ntp;
+               }
+               ntip = ntp;
+               ntp = NULL;
        }
        }
-       if (!mynet) {
+       if (ntp)
+               (void) free((char *)ntp);
+       if (nettab == NULL) {
                syslog(LOG_ERR, "No network usable");
                exit(1);
        }
 
                syslog(LOG_ERR, "No network usable");
                exit(1);
        }
 
+       for (ntp = nettab; ntp != NULL; ntp = ntp->next)
+               lookformaster(ntp);
+       setstatus();
+       /*
+        * Take care of some basic initialization.
+        */
        /* us. delay to be used in response to broadcast */
        delay1 = casual((long)10000, 200000);   
 
        /* election timer delay in secs. */
        delay2 = casual((long)MINTOUT, (long)MAXTOUT);
 
        /* us. delay to be used in response to broadcast */
        delay1 = casual((long)10000, 200000);   
 
        /* election timer delay in secs. */
        delay2 = casual((long)MINTOUT, (long)MAXTOUT);
 
-       /* look for master */
-       resp.tsp_type = TSP_MASTERREQ;
-       (void)strcpy(resp.tsp_name, hostname);
-       answer = acksend(&resp, (char *)ANYADDR, TSP_MASTERACK);
-       if (answer == NULL) {
-               status = MASTER;
-       } else {
-               status = SLAVE;
-               (void)strcpy(mastername, answer->tsp_name);
-               masteraddr = from;
-
-               /*
-                * If network has been partitioned, there might be other
-                * masters; tell the one we have just acknowledged that 
-                * it has to gain control over the others. 
-                */
-               time.tv_sec = 0;
-               time.tv_usec = 300000;
-               answer = readmsg(TSP_MASTERACK, (char *)ANYADDR, &time);
-               /*
-                * checking also not to send CONFLICT to ack'ed master
-                * due to duplicated MASTERACKs
-                */
-               if (answer != NULL && 
-                               strcmp(answer->tsp_name, mastername) != 0) {
-                       conflict.tsp_type = TSP_CONFLICT;
-                       (void)strcpy(conflict.tsp_name, hostname);
-                       server = masteraddr;
-                       if (acksend(&conflict, (char *)mastername, 
-                                                       TSP_ACK) == NULL) {
-                               syslog(LOG_ERR, "error on sending TSP_CONFLICT");
-                               exit(1);
-                       }
-               }
-       }
        if (Mflag) {
        if (Mflag) {
-               /* open raw socket used to measure time differences */
-               sock_raw = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); 
-               if (sock_raw < 0)  {
-                       syslog(LOG_ERR, "opening raw socket: %m");
-                       exit (1);
-               }
-
                /*
                 * number (increased by 1) of slaves controlled by master: 
                 * used in master.c, candidate.c, networkdelta.c, and 
                 * correct.c 
                 */
                slvcount = 1;
                /*
                 * number (increased by 1) of slaves controlled by master: 
                 * used in master.c, candidate.c, networkdelta.c, and 
                 * correct.c 
                 */
                slvcount = 1;
-
-               /*
-                * Various conditions can cause conflict: race between
-                * two just started timedaemons when no master is present,
-                * or timedaemon started during an election.
-                * Conservative approach is taken: give up and became a
-                * slave postponing election of a master until first
-                * timer expires.
-                */
-               if (status == MASTER) {
-                       time.tv_sec = time.tv_usec = 0;
-                       answer = readmsg(TSP_MASTERREQ, (char *)ANYADDR, &time);
-                       if (answer != NULL) {
-                               status = SLAVE;
-                               goto startd;
-                       }
-       
-                       time.tv_sec = time.tv_usec = 0;
-                       answer = readmsg(TSP_MASTERUP, (char *)ANYADDR, &time);
-                       if (answer != NULL) {
-                               status = SLAVE;
-                               goto startd;
-                       }
-       
-                       time.tv_sec = time.tv_usec = 0;
-                       answer = readmsg(TSP_ELECTION, (char *)ANYADDR, &time);
-                       if (answer != NULL) 
-                               status = SLAVE;
-               }
-startd:
                ret = setjmp(jmpenv);
                ret = setjmp(jmpenv);
+
                switch (ret) {
 
                case 0: 
                switch (ret) {
 
                case 0: 
+                       makeslave(firstslavenet());
+                       setstatus();
                        break;
                case 1: 
                        break;
                case 1: 
-                       /* from slave */
-                       status = election();
+                       /* Just lost our master */
+                       setstatus();
+                       slavenet->status = election(slavenet);
+                       checkignorednets();
+                       setstatus();
+                       if (slavenet->status == MASTER)
+                               makeslave(firstslavenet());
+                       else
+                               makeslave(slavenet);
+                       setstatus();
                        break;
                case 2:
                        break;
                case 2:
-                       /* from master */
-                       status = SLAVE;
+                       /* Just been told to quit */
+                       fromnet->status = SLAVE;
+                       setstatus();
+                       savefromnet = fromnet;
+                       rmnetmachs(fromnet);
+                       checkignorednets();
+                       if (slavenet)
+                               makeslave(slavenet);
+                       else
+                               makeslave(savefromnet);
+                       setstatus();
+                       justquit = 1;
                        break;
                        break;
+                       
                default:
                        /* this should not happen */
                        syslog(LOG_ERR, "Attempt to enter invalid state");
                        break;
                }
                        
                default:
                        /* this should not happen */
                        syslog(LOG_ERR, "Attempt to enter invalid state");
                        break;
                }
                        
+               if (status & MASTER) {
+                       /* open raw socket used to measure time differences */
+                       if (sock_raw == -1) {
+                           sock_raw = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); 
+                           if (sock_raw < 0)  {
+                                   syslog(LOG_ERR, "opening raw socket: %m");
+                                   exit (1);
+                           }
+                       }
+               } else {
+                       /* sock_raw is not being used now */
+                       if (sock_raw != -1) {
+                           (void)close(sock_raw);
+                           sock_raw = -1;
+                       }
+               }
+
                if (status == MASTER) 
                        master();
                else 
                        slave();
        } else {
                if (status == MASTER) 
                        master();
                else 
                        slave();
        } else {
-               status = SLAVE;
                /* if Mflag is not set timedaemon is forced to act as a slave */
                /* if Mflag is not set timedaemon is forced to act as a slave */
+               status = SLAVE;
                if (setjmp(jmpenv)) {
                if (setjmp(jmpenv)) {
-                       resp.tsp_type = TSP_SLAVEUP;
-                       (void)strcpy(resp.tsp_name, hostname);
-                       broadcast(&resp);
+                       setstatus();
+                       checkignorednets();
                }
                }
+               makeslave(firstslavenet());
+               for (ntp = nettab; ntp != NULL; ntp = ntp->next)
+                       if (ntp->status == MASTER)
+                               ntp->status = IGNORE;
+               setstatus();
                slave();
        }
 }
 
                slave();
        }
 }
 
-/* 
+/*
+ * Try to become master over ignored nets..
+ */
+checkignorednets()
+{
+       register struct netinfo *ntp;
+       for (ntp = nettab; ntp != NULL; ntp = ntp->next)
+               if (ntp->status == IGNORE)
+                       lookformaster(ntp);
+}
+
+lookformaster(ntp)
+       register struct netinfo *ntp;
+{
+       struct tsp resp, conflict, *answer, *readmsg(), *acksend();
+       struct timeval time;
+       char mastername[MAXHOSTNAMELEN];
+       struct sockaddr_in masteraddr;
+
+       ntp->status = SLAVE;
+       /* look for master */
+       resp.tsp_type = TSP_MASTERREQ;
+       (void)strcpy(resp.tsp_name, hostname);
+       answer = acksend(&resp, &ntp->dest_addr, (char *)ANYADDR, 
+           TSP_MASTERACK, ntp);
+       if (answer == NULL) {
+               /*
+                * Various conditions can cause conflict: race between
+                * two just started timedaemons when no master is
+                * present, or timedaemon started during an election.
+                * Conservative approach is taken: give up and became a
+                * slave postponing election of a master until first
+                * timer expires.
+                */
+               time.tv_sec = time.tv_usec = 0;
+               answer = readmsg(TSP_MASTERREQ, (char *)ANYADDR,
+                   &time, ntp);
+               if (answer != NULL) {
+                       ntp->status = SLAVE;
+                       return;
+               }
+
+               time.tv_sec = time.tv_usec = 0;
+               answer = readmsg(TSP_MASTERUP, (char *)ANYADDR,
+                   &time, ntp);
+               if (answer != NULL) {
+                       ntp->status = SLAVE;
+                       return;
+               }
+
+               time.tv_sec = time.tv_usec = 0;
+               answer = readmsg(TSP_ELECTION, (char *)ANYADDR,
+                   &time, ntp);
+               if (answer != NULL) {
+                       ntp->status = SLAVE;
+                       return;
+               }
+               ntp->status = MASTER;
+       } else {
+               (void)strcpy(mastername, answer->tsp_name);
+               masteraddr = from;
+
+               /*
+                * If network has been partitioned, there might be other
+                * masters; tell the one we have just acknowledged that 
+                * it has to gain control over the others. 
+                */
+               time.tv_sec = 0;
+               time.tv_usec = 300000;
+               answer = readmsg(TSP_MASTERACK, (char *)ANYADDR, &time,
+                   ntp);
+               /*
+                * checking also not to send CONFLICT to ack'ed master
+                * due to duplicated MASTERACKs
+                */
+               if (answer != NULL && 
+                   strcmp(answer->tsp_name, mastername) != 0) {
+                       conflict.tsp_type = TSP_CONFLICT;
+                       (void)strcpy(conflict.tsp_name, hostname);
+                       if (acksend(&conflict, &masteraddr, mastername,
+                           TSP_ACK, (struct netinfo *)NULL) == NULL) {
+                               syslog(LOG_ERR, 
+                                   "error on sending TSP_CONFLICT");
+                               exit(1);
+                       }
+               }
+       }
+}
+/*
+ * based on the current network configuration, set the status, and count
+ * networks;
+ */
+setstatus()
+{
+       register struct netinfo *ntp;
+
+       status = 0;
+       nmasternets = nslavenets = nnets = nignorednets = 0;
+       if (trace)
+               fprintf(fd, "Net status:\n");
+       for (ntp = nettab; ntp != NULL; ntp = ntp->next) {
+               switch ((int)ntp->status) {
+                 case MASTER:
+                       nmasternets++;
+                       break;
+                 case SLAVE:
+                       nslavenets++;
+                       break;
+                 case IGNORE:
+                       nignorednets++;
+                       break;
+               }
+               if (trace) {
+                       fprintf(fd, "\t%-16s", inet_ntoa(ntp->net));
+                       switch ((int)ntp->status) {
+                         case MASTER:
+                               fprintf(fd, "MASTER\n");
+                               break;
+                         case SLAVE:
+                               fprintf(fd, "SLAVE\n");
+                               break;
+                         case IGNORE:
+                               fprintf(fd, "IGNORE\n");
+                               break;
+                         default:
+                               fprintf(fd, "invalid state %d\n",(int)ntp->status);
+                               break;
+                       }
+               }
+               nnets++;
+               status |= ntp->status;
+       }
+       status &= ~IGNORE;
+       if (trace)
+               fprintf(fd,
+                     "\tnets = %d, masters = %d, slaves = %d, ignored = %d\n",
+                     nnets, nmasternets, nslavenets, nignorednets);
+}
+
+makeslave(net)
+       struct netinfo *net;
+{
+       register struct netinfo *ntp;
+
+       for (ntp = nettab; ntp != NULL; ntp = ntp->next)
+               if (ntp->status == SLAVE && ntp != net)
+                       ntp->status = IGNORE;
+       slavenet = net;
+}
+       
+struct netinfo *
+firstslavenet()
+{
+       register struct netinfo *ntp;
+
+       for (ntp = nettab; ntp != NULL; ntp = ntp->next)
+               if (ntp->status == SLAVE)
+                       return (ntp);
+       return ((struct netinfo *)0);
+}
+
+/*
  * `casual' returns a random number in the range [inf, sup]
  */
 
  * `casual' returns a random number in the range [inf, sup]
  */
 
-long casual(inf, sup)
+long
+casual(inf, sup)
 long inf;
 long sup;
 {
        float value;
 long inf;
 long sup;
 {
        float value;
-       long random();
 
        value = (float)(random() & 0x7fffffff) / 0x7fffffff;
        return(inf + (sup - inf) * value);
 
        value = (float)(random() & 0x7fffffff) / 0x7fffffff;
        return(inf + (sup - inf) * value);
@@ -397,11 +601,25 @@ long sup;
 char *
 date()
 {
 char *
 date()
 {
-       char    *ret;
        char    *ctime();
        struct  timeval tv;
 
        (void)gettimeofday(&tv, (struct timezone *)0);
        char    *ctime();
        struct  timeval tv;
 
        (void)gettimeofday(&tv, (struct timezone *)0);
-       ret = ctime(&tv.tv_sec);
-       return(ret);
+       return (ctime(&tv.tv_sec));
+}
+
+addnetname(name)
+       char *name;
+{
+       register struct nets **netlist = &nets;
+
+       while (*netlist)
+               netlist = &((*netlist)->next);
+       *netlist = (struct nets *)malloc(sizeof **netlist);
+       if (*netlist == (struct nets *)0) {
+               syslog(LOG_ERR, "malloc failed");
+               exit(1);
+       }
+       bzero((char *)*netlist, sizeof(**netlist));
+       (*netlist)->name = name;
 }
 }