Index: head/usr.sbin/timed/timed/acksend.c =================================================================== --- head/usr.sbin/timed/timed/acksend.c (revision 299706) +++ head/usr.sbin/timed/timed/acksend.c (revision 299707) @@ -1,125 +1,125 @@ /*- * Copyright (c) 1985, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef lint #if 0 static char sccsid[] = "@(#)acksend.c 8.1 (Berkeley) 6/6/93"; #endif static const char rcsid[] = "$FreeBSD$"; #endif /* not lint */ #include "globals.h" struct tsp *answer; extern u_short sequence; void xmit(int type, u_int seq, struct sockaddr_in *addr) { static struct tsp msg; msg.tsp_type = type; msg.tsp_seq = seq; msg.tsp_vers = TSPVERSION; (void)strcpy(msg.tsp_name, hostname); bytenetorder(&msg); if (sendto(sock, (char *)&msg, sizeof(struct tsp), 0, (struct sockaddr*)addr, sizeof(struct sockaddr)) < 0) { trace_sendto_err(addr->sin_addr); } } /* * Acksend implements reliable datagram transmission by using sequence * numbers and retransmission when necessary. * If `name' is ANYADDR, this routine implements reliable broadcast. * * Because this function calls readmsg(), none of its args may be in * a message provided by readmsg(). * message this message * addr to here * ack look for this ack * net receive from this network * bad 1=losing patience */ struct tsp * acksend(struct tsp *message, struct sockaddr_in *addr, char *name, int ack, struct netinfo *net, int bad) { struct timeval twait; int count; long msec; message->tsp_vers = TSPVERSION; message->tsp_seq = sequence; if (trace) { fprintf(fd, "acksend: to %s: ", (name == ANYADDR ? "broadcast" : name)); print(message, addr); } bytenetorder(message); msec = 200; count = bad ? 1 : 5; /* 5 packets in 6.4 seconds */ - answer = 0; + answer = NULL; do { if (!answer) { /* do not go crazy transmitting just because the * other guy cannot keep our sequence numbers * straight. */ if (sendto(sock, (char *)message, sizeof(struct tsp), 0, (struct sockaddr*)addr, sizeof(struct sockaddr)) < 0) { trace_sendto_err(addr->sin_addr); break; } } mstotvround(&twait, msec); answer = readmsg(ack, name, &twait, net); - if (answer != 0) { + if (answer != NULL) { if (answer->tsp_seq != sequence) { if (trace) fprintf(fd,"acksend: seq # %u!=%u\n", answer->tsp_seq, sequence); continue; } break; } msec *= 2; } while (--count > 0); sequence++; return(answer); } Index: head/usr.sbin/timed/timed/master.c =================================================================== --- head/usr.sbin/timed/timed/master.c (revision 299706) +++ head/usr.sbin/timed/timed/master.c (revision 299707) @@ -1,839 +1,839 @@ /*- * Copyright (c) 1985, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef lint #if 0 static char sccsid[] = "@(#)master.c 8.1 (Berkeley) 6/6/93"; #endif static const char rcsid[] = "$FreeBSD$"; #endif /* not lint */ #include "globals.h" #include #include #include #include #include #include "pathnames.h" extern int measure_delta; extern jmp_buf jmpenv; extern int Mflag; extern int justquit; static int dictate; static int slvcount; /* slaves listening to our clock */ static void mchgdate(struct tsp *); /* * The main function of `master' is to periodically compute the differences * (deltas) between its clock and the clocks of the slaves, to compute the * network average delta, and to send to the slaves the differences between * their individual deltas and the network delta. * While waiting, it receives messages from the slaves (i.e. requests for * master's name, remote requests to set the network time, ...), and * takes the appropriate action. */ int master(void) { struct hosttbl *htp; long pollingtime; #define POLLRATE 4 int polls; struct timeval wait, ntime; time_t tsp_time_sec; struct tsp *msg, *answer, to; char newdate[32]; struct sockaddr_in taddr; char tname[MAXHOSTNAMELEN]; struct netinfo *ntp; int i; syslog(LOG_NOTICE, "This machine is master"); if (trace) fprintf(fd, "This machine is master\n"); for (ntp = nettab; ntp != NULL; ntp = ntp->next) { if (ntp->status == MASTER) masterup(ntp); } (void)gettimeofday(&ntime, NULL); pollingtime = ntime.tv_sec+3; if (justquit) polls = 0; else polls = POLLRATE-1; /* Process all outstanding messages before spending the long time necessary * to update all timers. */ loop: (void)gettimeofday(&ntime, NULL); wait.tv_sec = pollingtime - ntime.tv_sec; if (wait.tv_sec < 0) wait.tv_sec = 0; wait.tv_usec = 0; msg = readmsg(TSP_ANY, ANYADDR, &wait, 0); if (!msg) { (void)gettimeofday(&ntime, NULL); if (ntime.tv_sec >= pollingtime) { pollingtime = ntime.tv_sec + SAMPLEINTVL; get_goodgroup(0); /* If a bogus master told us to quit, we can have decided to ignore a * network. Therefore, periodically try to take over everything. */ polls = (polls + 1) % POLLRATE; if (0 == polls && nignorednets > 0) { trace_msg("Looking for nets to re-master\n"); for (ntp = nettab; ntp; ntp = ntp->next) { if (ntp->status == IGNORE || ntp->status == NOMASTER) { lookformaster(ntp); if (ntp->status == MASTER) { masterup(ntp); polls = POLLRATE-1; } } if (ntp->status == MASTER && --ntp->quit_count < 0) ntp->quit_count = 0; } if (polls != 0) setstatus(); } synch(0L); for (ntp = nettab; ntp != NULL; ntp = ntp->next) { to.tsp_type = TSP_LOOP; to.tsp_vers = TSPVERSION; to.tsp_seq = sequence++; to.tsp_hopcnt = MAX_HOPCNT; (void)strcpy(to.tsp_name, hostname); bytenetorder(&to); if (sendto(sock, (char *)&to, sizeof(struct tsp), 0, (struct sockaddr*)&ntp->dest_addr, sizeof(ntp->dest_addr)) < 0) { trace_sendto_err(ntp->dest_addr.sin_addr); } } } } else { switch (msg->tsp_type) { case TSP_MASTERREQ: break; case TSP_SLAVEUP: newslave(msg); break; case TSP_SETDATE: /* * XXX check to see it is from ourself */ tsp_time_sec = msg->tsp_time.tv_sec; (void)strcpy(newdate, ctime(&tsp_time_sec)); if (!good_host_name(msg->tsp_name)) { syslog(LOG_NOTICE, "attempted date change by %s to %s", msg->tsp_name, newdate); spreadtime(); break; } mchgdate(msg); (void)gettimeofday(&ntime, NULL); pollingtime = ntime.tv_sec + SAMPLEINTVL; break; case TSP_SETDATEREQ: if (!fromnet || fromnet->status != MASTER) break; tsp_time_sec = msg->tsp_time.tv_sec; (void)strcpy(newdate, ctime(&tsp_time_sec)); htp = findhost(msg->tsp_name); - if (htp == 0) { + if (htp == NULL) { syslog(LOG_ERR, "attempted SET DATEREQ by uncontrolled %s to %s", msg->tsp_name, newdate); break; } if (htp->seq == msg->tsp_seq) break; htp->seq = msg->tsp_seq; if (!htp->good) { syslog(LOG_NOTICE, "attempted SET DATEREQ by untrusted %s to %s", msg->tsp_name, newdate); spreadtime(); break; } mchgdate(msg); (void)gettimeofday(&ntime, NULL); pollingtime = ntime.tv_sec + SAMPLEINTVL; break; case TSP_MSITE: xmit(TSP_ACK, msg->tsp_seq, &from); break; case TSP_MSITEREQ: break; case TSP_TRACEON: traceon(); break; case TSP_TRACEOFF: traceoff("Tracing ended at %s\n"); break; case TSP_ELECTION: if (!fromnet) break; if (fromnet->status == MASTER) { pollingtime = 0; (void)addmach(msg->tsp_name, &from,fromnet); } taddr = from; (void)strcpy(tname, msg->tsp_name); to.tsp_type = TSP_QUIT; (void)strcpy(to.tsp_name, hostname); answer = acksend(&to, &taddr, tname, TSP_ACK, 0, 1); if (answer == NULL) { syslog(LOG_ERR, "election error by %s", tname); } break; case TSP_CONFLICT: /* * After a network partition, there can be * more than one master: the first slave to * come up will notify here the situation. */ if (!fromnet || fromnet->status != MASTER) break; (void)strcpy(to.tsp_name, hostname); /* The other master often gets into the same state, * with boring results if we stay at it forever. */ ntp = fromnet; /* (acksend() can leave fromnet=0 */ for (i = 0; i < 3; i++) { to.tsp_type = TSP_RESOLVE; (void)strcpy(to.tsp_name, hostname); answer = acksend(&to, &ntp->dest_addr, ANYADDR, TSP_MASTERACK, ntp, 0); if (!answer) break; htp = addmach(answer->tsp_name,&from,ntp); to.tsp_type = TSP_QUIT; msg = acksend(&to, &htp->addr, htp->name, TSP_ACK, 0, htp->noanswer); if (msg == NULL) { syslog(LOG_ERR, "no response from %s to CONFLICT-QUIT", htp->name); } } masterup(ntp); pollingtime = 0; break; case TSP_RESOLVE: if (!fromnet || fromnet->status != MASTER) break; /* * do not want to call synch() while waiting * to be killed! */ (void)gettimeofday(&ntime, NULL); pollingtime = ntime.tv_sec + SAMPLEINTVL; break; case TSP_QUIT: doquit(msg); /* become a slave */ break; case TSP_LOOP: if (!fromnet || fromnet->status != MASTER || !strcmp(msg->tsp_name, hostname)) break; /* * We should not have received this from a net * we are master on. There must be two masters. */ htp = addmach(msg->tsp_name, &from,fromnet); to.tsp_type = TSP_QUIT; (void)strcpy(to.tsp_name, hostname); answer = acksend(&to, &htp->addr, htp->name, TSP_ACK, 0, 1); if (!answer) { syslog(LOG_WARNING, "loop breakage: no reply from %s=%s to QUIT", htp->name, inet_ntoa(htp->addr.sin_addr)); (void)remmach(htp); } case TSP_TEST: if (trace) { fprintf(fd, "\tnets = %d, masters = %d, slaves = %d, ignored = %d\n", nnets, nmasternets, nslavenets, nignorednets); setstatus(); } pollingtime = 0; polls = POLLRATE-1; break; default: if (trace) { fprintf(fd, "garbage message: "); print(msg, &from); } break; } } goto loop; } /* * change the system date on the master */ static void mchgdate(struct tsp *msg) { char tname[MAXHOSTNAMELEN]; char olddate[32]; struct timeval otime, ntime, tmptv; struct utmpx utx; (void)strcpy(tname, msg->tsp_name); xmit(TSP_DATEACK, msg->tsp_seq, &from); (void)strcpy(olddate, date()); /* adjust time for residence on the queue */ (void)gettimeofday(&otime, NULL); adj_msg_time(msg,&otime); tmptv.tv_sec = msg->tsp_time.tv_sec; tmptv.tv_usec = msg->tsp_time.tv_usec; timevalsub(&ntime, &tmptv, &otime); if (ntime.tv_sec < MAXADJ && ntime.tv_sec > -MAXADJ) { /* * do not change the clock if we can adjust it */ dictate = 3; synch(tvtomsround(ntime)); } else { utx.ut_type = OLD_TIME; (void)gettimeofday(&utx.ut_tv, NULL); pututxline(&utx); (void)settimeofday(&tmptv, 0); utx.ut_type = NEW_TIME; (void)gettimeofday(&utx.ut_tv, NULL); pututxline(&utx); spreadtime(); } syslog(LOG_NOTICE, "date changed by %s from %s", tname, olddate); } /* * synchronize all of the slaves */ void synch(long mydelta) { struct hosttbl *htp; int measure_status; struct timeval check, stop, wait; if (slvcount > 0) { if (trace) fprintf(fd, "measurements starting at %s\n", date()); (void)gettimeofday(&check, NULL); for (htp = self.l_fwd; htp != &self; htp = htp->l_fwd) { if (htp->noanswer != 0) { measure_status = measure(500, 100, htp->name, &htp->addr,0); } else { measure_status = measure(3000, 100, htp->name, &htp->addr,0); } if (measure_status != GOOD) { /* The slave did not respond. We have * just wasted lots of time on it. */ htp->delta = HOSTDOWN; if (++htp->noanswer >= LOSTHOST) { if (trace) { fprintf(fd, "purging %s for not answering ICMP\n", htp->name); (void)fflush(fd); } htp = remmach(htp); } } else { htp->delta = measure_delta; } (void)gettimeofday(&stop, NULL); timevalsub(&stop, &stop, &check); if (stop.tv_sec >= 1) { if (trace) (void)fflush(fd); /* * ack messages periodically */ wait.tv_sec = 0; wait.tv_usec = 0; if (0 != readmsg(TSP_TRACEON,ANYADDR, &wait,0)) traceon(); (void)gettimeofday(&check, NULL); } } if (trace) fprintf(fd, "measurements finished at %s\n", date()); } if (!(status & SLAVE)) { if (!dictate) { mydelta = networkdelta(); } else { dictate--; } } if (trace && (mydelta != 0 || (status & SLAVE))) fprintf(fd,"local correction of %ld ms.\n", mydelta); correct(mydelta); } /* * sends the time to each slave after the master * has received the command to set the network time */ void spreadtime(void) { struct hosttbl *htp; struct tsp to; struct tsp *answer; struct timeval tmptv; /* Do not listen to the consensus after forcing the time. This is because * the consensus takes a while to reach the time we are dictating. */ dictate = 2; for (htp = self.l_fwd; htp != &self; htp = htp->l_fwd) { to.tsp_type = TSP_SETTIME; (void)strcpy(to.tsp_name, hostname); (void)gettimeofday(&tmptv, NULL); to.tsp_time.tv_sec = tmptv.tv_sec; to.tsp_time.tv_usec = tmptv.tv_usec; answer = acksend(&to, &htp->addr, htp->name, TSP_ACK, 0, htp->noanswer); - if (answer == 0) { + if (answer == NULL) { /* We client does not respond, then we have * just wasted lots of time on it. */ syslog(LOG_WARNING, "no reply to SETTIME from %s", htp->name); if (++htp->noanswer >= LOSTHOST) { if (trace) { fprintf(fd, "purging %s for not answering", htp->name); (void)fflush(fd); } htp = remmach(htp); } } } } void prthp(clock_t delta) { static time_t next_time; time_t this_time; struct tms tm; struct hosttbl *htp; int length, l; int i; if (!fd) /* quit if tracing already off */ return; this_time = times(&tm); if ((time_t)(this_time + delta) < next_time) return; next_time = this_time + CLK_TCK; fprintf(fd, "host table: %d entries at %s\n", slvcount, date()); htp = self.l_fwd; length = 1; for (i = 1; i <= slvcount; i++, htp = htp->l_fwd) { l = strlen(htp->name) + 1; if (length+l >= 80) { fprintf(fd, "\n"); length = 0; } length += l; fprintf(fd, " %s", htp->name); } fprintf(fd, "\n"); } static struct hosttbl *newhost_hash; static struct hosttbl *lasthfree = &hosttbl[0]; struct hosttbl * /* answer or 0 */ findhost(char *name) { int i, j; struct hosttbl *htp; char *p; j= 0; for (p = name, i = 0; i < 8 && *p != '\0'; i++, p++) j = (j << 2) ^ *p; newhost_hash = &hosttbl[j % NHOSTS]; htp = newhost_hash; if (htp->name[0] == '\0') return(0); do { if (!strcmp(name, htp->name)) return(htp); htp = htp->h_fwd; } while (htp != newhost_hash); return(0); } /* * add a host to the list of controlled machines if not already there */ struct hosttbl * addmach(char *name, struct sockaddr_in *addr, struct netinfo *ntp) { struct hosttbl *ret, *p, *b, *f; ret = findhost(name); - if (ret == 0) { + if (ret == NULL) { if (slvcount >= NHOSTS) { if (trace) { fprintf(fd, "no more slots in host table\n"); prthp(CLK_TCK); } syslog(LOG_ERR, "no more slots in host table"); Mflag = 0; longjmp(jmpenv, 2); /* give up and be a slave */ } /* if our home hash slot is occupied, find a free entry * in the hash table */ if (newhost_hash->name[0] != '\0') { do { ret = lasthfree; if (++lasthfree > &hosttbl[NHOSTS]) lasthfree = &hosttbl[1]; } while (ret->name[0] != '\0'); if (!newhost_hash->head) { /* Move an interloper using our home. Use * scratch pointers in case the new head is * pointing to itself. */ f = newhost_hash->h_fwd; b = newhost_hash->h_bak; f->h_bak = ret; b->h_fwd = ret; f = newhost_hash->l_fwd; b = newhost_hash->l_bak; f->l_bak = ret; b->l_fwd = ret; bcopy(newhost_hash,ret,sizeof(*ret)); ret = newhost_hash; ret->head = 1; ret->h_fwd = ret; ret->h_bak = ret; } else { /* link to an existing chain in our home */ ret->head = 0; p = newhost_hash->h_bak; ret->h_fwd = newhost_hash; ret->h_bak = p; p->h_fwd = ret; newhost_hash->h_bak = ret; } } else { ret = newhost_hash; ret->head = 1; ret->h_fwd = ret; ret->h_bak = ret; } ret->addr = *addr; ret->ntp = ntp; (void)strlcpy(ret->name, name, sizeof(ret->name)); ret->good = good_host_name(name); ret->l_fwd = &self; ret->l_bak = self.l_bak; self.l_bak->l_fwd = ret; self.l_bak = ret; slvcount++; ret->noanswer = 0; ret->need_set = 1; } else { ret->noanswer = (ret->noanswer != 0); } /* need to clear sequence number anyhow */ ret->seq = 0; return(ret); } /* * remove the machine with the given index in the host table. */ struct hosttbl * remmach(struct hosttbl *htp) { struct hosttbl *lprv, *hnxt, *f, *b; if (trace) fprintf(fd, "remove %s\n", htp->name); /* get out of the lists */ htp->l_fwd->l_bak = lprv = htp->l_bak; htp->l_bak->l_fwd = htp->l_fwd; htp->h_fwd->h_bak = htp->h_bak; htp->h_bak->h_fwd = hnxt = htp->h_fwd; /* If we are in the home slot, pull up the chain */ if (htp->head && hnxt != htp) { if (lprv == hnxt) lprv = htp; /* Use scratch pointers in case the new head is pointing to * itself. */ f = hnxt->h_fwd; b = hnxt->h_bak; f->h_bak = htp; b->h_fwd = htp; f = hnxt->l_fwd; b = hnxt->l_bak; f->l_bak = htp; b->l_fwd = htp; hnxt->head = 1; bcopy(hnxt, htp, sizeof(*htp)); lasthfree = hnxt; } else { lasthfree = htp; } lasthfree->name[0] = '\0'; - lasthfree->h_fwd = 0; - lasthfree->l_fwd = 0; + lasthfree->h_fwd = NULL; + lasthfree->l_fwd = NULL; slvcount--; return lprv; } /* * Remove all the machines from the host table that exist on the given * network. This is called when a master transitions to a slave on a * given network. */ void rmnetmachs(struct netinfo *ntp) { struct hosttbl *htp; if (trace) prthp(CLK_TCK); for (htp = self.l_fwd; htp != &self; htp = htp->l_fwd) { if (ntp == htp->ntp) htp = remmach(htp); } if (trace) prthp(CLK_TCK); } void masterup(struct netinfo *net) { xmit(TSP_MASTERUP, 0, &net->dest_addr); /* * Do not tell new slaves our time for a while. This ensures * we do not tell them to start using our time, before we have * found a good master. */ (void)gettimeofday(&net->slvwait, NULL); } void newslave(struct tsp *msg) { struct hosttbl *htp; struct tsp *answer, to; struct timeval now, tmptv; if (!fromnet || fromnet->status != MASTER) return; htp = addmach(msg->tsp_name, &from,fromnet); htp->seq = msg->tsp_seq; if (trace) prthp(0); /* * If we are stable, send our time to the slave. * Do not go crazy if the date has been changed. */ (void)gettimeofday(&now, NULL); if (now.tv_sec >= fromnet->slvwait.tv_sec+3 || now.tv_sec < fromnet->slvwait.tv_sec) { to.tsp_type = TSP_SETTIME; (void)strcpy(to.tsp_name, hostname); (void)gettimeofday(&tmptv, NULL); to.tsp_time.tv_sec = tmptv.tv_sec; to.tsp_time.tv_usec = tmptv.tv_usec; answer = acksend(&to, &htp->addr, htp->name, TSP_ACK, 0, htp->noanswer); if (answer) { htp->need_set = 0; } else { syslog(LOG_WARNING, "no reply to initial SETTIME from %s", htp->name); htp->noanswer = LOSTHOST; } } } /* * react to a TSP_QUIT: */ void doquit(struct tsp *msg) { if (fromnet->status == MASTER) { if (!good_host_name(msg->tsp_name)) { if (fromnet->quit_count <= 0) { syslog(LOG_NOTICE,"untrusted %s told us QUIT", msg->tsp_name); suppress(&from, msg->tsp_name, fromnet); fromnet->quit_count = 1; return; } syslog(LOG_NOTICE, "untrusted %s told us QUIT twice", msg->tsp_name); fromnet->quit_count = 2; fromnet->status = NOMASTER; } else { fromnet->status = SLAVE; } rmnetmachs(fromnet); longjmp(jmpenv, 2); /* give up and be a slave */ } else { if (!good_host_name(msg->tsp_name)) { syslog(LOG_NOTICE, "untrusted %s told us QUIT", msg->tsp_name); fromnet->quit_count = 2; } } } void traceon(void) { if (!fd) { fd = fopen(_PATH_TIMEDLOG, "w"); if (!fd) { trace = 0; return; } fprintf(fd,"Tracing started at %s\n", date()); } trace = 1; get_goodgroup(1); setstatus(); prthp(CLK_TCK); } void traceoff(char *msg) { get_goodgroup(1); setstatus(); prthp(CLK_TCK); if (trace) { fprintf(fd, msg, date()); (void)fclose(fd); - fd = 0; + fd = NULL; } #ifdef GPROF moncontrol(0); _mcleanup(); moncontrol(1); #endif trace = OFF; } Index: head/usr.sbin/timed/timed/readmsg.c =================================================================== --- head/usr.sbin/timed/timed/readmsg.c (revision 299706) +++ head/usr.sbin/timed/timed/readmsg.c (revision 299707) @@ -1,502 +1,502 @@ /*- * Copyright (c) 1985, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef lint #if 0 static char sccsid[] = "@(#)readmsg.c 8.1 (Berkeley) 6/6/93"; #endif static const char rcsid[] = "$FreeBSD$"; #endif /* not lint */ #define TSPTYPES #include "globals.h" /* * LOOKAT checks if the message is of the requested type and comes from * the right machine, returning 1 in case of affirmative answer */ #define LOOKAT(msg, mtype, mfrom, netp, froms) \ (((mtype) == TSP_ANY || (mtype) == (msg).tsp_type) && \ ((mfrom) == 0 || !strcmp((mfrom), (msg).tsp_name)) && \ ((netp) == 0 || \ ((netp)->mask & (froms).sin_addr.s_addr) == (netp)->net.s_addr)) struct timeval rtime, rwait, rtout; struct tsp msgin; static struct tsplist { struct tsp info; struct timeval when; struct sockaddr_in addr; struct tsplist *p; } msgslist; struct sockaddr_in from; struct netinfo *fromnet; struct timeval from_when; /* * `readmsg' returns message `type' sent by `machfrom' if it finds it * either in the receive queue, or in a linked list of previously received * messages that it maintains. * Otherwise it waits to see if the appropriate message arrives within * `intvl' seconds. If not, it returns NULL. */ struct tsp * readmsg(int type, char *machfrom, struct timeval *intvl, struct netinfo *netfrom) { int length; fd_set ready; static struct tsplist *head = &msgslist; static struct tsplist *tail = &msgslist; static int msgcnt = 0; struct tsplist *prev; register struct netinfo *ntp; register struct tsplist *ptr; ssize_t n; if (trace) { fprintf(fd, "readmsg: looking for %s from %s, %s\n", tsptype[type], machfrom == NULL ? "ANY" : machfrom, netfrom == NULL ? "ANYNET" : inet_ntoa(netfrom->net)); - if (head->p != 0) { + if (head->p != NULL) { length = 1; - for (ptr = head->p; ptr != 0; ptr = ptr->p) { + for (ptr = head->p; ptr != NULL; ptr = ptr->p) { /* do not repeat the hundreds of messages */ if (++length > 3) { if (ptr == tail) { fprintf(fd,"\t ...%d skipped\n", length); } else { continue; } } fprintf(fd, length > 1 ? "\t" : "queue:\t"); print(&ptr->info, &ptr->addr); } } } ptr = head->p; prev = head; /* * Look for the requested message scanning through the * linked list. If found, return it and free the space */ while (ptr != NULL) { if (LOOKAT(ptr->info, type, machfrom, netfrom, ptr->addr)) { again: msgin = ptr->info; from = ptr->addr; from_when = ptr->when; prev->p = ptr->p; if (ptr == tail) tail = prev; free((char *)ptr); fromnet = NULL; if (netfrom == NULL) for (ntp = nettab; ntp != NULL; ntp = ntp->next) { if ((ntp->mask & from.sin_addr.s_addr) == ntp->net.s_addr) { fromnet = ntp; break; } } else fromnet = netfrom; if (trace) { fprintf(fd, "readmsg: found "); print(&msgin, &from); } /* The protocol can get far behind. When it does, it gets * hopelessly confused. So delete duplicate messages. */ for (ptr = prev; (ptr = ptr->p) != NULL; prev = ptr) { if (ptr->addr.sin_addr.s_addr == from.sin_addr.s_addr && ptr->info.tsp_type == msgin.tsp_type) { if (trace) fprintf(fd, "\tdup "); goto again; } } msgcnt--; return(&msgin); } else { prev = ptr; ptr = ptr->p; } } /* * If the message was not in the linked list, it may still be * coming from the network. Set the timer and wait * on a select to read the next incoming message: if it is the * right one, return it, otherwise insert it in the linked list. */ (void)gettimeofday(&rtout, NULL); timevaladd(&rtout, intvl); FD_ZERO(&ready); for (;;) { (void)gettimeofday(&rtime, NULL); timevalsub(&rwait, &rtout, &rtime); if (rwait.tv_sec < 0) rwait.tv_sec = rwait.tv_usec = 0; else if (rwait.tv_sec == 0 && rwait.tv_usec < 1000000/CLK_TCK) rwait.tv_usec = 1000000/CLK_TCK; if (trace) { fprintf(fd, "readmsg: wait %jd.%6ld at %s\n", (intmax_t)rwait.tv_sec, rwait.tv_usec, date()); /* Notice a full disk, as we flush trace info. * It is better to flush periodically than at * every line because the tracing consists of bursts * of many lines. Without care, tracing slows * down the code enough to break the protocol. */ if (rwait.tv_sec != 0 && EOF == fflush(fd)) traceoff("Tracing ended for cause at %s\n"); } FD_SET(sock, &ready); if (!select(sock+1, &ready, (fd_set *)0, (fd_set *)0, &rwait)) { if (rwait.tv_sec == 0 && rwait.tv_usec == 0) return(0); continue; } length = sizeof(from); if ((n = recvfrom(sock, (char *)&msgin, sizeof(struct tsp), 0, (struct sockaddr*)&from, &length)) < 0) { syslog(LOG_ERR, "recvfrom: %m"); exit(1); } /* * The 4.3BSD protocol spec had a 32-byte tsp_name field, and * this is still OS-dependent. Demand that the packet is at * least long enough to hold a 4.3BSD packet. */ if (n < (ssize_t)(sizeof(struct tsp) - MAXHOSTNAMELEN + 32)) { syslog(LOG_NOTICE, "short packet (%zd/%zu bytes) from %s", n, sizeof(struct tsp) - MAXHOSTNAMELEN + 32, inet_ntoa(from.sin_addr)); continue; } (void)gettimeofday(&from_when, NULL); bytehostorder(&msgin); if (msgin.tsp_vers > TSPVERSION) { if (trace) { fprintf(fd,"readmsg: version mismatch\n"); /* should do a dump of the packet */ } continue; } if (memchr(msgin.tsp_name, '\0', sizeof msgin.tsp_name) == NULL) { syslog(LOG_NOTICE, "hostname field not NUL terminated " "in packet from %s", inet_ntoa(from.sin_addr)); continue; } fromnet = NULL; for (ntp = nettab; ntp != NULL; ntp = ntp->next) if ((ntp->mask & from.sin_addr.s_addr) == ntp->net.s_addr) { fromnet = ntp; break; } /* * drop packets from nets we are ignoring permanently */ if (fromnet == NULL) { /* * The following messages may originate on * this host with an ignored network address */ if (msgin.tsp_type != TSP_TRACEON && msgin.tsp_type != TSP_SETDATE && msgin.tsp_type != TSP_MSITE && msgin.tsp_type != TSP_TEST && msgin.tsp_type != TSP_TRACEOFF) { if (trace) { fprintf(fd,"readmsg: discard null net "); print(&msgin, &from); } continue; } } /* * Throw away messages coming from this machine, * unless they are of some particular type. * This gets rid of broadcast messages and reduces * master processing time. */ if (!strcmp(msgin.tsp_name, hostname) && msgin.tsp_type != TSP_SETDATE && msgin.tsp_type != TSP_TEST && msgin.tsp_type != TSP_MSITE && msgin.tsp_type != TSP_TRACEON && msgin.tsp_type != TSP_TRACEOFF && msgin.tsp_type != TSP_LOOP) { if (trace) { fprintf(fd, "readmsg: discard own "); print(&msgin, &from); } continue; } /* * Send acknowledgements here; this is faster and * avoids deadlocks that would occur if acks were * sent from a higher level routine. Different * acknowledgements are necessary, depending on * status. */ if (fromnet == NULL) /* do not de-reference 0 */ ignoreack(); else if (fromnet->status == MASTER) masterack(); else if (fromnet->status == SLAVE) slaveack(); else ignoreack(); if (LOOKAT(msgin, type, machfrom, netfrom, from)) { if (trace) { fprintf(fd, "readmsg: "); print(&msgin, &from); } return(&msgin); } else if (++msgcnt > NHOSTS*3) { /* The protocol gets hopelessly confused if it gets too far * behind. However, it seems able to recover from all cases of lost * packets. Therefore, if we are swamped, throw everything away. */ if (trace) fprintf(fd, "readmsg: discarding %d msgs\n", msgcnt); msgcnt = 0; while ((ptr=head->p) != NULL) { head->p = ptr->p; free((char *)ptr); } tail = head; } else { tail->p = (struct tsplist *) malloc(sizeof(struct tsplist)); tail = tail->p; tail->p = NULL; tail->info = msgin; tail->addr = from; /* timestamp msgs so SETTIMEs are correct */ tail->when = from_when; } } } /* * Send the necessary acknowledgements: * only the type ACK is to be sent by a slave */ void slaveack(void) { switch(msgin.tsp_type) { case TSP_ADJTIME: case TSP_SETTIME: case TSP_ACCEPT: case TSP_REFUSE: case TSP_TRACEON: case TSP_TRACEOFF: case TSP_QUIT: if (trace) { fprintf(fd, "Slaveack: "); print(&msgin, &from); } xmit(TSP_ACK,msgin.tsp_seq, &from); break; default: if (trace) { fprintf(fd, "Slaveack: no ack: "); print(&msgin, &from); } break; } } /* * Certain packets may arrive from this machine on ignored networks. * These packets should be acknowledged. */ void ignoreack(void) { switch(msgin.tsp_type) { case TSP_TRACEON: case TSP_TRACEOFF: case TSP_QUIT: if (trace) { fprintf(fd, "Ignoreack: "); print(&msgin, &from); } xmit(TSP_ACK,msgin.tsp_seq, &from); break; default: if (trace) { fprintf(fd, "Ignoreack: no ack: "); print(&msgin, &from); } break; } } /* * `masterack' sends the necessary acknowledgments * to the messages received by a master */ void masterack(void) { struct tsp resp; resp = msgin; resp.tsp_vers = TSPVERSION; (void)strcpy(resp.tsp_name, hostname); switch(msgin.tsp_type) { case TSP_QUIT: case TSP_TRACEON: case TSP_TRACEOFF: case TSP_MSITEREQ: if (trace) { fprintf(fd, "Masterack: "); print(&msgin, &from); } xmit(TSP_ACK,msgin.tsp_seq, &from); break; case TSP_RESOLVE: case TSP_MASTERREQ: if (trace) { fprintf(fd, "Masterack: "); print(&msgin, &from); } xmit(TSP_MASTERACK,msgin.tsp_seq, &from); break; default: if (trace) { fprintf(fd,"Masterack: no ack: "); print(&msgin, &from); } break; } } /* * Print a TSP message */ void print(struct tsp *msg, struct sockaddr_in *addr) { char tm[26]; time_t tsp_time_sec; if (msg->tsp_type >= TSPTYPENUMBER) { fprintf(fd, "bad type (%u) on packet from %s\n", msg->tsp_type, inet_ntoa(addr->sin_addr)); return; } switch (msg->tsp_type) { case TSP_LOOP: fprintf(fd, "%s %d %-6u #%d %-15s %s\n", tsptype[msg->tsp_type], msg->tsp_vers, msg->tsp_seq, msg->tsp_hopcnt, inet_ntoa(addr->sin_addr), msg->tsp_name); break; case TSP_SETTIME: case TSP_SETDATE: case TSP_SETDATEREQ: tsp_time_sec = msg->tsp_time.tv_sec; strncpy(tm, ctime(&tsp_time_sec)+3+1, sizeof(tm)); tm[15] = '\0'; /* ugh */ fprintf(fd, "%s %d %-6u %s %-15s %s\n", tsptype[msg->tsp_type], msg->tsp_vers, msg->tsp_seq, tm, inet_ntoa(addr->sin_addr), msg->tsp_name); break; case TSP_ADJTIME: fprintf(fd, "%s %d %-6u (%d,%d) %-15s %s\n", tsptype[msg->tsp_type], msg->tsp_vers, msg->tsp_seq, msg->tsp_time.tv_sec, msg->tsp_time.tv_usec, inet_ntoa(addr->sin_addr), msg->tsp_name); break; default: fprintf(fd, "%s %d %-6u %-15s %s\n", tsptype[msg->tsp_type], msg->tsp_vers, msg->tsp_seq, inet_ntoa(addr->sin_addr), msg->tsp_name); break; } } Index: head/usr.sbin/timed/timed/slave.c =================================================================== --- head/usr.sbin/timed/timed/slave.c (revision 299706) +++ head/usr.sbin/timed/timed/slave.c (revision 299707) @@ -1,690 +1,690 @@ /*- * Copyright (c) 1985, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef lint #if 0 static char sccsid[] = "@(#)slave.c 8.1 (Berkeley) 6/6/93"; #endif static const char rcsid[] = "$FreeBSD$"; #endif /* not lint */ #include "globals.h" #include #include #include "pathnames.h" extern jmp_buf jmpenv; extern int Mflag; extern int justquit; extern u_short sequence; static char master_name[MAXHOSTNAMELEN]; static struct netinfo *old_slavenet; static int old_status; static void schgdate(struct tsp *, char *); static void setmaster(struct tsp *); static void answerdelay(void); int slave(void) { int tries; long electiontime, refusetime, looktime, looptime, adjtime; u_short seq; long fastelection; #define FASTTOUT 3 struct in_addr cadr; struct timeval otime; struct sockaddr_in taddr; char tname[MAXHOSTNAMELEN]; struct tsp *msg, to; struct timeval ntime, wait, tmptv; time_t tsp_time_sec; struct tsp *answer; int timeout(); char olddate[32]; char newdate[32]; struct netinfo *ntp; struct hosttbl *htp; struct utmpx utx; - old_slavenet = 0; + old_slavenet = NULL; seq = 0; refusetime = 0; adjtime = 0; (void)gettimeofday(&ntime, NULL); electiontime = ntime.tv_sec + delay2; fastelection = ntime.tv_sec + FASTTOUT; if (justquit) looktime = electiontime; else looktime = fastelection; looptime = fastelection; if (slavenet) xmit(TSP_SLAVEUP, 0, &slavenet->dest_addr); if (status & MASTER) { for (ntp = nettab; ntp != NULL; ntp = ntp->next) { if (ntp->status == MASTER) masterup(ntp); } } loop: get_goodgroup(0); (void)gettimeofday(&ntime, NULL); if (ntime.tv_sec > electiontime) { if (trace) fprintf(fd, "election timer expired\n"); longjmp(jmpenv, 1); } if (ntime.tv_sec >= looktime) { if (trace) fprintf(fd, "Looking for nets to master\n"); if (Mflag && nignorednets > 0) { for (ntp = nettab; ntp != NULL; ntp = ntp->next) { if (ntp->status == IGNORE || ntp->status == NOMASTER) { lookformaster(ntp); if (ntp->status == MASTER) { masterup(ntp); } else if (ntp->status == MASTER) { ntp->status = NOMASTER; } } if (ntp->status == MASTER && --ntp->quit_count < 0) ntp->quit_count = 0; } makeslave(slavenet); /* prune extras */ setstatus(); } (void)gettimeofday(&ntime, NULL); looktime = ntime.tv_sec + delay2; } if (ntime.tv_sec >= looptime) { if (trace) fprintf(fd, "Looking for loops\n"); for (ntp = nettab; ntp != NULL; ntp = ntp->next) { if (ntp->status == MASTER) { to.tsp_type = TSP_LOOP; to.tsp_vers = TSPVERSION; to.tsp_seq = sequence++; to.tsp_hopcnt = MAX_HOPCNT; (void)strcpy(to.tsp_name, hostname); bytenetorder(&to); if (sendto(sock, (char *)&to, sizeof(struct tsp), 0, (struct sockaddr*)&ntp->dest_addr, sizeof(ntp->dest_addr)) < 0) { trace_sendto_err(ntp->dest_addr.sin_addr); } } } (void)gettimeofday(&ntime, NULL); looptime = ntime.tv_sec + delay2; } wait.tv_sec = min(electiontime,min(looktime,looptime)) - ntime.tv_sec; if (wait.tv_sec < 0) wait.tv_sec = 0; wait.tv_sec += FASTTOUT; wait.tv_usec = 0; msg = readmsg(TSP_ANY, ANYADDR, &wait, 0); if (msg != NULL) { /* * filter stuff not for us */ switch (msg->tsp_type) { case TSP_SETDATE: case TSP_TRACEOFF: case TSP_TRACEON: /* * XXX check to see they are from ourself */ break; case TSP_TEST: case TSP_MSITE: break; case TSP_MASTERUP: if (!fromnet) { if (trace) { fprintf(fd, "slave ignored: "); print(msg, &from); } goto loop; } break; default: if (!fromnet || fromnet->status == IGNORE || fromnet->status == NOMASTER) { if (trace) { fprintf(fd, "slave ignored: "); print(msg, &from); } goto loop; } break; } /* * now process the message */ switch (msg->tsp_type) { case TSP_ADJTIME: if (fromnet != slavenet) break; if (!good_host_name(msg->tsp_name)) { syslog(LOG_NOTICE, "attempted time adjustment by %s", msg->tsp_name); suppress(&from, msg->tsp_name, fromnet); break; } /* * Speed up loop detection in case we have a loop. * Otherwise the clocks can race until the loop * is found. */ (void)gettimeofday(&otime, NULL); if (adjtime < otime.tv_sec) looptime -= (looptime-otime.tv_sec)/2 + 1; setmaster(msg); if (seq != msg->tsp_seq) { seq = msg->tsp_seq; synch(tvtomsround(msg->tsp_time)); } (void)gettimeofday(&ntime, NULL); electiontime = ntime.tv_sec + delay2; fastelection = ntime.tv_sec + FASTTOUT; adjtime = ntime.tv_sec + SAMPLEINTVL*2; break; case TSP_SETTIME: if (fromnet != slavenet) break; if (seq == msg->tsp_seq) break; seq = msg->tsp_seq; /* adjust time for residence on the queue */ (void)gettimeofday(&otime, NULL); adj_msg_time(msg,&otime); /* * the following line is necessary due to syslog * calling ctime() which clobbers the static buffer */ (void)strcpy(olddate, date()); tsp_time_sec = msg->tsp_time.tv_sec; (void)strcpy(newdate, ctime(&tsp_time_sec)); if (!good_host_name(msg->tsp_name)) { syslog(LOG_NOTICE, "attempted time setting by untrusted %s to %s", msg->tsp_name, newdate); suppress(&from, msg->tsp_name, fromnet); break; } setmaster(msg); tmptv.tv_sec = msg->tsp_time.tv_sec; tmptv.tv_usec = msg->tsp_time.tv_usec; timevalsub(&ntime, &tmptv, &otime); if (ntime.tv_sec < MAXADJ && ntime.tv_sec > -MAXADJ) { /* * do not change the clock if we can adjust it */ synch(tvtomsround(ntime)); } else { utx.ut_type = OLD_TIME; gettimeofday(&utx.ut_tv, NULL); pututxline(&utx); (void)settimeofday(&tmptv, 0); utx.ut_type = NEW_TIME; gettimeofday(&utx.ut_tv, NULL); pututxline(&utx); syslog(LOG_NOTICE, "date changed by %s from %s", msg->tsp_name, olddate); if (status & MASTER) spreadtime(); } (void)gettimeofday(&ntime, NULL); electiontime = ntime.tv_sec + delay2; fastelection = ntime.tv_sec + FASTTOUT; /* This patches a bad protocol bug. Imagine a system with several networks, * where there are a pair of redundant gateways between a pair of networks, * each running timed. Assume that we start with a third machine mastering * one of the networks, and one of the gateways mastering the other. * Imagine that the third machine goes away and the non-master gateway * decides to replace it. If things are timed just 'right,' we will have * each gateway mastering one network for a little while. If a SETTIME * message gets into the network at that time, perhaps from the newly * masterful gateway as it was taking control, the SETTIME will loop * forever. Each time a gateway receives it on its slave side, it will * call spreadtime to forward it on its mastered network. We are now in * a permanent loop, since the SETTIME msgs will keep any clock * in the network from advancing. Normally, the 'LOOP' stuff will detect * and correct the situation. However, with the clocks stopped, the * 'looptime' timer cannot expire. While they are in this state, the * masters will try to saturate the network with SETTIME packets. */ looptime = ntime.tv_sec + (looptime-otime.tv_sec)/2-1; break; case TSP_MASTERUP: if (slavenet && fromnet != slavenet) break; if (!good_host_name(msg->tsp_name)) { suppress(&from, msg->tsp_name, fromnet); if (electiontime > fastelection) electiontime = fastelection; break; } makeslave(fromnet); setmaster(msg); setstatus(); answerdelay(); xmit(TSP_SLAVEUP, 0, &from); (void)gettimeofday(&ntime, NULL); electiontime = ntime.tv_sec + delay2; fastelection = ntime.tv_sec + FASTTOUT; refusetime = 0; break; case TSP_MASTERREQ: if (fromnet->status != SLAVE) break; (void)gettimeofday(&ntime, NULL); electiontime = ntime.tv_sec + delay2; break; case TSP_SETDATE: tsp_time_sec = msg->tsp_time.tv_sec; (void)strcpy(newdate, ctime(&tsp_time_sec)); schgdate(msg, newdate); break; case TSP_SETDATEREQ: if (fromnet->status != MASTER) break; tsp_time_sec = msg->tsp_time.tv_sec; (void)strcpy(newdate, ctime(&tsp_time_sec)); htp = findhost(msg->tsp_name); - if (0 == htp) { + if (htp == NULL) { syslog(LOG_WARNING, "DATEREQ from uncontrolled machine"); break; } if (!htp->good) { syslog(LOG_WARNING, "attempted date change by untrusted %s to %s", htp->name, newdate); spreadtime(); break; } schgdate(msg, newdate); break; case TSP_TRACEON: traceon(); break; case TSP_TRACEOFF: traceoff("Tracing ended at %s\n"); break; case TSP_SLAVEUP: newslave(msg); break; case TSP_ELECTION: if (fromnet->status == SLAVE) { (void)gettimeofday(&ntime, NULL); electiontime = ntime.tv_sec + delay2; fastelection = ntime.tv_sec + FASTTOUT; seq = 0; if (!good_host_name(msg->tsp_name)) { syslog(LOG_NOTICE, "suppress election of %s", msg->tsp_name); to.tsp_type = TSP_QUIT; electiontime = fastelection; } else if (cadr.s_addr != from.sin_addr.s_addr && ntime.tv_sec < refusetime) { /* if the candidate has to repeat itself, the old code would refuse it * the second time. That would prevent elections. */ to.tsp_type = TSP_REFUSE; } else { cadr.s_addr = from.sin_addr.s_addr; to.tsp_type = TSP_ACCEPT; refusetime = ntime.tv_sec + 30; } taddr = from; (void)strcpy(tname, msg->tsp_name); (void)strcpy(to.tsp_name, hostname); answerdelay(); if (!acksend(&to, &taddr, tname, TSP_ACK, 0, 0)) syslog(LOG_WARNING, "no answer from candidate %s\n", tname); } else { /* fromnet->status == MASTER */ htp = addmach(msg->tsp_name, &from,fromnet); to.tsp_type = TSP_QUIT; (void)strcpy(to.tsp_name, hostname); if (!acksend(&to, &htp->addr, htp->name, TSP_ACK, 0, htp->noanswer)) { syslog(LOG_ERR, "no reply from %s to ELECTION-QUIT", htp->name); (void)remmach(htp); } } break; case TSP_CONFLICT: if (fromnet->status != MASTER) break; /* * After a network partition, there can be * more than one master: the first slave to * come up will notify here the situation. */ (void)strcpy(to.tsp_name, hostname); /* The other master often gets into the same state, * with boring results. */ ntp = fromnet; /* (acksend() can leave fromnet=0 */ for (tries = 0; tries < 3; tries++) { to.tsp_type = TSP_RESOLVE; answer = acksend(&to, &ntp->dest_addr, ANYADDR, TSP_MASTERACK, ntp, 0); if (answer == NULL) break; htp = addmach(answer->tsp_name,&from,ntp); to.tsp_type = TSP_QUIT; answer = acksend(&to, &htp->addr, htp->name, TSP_ACK, 0, htp->noanswer); if (!answer) { syslog(LOG_WARNING, "conflict error: no reply from %s to QUIT", htp->name); (void)remmach(htp); } } masterup(ntp); break; case TSP_MSITE: if (!slavenet) break; taddr = from; to.tsp_type = TSP_MSITEREQ; to.tsp_vers = TSPVERSION; to.tsp_seq = 0; (void)strcpy(to.tsp_name, hostname); answer = acksend(&to, &slavenet->dest_addr, ANYADDR, TSP_ACK, slavenet, 0); if (answer != NULL && good_host_name(answer->tsp_name)) { setmaster(answer); to.tsp_type = TSP_ACK; (void)strcpy(to.tsp_name, answer->tsp_name); bytenetorder(&to); if (sendto(sock, (char *)&to, sizeof(struct tsp), 0, (struct sockaddr*)&taddr, sizeof(taddr)) < 0) { trace_sendto_err(taddr.sin_addr); } } break; case TSP_MSITEREQ: break; case TSP_ACCEPT: case TSP_REFUSE: case TSP_RESOLVE: break; case TSP_QUIT: doquit(msg); /* become a slave */ break; case TSP_TEST: electiontime = 0; break; case TSP_LOOP: /* looking for loops of masters */ if (!(status & MASTER)) break; if (fromnet->status == SLAVE) { if (!strcmp(msg->tsp_name, hostname)) { /* * Someone forwarded our message back to * us. There must be a loop. Tell the * master of this network to quit. * * The other master often gets into * the same state, with boring results. */ ntp = fromnet; for (tries = 0; tries < 3; tries++) { to.tsp_type = TSP_RESOLVE; answer = acksend(&to, &ntp->dest_addr, ANYADDR, TSP_MASTERACK, ntp,0); if (answer == NULL) break; taddr = from; (void)strcpy(tname, answer->tsp_name); to.tsp_type = TSP_QUIT; (void)strcpy(to.tsp_name, hostname); if (!acksend(&to, &taddr, tname, TSP_ACK, 0, 1)) { syslog(LOG_ERR, "no reply from %s to slave LOOP-QUIT", tname); } else { electiontime = 0; } } (void)gettimeofday(&ntime, NULL); looptime = ntime.tv_sec + FASTTOUT; } else { if (msg->tsp_hopcnt-- < 1) break; bytenetorder(msg); - for (ntp = nettab; ntp != 0; ntp = ntp->next) { + for (ntp = nettab; ntp != NULL; ntp = ntp->next) { if (ntp->status == MASTER && 0 > sendto(sock, (char *)msg, sizeof(struct tsp), 0, (struct sockaddr*)&ntp->dest_addr, sizeof(ntp->dest_addr))) trace_sendto_err(ntp->dest_addr.sin_addr); } } } else { /* fromnet->status == MASTER */ /* * We should not have received this from a net * we are master on. There must be two masters, * unless the packet was really from us. */ if (from.sin_addr.s_addr == fromnet->my_addr.s_addr) { if (trace) fprintf(fd,"discarding forwarded LOOP\n"); break; } /* * The other master often gets into the same * state, with boring results. */ ntp = fromnet; for (tries = 0; tries < 3; tries++) { to.tsp_type = TSP_RESOLVE; answer = acksend(&to, &ntp->dest_addr, ANYADDR, TSP_MASTERACK, ntp,0); if (!answer) break; htp = addmach(answer->tsp_name, &from,ntp); to.tsp_type = TSP_QUIT; (void)strcpy(to.tsp_name, hostname); if (!acksend(&to,&htp->addr,htp->name, TSP_ACK, 0, htp->noanswer)) { syslog(LOG_ERR, "no reply from %s to master LOOP-QUIT", htp->name); (void)remmach(htp); } } (void)gettimeofday(&ntime, NULL); looptime = ntime.tv_sec + FASTTOUT; } break; default: if (trace) { fprintf(fd, "garbage message: "); print(msg, &from); } break; } } goto loop; } /* * tell the world who our master is */ static void setmaster(struct tsp *msg) { if (slavenet && (slavenet != old_slavenet || strcmp(msg->tsp_name, master_name) || old_status != status)) { (void)strcpy(master_name, msg->tsp_name); old_slavenet = slavenet; old_status = status; if (status & MASTER) { syslog(LOG_NOTICE, "submaster to %s", master_name); if (trace) fprintf(fd, "submaster to %s\n", master_name); } else { syslog(LOG_NOTICE, "slave to %s", master_name); if (trace) fprintf(fd, "slave to %s\n", master_name); } } } /* * handle date change request on a slave */ static void schgdate(struct tsp *msg, char *newdate) { struct tsp to; u_short seq; struct sockaddr_in taddr; struct timeval otime; if (!slavenet) return; /* no where to forward */ taddr = from; seq = msg->tsp_seq; syslog(LOG_INFO, "forwarding date change by %s to %s", msg->tsp_name, newdate); /* adjust time for residence on the queue */ (void)gettimeofday(&otime, NULL); adj_msg_time(msg, &otime); to.tsp_type = TSP_SETDATEREQ; to.tsp_time = msg->tsp_time; (void)strcpy(to.tsp_name, hostname); if (!acksend(&to, &slavenet->dest_addr, ANYADDR, TSP_DATEACK, slavenet, 0)) return; /* no answer */ xmit(TSP_DATEACK, seq, &taddr); } /* * Used before answering a broadcast message to avoid network * contention and likely collisions. */ static void answerdelay(void) { struct timeval timeout; timeout.tv_sec = 0; timeout.tv_usec = delay1; (void)select(0, (fd_set *)NULL, (fd_set *)NULL, (fd_set *)NULL, &timeout); return; } Index: head/usr.sbin/timed/timed/timed.c =================================================================== --- head/usr.sbin/timed/timed/timed.c (revision 299706) +++ head/usr.sbin/timed/timed/timed.c (revision 299707) @@ -1,833 +1,833 @@ /*- * Copyright (c) 1985, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef lint static const char copyright[] = "@(#) Copyright (c) 1985, 1993\n\ The Regents of the University of California. All rights reserved.\n"; #endif /* not lint */ #if 0 #ifndef lint static char sccsid[] = "@(#)timed.c 8.1 (Berkeley) 6/6/93"; #endif /* not lint */ #endif #include __FBSDID("$FreeBSD$"); #include "globals.h" #include #include #include #include #include "pathnames.h" #include #include #include int trace = 0; int sock, sock_raw = -1; int status = 0; u_short sequence; /* sequence number */ long delay1; long delay2; int nslavenets; /* nets were I could be a slave */ int nmasternets; /* nets were I could be a master */ int nignorednets; /* ignored nets */ int nnets; /* nets I am connected to */ FILE *fd; /* trace file FD */ jmp_buf jmpenv; -struct netinfo *nettab = 0; +struct netinfo *nettab = NULL; struct netinfo *slavenet; int Mflag; int justquit = 0; int debug; static struct nets { char *name; long net; struct nets *next; -} *nets = 0; +} *nets = NULL; struct hosttbl hosttbl[NHOSTS+1]; /* known hosts */ static struct goodhost { /* hosts that we trust */ char name[MAXHOSTNAMELEN]; struct goodhost *next; char perm; } *goodhosts; static char *goodgroup; /* net group of trusted hosts */ static void checkignorednets(void); static void pickslavenet(struct netinfo *); static void add_good_host(char *, int); static void usage(void); /* * The timedaemons synchronize the clocks of hosts in a local area network. * One daemon runs as master, all the others as slaves. The master * performs the task of computing clock differences and sends correction * values to the slaves. * Slaves start an election to choose a new master when the latter disappears * because of a machine crash, network partition, or when killed. * A resolution protocol is used to kill all but one of the masters * that happen to exist in segments of a partitioned network when the * network partition is fixed. * * Authors: Riccardo Gusella & Stefano Zatti * * overhauled at Silicon Graphics */ int main(int argc, char *argv[]) { int on; int ret; int nflag, iflag; struct timeval ntime; struct servent *srvp; char buf[BUFSIZ], *cp, *cplim; struct ifconf ifc; struct ifreq ifreq, ifreqf, *ifr; register struct netinfo *ntp; struct netinfo *ntip; struct netinfo *savefromnet; struct netent *nentp; struct nets *nt; struct sockaddr_in server; u_short port; int c; #ifdef lint ntip = NULL; #endif on = 1; nflag = OFF; iflag = OFF; opterr = 0; while ((c = getopt(argc, argv, "Mtdn:i:F:G:P:")) != -1) { switch (c) { case 'M': Mflag = 1; break; case 't': trace = 1; break; case 'n': if (iflag) { errx(1, "-i and -n make no sense together"); } else { nflag = ON; addnetname(optarg); } break; case 'i': if (nflag) { errx(1, "-i and -n make no sense together"); } else { iflag = ON; addnetname(optarg); } break; case 'F': add_good_host(optarg,1); while (optind < argc && argv[optind][0] != '-') add_good_host(argv[optind++], 1); break; case 'd': debug = 1; break; case 'G': - if (goodgroup != 0) + if (goodgroup != NULL) errx(1, "only one net group"); goodgroup = optarg; break; default: usage(); break; } } if (optind < argc) usage(); /* If we care about which machine is the master, then we must * be willing to be a master */ - if (0 != goodgroup || 0 != goodhosts) + if (goodgroup != NULL || goodhosts != NULL) Mflag = 1; if (gethostname(hostname, sizeof(hostname) - 1) < 0) err(1, "gethostname"); self.l_bak = &self; self.l_fwd = &self; self.h_bak = &self; self.h_fwd = &self; self.head = 1; self.good = 1; - if (goodhosts != 0) /* trust ourself */ + if (goodhosts != NULL) /* trust ourself */ add_good_host(hostname,1); srvp = getservbyname("timed", "udp"); - if (srvp == 0) + if (srvp == NULL) errx(1, "timed/udp: unknown service"); port = srvp->s_port; bzero(&server, sizeof(struct sockaddr_in)); server.sin_port = srvp->s_port; server.sin_family = AF_INET; sock = socket(AF_INET, SOCK_DGRAM, 0); if (sock < 0) err(1, "socket"); if (setsockopt(sock, SOL_SOCKET, SO_BROADCAST, (char *)&on, sizeof(on)) < 0) err(1, "setsockopt"); if (bind(sock, (struct sockaddr*)&server, sizeof(server))) { if (errno == EADDRINUSE) warnx("time daemon already running"); else warn("bind"); exit(1); } /* choose a unique seed for random number generation */ (void)gettimeofday(&ntime, NULL); srandom(ntime.tv_sec + ntime.tv_usec); sequence = random(); /* initial seq number */ /* rounds kernel variable time to multiple of 5 ms. */ ntime.tv_sec = 0; ntime.tv_usec = -((ntime.tv_usec/1000) % 5) * 1000; (void)adjtime(&ntime, (struct timeval *)0); for (nt = nets; nt; nt = nt->next) { nentp = getnetbyname(nt->name); - if (nentp == 0) { + if (nentp == NULL) { nt->net = inet_network(nt->name); if (nt->net != INADDR_NONE) nentp = getnetbyaddr(nt->net, AF_INET); } - if (nentp != 0) { + if (nentp != NULL) { nt->net = nentp->n_net; } else if (nt->net == INADDR_NONE) { errx(1, "unknown net %s", nt->name); } else if (nt->net == INADDR_ANY) { errx(1, "bad net %s", nt->name); } else { warnx("warning: %s unknown in /etc/networks", nt->name); } if (0 == (nt->net & 0xff000000)) nt->net <<= 8; if (0 == (nt->net & 0xff000000)) nt->net <<= 8; if (0 == (nt->net & 0xff000000)) nt->net <<= 8; } ifc.ifc_len = sizeof(buf); ifc.ifc_buf = buf; if (ioctl(sock, SIOCGIFCONF, (char *)&ifc) < 0) err(1, "get interface configuration"); ntp = NULL; #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; if (!ntp) ntp = (struct netinfo*)malloc(sizeof(struct netinfo)); bzero(ntp,sizeof(*ntp)); ntp->my_addr=((struct sockaddr_in *)&ifr->ifr_addr)->sin_addr; ntp->status = NOMASTER; ifreq = *ifr; ifreqf = *ifr; if (ioctl(sock, SIOCGIFFLAGS, (char *)&ifreqf) < 0) { warn("get interface flags"); continue; } if ((ifreqf.ifr_flags & IFF_UP) == 0) continue; if ((ifreqf.ifr_flags & IFF_BROADCAST) == 0 && (ifreqf.ifr_flags & IFF_POINTOPOINT) == 0) { continue; } if (ioctl(sock, SIOCGIFNETMASK, (char *)&ifreq) < 0) { warn("get netmask"); continue; } ntp->mask = ((struct sockaddr_in *) &ifreq.ifr_addr)->sin_addr.s_addr; if (ifreqf.ifr_flags & IFF_BROADCAST) { if (ioctl(sock, SIOCGIFBRDADDR, (char *)&ifreq) < 0) { warn("get broadaddr"); continue; } ntp->dest_addr = *(struct sockaddr_in *)&ifreq.ifr_broadaddr; /* What if the broadcast address is all ones? * So we cannot just mask ntp->dest_addr. */ ntp->net = ntp->my_addr; ntp->net.s_addr &= ntp->mask; } else { if (ioctl(sock, SIOCGIFDSTADDR, (char *)&ifreq) < 0) { warn("get destaddr"); continue; } ntp->dest_addr = *(struct sockaddr_in *)&ifreq.ifr_dstaddr; ntp->net = ntp->dest_addr.sin_addr; } ntp->dest_addr.sin_port = port; for (nt = nets; nt; nt = nt->next) { if (ntp->net.s_addr == htonl(nt->net)) break; } if ((nflag && !nt) || (iflag && nt)) continue; ntp->next = NULL; if (nettab == NULL) { nettab = ntp; } else { ntip->next = ntp; } ntip = ntp; ntp = NULL; } if (ntp) (void) free((char *)ntp); if (nettab == NULL) errx(1, "no network usable"); /* microseconds to delay before responding to a broadcast */ delay1 = casual(1, 100*1000); /* election timer delay in secs. */ delay2 = casual(MINTOUT, MAXTOUT); if (!debug) daemon(debug, 0); if (trace) traceon(); openlog("timed", LOG_CONS|LOG_PID, LOG_DAEMON); /* * keep returning here */ ret = setjmp(jmpenv); savefromnet = fromnet; setstatus(); if (Mflag) { switch (ret) { case 0: checkignorednets(); pickslavenet(0); break; case 1: /* Just lost our master */ - if (slavenet != 0) + if (slavenet != NULL) slavenet->status = election(slavenet); if (!slavenet || slavenet->status == MASTER) { checkignorednets(); pickslavenet(0); } else { makeslave(slavenet); /* prune extras */ } break; case 2: /* Just been told to quit */ justquit = 1; pickslavenet(savefromnet); break; } setstatus(); if (!(status & MASTER) && sock_raw != -1) { /* sock_raw is not being used now */ (void)close(sock_raw); sock_raw = -1; } if (status == MASTER) master(); else slave(); } else { if (sock_raw != -1) { (void)close(sock_raw); sock_raw = -1; } if (ret) { /* we just lost our master or were told to quit */ justquit = 1; } for (ntp = nettab; ntp != NULL; ntp = ntp->next) { if (ntp->status == MASTER) { rmnetmachs(ntp); ntp->status = NOMASTER; } } checkignorednets(); pickslavenet(0); setstatus(); slave(); } /* NOTREACHED */ return(0); } static void usage(void) { #ifdef HAVENIS fprintf(stderr, "usage: timed [-dtM] [-i net|-n net] [-F host1 host2 ...] [-G netgp]\n"); #else fprintf(stderr, "usage: timed [-dtM] [-i net|-n net] [-F host1 host2 ...]\n"); #endif /* HAVENIS */ exit(1); } /* * suppress an upstart, untrustworthy, self-appointed master */ void suppress(struct sockaddr_in *addr, char *name, struct netinfo *net) { struct sockaddr_in tgt; char tname[MAXHOSTNAMELEN]; struct tsp msg; static struct timeval wait; if (trace) fprintf(fd, "suppress: %s\n", name); tgt = *addr; (void)strcpy(tname, name); while (0 != readmsg(TSP_ANY, ANYADDR, &wait, net)) { if (trace) fprintf(fd, "suppress:\tdiscarded packet from %s\n", name); } syslog(LOG_NOTICE, "suppressing false master %s", tname); msg.tsp_type = TSP_QUIT; (void)strcpy(msg.tsp_name, hostname); (void)acksend(&msg, &tgt, tname, TSP_ACK, 0, 1); } void lookformaster(struct netinfo *ntp) { struct tsp resp, conflict, *answer; struct timeval ntime; char mastername[MAXHOSTNAMELEN]; struct sockaddr_in masteraddr; get_goodgroup(0); ntp->status = SLAVE; /* look for master */ resp.tsp_type = TSP_MASTERREQ; (void)strcpy(resp.tsp_name, hostname); answer = acksend(&resp, &ntp->dest_addr, ANYADDR, TSP_MASTERACK, ntp, 0); - if (answer != 0 && !good_host_name(answer->tsp_name)) { + if (answer != NULL && !good_host_name(answer->tsp_name)) { suppress(&from, answer->tsp_name, ntp); ntp->status = NOMASTER; - answer = 0; + answer = NULL; } - if (answer == 0) { + if (answer == NULL) { /* * Various conditions can cause conflict: races between * two just started timedaemons when no master is * present, or timedaemons started during an election. * A conservative approach is taken. Give up and became a * slave, postponing election of a master until first * timer expires. */ ntime.tv_sec = ntime.tv_usec = 0; answer = readmsg(TSP_MASTERREQ, ANYADDR, &ntime, ntp); - if (answer != 0) { + if (answer != NULL) { if (!good_host_name(answer->tsp_name)) { suppress(&from, answer->tsp_name, ntp); ntp->status = NOMASTER; } return; } ntime.tv_sec = ntime.tv_usec = 0; answer = readmsg(TSP_MASTERUP, ANYADDR, &ntime, ntp); - if (answer != 0) { + if (answer != NULL) { if (!good_host_name(answer->tsp_name)) { suppress(&from, answer->tsp_name, ntp); ntp->status = NOMASTER; } return; } ntime.tv_sec = ntime.tv_usec = 0; answer = readmsg(TSP_ELECTION, ANYADDR, &ntime, ntp); - if (answer != 0) { + if (answer != NULL) { if (!good_host_name(answer->tsp_name)) { suppress(&from, answer->tsp_name, ntp); ntp->status = NOMASTER; } return; } if (Mflag) ntp->status = MASTER; else ntp->status = NOMASTER; return; } ntp->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. */ ntime.tv_sec = 0; ntime.tv_usec = 300000; answer = readmsg(TSP_MASTERACK, ANYADDR, &ntime, 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, 0, 0)) { syslog(LOG_ERR, "error on sending TSP_CONFLICT"); } } } /* * based on the current network configuration, set the status, and count * networks; */ void setstatus(void) { 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 NOMASTER: case IGNORE: nignorednets++; break; } if (trace) { fprintf(fd, "\t%-16s", inet_ntoa(ntp->net)); switch ((int)ntp->status) { case NOMASTER: fprintf(fd, "NOMASTER\n"); break; 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 delay2=%ld\n", nnets, nmasternets, nslavenets, nignorednets, delay2); } void makeslave(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; } /* * Try to become master over ignored nets.. */ static void checkignorednets(void) { register struct netinfo *ntp; for (ntp = nettab; ntp != NULL; ntp = ntp->next) { if (!Mflag && ntp->status == SLAVE) break; if (ntp->status == IGNORE || ntp->status == NOMASTER) { lookformaster(ntp); if (!Mflag && ntp->status == SLAVE) break; } } } /* * choose a good network on which to be a slave * The ignored networks must have already been checked. * Take a hint about for a good network. */ static void pickslavenet(struct netinfo *ntp) { - if (slavenet != 0 && slavenet->status == SLAVE) { + if (slavenet != NULL && slavenet->status == SLAVE) { makeslave(slavenet); /* prune extras */ return; } - if (ntp == 0 || ntp->status != SLAVE) { - for (ntp = nettab; ntp != 0; ntp = ntp->next) { + if (ntp == NULL || ntp->status != SLAVE) { + for (ntp = nettab; ntp != NULL; ntp = ntp->next) { if (ntp->status == SLAVE) break; } } makeslave(ntp); } /* * returns a random number in the range [inf, sup] */ long casual(long inf, long sup) { double value; value = ((double)(random() & 0x7fffffff)) / (0x7fffffff*1.0); return(inf + (sup - inf)*value); } char * date(void) { time_t tv_sec; tv_sec = time(NULL); return (ctime(&tv_sec)); } void addnetname(char *name) { register struct nets **netlist = &nets; while (*netlist) netlist = &((*netlist)->next); *netlist = (struct nets *)malloc(sizeof **netlist); - if (*netlist == 0) + if (*netlist == NULL) errx(1, "malloc failed"); bzero((char *)*netlist, sizeof(**netlist)); (*netlist)->name = name; } /* note a host as trustworthy * perm 1=not part of the netgroup */ static void add_good_host(char *name, int perm) { register struct goodhost *ghp; register struct hostent *hentp; ghp = (struct goodhost*)malloc(sizeof(*ghp)); if (!ghp) { syslog(LOG_ERR, "malloc failed"); exit(1); } bzero((char*)ghp, sizeof(*ghp)); (void)strncpy(&ghp->name[0], name, sizeof(ghp->name)); ghp->next = goodhosts; ghp->perm = perm; goodhosts = ghp; hentp = gethostbyname(name); - if (0 == hentp && perm) + if (hentp == NULL && perm) warnx("unknown host %s", name); } /* update our image of the net-group of trustworthy hosts */ void get_goodgroup(int force) { # define NG_DELAY (30*60*CLK_TCK) /* 30 minutes */ static unsigned long last_update = -NG_DELAY; unsigned long new_update; struct goodhost *ghp, **ghpp; #ifdef HAVENIS struct hosttbl *htp; char *mach, *usr, *dom; #endif /* HAVENIS */ struct tms tm; /* if no netgroup, then we are finished */ - if (goodgroup == 0 || !Mflag) + if (goodgroup == NULL || !Mflag) return; /* Do not chatter with the netgroup master too often. */ new_update = times(&tm); if (new_update < last_update + NG_DELAY && !force) return; last_update = new_update; /* forget the old temporary entries */ ghpp = &goodhosts; - while (0 != (ghp = *ghpp)) { + while ((ghp = *ghpp) != NULL) { if (!ghp->perm) { *ghpp = ghp->next; - free((char*)ghp); + free(ghp); } else { ghpp = &ghp->next; } } #ifdef HAVENIS /* quit now if we are not one of the trusted masters */ if (!innetgr(goodgroup, &hostname[0], 0,0)) { if (trace) (void)fprintf(fd, "get_goodgroup: %s not in %s\n", &hostname[0], goodgroup); return; } if (trace) (void)fprintf(fd, "get_goodgroup: %s in %s\n", &hostname[0], goodgroup); /* mark the entire netgroup as trusted */ (void)setnetgrent(goodgroup); while (getnetgrent(&mach,&usr,&dom)) { - if (0 != mach) + if (mach != NULL) add_good_host(mach,0); } (void)endnetgrent(); /* update list of slaves */ for (htp = self.l_fwd; htp != &self; htp = htp->l_fwd) { htp->good = good_host_name(&htp->name[0]); } #endif /* HAVENIS */ } /* see if a machine is trustworthy */ int /* 1=trust hp to change our date */ good_host_name(char *name) { register struct goodhost *ghp = goodhosts; register char c; if (!ghp || !Mflag) /* trust everyone if no one named */ return 1; c = *name; do { if (c == ghp->name[0] && !strcasecmp(name, ghp->name)) return 1; /* found him, so say so */ - } while (0 != (ghp = ghp->next)); + } while ((ghp = ghp->next) != NULL); if (!strcasecmp(name,hostname)) /* trust ourself */ return 1; return 0; /* did not find him */ } Index: head/usr.sbin/timed/timedc/cmds.c =================================================================== --- head/usr.sbin/timed/timedc/cmds.c (revision 299706) +++ head/usr.sbin/timed/timedc/cmds.c (revision 299707) @@ -1,542 +1,542 @@ /*- * Copyright (c) 1985, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #if 0 #ifndef lint static char sccsid[] = "@(#)cmds.c 8.1 (Berkeley) 6/6/93"; #endif /* not lint */ #endif #include __FBSDID("$FreeBSD$"); #include "timedc.h" #include #include #include #include #include #include #include #include #include #define TSPTYPES #include #define SECHR (60*60) #define SECDAY (24*SECHR) # define DATE_PROTO "udp" # define DATE_PORT "time" int sock; int sock_raw; char myname[MAXHOSTNAMELEN]; struct hostent *hp; struct sockaddr_in server; struct sockaddr_in dayaddr; extern int measure_delta; void bytenetorder(struct tsp *); void bytehostorder(struct tsp *); #define BU (2208988800UL) /* seconds before UNIX epoch */ /* compute the difference between our date and another machine */ static int /* difference in days from our time */ daydiff(char *hostname) { int i; int trials; struct timeval tout, now; fd_set ready; struct sockaddr from; int fromlen; unsigned long sec; /* wait 2 seconds between 10 tries */ tout.tv_sec = 2; tout.tv_usec = 0; for (trials = 0; trials < 10; trials++) { /* ask for the time */ sec = 0; if (sendto(sock, &sec, sizeof(sec), 0, (struct sockaddr*)&dayaddr, sizeof(dayaddr)) < 0) { warn("sendto(sock)"); return 0; } for (;;) { FD_ZERO(&ready); FD_SET(sock, &ready); i = select(sock+1, &ready, (fd_set *)0, (fd_set *)0, &tout); if (i < 0) { if (errno == EINTR) continue; warn("select(date read)"); return 0; } if (0 == i) break; fromlen = sizeof(from); if (recvfrom(sock,&sec,sizeof(sec),0, &from,&fromlen) < 0) { warn("recvfrom(date read)"); return 0; } sec = ntohl(sec); if (sec < BU) { warnx("%s says it is before 1970: %lu", hostname, sec); return 0; } sec -= BU; (void)gettimeofday(&now, NULL); return (sec - now.tv_sec); } } /* if we get here, we tried too many times */ warnx("%s will not tell us the date", hostname); return 0; } /* * Clockdiff computes the difference between the time of the machine on * which it is called and the time of the machines given as argument. * The time differences measured by clockdiff are obtained using a sequence * of ICMP TSTAMP messages which are returned to the sender by the IP module * in the remote machine. * In order to compare clocks of machines in different time zones, the time * is transmitted (as a 32-bit value) in milliseconds since midnight UT. * If a hosts uses a different time format, it should set the high order * bit of the 32-bit quantity it transmits. * However, VMS apparently transmits the time in milliseconds since midnight * local time (rather than GMT) without setting the high order bit. * Furthermore, it does not understand daylight-saving time. This makes * clockdiff behaving inconsistently with hosts running VMS. * * In order to reduce the sensitivity to the variance of message transmission * time, clockdiff sends a sequence of messages. Yet, measures between * two `distant' hosts can be affected by a small error. The error can, * however, be reduced by increasing the number of messages sent in each * measurement. */ void clockdiff(int argc, char *argv[]) { int measure_status; extern int measure(u_long, u_long, char *, struct sockaddr_in*, int); register int avg_cnt; register long avg; struct servent *sp; if (argc < 2) { printf("usage: timedc clockdiff host ...\n"); return; } if (gethostname(myname, sizeof(myname) - 1) < 0) err(1, "gethostname"); /* get the address for the date ready */ sp = getservbyname(DATE_PORT, DATE_PROTO); if (!sp) { warnx("%s/%s: unknown service", DATE_PORT, DATE_PROTO); dayaddr.sin_port = 0; } else { dayaddr.sin_port = sp->s_port; } while (argc > 1) { argc--; argv++; hp = gethostbyname(*argv); if (hp == NULL) { warnx("%s: %s", *argv, hstrerror(h_errno)); continue; } server.sin_family = hp->h_addrtype; bcopy(hp->h_addr, &server.sin_addr.s_addr, hp->h_length); for (avg_cnt = 0, avg = 0; avg_cnt < 16; avg_cnt++) { measure_status = measure(10000,100, *argv, &server, 1); if (measure_status != GOOD) break; avg += measure_delta; } if (measure_status == GOOD) measure_delta = avg/avg_cnt; switch (measure_status) { case HOSTDOWN: printf("%s is down\n", hp->h_name); continue; case NONSTDTIME: printf("%s transmits a non-standard time format\n", hp->h_name); continue; case UNREACHABLE: printf("%s is unreachable\n", hp->h_name); continue; } /* * Try to get the date only after using ICMP timestamps to * get the time. This is because the date protocol * is optional. */ if (dayaddr.sin_port != 0) { dayaddr.sin_family = hp->h_addrtype; bcopy(hp->h_addr, &dayaddr.sin_addr.s_addr, hp->h_length); avg = daydiff(*argv); if (avg > SECDAY) { printf("time on %s is %ld days ahead %s\n", hp->h_name, avg/SECDAY, myname); continue; } else if (avg < -SECDAY) { printf("time on %s is %ld days behind %s\n", hp->h_name, -avg/SECDAY, myname); continue; } } if (measure_delta > 0) { printf("time on %s is %d ms. ahead of time on %s\n", hp->h_name, measure_delta, myname); } else if (measure_delta == 0) { printf("%s and %s have the same time\n", hp->h_name, myname); } else { printf("time on %s is %d ms. behind time on %s\n", hp->h_name, -measure_delta, myname); } } return; } /* * finds location of master timedaemon */ void msite(int argc, char *argv[]) { ssize_t cc; fd_set ready; struct sockaddr_in dest; int i, length; struct sockaddr_in from; struct timeval tout; struct tsp msg; struct servent *srvp; char *tgtname; if (argc < 1) { printf("usage: timedc msite [host ...]\n"); return; } srvp = getservbyname("timed", "udp"); - if (srvp == 0) { + if (srvp == NULL) { warnx("timed/udp: unknown service"); return; } dest.sin_port = srvp->s_port; dest.sin_family = AF_INET; if (gethostname(myname, sizeof(myname) - 1) < 0) err(1, "gethostname"); i = 1; do { tgtname = (i >= argc) ? myname : argv[i]; hp = gethostbyname(tgtname); - if (hp == 0) { + if (hp == NULL) { warnx("%s: %s", tgtname, hstrerror(h_errno)); continue; } bcopy(hp->h_addr, &dest.sin_addr.s_addr, hp->h_length); (void)strlcpy(msg.tsp_name, myname, sizeof(msg.tsp_name)); msg.tsp_type = TSP_MSITE; msg.tsp_vers = TSPVERSION; bytenetorder(&msg); if (sendto(sock, &msg, sizeof(struct tsp), 0, (struct sockaddr*)&dest, sizeof(struct sockaddr)) < 0) { warn("sendto"); continue; } tout.tv_sec = 15; tout.tv_usec = 0; FD_ZERO(&ready); FD_SET(sock, &ready); if (select(FD_SETSIZE, &ready, (fd_set *)0, (fd_set *)0, &tout)) { length = sizeof(from); cc = recvfrom(sock, &msg, sizeof(struct tsp), 0, (struct sockaddr *)&from, &length); if (cc < 0) { warn("recvfrom"); continue; } /* * The 4.3BSD protocol spec had a 32-byte tsp_name field, and * this is still OS-dependent. Demand that the packet is at * least long enough to hold a 4.3BSD packet. */ if (cc < (sizeof(struct tsp) - MAXHOSTNAMELEN + 32)) { fprintf(stderr, "short packet (%zd/%zu bytes) from %s\n", cc, sizeof(struct tsp) - MAXHOSTNAMELEN + 32, inet_ntoa(from.sin_addr)); continue; } bytehostorder(&msg); if (msg.tsp_type == TSP_ACK) { printf("master timedaemon at %s is %s\n", tgtname, msg.tsp_name); } else { if (msg.tsp_type >= TSPTYPENUMBER) printf("unknown ack received: %u\n", msg.tsp_type); else printf("wrong ack received: %s\n", tsptype[msg.tsp_type]); } } else { printf("communication error with %s\n", tgtname); } } while (++i < argc); } /* * quits timedc */ void quit(void) { exit(0); } /* * Causes the election timer to expire on the selected hosts * It sends just one udp message per machine, relying on * reliability of communication channel. */ void testing(int argc, char *argv[]) { struct servent *srvp; struct sockaddr_in sin; struct tsp msg; if (argc < 2) { printf("usage: timedc election host1 [host2 ...]\n"); return; } srvp = getservbyname("timed", "udp"); - if (srvp == 0) { + if (srvp == NULL) { warnx("timed/udp: unknown service"); return; } while (argc > 1) { argc--; argv++; hp = gethostbyname(*argv); if (hp == NULL) { warnx("%s: %s", *argv, hstrerror(h_errno)); argc--; argv++; continue; } sin.sin_port = srvp->s_port; sin.sin_family = hp->h_addrtype; bcopy(hp->h_addr, &sin.sin_addr.s_addr, hp->h_length); msg.tsp_type = TSP_TEST; msg.tsp_vers = TSPVERSION; if (gethostname(myname, sizeof(myname) - 1) < 0) err(1, "gethostname"); (void)strlcpy(msg.tsp_name, myname, sizeof(msg.tsp_name)); bytenetorder(&msg); if (sendto(sock, &msg, sizeof(struct tsp), 0, (struct sockaddr*)&sin, sizeof(struct sockaddr)) < 0) { warn("sendto"); } } } /* * Enables or disables tracing on local timedaemon */ void tracing(int argc, char *argv[]) { int onflag; int length; ssize_t cc; fd_set ready; struct sockaddr_in dest; struct sockaddr_in from; struct timeval tout; struct tsp msg; struct servent *srvp; if (argc != 2) { printf("usage: timedc trace { on | off }\n"); return; } srvp = getservbyname("timed", "udp"); - if (srvp == 0) { + if (srvp == NULL) { warnx("timed/udp: unknown service"); return; } dest.sin_port = srvp->s_port; dest.sin_family = AF_INET; if (gethostname(myname, sizeof(myname) - 1) < 0) err(1, "gethostname"); hp = gethostbyname(myname); bcopy(hp->h_addr, &dest.sin_addr.s_addr, hp->h_length); if (strcmp(argv[1], "on") == 0) { msg.tsp_type = TSP_TRACEON; onflag = ON; } else { msg.tsp_type = TSP_TRACEOFF; onflag = OFF; } (void)strcpy(msg.tsp_name, myname); msg.tsp_vers = TSPVERSION; bytenetorder(&msg); if (sendto(sock, &msg, sizeof(struct tsp), 0, (struct sockaddr*)&dest, sizeof(struct sockaddr)) < 0) { warn("sendto"); return; } tout.tv_sec = 5; tout.tv_usec = 0; FD_ZERO(&ready); FD_SET(sock, &ready); if (select(FD_SETSIZE, &ready, (fd_set *)0, (fd_set *)0, &tout)) { length = sizeof(from); cc = recvfrom(sock, &msg, sizeof(struct tsp), 0, (struct sockaddr *)&from, &length); if (cc < 0) { warn("recvfrom"); return; } /* * The 4.3BSD protocol spec had a 32-byte tsp_name field, and * this is still OS-dependent. Demand that the packet is at * least long enough to hold a 4.3BSD packet. */ if (cc < (sizeof(struct tsp) - MAXHOSTNAMELEN + 32)) { fprintf(stderr, "short packet (%zd/%zu bytes) from %s\n", cc, sizeof(struct tsp) - MAXHOSTNAMELEN + 32, inet_ntoa(from.sin_addr)); return; } bytehostorder(&msg); if (msg.tsp_type == TSP_ACK) if (onflag) printf("timed tracing enabled\n"); else printf("timed tracing disabled\n"); else { if (msg.tsp_type >= TSPTYPENUMBER) printf("unknown ack received: %u\n", msg.tsp_type); else printf("wrong ack received: %s\n", tsptype[msg.tsp_type]); } } else printf("communication error\n"); } int priv_resources(void) { int port; struct sockaddr_in sin; sock = socket(AF_INET, SOCK_DGRAM, 0); if (sock < 0) { warn("opening socket"); return(-1); } sin.sin_family = AF_INET; sin.sin_addr.s_addr = 0; for (port = IPPORT_RESERVED - 1; port > IPPORT_RESERVED / 2; port--) { sin.sin_port = htons((u_short)port); if (bind(sock, (struct sockaddr*)&sin, sizeof (sin)) >= 0) break; if (errno != EADDRINUSE && errno != EADDRNOTAVAIL) { warn("bind"); (void) close(sock); return(-1); } } if (port == IPPORT_RESERVED / 2) { warnx("all reserved ports in use"); (void) close(sock); return(-1); } sock_raw = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP); if (sock_raw < 0) { warn("opening raw socket"); (void) close(sock); return(-1); } return(1); } Index: head/usr.sbin/timed/timedc/timedc.c =================================================================== --- head/usr.sbin/timed/timedc/timedc.c (revision 299706) +++ head/usr.sbin/timed/timedc/timedc.c (revision 299707) @@ -1,252 +1,252 @@ /*- * Copyright (c) 1985, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 4. 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 BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef lint static const char copyright[] = "@(#) Copyright (c) 1985, 1993\n\ The Regents of the University of California. All rights reserved.\n"; #endif /* not lint */ #ifndef lint #if 0 static char sccsid[] = "@(#)timedc.c 8.1 (Berkeley) 6/6/93"; #endif static const char rcsid[] = "$FreeBSD$"; #endif /* not lint */ #include "timedc.h" #include #include #include #include #include #include #include #include int trace = 0; -FILE *fd = 0; +FILE *fd = NULL; int margc; int fromatty; #define MAX_MARGV 20 char *margv[MAX_MARGV]; char cmdline[200]; jmp_buf toplevel; static struct cmd *getcmd(char *); int main(int argc, char *argv[]) { register struct cmd *c; openlog("timedc", 0, LOG_AUTH); /* * security dictates! */ if (priv_resources() < 0) errx(1, "could not get privileged resources"); if (setuid(getuid()) != 0) err(1, "setuid()"); if (--argc > 0) { c = getcmd(*++argv); if (c == (struct cmd *)-1) { printf("?Ambiguous command\n"); exit(1); } - if (c == 0) { + if (c == NULL) { printf("?Invalid command\n"); exit(1); } if (c->c_priv && getuid()) { printf("?Privileged command\n"); exit(1); } (*c->c_handler)(argc, argv); exit(0); } fromatty = isatty(fileno(stdin)); if (setjmp(toplevel)) putchar('\n'); (void) signal(SIGINT, intr); for (;;) { if (fromatty) { printf("timedc> "); (void) fflush(stdout); } if (fgets(cmdline, sizeof(cmdline), stdin) == NULL) quit(); if (cmdline[0] == 0) break; makeargv(); - if (margv[0] == 0) + if (margv[0] == NULL) continue; c = getcmd(margv[0]); if (c == (struct cmd *)-1) { printf("?Ambiguous command\n"); continue; } - if (c == 0) { + if (c == NULL) { printf("?Invalid command\n"); continue; } if (c->c_priv && getuid()) { printf("?Privileged command\n"); continue; } (*c->c_handler)(margc, margv); } return 0; } void intr(int signo __unused) { if (!fromatty) exit(0); longjmp(toplevel, 1); } static struct cmd * getcmd(char *name) { register char *p, *q; register struct cmd *c, *found; register int nmatches, longest; extern int NCMDS; longest = 0; nmatches = 0; - found = 0; + found = NULL; for (c = cmdtab; c < &cmdtab[NCMDS]; c++) { p = c->c_name; for (q = name; *q == *p++; q++) if (*q == 0) /* exact match? */ return(c); if (!*q) { /* the name was a prefix */ if (q - name > longest) { longest = q - name; nmatches = 1; found = c; } else if (q - name == longest) nmatches++; } } if (nmatches > 1) return((struct cmd *)-1); return(found); } /* * Slice a string up into argc/argv. */ void makeargv(void) { register char *cp; register char **argp = margv; margc = 0; for (cp = cmdline; margc < MAX_MARGV - 1 && *cp; ) { while (isspace(*cp)) cp++; if (*cp == '\0') break; *argp++ = cp; margc += 1; while (*cp != '\0' && !isspace(*cp)) cp++; if (*cp == '\0') break; *cp++ = '\0'; } - *argp++ = 0; + *argp++ = NULL; } #define HELPINDENT (sizeof ("directory")) /* * Help command. */ void help(int argc, char *argv[]) { register struct cmd *c; if (argc == 1) { register int i, j, w; int columns, width = 0, lines; extern int NCMDS; printf("Commands may be abbreviated. Commands are:\n\n"); for (c = cmdtab; c < &cmdtab[NCMDS]; c++) { int len = strlen(c->c_name); if (len > width) width = len; } width = (width + 8) &~ 7; columns = 80 / width; if (columns == 0) columns = 1; lines = (NCMDS + columns - 1) / columns; for (i = 0; i < lines; i++) { for (j = 0; j < columns; j++) { c = cmdtab + j * lines + i; printf("%s", c->c_name); if (c + lines >= &cmdtab[NCMDS]) { printf("\n"); break; } w = strlen(c->c_name); while (w < width) { w = (w + 8) &~ 7; putchar('\t'); } } } return; } while (--argc > 0) { register char *arg; arg = *++argv; c = getcmd(arg); if (c == (struct cmd *)-1) printf("?Ambiguous help command %s\n", arg); else if (c == (struct cmd *)0) printf("?Invalid help command %s\n", arg); else printf("%-*s\t%s\n", (int)HELPINDENT, c->c_name, c->c_help); } }