Ejemplo n.º 1
0
/*
 * set_freq - set clock frequency correction
 *
 * Used to step the frequency correction at startup, possibly again once
 * the frequency is measured (that is, transitioning from EVNT_NSET to
 * EVNT_FSET), and finally to switch between daemon and kernel loop
 * discipline at runtime.
 *
 * When the kernel loop discipline is available but the daemon loop is
 * in use, the kernel frequency correction is disabled (set to 0) to
 * ensure drift_comp is applied by only one of the loops.
 */
static void
set_freq(
	double	freq		/* frequency update */
	)
{
	const char *	loop_desc;
	int ntp_adj_ret;

	drift_comp = freq;
	loop_desc = "ntpd";
#ifdef KERNEL_PLL
	if (pll_control) {
		ZERO(ntv);
		ntv.modes = MOD_FREQUENCY;
		if (kern_enable) {
			loop_desc = "kernel";
			ntv.freq = DTOFREQ(drift_comp);
		}
		if ((ntp_adj_ret = ntp_adjtime(&ntv)) != 0) {
		    ntp_adjtime_error_handler(__func__, &ntv, ntp_adj_ret, errno, 0, 0, __LINE__ - 1);
		}
	}
#endif /* KERNEL_PLL */
	mprintf_event(EVNT_FSET, NULL, "%s %.3f PPM", loop_desc,
	    drift_comp * 1e6);
}
Ejemplo n.º 2
0
/*
 * unpeer - remove peer structure from hash table and free structure
 */
void
unpeer(
	struct peer *peer
	)
{
	mprintf_event(PEVNT_DEMOBIL, peer, "assoc %u", peer->associd);
	restrict_source(&peer->srcadr, 1, 0);
	set_peerdstadr(peer, NULL);
	peer_demobilizations++;
	peer_associations--;
	if (FLAG_PREEMPT & peer->flags)
		peer_preempt--;
#ifdef REFCLOCK
	/*
	 * If this peer is actually a clock, shut it down first
	 */
	if (FLAG_REFCLOCK & peer->flags)
		refclock_unpeer(peer);
#endif

	free_peer(peer, TRUE);
}
Ejemplo n.º 3
0
/*
 * stats_config - configure the stats operation
 */
void
stats_config(
	int item,
	const char *invalue	/* only one type so far */
	)
{
	FILE	*fp;
	const char *value;
	int	len;
	double	old_drift;
	l_fp	now;
	time_t  ttnow;
#ifndef VMS
	const char temp_ext[] = ".TEMP";
#else
	const char temp_ext[] = "-TEMP";
#endif

	/*
	 * Expand environment strings under Windows NT, since the
	 * command interpreter doesn't do this, the program must.
	 */
#ifdef SYS_WINNT
	char newvalue[MAX_PATH], parameter[MAX_PATH];

	if (!ExpandEnvironmentStrings(invalue, newvalue, MAX_PATH)) {
		switch (item) {
		case STATS_FREQ_FILE:
			strlcpy(parameter, "STATS_FREQ_FILE",
				sizeof(parameter));
			break;

		case STATS_LEAP_FILE:
			strlcpy(parameter, "STATS_LEAP_FILE",
				sizeof(parameter));
			break;

		case STATS_STATSDIR:
			strlcpy(parameter, "STATS_STATSDIR",
				sizeof(parameter));
			break;

		case STATS_PID_FILE:
			strlcpy(parameter, "STATS_PID_FILE",
				sizeof(parameter));
			break;

		default:
			strlcpy(parameter, "UNKNOWN",
				sizeof(parameter));
			break;
		}
		value = invalue;
		msyslog(LOG_ERR,
			"ExpandEnvironmentStrings(%s) failed: %m\n",
			parameter);
	} else {
		value = newvalue;
	}
#else	 
	value = invalue;
#endif /* SYS_WINNT */

	switch (item) {

	/*
	 * Open and read frequency file.
	 */
	case STATS_FREQ_FILE:
		if (!value || (len = strlen(value)) == 0)
			break;

		stats_drift_file = erealloc(stats_drift_file, len + 1);
		stats_temp_file = erealloc(stats_temp_file, 
		    len + sizeof(".TEMP"));
		memcpy(stats_drift_file, value, (size_t)(len+1));
		memcpy(stats_temp_file, value, (size_t)len);
		memcpy(stats_temp_file + len, temp_ext, sizeof(temp_ext));

		/*
		 * Open drift file and read frequency. If the file is
		 * missing or contains errors, tell the loop to reset.
		 */
		if ((fp = fopen(stats_drift_file, "r")) == NULL)
			break;

		if (fscanf(fp, "%lf", &old_drift) != 1) {
			msyslog(LOG_ERR,
				"format error frequency file %s", 
				stats_drift_file);
			fclose(fp);
			break;

		}
		fclose(fp);
		loop_config(LOOP_FREQ, old_drift);
		prev_drift_comp = drift_comp;
		break;

	/*
	 * Specify statistics directory.
	 */
	case STATS_STATSDIR:

		/* - 1 since value may be missing the DIR_SEP. */
		if (strlen(value) >= sizeof(statsdir) - 1) {
			msyslog(LOG_ERR,
			    "statsdir too long (>%d, sigh)",
			    (int)sizeof(statsdir) - 2);
		} else {
			int add_dir_sep;
			int value_l;

			/* Add a DIR_SEP unless we already have one. */
			value_l = strlen(value);
			if (0 == value_l)
				add_dir_sep = FALSE;
			else
				add_dir_sep = (DIR_SEP !=
				    value[value_l - 1]);

			if (add_dir_sep)
				snprintf(statsdir, sizeof(statsdir),
				    "%s%c", value, DIR_SEP);
			else
				snprintf(statsdir, sizeof(statsdir),
				    "%s", value);
			filegen_statsdir();
		}
		break;

	/*
	 * Open pid file.
	 */
	case STATS_PID_FILE:
		if ((fp = fopen(value, "w")) == NULL) {
			msyslog(LOG_ERR, "pid file %s: %m",
			    value);
			break;
		}
		fprintf(fp, "%d", (int)getpid());
		fclose(fp);
		break;

	/*
	 * Read leapseconds file.
	 *
	 * Note: Currently a leap file without SHA1 signature is
	 * accepted, but if there is a signature line, the signature
	 * must be valid or the file is rejected.
	 */
	case STATS_LEAP_FILE:
		if (!value || (len = strlen(value)) == 0)
			break;

		leapfile_name = erealloc(leapfile_name, len + 1);
		memcpy(leapfile_name, value, len + 1);

		if (leapsec_load_file(
			    leapfile_name, &leapfile_stat, TRUE, TRUE))
		{
			leap_signature_t lsig;

			get_systime(&now);
			time(&ttnow);
			leapsec_getsig(&lsig);
			mprintf_event(EVNT_TAI, NULL,
				      "%d leap %s %s %s",
				      lsig.taiof,
				      fstostr(lsig.ttime),
				      leapsec_expired(now.l_ui, NULL)
					  ? "expired"
					  : "expires",
				      fstostr(lsig.etime));

			have_leapfile = TRUE;

			/* force an immediate daily expiration check of
			 * the leap seconds table
			 */
			check_leap_expiration(TRUE, now.l_ui, &ttnow);
		}
		break;

	default:
		/* oh well */
		break;
	}
}
Ejemplo n.º 4
0
/*
 * acts_timeout - called on timeout
 */
static void
acts_timeout(
	struct peer *peer,
	teModemState	dstate
	)
{
	struct actsunit *up;
	struct refclockproc *pp;
	int	fd;
	int	rc;
	char	device[20];
	char	lockfile[128], pidbuf[8];

	/*
	 * The state machine is driven by messages from the modem,
	 * when first started and at timeout.
	 */
	pp = peer->procptr;
	up = pp->unitptr;
	switch (dstate) {

	/*
	 * System poll event. Lock the modem port, open the device
	 * and send the setup command.
	 */
	case S_IDLE:
		if (-1 != pp->io.fd)
			return;		/* port is already open */

		/*
		 * Lock the modem port. If busy, retry later. Note: if
		 * something fails between here and the close, the lock
		 * file may not be removed.
		 */
		if (pp->sloppyclockflag & CLK_FLAG2) {
			snprintf(lockfile, sizeof(lockfile), LOCKFILE,
			    up->unit);
			fd = open(lockfile, O_WRONLY | O_CREAT | O_EXCL,
			    0644);
			if (fd < 0) {
				report_event(PEVNT_CLOCK, peer, "acts: port busy");
				return;
			}
			snprintf(pidbuf, sizeof(pidbuf), "%d\n",
			    (u_int)getpid());
			if (write(fd, pidbuf, strlen(pidbuf)) < 0)
				msyslog(LOG_ERR, "acts: write lock fails %m");
			close(fd);
		}

		/*
		 * Open the device in raw mode and link the I/O.
		 */
		snprintf(device, sizeof(device), DEVICE,
		    up->unit);
		fd = refclock_open(device, SPEED232, LDISC_ACTS |
		    LDISC_RAW | LDISC_REMOTE);
		if (fd < 0) {
			msyslog(LOG_ERR, "acts: open fails %m");
			return;
		}
		pp->io.fd = fd;
		if (!io_addclock(&pp->io)) {
			msyslog(LOG_ERR, "acts: addclock fails");
			close(fd);
			pp->io.fd = -1;
			return;
		}
		up->msgcnt = 0;
		up->bufptr = up->buf;

		/*
		 * If the port is directly connected to the device, skip
		 * the modem business and send 'T' for Spectrabum.
		 */
		if (sys_phone[up->retry] == NULL) {
			if (write(pp->io.fd, "T", 1) < 0)
				msyslog(LOG_ERR, "acts: write T fails %m");
			up->state = S_MSG;
			up->timer = TIMECODE;
			return;
		}

		/*
		 * Initialize the modem. This works with Hayes-
		 * compatible modems.
		 */
		mprintf_event(PEVNT_CLOCK, peer, "SETUP %s",
			      modem_setup);
		rc = write(pp->io.fd, modem_setup, strlen(modem_setup));
		if (rc < 0)
			msyslog(LOG_ERR, "acts: write SETUP fails %m");
		write(pp->io.fd, "\r", 1);
		up->state = S_SETUP;
		up->timer = SETUP;
		return;

	/*
	 * In SETUP state the modem did not respond OK to setup string.
	 */
	case S_SETUP:
		report_event(PEVNT_CLOCK, peer, "no modem");
		break;

	/*
	 * In CONNECT state the call did not complete. Abort the call.
	 */
	case S_CONNECT:
		report_event(PEVNT_CLOCK, peer, "no answer");
		break;

	/*
	 * In MSG states no further timecodes are expected. If any
	 * timecodes have arrived, update the clock. In any case,
	 * terminate the call.
	 */
	case S_MSG:
		if (up->msgcnt == 0) {
			report_event(PEVNT_CLOCK, peer, "no timecodes");
		} else {
			pp->lastref = pp->lastrec;
			record_clock_stats(&peer->srcadr, pp->a_lastcode);
			refclock_receive(peer);
		}
		break;
	}
	acts_close(peer);
}
Ejemplo n.º 5
0
/*
 * acts_message - process message
 */
void
acts_message(
	struct peer *peer,
	const char *msg
	)
{
	struct actsunit *up;
	struct refclockproc *pp;
	char	tbuf[BMAX];
	int		dtr = TIOCM_DTR;

	DPRINTF(1, ("acts: %d %s\n", (int)strlen(msg), msg));

	/*
	 * What to do depends on the state and the first token in the
	 * message.
	 */
	pp = peer->procptr;
	up = pp->unitptr;

	/*
	 * Extract the first token in the line.
	 */
	strlcpy(tbuf, msg, sizeof(tbuf));
	strtok(tbuf, " ");
	switch (up->state) {

	/*
	 * We are waiting for the OK response to the modem setup
	 * command. When this happens, dial the number followed.
	 * If anything other than OK is received, just ignore it
	 * and wait for timeoue.
	 */
	case S_SETUP:
		if (strcmp(tbuf, "OK") != 0) {
			/*
			 * We disable echo with MODEM_SETUP's E0 but
			 * if the modem was previously E1, we will
			 * see MODEM_SETUP echoed before the OK/ERROR.
			 * Ignore it.
			 */
			if (!strcmp(tbuf, modem_setup))
				return;
			break;
		}

		mprintf_event(PEVNT_CLOCK, peer, "DIAL #%d %s",
			      up->retry, sys_phone[up->retry]);
		if (ioctl(pp->io.fd, TIOCMBIS, &dtr) < 0)
			msyslog(LOG_ERR, "acts: ioctl(TIOCMBIS) failed: %m");
		if (write(pp->io.fd, sys_phone[up->retry],
		    strlen(sys_phone[up->retry])) < 0)
			msyslog(LOG_ERR, "acts: write DIAL fails %m");
		write(pp->io.fd, "\r", 1);
		up->retry++;
		up->state = S_CONNECT;
		up->timer = ANSWER;
		return;

	/*
	 * We are waiting for the CONNECT response to the dial
	 * command. When this happens, listen for timecodes. If
	 * somthing other than CONNECT is received, like BUSY
	 * or NO CARRIER, abort the call.
	 */
	case S_CONNECT:
		if (strcmp(tbuf, "CONNECT") != 0)
			break;

		report_event(PEVNT_CLOCK, peer, msg);
		up->state = S_MSG;
		up->timer = TIMECODE;
		return;

	/*
	 * We are waiting for a timecode response. Pass it to
	 * the parser. If NO CARRIER is received, save the
	 * messages and abort the call.
	 */
	case S_MSG:
		if (strcmp(tbuf, "NO") == 0)
			report_event(PEVNT_CLOCK, peer, msg);
		if (up->msgcnt < MAXCODE)
			acts_timecode(peer, msg);
		else
			acts_timeout(peer, S_MSG);
		return;
	}

	/*
	 * Other response. Tell us about it.
	 */
	report_event(PEVNT_CLOCK, peer, msg);
	acts_close(peer);
}