Пример #1
0
/*
 * TTY initialization routines.
 */
int
init_clock_sig(
	struct refclockio *rio
	)
{
# ifdef USE_TTY_SIGPOLL
	{
		/* DO NOT ATTEMPT TO MAKE CLOCK-FD A CTTY: not portable, unreliable */
		if (ioctl(rio->fd, I_SETSIG, S_INPUT) < 0)
		{
			msyslog(LOG_ERR,
				"init_clock_sig: ioctl(I_SETSIG, S_INPUT) failed: %m");
			return 1;
		}
		return 0;
	}
# else
	/*
	 * Special cases first!
	 */
	/* Was: defined(SYS_HPUX) */
#  if defined(FIOSSAIOOWN) && defined(FIOSNBIO) && defined(FIOSSAIOSTAT)
#define CLOCK_DONE
	{
		int pgrp, on = 1;

		/* DO NOT ATTEMPT TO MAKE CLOCK-FD A CTTY: not portable, unreliable */
		pgrp = getpid();
		if (ioctl(rio->fd, FIOSSAIOOWN, (char *)&pgrp) == -1)
		{
			msyslog(LOG_ERR, "ioctl(FIOSSAIOOWN) fails for clock I/O: %m");
			exit(1);
			/*NOTREACHED*/
		}

		/*
		 * set non-blocking, async I/O on the descriptor
		 */
		if (ioctl(rio->fd, FIOSNBIO, (char *)&on) == -1)
		{
			msyslog(LOG_ERR, "ioctl(FIOSNBIO) fails for clock I/O: %m");
			exit(1);
			/*NOTREACHED*/
		}

		if (ioctl(rio->fd, FIOSSAIOSTAT, (char *)&on) == -1)
		{
			msyslog(LOG_ERR, "ioctl(FIOSSAIOSTAT) fails for clock I/O: %m");
			exit(1);
			/*NOTREACHED*/
		}
		return 0;
	}
#  endif /* SYS_HPUX: FIOSSAIOOWN && FIOSNBIO && FIOSSAIOSTAT */
	/* Was: defined(SYS_AIX) && !defined(_BSD) */
#  if !defined(_BSD) && defined(_AIX) && defined(FIOASYNC) && defined(FIOSETOWN)
	/*
	 * SYSV compatibility mode under AIX.
	 */
#define CLOCK_DONE
	{
		int pgrp, on = 1;

		/* DO NOT ATTEMPT TO MAKE CLOCK-FD A CTTY: not portable, unreliable */
		if (ioctl(rio->fd, FIOASYNC, (char *)&on) == -1)
		{
			msyslog(LOG_ERR, "ioctl(FIOASYNC) fails for clock I/O: %m");
			return 1;
		}
		pgrp = -getpid();
		if (ioctl(rio->fd, FIOSETOWN, (char*)&pgrp) == -1)
		{
			msyslog(LOG_ERR, "ioctl(FIOSETOWN) fails for clock I/O: %m");
			return 1;
		}

		if (fcntl(rio->fd, F_SETFL, FNDELAY|FASYNC) < 0)
		{
			msyslog(LOG_ERR, "fcntl(FNDELAY|FASYNC) fails for clock I/O: %m");
			return 1;
		}
		return 0;
	}
#  endif /* AIX && !BSD: !_BSD && FIOASYNC && FIOSETOWN */
#  ifndef  CLOCK_DONE
	{
		/* DO NOT ATTEMPT TO MAKE CLOCK-FD A CTTY: not portable, unreliable */
#	if defined(TIOCSCTTY) && defined(USE_FSETOWNCTTY)
		/*
		 * there are, however, always exceptions to the rules
		 * one is, that OSF accepts SETOWN on TTY fd's only, iff they are
		 * CTTYs. SunOS and HPUX do not semm to have this restriction.
		 * another question is: how can you do multiple SIGIO from several
		 * ttys (as they all should be CTTYs), wondering...
		 *
		 * kd 95-07-16
		 */
		if (ioctl(rio->fd, TIOCSCTTY, 0) == -1)
		{
			msyslog(LOG_ERR, "ioctl(TIOCSCTTY, 0) fails for clock I/O: %m");
			return 1;
		}
#	endif /* TIOCSCTTY && USE_FSETOWNCTTY */

		if (fcntl(rio->fd, F_SETOWN, getpid()) == -1)
		{
			msyslog(LOG_ERR, "fcntl(F_SETOWN) fails for clock I/O: %m");
			return 1;
		}

		if (fcntl(rio->fd, F_SETFL, FNDELAY|FASYNC) < 0)
		{
			msyslog(LOG_ERR,
				"fcntl(FNDELAY|FASYNC) fails for clock I/O: %m");
			return 1;
		}
		return 0;
	}
#  endif /* CLOCK_DONE */
# endif /* !USE_TTY_SIGPOLL  */
}
Пример #2
0
/*
 * Set the process priority
 */
static void
set_process_priority(void)
{

#ifdef DEBUG
	if (debug > 1)
		msyslog(LOG_DEBUG, "set_process_priority: %s: priority_done is <%d>",
			((priority_done)
			 ? "Leave priority alone"
			 : "Attempt to set priority"
				),
			priority_done);
#endif /* DEBUG */

#if defined(HAVE_SCHED_SETSCHEDULER)
	if (!priority_done) {
		extern int config_priority_override, config_priority;
		int pmax, pmin;
		struct sched_param sched;

		pmax = sched_get_priority_max(SCHED_FIFO);
		sched.sched_priority = pmax;
		if ( config_priority_override ) {
			pmin = sched_get_priority_min(SCHED_FIFO);
			if ( config_priority > pmax )
				sched.sched_priority = pmax;
			else if ( config_priority < pmin )
				sched.sched_priority = pmin;
			else
				sched.sched_priority = config_priority;
		}
		if ( sched_setscheduler(0, SCHED_FIFO, &sched) == -1 )
			msyslog(LOG_ERR, "sched_setscheduler(): %m");
		else
			++priority_done;
	}
#endif /* HAVE_SCHED_SETSCHEDULER */
#if defined(HAVE_RTPRIO)
# ifdef RTP_SET
	if (!priority_done) {
		struct rtprio srtp;

		srtp.type = RTP_PRIO_REALTIME;	/* was: RTP_PRIO_NORMAL */
		srtp.prio = 0;		/* 0 (hi) -> RTP_PRIO_MAX (31,lo) */

		if (rtprio(RTP_SET, getpid(), &srtp) < 0)
			msyslog(LOG_ERR, "rtprio() error: %m");
		else
			++priority_done;
	}
# else /* not RTP_SET */
	if (!priority_done) {
		if (rtprio(0, 120) < 0)
			msyslog(LOG_ERR, "rtprio() error: %m");
		else
			++priority_done;
	}
# endif /* not RTP_SET */
#endif  /* HAVE_RTPRIO */
#if defined(NTPD_PRIO) && NTPD_PRIO != 0
# ifdef HAVE_ATT_NICE
	if (!priority_done) {
		errno = 0;
		if (-1 == nice (NTPD_PRIO) && errno != 0)
			msyslog(LOG_ERR, "nice() error: %m");
		else
			++priority_done;
	}
# endif /* HAVE_ATT_NICE */
# ifdef HAVE_BSD_NICE
	if (!priority_done) {
		if (-1 == setpriority(PRIO_PROCESS, 0, NTPD_PRIO))
			msyslog(LOG_ERR, "setpriority() error: %m");
		else
			++priority_done;
	}
# endif /* HAVE_BSD_NICE */
#endif /* NTPD_PRIO && NTPD_PRIO != 0 */
	if (!priority_done)
		msyslog(LOG_ERR, "set_process_priority: No way found to improve our priority");
}
Пример #3
0
/*
 * authreadkeys - (re)read keys from a file.
 */
int
authreadkeys(
	const char *file
	)
{
	FILE	*fp;
	char	*line;
	char	*token;
	keyid_t	keyno;
	int	keytype;
	char	buf[512];		/* lots of room for line */
	u_char	keystr[20];
	size_t	len;
	size_t	j;

	/*
	 * Open file.  Complain and return if it can't be opened.
	 */
	fp = fopen(file, "r");
	if (fp == NULL) {
		msyslog(LOG_ERR, "authreadkeys: file %s: %m",
		    file);
		return (0);
	}
	INIT_SSL();

	/*
	 * Remove all existing keys
	 */
	auth_delkeys();

	/*
	 * Now read lines from the file, looking for key entries
	 */
	while ((line = fgets(buf, sizeof buf, fp)) != NULL) {
		token = nexttok(&line);
		if (token == NULL)
			continue;
		
		/*
		 * First is key number.  See if it is okay.
		 */
		keyno = atoi(token);
		if (keyno == 0) {
			msyslog(LOG_ERR,
			    "authreadkeys: cannot change key %s", token);
			continue;
		}

		if (keyno > NTP_MAXKEY) {
			msyslog(LOG_ERR,
			    "authreadkeys: key %s > %d reserved for Autokey",
			    token, NTP_MAXKEY);
			continue;
		}

		/*
		 * Next is keytype. See if that is all right.
		 */
		token = nexttok(&line);
		if (token == NULL) {
			msyslog(LOG_ERR,
			    "authreadkeys: no key type for key %d", keyno);
			continue;
		}
#ifdef OPENSSL
		/*
		 * The key type is the NID used by the message digest 
		 * algorithm. There are a number of inconsistencies in
		 * the OpenSSL database. We attempt to discover them
		 * here and prevent use of inconsistent data later.
		 */
		keytype = keytype_from_text(token, NULL);
		if (keytype == 0) {
			msyslog(LOG_ERR,
			    "authreadkeys: invalid type for key %d", keyno);
			continue;
		}
		if (EVP_get_digestbynid(keytype) == NULL) {
			msyslog(LOG_ERR,
			    "authreadkeys: no algorithm for key %d", keyno);
			continue;
		}
#else	/* !OPENSSL follows */

		/*
		 * The key type is unused, but is required to be 'M' or
		 * 'm' for compatibility.
		 */
		if (!(*token == 'M' || *token == 'm')) {
			msyslog(LOG_ERR,
			    "authreadkeys: invalid type for key %d", keyno);
			continue;
		}
		keytype = KEY_TYPE_MD5;
#endif	/* !OPENSSL */

		/*
		 * Finally, get key and insert it. If it is longer than 20
		 * characters, it is a binary string encoded in hex;
		 * otherwise, it is a text string of printable ASCII
		 * characters.
		 */
		token = nexttok(&line);
		if (token == NULL) {
			msyslog(LOG_ERR,
			    "authreadkeys: no key for key %d", keyno);
			continue;
		}
		len = strlen(token);
		if (len <= sizeof(keystr)) {
			MD5auth_setkey(keyno, keytype, (u_char *)token, len);
		} else {
			char	hex[] = "0123456789abcdef";
			u_char	temp;
			char	*ptr;
			size_t	jlim;

			jlim = min(len, 2 * sizeof(keystr));
			for (j = 0; j < jlim; j++) {
				ptr = strchr(hex, tolower((unsigned char)token[j]));
				if (ptr == NULL)
					break;	/* abort decoding */
				temp = (u_char)(ptr - hex);
				if (j & 1)
					keystr[j / 2] |= temp;
				else
					keystr[j / 2] = temp << 4;
			}
			if (j < jlim) {
				msyslog(LOG_ERR,
					"authreadkeys: invalid hex digit for key %d", keyno);
				continue;
			}
			MD5auth_setkey(keyno, keytype, keystr, jlim / 2);
		}
	}
	fclose(fp);
	return (1);
}
Пример #4
0
static void
neoclock4x_receive(struct recvbuf *rbufp)
{
  struct neoclock4x_unit *up;
  struct refclockproc *pp;
  struct peer *peer;
  unsigned long calc_utc;
  int day;
  int month;	/* ddd conversion */
  int c;
  int dsec;
  unsigned char calc_chksum;
  int recv_chksum;

  peer = rbufp->recv_peer;
  pp = peer->procptr;
  up = pp->unitptr;

  /* wait till poll interval is reached */
  if(0 == up->recvnow)
    return;

  /* reset poll interval flag */
  up->recvnow = 0;

  /* read last received timecode */
  pp->lencode = refclock_gtlin(rbufp, pp->a_lastcode, BMAX, &pp->lastrec);
  pp->leap = LEAP_NOWARNING;

  if(NEOCLOCK4X_TIMECODELEN != pp->lencode)
    {
      NLOG(NLOG_CLOCKEVENT)
	msyslog(LOG_WARNING, "NeoClock4X(%d): received data has invalid length, expected %d bytes, received %d bytes: %s",
		up->unit, NEOCLOCK4X_TIMECODELEN, pp->lencode, pp->a_lastcode);
      refclock_report(peer, CEVNT_BADREPLY);
      return;
    }

  neol_hexatoi_len(&pp->a_lastcode[NEOCLOCK4X_OFFSET_CRC], &recv_chksum, 2);

  /* calculate checksum */
  calc_chksum = 0;
  for(c=0; c < NEOCLOCK4X_OFFSET_CRC; c++)
    {
      calc_chksum += pp->a_lastcode[c];
    }
  if(recv_chksum != calc_chksum)
    {
      NLOG(NLOG_CLOCKEVENT)
	msyslog(LOG_WARNING, "NeoClock4X(%d): received data has invalid chksum: %s",
		up->unit, pp->a_lastcode);
      refclock_report(peer, CEVNT_BADREPLY);
      return;
    }

  /* Allow synchronization even is quartz clock is
   * never initialized.
   * WARNING: This is dangerous!
   */
  up->quarzstatus = pp->a_lastcode[NEOCLOCK4X_OFFSET_QUARZSTATUS];
  if(0==(pp->sloppyclockflag & CLK_FLAG2))
    {
      if('I' != up->quarzstatus)
	{
	  NLOG(NLOG_CLOCKEVENT)
	    msyslog(LOG_NOTICE, "NeoClock4X(%d): quartz clock is not initialized: %s",
		    up->unit, pp->a_lastcode);
	  pp->leap = LEAP_NOTINSYNC;
	  refclock_report(peer, CEVNT_BADDATE);
	  return;
	}
    }
  if('I' != up->quarzstatus)
    {
      NLOG(NLOG_CLOCKEVENT)
	msyslog(LOG_NOTICE, "NeoClock4X(%d): using uninitialized quartz clock for time synchronization: %s",
		up->unit, pp->a_lastcode);
    }

  /*
   * If NeoClock4X is not synchronized to a radio clock
   * check if we're allowed to synchronize with the quartz
   * clock.
   */
  up->timesource = pp->a_lastcode[NEOCLOCK4X_OFFSET_TIMESOURCE];
  if(0==(pp->sloppyclockflag & CLK_FLAG2))
    {
      if('A' != up->timesource)
	{
	  /* not allowed to sync with quartz clock */
	  if(0==(pp->sloppyclockflag & CLK_FLAG1))
	    {
	      refclock_report(peer, CEVNT_BADTIME);
	      pp->leap = LEAP_NOTINSYNC;
	      return;
	    }
	}
    }

  /* this should only used when first install is done */
  if(pp->sloppyclockflag & CLK_FLAG4)
    {
      msyslog(LOG_DEBUG, "NeoClock4X(%d): received data: %s",
	      up->unit, pp->a_lastcode);
    }

  /* 123456789012345678901234567890123456789012345 */
  /* S/N123456DCF1004021010001202ASX1213CR\r\n */

  neol_atoi_len(&pp->a_lastcode[NEOCLOCK4X_OFFSET_YEAR], &pp->year, 2);
  neol_atoi_len(&pp->a_lastcode[NEOCLOCK4X_OFFSET_MONTH], &month, 2);
  neol_atoi_len(&pp->a_lastcode[NEOCLOCK4X_OFFSET_DAY], &day, 2);
  neol_atoi_len(&pp->a_lastcode[NEOCLOCK4X_OFFSET_HOUR], &pp->hour, 2);
  neol_atoi_len(&pp->a_lastcode[NEOCLOCK4X_OFFSET_MINUTE], &pp->minute, 2);
  neol_atoi_len(&pp->a_lastcode[NEOCLOCK4X_OFFSET_SECOND], &pp->second, 2);
  neol_atoi_len(&pp->a_lastcode[NEOCLOCK4X_OFFSET_HSEC], &dsec, 2);
#if defined(NTP_PRE_420)
  pp->msec = dsec * 10; /* convert 1/100s from neoclock to real miliseconds */
#else
  pp->nsec = dsec * 10 * NSEC_TO_MILLI; /* convert 1/100s from neoclock to nanoseconds */
#endif

  memcpy(up->radiosignal, &pp->a_lastcode[NEOCLOCK4X_OFFSET_RADIOSIGNAL], 3);
  up->radiosignal[3] = 0;
  memcpy(up->serial, &pp->a_lastcode[NEOCLOCK4X_OFFSET_SERIAL], 6);
  up->serial[6] = 0;
  up->dststatus = pp->a_lastcode[NEOCLOCK4X_OFFSET_DSTSTATUS];
  neol_hexatoi_len(&pp->a_lastcode[NEOCLOCK4X_OFFSET_ANTENNA1], &up->antenna1, 2);
  neol_hexatoi_len(&pp->a_lastcode[NEOCLOCK4X_OFFSET_ANTENNA2], &up->antenna2, 2);

  /*
    Validate received values at least enough to prevent internal
    array-bounds problems, etc.
  */
  if((pp->hour < 0) || (pp->hour > 23) ||
     (pp->minute < 0) || (pp->minute > 59) ||
     (pp->second < 0) || (pp->second > 60) /*Allow for leap seconds.*/ ||
     (day < 1) || (day > 31) ||
     (month < 1) || (month > 12) ||
     (pp->year < 0) || (pp->year > 99)) {
    /* Data out of range. */
    NLOG(NLOG_CLOCKEVENT)
      msyslog(LOG_WARNING, "NeoClock4X(%d): date/time out of range: %s",
	      up->unit, pp->a_lastcode);
    refclock_report(peer, CEVNT_BADDATE);
    return;
  }

  /* Year-2000 check not needed anymore. Same problem
   * will arise at 2099 but what should we do...?
   *
   * wrap 2-digit date into 4-digit
   *
   * if(pp->year < YEAR_PIVOT)
   * {
   *   pp->year += 100;
   * }
  */
  pp->year += 2000;

  /* adjust NeoClock4X local time to UTC */
  calc_utc = neol_mktime(pp->year, month, day, pp->hour, pp->minute, pp->second);
  calc_utc -= 3600;
  /* adjust NeoClock4X daylight saving time if needed */
  if('S' == up->dststatus)
    calc_utc -= 3600;
  neol_localtime(calc_utc, &pp->year, &month, &day, &pp->hour, &pp->minute, &pp->second);

  /*
    some preparations
  */
  pp->day = ymd2yd(pp->year, month, day);
  pp->leap = 0;

  if(pp->sloppyclockflag & CLK_FLAG4)
    {
      msyslog(LOG_DEBUG, "NeoClock4X(%d): calculated UTC date/time: %04d-%02d-%02d %02d:%02d:%02d.%03ld",
	      up->unit,
	      pp->year, month, day,
	      pp->hour, pp->minute, pp->second,
#if defined(NTP_PRE_420)
              pp->msec
#else
              pp->nsec/NSEC_TO_MILLI
#endif
              );
    }

  up->utc_year   = pp->year;
  up->utc_month  = month;
  up->utc_day    = day;
  up->utc_hour   = pp->hour;
  up->utc_minute = pp->minute;
  up->utc_second = pp->second;
#if defined(NTP_PRE_420)
  up->utc_msec   = pp->msec;
#else
  up->utc_msec   = pp->nsec/NSEC_TO_MILLI;
#endif

  if(!refclock_process(pp))
    {
      NLOG(NLOG_CLOCKEVENT)
	msyslog(LOG_WARNING, "NeoClock4X(%d): refclock_process failed!", up->unit);
      refclock_report(peer, CEVNT_FAULT);
      return;
    }
  refclock_receive(peer);

  /* report good status */
  refclock_report(peer, CEVNT_NOMINAL);

  record_clock_stats(&peer->srcadr, pp->a_lastcode);
}
Пример #5
0
static int
neol_query_firmware(int fd,
		    int unit,
		    char *firmware,
		    int maxlen)
{
  char tmpbuf[256];
  int len;
  int lastsearch;
  unsigned char c;
  int last_c_was_crlf;
  int last_crlf_conv_len;
  int init;
  int read_errors;
  int flag = 0;
  int chars_read;

  /* wait a little bit */
  sleep(1);
  if(-1 != write(fd, "V", 1))
    {
      /* wait a little bit */
      sleep(1);
      memset(tmpbuf, 0x00, sizeof(tmpbuf));

      len = 0;
      lastsearch = 0;
      last_c_was_crlf = 0;
      last_crlf_conv_len = 0;
      init = 1;
      read_errors = 0;
      chars_read = 0;
      for(;;)
	{
	  if(read_errors > 5)
	    {
	      msyslog(LOG_ERR, "NeoClock4X(%d): can't read firmware version (timeout)", unit);
	      strlcpy(tmpbuf, "unknown due to timeout", sizeof(tmpbuf));
	      break;
	    }
          if(chars_read > 500)
            {
	      msyslog(LOG_ERR, "NeoClock4X(%d): can't read firmware version (garbage)", unit);
	      strlcpy(tmpbuf, "unknown due to garbage input", sizeof(tmpbuf));
	      break;
            }
	  if(-1 == read(fd, &c, 1))
	    {
              if(EAGAIN != errno)
                {
                  msyslog(LOG_DEBUG, "NeoClock4x(%d): read: %m", unit);
                  read_errors++;
                }
              else
                {
                  sleep(1);
                }
	      continue;
	    }
          else
            {
              chars_read++;
            }

	  if(init)
	    {
	      if(0xA9 != c) /* wait for (c) char in input stream */
		continue;

	      strlcpy(tmpbuf, "(c)", sizeof(tmpbuf));
	      len = 3;
	      init = 0;
	      continue;
	    }

#if 0
	  msyslog(LOG_NOTICE, "NeoClock4X(%d): firmware %c = %02Xh", unit, c, c);
#endif

	  if(0x0A == c || 0x0D == c)
	    {
	      if(last_c_was_crlf)
		{
		  char *ptr;
		  ptr = strstr(&tmpbuf[lastsearch], "S/N");
		  if(NULL != ptr)
		    {
		      tmpbuf[last_crlf_conv_len] = 0;
		      flag = 1;
		      break;
		    }
		  /* convert \n to / */
		  last_crlf_conv_len = len;
		  tmpbuf[len++] = ' ';
		  tmpbuf[len++] = '/';
		  tmpbuf[len++] = ' ';
		  lastsearch = len;
		}
	      last_c_was_crlf = 1;
	    }
	  else
	    {
	      last_c_was_crlf = 0;
	      if(0x00 != c)
		tmpbuf[len++] = (char) c;
	    }
	  tmpbuf[len] = '\0';
	  if(len > sizeof(tmpbuf)-5)
	    break;
	}
    }
  else
    {
      msyslog(LOG_ERR, "NeoClock4X(%d): can't query firmware version", unit);
      strlcpy(tmpbuf, "unknown error", sizeof(tmpbuf));
    }
  if (strlcpy(firmware, tmpbuf, maxlen) >= maxlen)
    strlcpy(firmware, "buffer too small", maxlen);

  if(flag)
    {
      NLOG(NLOG_CLOCKINFO)
	msyslog(LOG_INFO, "NeoClock4X(%d): firmware version: %s", unit, firmware);

      if(strstr(firmware, "/R2"))
	{
	  msyslog(LOG_INFO, "NeoClock4X(%d): Your NeoClock4X uses the new R2 firmware release. Please note the changed LED behaviour.", unit);
	}

    }

  return (flag);
}
Пример #6
0
/*
 * arc_start - open the devices and initialize data for processing
 */
static int
arc_start(
	int unit,
	struct peer *peer
	)
{
	register struct arcunit *up;
	struct refclockproc *pp;
	int temp_fd;
	int fd;
	char device[20];
#ifdef HAVE_TERMIOS
	struct termios arg;
#endif

	msyslog(LOG_NOTICE, "MSF_ARCRON %s: opening unit %d",
		arc_version, unit);
	DPRINTF(1, ("arc: %s: attempt to open unit %d.\n", arc_version,
		unit));

	/*
	 * Open serial port. Use CLK line discipline, if available.
	 */
	snprintf(device, sizeof(device), DEVICE, unit);
	temp_fd = refclock_open(device, SPEED, LDISC_CLK);
	if (temp_fd <= 0)
		return 0;
	DPRINTF(1, ("arc: unit %d using tty_open().\n", unit));
	fd = tty_open(device, OPEN_FLAGS, 0777);
	if (fd < 0) {
		msyslog(LOG_ERR, "MSF_ARCRON(%d): failed second open(%s, 0777): %m.\n",
			unit, device);
		close(temp_fd);
		return 0;
	}
	close(temp_fd);
	temp_fd = -1;

#ifndef SYS_WINNT
	fcntl(fd, F_SETFL, 0); /* clear the descriptor flags */
#endif
	DPRINTF(1, ("arc: opened RS232 port with file descriptor %d.\n", fd));

#ifdef HAVE_TERMIOS

	if (tcgetattr(fd, &arg) < 0) {
		msyslog(LOG_ERR, "MSF_ARCRON(%d): tcgetattr(%s): %m.\n",
			unit, device);
		close(fd);
		return 0;
	}

	arg.c_iflag = IGNBRK | ISTRIP;
	arg.c_oflag = 0;
	arg.c_cflag = B300 | CS8 | CREAD | CLOCAL | CSTOPB;
	arg.c_lflag = 0;
	arg.c_cc[VMIN] = 1;
	arg.c_cc[VTIME] = 0;

	if (tcsetattr(fd, TCSANOW, &arg) < 0) {
		msyslog(LOG_ERR, "MSF_ARCRON(%d): tcsetattr(%s): %m.\n",
			unit, device);
		close(fd);
		return 0;
	}

#else

	msyslog(LOG_ERR, "ARCRON: termios required by this driver");
	(void)close(fd);

	return 0;

#endif

	/* Set structure to all zeros... */
	up = emalloc_zero(sizeof(*up));
	pp = peer->procptr;
	pp->io.clock_recv = arc_receive;
	pp->io.srcclock = (caddr_t)peer;
	pp->io.datalen = 0;
	pp->io.fd = fd;
	if (!io_addclock(&pp->io)) {
		close(fd);
		pp->io.fd = -1;
		free(up); 
		return(0); 
	}
	pp->unitptr = up;

	/*
	 * Initialize miscellaneous variables
	 */
	peer->precision = PRECISION;
	peer->stratum = 2;              /* Default to stratum 2 not 0. */
	pp->clockdesc = DESCRIPTION;
	if (peer->MODE > 3) {
		msyslog(LOG_NOTICE, "ARCRON: Invalid mode %d", peer->MODE);
		return 0;
	}
#ifdef DEBUG
	if(debug) { printf("arc: mode = %d.\n", peer->MODE); }
#endif
	switch (peer->MODE) {
	    case 1:
		memcpy((char *)&pp->refid, REFID_MSF, 4);
		break;
	    case 2:
		memcpy((char *)&pp->refid, REFID_DCF77, 4);
		break;
	    case 3:
		memcpy((char *)&pp->refid, REFID_WWVB, 4);
		break;
	    default:
		memcpy((char *)&pp->refid, REFID, 4);
		break;
	}
	/* Spread out resyncs so that they should remain separated. */
	up->next_resync = current_time + INITIAL_RESYNC_DELAY + (67*unit)%1009;

#if 0 /* Not needed because of zeroing of arcunit structure... */
	up->resyncing = 0;              /* Not resyncing yet. */
	up->saved_flags = 0;            /* Default is all flags off. */
	/* Clear send buffer out... */
	{
		int i;
		for(i = CMDQUEUELEN; i >= 0; --i) { up->cmdqueue[i] = '\0'; }
	}
#endif

#ifdef ARCRON_KEEN
	up->quality = QUALITY_UNKNOWN;  /* Trust the clock immediately. */
#else
	up->quality = MIN_CLOCK_QUALITY;/* Don't trust the clock yet. */
#endif

	peer->action = arc_event_handler;

	ENQUEUE(up);

	return(1);
}
Пример #7
0
/* psc_poll:  read, decode, and record device time */
static void
psc_poll(
    int		unit,
    struct peer	*peer
    )
{
    struct refclockproc	*pp = peer->procptr;
    struct psc_unit		*up;
    unsigned			tlo, thi;
    unsigned char		status;

    up = (struct psc_unit *) pp->unitptr;
    tlo = regp[unit]->low_time;		/* latch and read first 4 bytes	*/
    thi = regp[unit]->high_time;	/* read 4 higher order bytes	*/
    status = regp[unit]->device_status;	/* read device status byte	*/

    if (!(status & PSC_SYNC_OK)) {
	refclock_report(peer, CEVNT_BADTIME);
	if (!up->msg_flag[unit]) {	/* write once to system log	*/
	    msyslog(LOG_WARNING,
		"SYNCHRONIZATION LOST on unit %1d, status %02x\n",
		unit, status);
	    up->msg_flag[unit] = 1;
	}
	return;
    }

    get_systime(&pp->lastrec);
    pp->polls++;
     
    tlo = SWAP(tlo);			/* little to big endian swap on	*/
    thi = SWAP(thi);			/* copy of data			*/
    /* convert the BCD time to broken down time used by refclockproc	*/
    pp->day	= BCD2INT3((thi & 0x0FFF0000) >> 16);
    pp->hour	= BCD2INT2((thi & 0x0000FF00) >> 8);
    pp->minute	= BCD2INT2(thi & 0x000000FF);
    pp->second	= BCD2INT2(tlo >> 24);
    /* ntp_process() in ntp_refclock.c appears to use usec as fraction of
       second in microseconds if usec is nonzero. */
    pp->nsec	= 1000000*BCD2INT3((tlo & 0x00FFF000) >> 12) +
	BCD2INT3(tlo & 0x00000FFF);

    snprintf(pp->a_lastcode, sizeof(pp->a_lastcode),
	     "%3.3d %2.2d:%2.2d:%2.2d.%09ld %02x %08x %08x", pp->day,
	     pp->hour, pp->minute, pp->second, pp->nsec, status, thi,
	     tlo);
    pp->lencode = strlen(pp->a_lastcode);

    /* compute the timecode timestamp	*/
    if (!refclock_process(pp)) {
	refclock_report(peer, CEVNT_BADTIME);
	return;
    }
    /* simulate the NTP receive and packet procedures	*/
    refclock_receive(peer);
    /* write clock statistics to file	*/
    record_clock_stats(&peer->srcadr, pp->a_lastcode);	

    /* With the first timecode beginning the day, check for a GPS
       leap second notification.      */
    if (pp->hour < up->last_hour) {
	check_leap_sec(pp, unit);
	up->msg_flag[0] = up->msg_flag[1] = 0;	/* reset flags	*/
    }
    up->last_hour = pp->hour;
}
Пример #8
0
static void
check_leapsec(
	u_int32        now  ,
	const time_t * tpiv ,
        int/*BOOL*/    reset)
{
	static const char leapmsg_p_step[] =
	    "Positive leap second, stepped backward.";
	static const char leapmsg_p_slew[] =
	    "Positive leap second, no step correction. "
	    "System clock will be inaccurate for a long time.";

	static const char leapmsg_n_step[] =
	    "Negative leap second, stepped forward.";
	static const char leapmsg_n_slew[] =
	    "Negative leap second, no step correction. "
	    "System clock will be inaccurate for a long time.";

	leap_result_t lsdata;
	u_int32       lsprox;
#ifdef AUTOKEY
	int/*BOOL*/   update_autokey = FALSE;
#endif

#ifndef SYS_WINNT  /* WinNT port has its own leap second handling */
# ifdef KERNEL_PLL
	leapsec_electric(pll_control && kern_enable);
# else
	leapsec_electric(0);
# endif
#endif
#ifdef LEAP_SMEAR
	leap_smear.enabled = leap_smear_intv != 0;
#endif
	if (reset)	{
		lsprox = LSPROX_NOWARN;
		leapsec_reset_frame();
		memset(&lsdata, 0, sizeof(lsdata));
	} else {
	  int fired = leapsec_query(&lsdata, now, tpiv);

	  DPRINTF(1, ("*** leapsec_query: fired %i, now %u (0x%08X), tai_diff %i, ddist %u\n",
		  fired, now, now, lsdata.tai_diff, lsdata.ddist));

#ifdef LEAP_SMEAR
	  leap_smear.in_progress = 0;
	  leap_smear.doffset = 0.0;

	  if (leap_smear.enabled) {
		if (lsdata.tai_diff) {
			if (leap_smear.interval == 0) {
				leap_smear.interval = leap_smear_intv;
				leap_smear.intv_end = lsdata.ttime.Q_s;
				leap_smear.intv_start = leap_smear.intv_end - leap_smear.interval;
				DPRINTF(1, ("*** leapsec_query: setting leap_smear interval %li, begin %.0f, end %.0f\n",
					leap_smear.interval, leap_smear.intv_start, leap_smear.intv_end));
			}
		}
		else {
			if (leap_smear.interval)
				DPRINTF(1, ("*** leapsec_query: clearing leap_smear interval\n"));
			leap_smear.interval = 0;
		}

		if (leap_smear.interval) {
			double dtemp = now;
			if (dtemp >= leap_smear.intv_start && dtemp <= leap_smear.intv_end) {
				double leap_smear_time = dtemp - leap_smear.intv_start;
				/*
				 * For now we just do a linear interpolation over the smear interval
				 */
#if 0
				// linear interpolation
				leap_smear.doffset = -(leap_smear_time * lsdata.tai_diff / leap_smear.interval);
#else
				// Google approach: lie(t) = (1.0 - cos(pi * t / w)) / 2.0
				leap_smear.doffset = -((double) lsdata.tai_diff - cos( M_PI * leap_smear_time / leap_smear.interval)) / 2.0;
#endif
				/*
				 * TODO see if we're inside an inserted leap second, so we need to compute
				 * leap_smear.doffset = 1.0 - leap_smear.doffset
				 */
				leap_smear.in_progress = 1;
#if 0 && defined( DEBUG )
				msyslog(LOG_NOTICE, "*** leapsec_query: [%.0f:%.0f] (%li), now %u (%.0f), smear offset %.6f ms\n",
					leap_smear.intv_start, leap_smear.intv_end, leap_smear.interval,
					now, leap_smear_time, leap_smear.doffset);
#else
				DPRINTF(1, ("*** leapsec_query: [%.0f:%.0f] (%li), now %u (%.0f), smear offset %.6f ms\n",
					leap_smear.intv_start, leap_smear.intv_end, leap_smear.interval,
					now, leap_smear_time, leap_smear.doffset));
#endif

			}
		}
	  }
	  else
		leap_smear.interval = 0;

	  /*
	   * Update the current leap smear offset, eventually 0.0 if outside smear interval.
	   */
	  DTOLFP(leap_smear.doffset, &leap_smear.offset);

#endif	/* LEAP_SMEAR */

	  if (fired) {
		/* Full hit. Eventually step the clock, but always
		 * announce the leap event has happened.
		 */
		const char *leapmsg = NULL;
		if (lsdata.warped < 0) {
			if (clock_max_back > 0.0 &&
			    clock_max_back < abs(lsdata.warped)) {
				step_systime(lsdata.warped);
				leapmsg = leapmsg_p_step;
			} else {
				leapmsg = leapmsg_p_slew;
			}
		} else 	if (lsdata.warped > 0) {
			if (clock_max_fwd > 0.0 &&
			    clock_max_fwd < abs(lsdata.warped)) {
				step_systime(lsdata.warped);
				leapmsg = leapmsg_n_step;
			} else {
				leapmsg = leapmsg_n_slew;
			}
		}
		if (leapmsg)
			msyslog(LOG_NOTICE, "%s", leapmsg);
		report_event(EVNT_LEAP, NULL, NULL);
#ifdef AUTOKEY
		update_autokey = TRUE;
#endif
		lsprox  = LSPROX_NOWARN;
		leapsec = LSPROX_NOWARN;
		sys_tai = lsdata.tai_offs;
	  } else {
#ifdef AUTOKEY
		update_autokey = (sys_tai != (u_int)lsdata.tai_offs);
#endif
		lsprox  = lsdata.proximity;
		sys_tai = lsdata.tai_offs;
	  }
	}

	/* We guard against panic alarming during the red alert phase.
	 * Strange and evil things might happen if we go from stone cold
	 * to piping hot in one step. If things are already that wobbly,
	 * we let the normal clock correction take over, even if a jump
	 * is involved.
         * Also make sure the alarming events are edge-triggered, that is,
         * ceated only when the threshold is crossed.
         */
	if (  (leapsec > 0 || lsprox < LSPROX_ALERT)
	    && leapsec < lsprox                     ) {
		if (  leapsec < LSPROX_SCHEDULE
                   && lsprox >= LSPROX_SCHEDULE) {
			if (lsdata.dynamic)
				report_event(PEVNT_ARMED, sys_peer, NULL);
			else
				report_event(EVNT_ARMED, NULL, NULL);
		}
		leapsec = lsprox;
	}
	if (leapsec > lsprox) {
		if (  leapsec >= LSPROX_SCHEDULE
                   && lsprox   < LSPROX_SCHEDULE) {
			report_event(EVNT_DISARMED, NULL, NULL);
		}
		leapsec = lsprox;
	}

	if (leapsec >= LSPROX_SCHEDULE)
		leapdif = lsdata.tai_diff;
	else
		leapdif = 0;

	check_leap_sec_in_progress(&lsdata);

#ifdef AUTOKEY
	if (update_autokey)
		crypto_update_taichange();
#endif
}
Пример #9
0
/*
 * refclock_newpeer - initialize and start a reference clock
 *
 * This routine allocates and initializes the interface structure which
 * supports a reference clock in the form of an ordinary NTP peer. A
 * driver-specific support routine completes the initialization, if
 * used. Default peer variables which identify the clock and establish
 * its reference ID and stratum are set here. It returns one if success
 * and zero if the clock address is invalid or already running,
 * insufficient resources are available or the driver declares a bum
 * rap.
 */
int
refclock_newpeer(
	struct peer *peer	/* peer structure pointer */
	)
{
	struct refclockproc *pp;
	u_char clktype;
	int unit;

	/*
	 * Check for valid clock address. If already running, shut it
	 * down first.
	 */
	if (!ISREFCLOCKADR(&peer->srcadr)) {
		msyslog(LOG_ERR,
			"refclock_newpeer: clock address %s invalid",
			stoa(&peer->srcadr));
		return (0);
	}
	clktype = (u_char)REFCLOCKTYPE(&peer->srcadr);
	unit = REFCLOCKUNIT(&peer->srcadr);
	if (clktype >= num_refclock_conf ||
		refclock_conf[clktype]->clock_start == noentry) {
		msyslog(LOG_ERR,
			"refclock_newpeer: clock type %d invalid\n",
			clktype);
		return (0);
	}

	/*
	 * Allocate and initialize interface structure
	 */
	pp = emalloc_zero(sizeof(*pp));
	peer->procptr = pp;

	/*
	 * Initialize structures
	 */
	peer->refclktype = clktype;
	peer->refclkunit = (u_char)unit;
	peer->flags |= FLAG_REFCLOCK;
	peer->leap = LEAP_NOTINSYNC;
	peer->stratum = STRATUM_REFCLOCK;
	peer->ppoll = peer->maxpoll;
	pp->type = clktype;
	pp->conf = refclock_conf[clktype];
	pp->timestarted = current_time;
	pp->io.fd = -1;

	/*
	 * Set peer.pmode based on the hmode. For appearances only.
	 */
	switch (peer->hmode) {
	case MODE_ACTIVE:
		peer->pmode = MODE_PASSIVE;
		break;

	default:
		peer->pmode = MODE_SERVER;
		break;
	}

	/*
	 * Do driver dependent initialization. The above defaults
	 * can be wiggled, then finish up for consistency.
	 */
	if (!((refclock_conf[clktype]->clock_start)(unit, peer))) {
		refclock_unpeer(peer);
		return (0);
	}
	peer->refid = pp->refid;
	return (1);
}
Пример #10
0
/*
 * true_receive - receive data from the serial interface on a clock
 */
static void
true_receive(
	struct recvbuf *rbufp
	)
{
	register struct true_unit *up;
	struct refclockproc *pp;
	struct peer *peer;
	u_short new_station;
	char synced;
	int i;
	int lat, lon, off;	/* GOES Satellite position */
        /* Use these variable to hold data until we decide its worth keeping */
        char    rd_lastcode[BMAX];
        l_fp    rd_tmp;
        u_short rd_lencode;

	/*
	 * Get the clock this applies to and pointers to the data.
	 */
	peer = (struct peer *)rbufp->recv_srcclock;
	pp = peer->procptr;
	up = (struct true_unit *)pp->unitptr;

	/*
	 * Read clock output.  Automatically handles STREAMS, CLKLDISC.
	 */
        rd_lencode = refclock_gtlin(rbufp, rd_lastcode, BMAX, &rd_tmp);
        rd_lastcode[rd_lencode] = '\0';

	/*
	 * There is a case where <cr><lf> generates 2 timestamps.
	 */
        if (rd_lencode == 0)
            return;
        pp->lencode = rd_lencode;
        strcpy(pp->a_lastcode, rd_lastcode);
        pp->lastrec = rd_tmp;
	true_debug(peer, "receive(%s) [%d]\n", pp->a_lastcode, pp->lencode);

	up->pollcnt = 2;
	record_clock_stats(&peer->srcadr, pp->a_lastcode);

	/*
	 * We get down to business, check the timecode format and decode
	 * its contents. This code decodes a multitude of different
	 * clock messages. Timecodes are processed if needed. All replies
	 * will be run through the state machine to tweak driver options
	 * and program the clock.
	 */

	/*
	 * Clock misunderstood our last command?
	 */
	if (pp->a_lastcode[0] == '?' ||
	    strcmp(pp->a_lastcode, "ERROR 05 NO SUCH FUNCTION") == 0) {
		true_doevent(peer, e_Huh);
		return;
	}

	/*
	 * Timecode: "nnnnn+nnn-nnn"
	 * (from GOES clock when asked about satellite position)
	 */
	if ((pp->a_lastcode[5] == '+' || pp->a_lastcode[5] == '-') &&
	    (pp->a_lastcode[9] == '+' || pp->a_lastcode[9] == '-') &&
	    sscanf(pp->a_lastcode, "%5d%*c%3d%*c%3d", &lon, &lat, &off) == 3
	    ) {
		const char *label = "Botch!";

		/*
		 * This is less than perfect.  Call the (satellite)
		 * either EAST or WEST and adjust slop accodingly
		 * Perfectionists would recalculate the exact delay
		 * and adjust accordingly...
		 */
		if (lon > 7000 && lon < 14000) {
			if (lon < 10000) {
				new_station = GOES_EAST;
				label = "EAST";
			} else {
				new_station = GOES_WEST;
				label = "WEST";
			}
				
			if (new_station != up->station) {
				double dtemp;

				dtemp = pp->fudgetime1;
				pp->fudgetime1 = pp->fudgetime2;
				pp->fudgetime2 = dtemp;
				up->station = new_station;
			}
		}
		else {
			/*refclock_report(peer, CEVNT_BADREPLY);*/
			label = "UNKNOWN";
		}
		true_debug(peer, "GOES: station %s\n", label);
		true_doevent(peer, e_Satellite);
		return;
	}

	/*
	 * Timecode: "Fnn"
	 * (from TM/TMD clock when it wants to tell us what it's up to.)
	 */
	if (sscanf(pp->a_lastcode, "F%2d", &i) == 1 && i > 0 && i < 80) {
		switch (i) {
		    case 50:
			true_doevent(peer, e_F50);
			break;
		    case 51:
			true_doevent(peer, e_F51);
			break;
		    default:
			true_debug(peer, "got F%02d - ignoring\n", i);
			break;
		}
		return;
	}

	/*
	 * Timecode: " TRUETIME Mk III" or " TRUETIME XL"
	 * (from a TM/TMD/XL clock during initialization.)
	 */
	if (strcmp(pp->a_lastcode, " TRUETIME Mk III") == 0 ||
	    strncmp(pp->a_lastcode, " TRUETIME XL", 12) == 0) {
		true_doevent(peer, e_F18);
		NLOG(NLOG_CLOCKSTATUS) {
			msyslog(LOG_INFO, "TM/TMD/XL: %s", pp->a_lastcode);
		}
		return;
	}
Пример #11
0
/*
 * init_timer - initialize the timer data structures
 */
void
init_timer(void)
{
	/*
	 * Initialize...
	 */
	alarm_flag = FALSE;
	alarm_overflow = 0;
	adjust_timer = 1;
	stats_timer = SECSPERHR;
	leapf_timer = SECSPERDAY;
	huffpuff_timer = 0;
	interface_timer = 0;
	current_time = 0;
	timer_overflows = 0;
	timer_xmtcalls = 0;
	timer_timereset = 0;

#ifndef SYS_WINNT
	/*
	 * Set up the alarm interrupt.	The first comes 2**EVENT_TIMEOUT
	 * seconds from now and they continue on every 2**EVENT_TIMEOUT
	 * seconds.
	 */
# ifndef VMS
#  ifdef HAVE_TIMER_CREATE
	if (TC_ERR == timer_create(CLOCK_REALTIME, NULL, &timer_id)) {
		msyslog(LOG_ERR, "timer_create failed, %m");
		exit(1);
	}
#  endif
	signal_no_reset(SIGALRM, alarming);
	itimer.it_interval.tv_sec =
		itimer.it_value.tv_sec = (1 << EVENT_TIMEOUT);
	itimer.it_interval.itv_frac = itimer.it_value.itv_frac = 0;
	set_timer_or_die(&itimer);
# else	/* VMS follows */
	vmsinc[0] = 10000000;		/* 1 sec */
	vmsinc[1] = 0;
	lib$emul(&(1<<EVENT_TIMEOUT), &vmsinc, &0, &vmsinc);

	sys$gettim(&vmstimer);	/* that's "now" as abstime */

	lib$addx(&vmsinc, &vmstimer, &vmstimer);
	sys$setimr(0, &vmstimer, alarming, alarming, 0);
# endif	/* VMS */
#else	/* SYS_WINNT follows */
	/*
	 * Set up timer interrupts for every 2**EVENT_TIMEOUT seconds
	 * Under Windows/NT,
	 */

	WaitableTimerHandle = CreateWaitableTimer(NULL, FALSE, NULL);
	if (WaitableTimerHandle == NULL) {
		msyslog(LOG_ERR, "CreateWaitableTimer failed: %m");
		exit(1);
	}
	else {
		DWORD		Period;
		LARGE_INTEGER	DueTime;
		BOOL		rc;

		Period = (1 << EVENT_TIMEOUT) * 1000;
		DueTime.QuadPart = Period * 10000i64;
		rc = SetWaitableTimer(WaitableTimerHandle, &DueTime,
				      Period, NULL, NULL, FALSE);
		if (!rc) {
			msyslog(LOG_ERR, "SetWaitableTimer failed: %m");
			exit(1);
		}
	}

#endif	/* SYS_WINNT */
}
Пример #12
0
static u_long
convert_rawdcf(
	       unsigned char   *buffer,
	       int              size,
	       struct dcfparam *dcfprm,
	       clocktime_t     *clock_time
	       )
{
	unsigned char *s = buffer;
	const unsigned char *b = dcfprm->onebits;
	const unsigned char *c = dcfprm->zerobits;
	int i;

	parseprintf(DD_RAWDCF,("parse: convert_rawdcf: \"%s\"\n", buffer));

	if (size < 57)
	{
#ifndef PARSEKERNEL
		msyslog(LOG_ERR, "parse: convert_rawdcf: INCOMPLETE DATA - time code only has %d bits", size);
#endif
		return CVT_NONE;
	}

	for (i = 0; i < size; i++)
	{
		if ((*s != *b) && (*s != *c))
		{
			/*
			 * we only have two types of bytes (ones and zeros)
			 */
#ifndef PARSEKERNEL
			msyslog(LOG_ERR, "parse: convert_rawdcf: BAD DATA - no conversion");
#endif
			return CVT_NONE;
		}
		if (*b) b++;
		if (*c) c++;
		s++;
	}

	/*
	 * check Start and Parity bits
	 */
	if ((ext_bf(buffer, DCF_S, dcfprm->zerobits) == 1) &&
	    pcheck(buffer, DCF_P_P1, dcfprm->zerobits) &&
	    pcheck(buffer, DCF_P_P2, dcfprm->zerobits) &&
	    pcheck(buffer, DCF_P_P3, dcfprm->zerobits))
	{
		/*
		 * buffer OK
		 */
		parseprintf(DD_RAWDCF,("parse: convert_rawdcf: parity check passed\n"));

		clock_time->flags  = PARSEB_S_ANTENNA|PARSEB_S_LEAP;
		clock_time->utctime= 0;
		clock_time->usecond= 0;
		clock_time->second = 0;
		clock_time->minute = ext_bf(buffer, DCF_M10, dcfprm->zerobits);
		clock_time->minute = TIMES10(clock_time->minute) + ext_bf(buffer, DCF_M1, dcfprm->zerobits);
		clock_time->hour   = ext_bf(buffer, DCF_H10, dcfprm->zerobits);
		clock_time->hour   = TIMES10(clock_time->hour) + ext_bf(buffer, DCF_H1, dcfprm->zerobits);
		clock_time->day    = ext_bf(buffer, DCF_D10, dcfprm->zerobits);
		clock_time->day    = TIMES10(clock_time->day) + ext_bf(buffer, DCF_D1, dcfprm->zerobits);
		clock_time->month  = ext_bf(buffer, DCF_MO0, dcfprm->zerobits);
		clock_time->month  = TIMES10(clock_time->month) + ext_bf(buffer, DCF_MO, dcfprm->zerobits);
		clock_time->year   = ext_bf(buffer, DCF_Y10, dcfprm->zerobits);
		clock_time->year   = TIMES10(clock_time->year) + ext_bf(buffer, DCF_Y1, dcfprm->zerobits);

		switch (ext_bf(buffer, DCF_Z, dcfprm->zerobits))
		{
		    case DCF_Z_MET:
			clock_time->utcoffset = -1*60*60;
			break;

		    case DCF_Z_MED:
			clock_time->flags     |= PARSEB_DST;
			clock_time->utcoffset  = -2*60*60;
			break;

		    default:
			parseprintf(DD_RAWDCF,("parse: convert_rawdcf: BAD TIME ZONE\n"));
			return CVT_FAIL|CVT_BADFMT;
		}

		if (ext_bf(buffer, DCF_A1, dcfprm->zerobits))
		    clock_time->flags |= PARSEB_ANNOUNCE;

		if (ext_bf(buffer, DCF_A2, dcfprm->zerobits))
		    clock_time->flags |= PARSEB_LEAPADD; /* default: DCF77 data format deficiency */

		if (ext_bf(buffer, DCF_R, dcfprm->zerobits))
		    clock_time->flags |= PARSEB_CALLBIT;

		parseprintf(DD_RAWDCF,("parse: convert_rawdcf: TIME CODE OK: %d:%d, %d.%d.%d, flags 0x%lx\n",
				       (int)clock_time->hour, (int)clock_time->minute, (int)clock_time->day, (int)clock_time->month,(int) clock_time->year,
				       (u_long)clock_time->flags));
		return CVT_OK;
	}
	else
	{
		/*
		 * bad format - not for us
		 */
#ifndef PARSEKERNEL
		msyslog(LOG_ERR, "parse: convert_rawdcf: parity check FAILED for \"%s\"", buffer);
#endif
		return CVT_FAIL|CVT_BADFMT;
	}
}
Пример #13
0
/*
** Check if it's data for us and whether it's useable or not.
**
** If not, return a failure code so we can delete this server from our list
** and continue with another one.
*/
int
process_pkt (
	struct pkt *rpkt,
	sockaddr_u *sender,
	int pkt_len,
	int mode,
	struct pkt *spkt,
	const char * func_name
	)
{
	u_int		key_id;
	struct key *	pkt_key;
	int		is_authentic;
	int		mac_size;
	u_int		exten_len;
	u_int32 *       exten_end;
	u_int32 *       packet_end;
	l_fp		sent_xmt;
	l_fp		resp_org;

	// key_id = 0;
	pkt_key = NULL;
	is_authentic = (HAVE_OPT(AUTHENTICATION)) ? 0 : -1;

	/*
	 * Parse the extension field if present. We figure out whether
	 * an extension field is present by measuring the MAC size. If
	 * the number of words following the packet header is 0, no MAC
	 * is present and the packet is not authenticated. If 1, the
	 * packet is a crypto-NAK; if 3, the packet is authenticated
	 * with DES; if 5, the packet is authenticated with MD5; if 6,
	 * the packet is authenticated with SHA. If 2 or 4, the packet
	 * is a runt and discarded forthwith. If greater than 6, an
	 * extension field is present, so we subtract the length of the
	 * field and go around again.
	 */
	if (pkt_len < (int)LEN_PKT_NOMAC || (pkt_len & 3) != 0) {
		msyslog(LOG_ERR,
			"%s: Incredible packet length: %d.  Discarding.",
			func_name, pkt_len);
		return PACKET_UNUSEABLE;
	}

	/* HMS: the following needs a bit of work */
	/* Note: pkt_len must be a multiple of 4 at this point! */
	packet_end = (void*)((char*)rpkt + pkt_len);
	exten_end = skip_efields(rpkt->exten, packet_end);
	if (NULL == exten_end) {
		msyslog(LOG_ERR,
			"%s: Missing extension field.  Discarding.",
			func_name);
		return PACKET_UNUSEABLE;
	}

	/* get size of MAC in cells; can be zero */
	exten_len = (u_int)(packet_end - exten_end);

	/* deduce action required from remaining length */
	switch (exten_len) {

	case 0:	/* no Legacy MAC */
		break;

	case 1:	/* crypto NAK */		
		/* Only if the keyID is 0 and there were no EFs */
		key_id = ntohl(*exten_end);
		printf("Crypto NAK = 0x%08x from %s\n", key_id, stoa(sender));
		break;

	case 3: /* key ID + 3DES MAC -- unsupported! */
		msyslog(LOG_ERR,
			"%s: Key ID + 3DES MAC is unsupported.  Discarding.",
			func_name);
		return PACKET_UNUSEABLE;

	case 5:	/* key ID + MD5 MAC */
	case 6:	/* key ID + SHA MAC */
		/*
		** Look for the key used by the server in the specified
		** keyfile and if existent, fetch it or else leave the
		** pointer untouched
		*/
		key_id = ntohl(*exten_end);
		get_key(key_id, &pkt_key);
		if (!pkt_key) {
			printf("unrecognized key ID = 0x%08x\n", key_id);
			break;
		}
		/*
		** Seems like we've got a key with matching keyid.
		**
		** Generate a md5sum of the packet with the key from our
		** keyfile and compare those md5sums.
		*/
		mac_size = exten_len << 2;
		if (!auth_md5(rpkt, pkt_len - mac_size,
			      mac_size - 4, pkt_key)) {
			is_authentic = FALSE;
			break;
		}
		/* Yay! Things worked out! */
		is_authentic = TRUE;
		TRACE(1, ("sntp %s: packet from %s authenticated using key id %d.\n",
			  func_name, stoa(sender), key_id));
		break;

	default:
		msyslog(LOG_ERR,
			"%s: Unexpected extension length: %d.  Discarding.",
			func_name, exten_len);
		return PACKET_UNUSEABLE;
	}

	switch (is_authentic) {

	case -1:	/* unknown */
		break;

	case 0:		/* not authentic */
		return SERVER_AUTH_FAIL;
		break;

	case 1:		/* authentic */
		break;

	default:	/* error */
		break;
	}

	/* Check for server's ntp version */
	if (PKT_VERSION(rpkt->li_vn_mode) < NTP_OLDVERSION ||
		PKT_VERSION(rpkt->li_vn_mode) > NTP_VERSION) {
		msyslog(LOG_ERR,
			"%s: Packet shows wrong version (%d)",
			func_name, PKT_VERSION(rpkt->li_vn_mode));
		return SERVER_UNUSEABLE;
	} 
	/* We want a server to sync with */
	if (PKT_MODE(rpkt->li_vn_mode) != mode &&
	    PKT_MODE(rpkt->li_vn_mode) != MODE_PASSIVE) {
		msyslog(LOG_ERR,
			"%s: mode %d stratum %d", func_name, 
			PKT_MODE(rpkt->li_vn_mode), rpkt->stratum);
		return SERVER_UNUSEABLE;
	}
	/* Stratum is unspecified (0) check what's going on */
	if (STRATUM_PKT_UNSPEC == rpkt->stratum) {
		char *ref_char;

		TRACE(1, ("%s: Stratum unspecified, going to check for KOD (stratum: %d)\n", 
			  func_name, rpkt->stratum));
		ref_char = (char *) &rpkt->refid;
		TRACE(1, ("%s: Packet refid: %c%c%c%c\n", func_name,
			  ref_char[0], ref_char[1], ref_char[2], ref_char[3]));
		/* If it's a KOD packet we'll just use the KOD information */
		if (ref_char[0] != 'X') {
			if (strncmp(ref_char, "DENY", 4) == 0)
				return KOD_DEMOBILIZE;
			if (strncmp(ref_char, "RSTR", 4) == 0)
				return KOD_DEMOBILIZE;
			if (strncmp(ref_char, "RATE", 4) == 0)
				return KOD_RATE;
			/*
			** There are other interesting kiss codes which
			** might be interesting for authentication.
			*/
		}
	}
	/* If the server is not synced it's not really useable for us */
	if (LEAP_NOTINSYNC == PKT_LEAP(rpkt->li_vn_mode)) {
		msyslog(LOG_ERR,
			"%s: %s not in sync, skipping this server",
			func_name, stoa(sender));
		return SERVER_UNUSEABLE;
	}

	/*
	 * Decode the org timestamp and make sure we're getting a response
	 * to our last request, but only if we're not in broadcast mode.
	 */
	if (MODE_BROADCAST == mode)
		return pkt_len;

	if (!L_ISEQU(&rpkt->org, &spkt->xmt)) {
		NTOHL_FP(&rpkt->org, &resp_org);
		NTOHL_FP(&spkt->xmt, &sent_xmt);
		msyslog(LOG_ERR,
			"%s response org expected to match sent xmt",
			stoa(sender));
		msyslog(LOG_ERR, "resp org: %s", prettydate(&resp_org));
		msyslog(LOG_ERR, "sent xmt: %s", prettydate(&sent_xmt));
		return PACKET_UNUSEABLE;
	}

	return pkt_len;
}
Пример #14
0
void
init_socket_sig(
	int fd
	)
{
# ifdef USE_UDP_SIGPOLL
	{
		if (ioctl(fd, I_SETSIG, S_INPUT) < 0)
		{
			msyslog(LOG_ERR,
				"init_socket_sig: ioctl(I_SETSIG, S_INPUT) failed: %m");
			exit(1);
		}
	}
# else /* USE_UDP_SIGPOLL */
	{
		int pgrp;
# ifdef FIOASYNC
		int on = 1;
# endif

#  if defined(FIOASYNC)
		if (ioctl(fd, FIOASYNC, (char *)&on) == -1)
		{
			msyslog(LOG_ERR, "ioctl(FIOASYNC) fails: %m");
			exit(1);
			/*NOTREACHED*/
		}
#  elif defined(FASYNC)
		{
			int flags;

			if ((flags = fcntl(fd, F_GETFL, 0)) == -1)
			{
				msyslog(LOG_ERR, "fcntl(F_GETFL) fails: %m");
				exit(1);
				/*NOTREACHED*/
			}
			if (fcntl(fd, F_SETFL, flags|FASYNC) < 0)
			{
				msyslog(LOG_ERR, "fcntl(...|FASYNC) fails: %m");
				exit(1);
				/*NOTREACHED*/
			}
		}
#  else
#	include "Bletch: Need asynchronous I/O!"
#  endif

#  ifdef UDP_BACKWARDS_SETOWN
		pgrp = -getpid();
#  else
		pgrp = getpid();
#  endif

#  if defined(SIOCSPGRP)
		if (ioctl(fd, SIOCSPGRP, (char *)&pgrp) == -1)
		{
			msyslog(LOG_ERR, "ioctl(SIOCSPGRP) fails: %m");
			exit(1);
			/*NOTREACHED*/
		}
#  elif defined(FIOSETOWN)
		if (ioctl(fd, FIOSETOWN, (char*)&pgrp) == -1)
		{
			msyslog(LOG_ERR, "ioctl(FIOSETOWN) fails: %m");
			exit(1);
			/*NOTREACHED*/
		}
#  elif defined(F_SETOWN)
		if (fcntl(fd, F_SETOWN, pgrp) == -1)
		{
			msyslog(LOG_ERR, "fcntl(F_SETOWN) fails: %m");
			exit(1);
			/*NOTREACHED*/
		}
#  else
#	include "Bletch: Need to set process(group) to receive SIG(IO|POLL)"
#  endif
	}
# endif /* USE_UDP_SIGPOLL */
}
Пример #15
0
/*
 * loop_config - configure the loop filter
 *
 * LOCKCLOCK: The LOOP_DRIFTINIT and LOOP_DRIFTCOMP cases are no-ops.
 */
void
loop_config(
	int	item,
	double	freq
	)
{
	int i;

#ifdef DEBUG
	if (debug > 1)
		printf("loop_config: item %d freq %f\n", item, freq);
#endif
	switch (item) {

	/*
	 * We first assume the kernel supports the ntp_adjtime()
	 * syscall. If that syscall works, initialize the kernel time
	 * variables. Otherwise, continue leaving no harm behind.
	 */
	case LOOP_DRIFTINIT:
#ifndef LOCKCLOCK
#ifdef KERNEL_PLL
		if (mode_ntpdate)
			break;

		pll_control = 1;
		memset(&ntv, 0, sizeof(ntv));
		ntv.modes = MOD_BITS;
		ntv.status = STA_PLL;
		ntv.maxerror = MAXDISPERSE;
		ntv.esterror = MAXDISPERSE;
		ntv.constant = sys_poll;
#ifdef SIGSYS
		/*
		 * Use sigsetjmp() to save state and then call
		 * ntp_adjtime(); if it fails, then siglongjmp() is used
		 * to return control
		 */
		newsigsys.sa_handler = pll_trap;
		newsigsys.sa_flags = 0;
		if (sigaction(SIGSYS, &newsigsys, &sigsys)) {
			msyslog(LOG_ERR,
			    "sigaction() fails to save SIGSYS trap: %m");
			pll_control = 0;
		}
		if (sigsetjmp(env, 1) == 0)
			ntp_adjtime(&ntv);
		if ((sigaction(SIGSYS, &sigsys,
		    (struct sigaction *)NULL))) {
			msyslog(LOG_ERR,
			    "sigaction() fails to restore SIGSYS trap: %m");
			pll_control = 0;
		}
#else /* SIGSYS */
		ntp_adjtime(&ntv);
#endif /* SIGSYS */

		/*
		 * Save the result status and light up an external clock
		 * if available.
		 */
		pll_status = ntv.status;
		if (pll_control) {
#ifdef STA_NANO
			if (pll_status & STA_CLK)
				ext_enable = 1;
#endif /* STA_NANO */
			report_event(EVNT_KERN, NULL,
 		  	    "kernel time sync enabled");
		}
#endif /* KERNEL_PLL */
#endif /* LOCKCLOCK */
		break;

	/*
	 * Initialize the frequency. If the frequency file is missing or
	 * broken, set the initial frequency to zero and set the state
	 * to NSET. Otherwise, set the initial frequency to the given
	 * value and the state to FSET.
	 */
	case LOOP_DRIFTCOMP:
#ifndef LOCKCLOCK
		if (freq > NTP_MAXFREQ || freq < -NTP_MAXFREQ) {
			set_freq(0);
			rstclock(EVNT_NSET, 0);
		} else {
			set_freq(freq);
			rstclock(EVNT_FSET, 0);
		}
#endif /* LOCKCLOCK */
		break;

	/*
	 * Disable the kernel at shutdown. The microkernel just abandons
	 * ship. The nanokernel carefully cleans up so applications can
	 * see this. Note the last programmed offset and frequency are
	 * left in place.
	 */
	case LOOP_KERN_CLEAR:
#ifndef LOCKCLOCK
#ifdef KERNEL_PLL
		if (pll_control && kern_enable) {
			memset((char *)&ntv, 0, sizeof(ntv));
			ntv.modes = MOD_STATUS;
			ntv.status = STA_UNSYNC;
			ntp_adjtime(&ntv);
			report_event(EVNT_KERN, NULL,
 		  	    "kernel time sync disabledx");
		   }
#endif /* KERNEL_PLL */
#endif /* LOCKCLOCK */
		break;

	/*
	 * Tinker command variables for Ulrich Windl. Very dangerous.
	 */
	case LOOP_ALLAN:	/* Allan intercept (log2) (allan) */
		allan_xpt = (u_char)freq;
		break;

	case LOOP_CODEC:	/* audio codec frequency (codec) */
		clock_codec = freq / 1e6;
		break;
	
	case LOOP_PHI:		/* dispersion threshold (dispersion) */
		clock_phi = freq / 1e6;
		break;

	case LOOP_FREQ:		/* initial frequency (freq) */	
		set_freq(freq / 1e6);
		rstclock(EVNT_FSET, 0);
		break;

	case LOOP_HUFFPUFF:	/* huff-n'-puff length (huffpuff) */
		if (freq < HUFFPUFF)
			freq = HUFFPUFF;
		sys_hufflen = (int)(freq / HUFFPUFF);
		sys_huffpuff = (double *)emalloc(sizeof(double) *
		    sys_hufflen);
		for (i = 0; i < sys_hufflen; i++)
			sys_huffpuff[i] = 1e9;
		sys_mindly = 1e9;
		break;

	case LOOP_PANIC:	/* panic threshold (panic) */
		clock_panic = freq;
		break;

	case LOOP_MAX:		/* step threshold (step) */
		clock_max = freq;
		if (clock_max == 0 || clock_max > 0.5)
			kern_enable = 0;
		break;

	case LOOP_MINSTEP:	/* stepout threshold (stepout) */
		clock_minstep = freq; 
		break;

	case LOOP_LEAP:		/* not used */
	default:
		msyslog(LOG_NOTICE,
		    "loop_config: unsupported option %d", item);
	}
}
Пример #16
0
/*
 * change_logfile()
 *
 * Used to change from syslog to a logfile, or from one logfile to
 * another, and to reopen logfiles after forking.  On systems where
 * ntpd forks, deals with converting relative logfile paths to
 * absolute (root-based) because we reopen logfiles after the current
 * directory has changed.
 */
int
change_logfile(
	const char *	fname,
	int		leave_crumbs
	)
{
	FILE *		new_file;
	const char *	log_fname;
	char *		abs_fname;
#if !defined(SYS_WINNT) && !defined(SYS_VXWORKS) && !defined(VMS)
	char		curdir[512];
	size_t		cd_octets;
	size_t		octets;
#endif	/* POSIX */

	NTP_REQUIRE(fname != NULL);
	log_fname = fname;

	/*
	 * In a forked child of a parent which is logging to a file
	 * instead of syslog, syslog_file will be NULL and both
	 * syslog_fname and syslog_abs_fname will be non-NULL.
	 * If we are given the same filename previously opened
	 * and it's still open, there's nothing to do here.
	 */
	if (syslog_file != NULL && syslog_fname != NULL &&
	    0 == strcmp(syslog_fname, log_fname))
		return 0;

	if (0 == strcmp(log_fname, "stderr")) {
		new_file = stderr;
		abs_fname = estrdup(log_fname);
	} else if (0 == strcmp(log_fname, "stdout")) {
		new_file = stdout;
		abs_fname = estrdup(log_fname);
	} else {
		if (syslog_fname != NULL &&
		    0 == strcmp(log_fname, syslog_fname))
			log_fname = syslog_abs_fname;
#if !defined(SYS_WINNT) && !defined(SYS_VXWORKS) && !defined(VMS)
		if (log_fname != syslog_abs_fname &&
		    DIR_SEP != log_fname[0] &&
		    0 != strcmp(log_fname, "stderr") &&
		    0 != strcmp(log_fname, "stdout") &&
		    NULL != getcwd(curdir, sizeof(curdir))) {
			cd_octets = strlen(curdir);
			/* trim any trailing '/' */
			if (cd_octets > 1 &&
			    DIR_SEP == curdir[cd_octets - 1])
				cd_octets--;
			octets = cd_octets;
			octets += 1;	/* separator '/' */
			octets += strlen(log_fname);
			octets += 1;	/* NUL terminator */
			abs_fname = emalloc(octets);
			snprintf(abs_fname, octets, "%.*s%c%s",
				 (int)cd_octets, curdir, DIR_SEP,
				 log_fname);
		} else
#endif
			abs_fname = estrdup(log_fname);
		TRACE(1, ("attempting to open log %s\n", abs_fname));
		new_file = fopen(abs_fname, "a");
	}

	if (NULL == new_file) {
		free(abs_fname);
		return -1;
	}

	/* leave a pointer in the old log */
	if (leave_crumbs && (syslogit || log_fname != syslog_abs_fname))
		msyslog(LOG_NOTICE, "switching logging to file %s",
			abs_fname);

	if (syslog_file != NULL &&
	    syslog_file != stderr && syslog_file != stdout &&
	    fileno(syslog_file) != fileno(new_file))
		fclose(syslog_file);
	syslog_file = new_file;
	if (log_fname == syslog_abs_fname) {
		free(abs_fname);
	} else {
		if (syslog_abs_fname != NULL &&
		    syslog_abs_fname != syslog_fname)
			free(syslog_abs_fname);
		if (syslog_fname != NULL)
			free(syslog_fname);
		syslog_fname = estrdup(log_fname);
		syslog_abs_fname = abs_fname;
	}
	syslogit = FALSE;

	return 0;
}
Пример #17
0
/*
 * arc_poll - called by the transmit procedure
 */
static void
arc_poll(
	int unit,
	struct peer *peer
	)
{
	register struct arcunit *up;
	struct refclockproc *pp;
	int resync_needed;              /* Should we start a resync? */

	pp = peer->procptr;
	up = pp->unitptr;
#if 0
	pp->lencode = 0;
	memset(pp->a_lastcode, 0, sizeof(pp->a_lastcode));
#endif

#if 0
	/* Flush input. */
	tcflush(pp->io.fd, TCIFLUSH);
#endif

	/* Resync if our next scheduled resync time is here or has passed. */
	resync_needed = ( !(pp->sloppyclockflag & CLK_FLAG2) &&
			  (up->next_resync <= current_time) );

#ifdef ARCRON_LEAPSECOND_KEEN
	/*
	  Try to catch a potential leap-second insertion or deletion quickly.

	  In addition to the normal NTP fun of clocks that don't report
	  leap-seconds spooking their hosts, this clock does not even
	  sample the radio sugnal the whole time, so may miss a
	  leap-second insertion or deletion for up to a whole sample
	  time.

	  To try to minimise this effect, if in the first few minutes of
	  the day immediately following a leap-second-insertion point
	  (ie in the first hour of the first day of the first and sixth
	  months), and if the last resync was in the previous day, and a
	  resync is not already in progress, resync the clock
	  immediately.

	*/
	if((possible_leap > 0) &&       /* Must be 00:XX 01/0{1,7}/XXXX. */
	   (!up->resyncing)) {          /* No resync in progress yet. */
		resync_needed = 1;
		possible_leap = -1;          /* Prevent multiple resyncs. */
		msyslog(LOG_NOTICE,"ARCRON: unit %d: checking for leap second",unit);
	}
#endif

	/* Do a resync if required... */
	if(resync_needed) {
		/* First, reset quality value to `unknown' so we can detect */
		/* when a quality message has been responded to by this     */
		/* being set to some other value.                           */
		up->quality = QUALITY_UNKNOWN;

		/* Note that we are resyncing... */
		up->resyncing = 1;

		/* Now actually send the resync command and an immediate poll. */
#ifdef DEBUG
		if(debug) { printf("arc: sending resync command (h\\r).\n"); }
#endif
		msyslog(LOG_NOTICE, "ARCRON: unit %d: sending resync command", unit);
		send_slow(up, pp->io.fd, "h\r");

		/* Schedule our next resync... */
		up->next_resync = current_time + DEFAULT_RESYNC_TIME;

		/* Drop through to request time if appropriate. */
	}

	/* If clock quality is too poor to trust, indicate a fault. */
	/* If quality is QUALITY_UNKNOWN and ARCRON_KEEN is defined,*/
	/* we'll cross our fingers and just hope that the thing     */
	/* synced so quickly we did not catch it---we'll            */
	/* double-check the clock is OK elsewhere.                  */
	if(
#ifdef ARCRON_KEEN
		(up->quality != QUALITY_UNKNOWN) &&
#else
		(up->quality == QUALITY_UNKNOWN) ||
#endif
		(up->quality < MIN_CLOCK_QUALITY_OK)) {
#ifdef DEBUG
		if(debug) {
			printf("arc: clock quality %d too poor.\n", up->quality);
		}
#endif
		pp->lencode = 0;
		refclock_report(peer, CEVNT_FAULT);
		return;
	}
	/* This is the normal case: request a timestamp. */
	request_time(unit, peer);
}
Пример #18
0
/*
 * audio_init - open and initialize audio device
 *
 * This code works with SunOS 4.x, Solaris 2.x, and PCM; however, it is
 * believed generic and applicable to other systems with a minor twid
 * or two. All it does is open the device, set the buffer size (Solaris
 * only), preset the gain and set the input port. It assumes that the
 * codec sample rate (8000 Hz), precision (8 bits), number of channels
 * (1) and encoding (ITU-T G.711 mu-law companded) have been set by
 * default.
 */
int
audio_init(
	const char *dname,	/* device name */
	int	bufsiz,		/* buffer size */
	int	unit		/* device unit (0-3) */
	)
{
#ifdef PCM_STYLE_SOUND
# define ACTL_DEV	"/dev/mixer%d"
	char actl_dev[30];
# ifdef HAVE_STRUCT_SND_SIZE
	struct snd_size s_size;
# endif
# ifdef AIOGFMT
	snd_chan_param s_c_p;
# endif
#endif
	int fd;
	int rval;
	const char *actl =
#ifdef PCM_STYLE_SOUND
		actl_dev
#else
		"/dev/audioctl"
#endif
		;

#ifdef PCM_STYLE_SOUND
	snprintf(actl_dev, sizeof(actl_dev), ACTL_DEV, unit);

	audio_config_read(unit, &actl, &dname);
	/* If we have values for cf_c_dev or cf_i_dev, use them. */
	if (*cf_c_dev)
		actl = cf_c_dev;
	if (*cf_i_dev)
		dname = cf_i_dev;
#endif

	/*
	 * Open audio device
	 */
	fd = open(dname, O_RDWR | O_NONBLOCK, 0777);
	if (fd < 0) {
		msyslog(LOG_ERR, "audio_init: %s %m\n", dname);
		return (fd);
	}

	/*
	 * Open audio control device.
	 */
	ctl_fd = open(actl, O_RDWR);
	if (ctl_fd < 0) {
		msyslog(LOG_ERR, "audio_init: invalid control device <%s>\n",
		    actl);
		close(fd);
		return(ctl_fd);
	}

	/*
	 * Set audio device parameters.
	 */
#ifdef PCM_STYLE_SOUND
	printf("audio_init: <%s> bufsiz %d\n", dname, bufsiz);
	rval = fd;

# ifdef HAVE_STRUCT_SND_SIZE
	if (ioctl(fd, AIOGSIZE, &s_size) == -1)
	    printf("audio_init: AIOGSIZE: %s\n", strerror(errno));
	else
	    printf("audio_init: orig: play_size %d, rec_size %d\n",
		s_size.play_size, s_size.rec_size);

	s_size.play_size = s_size.rec_size = bufsiz;
	printf("audio_init: want: play_size %d, rec_size %d\n",
	       s_size.play_size, s_size.rec_size);

	if (ioctl(fd, AIOSSIZE, &s_size) == -1)
	    printf("audio_init: AIOSSIZE: %s\n", strerror(errno));
	else
	    printf("audio_init: set:  play_size %d, rec_size %d\n",
		s_size.play_size, s_size.rec_size);
# endif /* HAVE_STRUCT_SND_SIZE */

# ifdef SNDCTL_DSP_SETFRAGMENT
	{
		int tmp = (16 << 16) + 6; /* 16 fragments, each 2^6 bytes */
		if (ioctl(fd, SNDCTL_DSP_SETFRAGMENT, &tmp) == -1)
		    printf("audio_init: SNDCTL_DSP_SETFRAGMENT: %s\n",
			   strerror(errno));
	}
# endif /* SNDCTL_DSP_SETFRAGMENT */

# ifdef AIOGFMT
	if (ioctl(fd, AIOGFMT, &s_c_p) == -1)
	    printf("audio_init: AIOGFMT: %s\n", strerror(errno));
	else
	    printf("audio_init: play_rate %lu, rec_rate %lu, play_format %#lx, rec_format %#lx\n",
		s_c_p.play_rate, s_c_p.rec_rate, s_c_p.play_format, s_c_p.rec_format);
# endif

	/* Grab the device and record masks */

	if (ioctl(ctl_fd, SOUND_MIXER_READ_DEVMASK, &devmask) == -1)
	    printf("SOUND_MIXER_READ_DEVMASK: %s\n", strerror(errno));
	if (ioctl(ctl_fd, SOUND_MIXER_READ_RECMASK, &recmask) == -1)
	    printf("SOUND_MIXER_READ_RECMASK: %s\n", strerror(errno));

	/* validate and set any specified config file stuff */
	if (cf_agc[0] != '\0') {
		int i;

		i = mixer_name(cf_agc, devmask);
		if (i >= 0)
			agc = MIXER_WRITE(i);
		else
			printf("input %s not in recmask %#x\n",
			       cf_agc, recmask);
	}

	if (cf_monitor[0] != '\0') {
		int i;

		/* devmask */
		i = mixer_name(cf_monitor, devmask);
		if (i >= 0)
			monitor = MIXER_WRITE(i);
		else
			printf("monitor %s not in devmask %#x\n",
			       cf_monitor, devmask);
	}

#else /* not PCM_STYLE_SOUND */
	AUDIO_INITINFO(&info);
	info.play.gain = AUDIO_MAX_GAIN;
	info.play.port = AUDIO_SPEAKER;
# ifdef HAVE_SYS_AUDIOIO_H
	info.record.buffer_size = bufsiz;
# endif /* HAVE_SYS_AUDIOIO_H */
	rval = ioctl(ctl_fd, (int)AUDIO_SETINFO, (char *)&info);
	if (rval < 0) {
		msyslog(LOG_ERR, "audio: invalid control device parameters\n");
		close(ctl_fd);
		close(fd);
		return(rval);
	}
	rval = fd;
#endif /* not PCM_STYLE_SOUND */
	return (rval);
}
Пример #19
0
/*
 * arc_receive - receive data from the serial interface
 */
static void
arc_receive(
	struct recvbuf *rbufp
	)
{
	register struct arcunit *up;
	struct refclockproc *pp;
	struct peer *peer;
	char c;
	int i, n, wday, month, flags, status;
	int arc_last_offset;
	static int quality_average = 0;
	static int quality_sum = 0;
	static int quality_polls = 0;

	/*
	 * Initialize pointers and read the timecode and timestamp
	 */
	peer = (struct peer *)rbufp->recv_srcclock;
	pp = peer->procptr;
	up = pp->unitptr;


	/*
	  If the command buffer is empty, and we are resyncing, insert a
	  g\r quality request into it to poll for signal quality again.
	*/
	if((up->resyncing) && (space_left(up) == CMDQUEUELEN)) {
#ifdef DEBUG
		if(debug > 1) { printf("arc: inserting signal-quality poll.\n"); }
#endif
		send_slow(up, pp->io.fd, "g\r");
	}

	/*
	  The `arc_last_offset' is the offset in lastcode[] of the last byte
	  received, and which we assume actually received the input
	  timestamp.

	  (When we get round to using tty_clk and it is available, we
	  assume that we will receive the whole timecode with the
	  trailing \r, and that that \r will be timestamped.  But this
	  assumption also works if receive the characters one-by-one.)
	*/
	arc_last_offset = pp->lencode+rbufp->recv_length - 1;

	/*
	  We catch a timestamp iff:

	  * The command code is `o' for a timestamp.

	  * If ARCRON_MULTIPLE_SAMPLES is undefined then we must have
	  exactly char in the buffer (the command code) so that we
	  only sample the first character of the timecode as our
	  `on-time' character.

	  * The first character in the buffer is not the echoed `\r'
	  from the `o` command (so if we are to timestamp an `\r' it
	  must not be first in the receive buffer with lencode==1.
	  (Even if we had other characters following it, we probably
	  would have a premature timestamp on the '\r'.)

	  * We have received at least one character (I cannot imagine
	  how it could be otherwise, but anyway...).
	*/
	c = rbufp->recv_buffer[0];
	if((pp->a_lastcode[0] == 'o') &&
#ifndef ARCRON_MULTIPLE_SAMPLES
	   (pp->lencode == 1) &&
#endif
	   ((pp->lencode != 1) || (c != '\r')) &&
	   (arc_last_offset >= 1)) {
		/* Note that the timestamp should be corrected if >1 char rcvd. */
		l_fp timestamp;
		timestamp = rbufp->recv_time;
#ifdef DEBUG
		if(debug) { /* Show \r as `R', other non-printing char as `?'. */
			printf("arc: stamp -->%c<-- (%d chars rcvd)\n",
			       ((c == '\r') ? 'R' : (isgraph((unsigned char)c) ? c : '?')),
			       rbufp->recv_length);
		}
#endif

		/*
		  Now correct timestamp by offset of last byte received---we
		  subtract from the receive time the delay implied by the
		  extra characters received.

		  Reject the input if the resulting code is too long, but
		  allow for the trailing \r, normally not used but a good
		  handle for tty_clk or somesuch kernel timestamper.
		*/
		if(arc_last_offset > LENARC) {
#ifdef DEBUG
			if(debug) {
				printf("arc: input code too long (%d cf %d); rejected.\n",
				       arc_last_offset, LENARC);
			}
#endif
			pp->lencode = 0;
			refclock_report(peer, CEVNT_BADREPLY);
			return;
		}

		L_SUBUF(&timestamp, charoffsets[arc_last_offset]);
#ifdef DEBUG
		if(debug > 1) {
			printf(
				"arc: %s%d char(s) rcvd, the last for lastcode[%d]; -%sms offset applied.\n",
				((rbufp->recv_length > 1) ? "*** " : ""),
				rbufp->recv_length,
				arc_last_offset,
				mfptoms((unsigned long)0,
					charoffsets[arc_last_offset],
					1));
		}
#endif

#ifdef ARCRON_MULTIPLE_SAMPLES
		/*
		  If taking multiple samples, capture the current adjusted
		  sample iff:

		  * No timestamp has yet been captured (it is zero), OR

		  * This adjusted timestamp is earlier than the one already
		  captured, on the grounds that this one suffered less
		  delay in being delivered to us and is more accurate.

		*/
		if(L_ISZERO(&(up->lastrec)) ||
		   L_ISGEQ(&(up->lastrec), &timestamp))
#endif
		{
#ifdef DEBUG
			if(debug > 1) {
				printf("arc: system timestamp captured.\n");
#ifdef ARCRON_MULTIPLE_SAMPLES
				if(!L_ISZERO(&(up->lastrec))) {
					l_fp diff;
					diff = up->lastrec;
					L_SUB(&diff, &timestamp);
					printf("arc: adjusted timestamp by -%sms.\n",
					       mfptoms(diff.l_i, diff.l_f, 3));
				}
#endif
			}
#endif
			up->lastrec = timestamp;
		}

	}

	/* Just in case we still have lots of rubbish in the buffer... */
	/* ...and to avoid the same timestamp being reused by mistake, */
	/* eg on receipt of the \r coming in on its own after the      */
	/* timecode.						       */
	if(pp->lencode >= LENARC) {
#ifdef DEBUG
		if(debug && (rbufp->recv_buffer[0] != '\r'))
		{ printf("arc: rubbish in pp->a_lastcode[].\n"); }
#endif
		pp->lencode = 0;
		return;
	}

	/* Append input to code buffer, avoiding overflow. */
	for(i = 0; i < rbufp->recv_length; i++) {
		if(pp->lencode >= LENARC) { break; } /* Avoid overflow... */
		c = rbufp->recv_buffer[i];

		/* Drop trailing '\r's and drop `h' command echo totally. */
		if(c != '\r' && c != 'h') { pp->a_lastcode[pp->lencode++] = c; }

		/*
		  If we've just put an `o' in the lastcode[0], clear the
		  timestamp in anticipation of a timecode arriving soon.

		  We would expect to get to process this before any of the
		  timecode arrives.
		*/
		if((c == 'o') && (pp->lencode == 1)) {
			L_CLR(&(up->lastrec));
#ifdef DEBUG
			if(debug > 1) { printf("arc: clearing timestamp.\n"); }
#endif
		}
	}
	if (pp->lencode == 0) return;

	/* Handle a quality message. */
	if(pp->a_lastcode[0] == 'g') {
		int r, q;

		if(pp->lencode < 3) { return; } /* Need more data... */
		r = (pp->a_lastcode[1] & 0x7f); /* Strip parity. */
		q = (pp->a_lastcode[2] & 0x7f); /* Strip parity. */
		if(((q & 0x70) != 0x30) || ((q & 0xf) > MAX_CLOCK_QUALITY) ||
		   ((r & 0x70) != 0x30)) {
			/* Badly formatted response. */
#ifdef DEBUG
			if(debug) { printf("arc: bad `g' response %2x %2x.\n", r, q); }
#endif
			return;
		}
		if(r == '3') { /* Only use quality value whilst sync in progress. */
			if (up->quality_stamp < current_time) {
				struct calendar cal;
				l_fp new_stamp;
			
				get_systime (&new_stamp);
				caljulian (new_stamp.l_ui, &cal);
				up->quality_stamp = 
					current_time + 60 - cal.second + 5;
				quality_sum = 0;
				quality_polls = 0;
			}
			quality_sum += (q & 0xf);
			quality_polls++;
			quality_average = (quality_sum / quality_polls);
#ifdef DEBUG
			if(debug) { printf("arc: signal quality %d (%d).\n", quality_average, (q & 0xf)); }
#endif
		} else if( /* (r == '2') && */ up->resyncing) {
			up->quality = quality_average;
#ifdef DEBUG
			if(debug)
			{
				printf("arc: sync finished, signal quality %d: %s\n",
				       up->quality,
				       quality_action(up->quality));
			}
#endif
			msyslog(LOG_NOTICE,
				"ARCRON: sync finished, signal quality %d: %s",
				up->quality,
				quality_action(up->quality));
			up->resyncing = 0; /* Resync is over. */
			quality_average = 0;
			quality_sum = 0;
			quality_polls = 0;

#ifdef ARCRON_KEEN
			/* Clock quality dubious; resync earlier than usual. */
			if((up->quality == QUALITY_UNKNOWN) ||
			   (up->quality < MIN_CLOCK_QUALITY_OK))
			{ up->next_resync = current_time + RETRY_RESYNC_TIME; }
#endif
		}
		pp->lencode = 0;
		return;
	}

	/* Stop now if this is not a timecode message. */
	if(pp->a_lastcode[0] != 'o') {
		pp->lencode = 0;
		refclock_report(peer, CEVNT_BADREPLY);
		return;
	}

	/* If we don't have enough data, wait for more... */
	if(pp->lencode < LENARC) { return; }


	/* WE HAVE NOW COLLECTED ONE TIMESTAMP (phew)... */
#ifdef DEBUG
	if(debug > 1) { printf("arc: NOW HAVE TIMESTAMP...\n"); }
#endif

	/* But check that we actually captured a system timestamp on it. */
	if(L_ISZERO(&(up->lastrec))) {
#ifdef DEBUG
		if(debug) { printf("arc: FAILED TO GET SYSTEM TIMESTAMP\n"); }
#endif
		pp->lencode = 0;
		refclock_report(peer, CEVNT_BADREPLY);
		return;
	}
	/*
	  Append a mark of the clock's received signal quality for the
	  benefit of Derek Mulcahy's Tcl/Tk utility (we map the `unknown'
	  quality value to `6' for his s/w) and terminate the string for
	  sure.  This should not go off the buffer end.
	*/
	pp->a_lastcode[pp->lencode] = ((up->quality == QUALITY_UNKNOWN) ?
				       '6' : ('0' + up->quality));
	pp->a_lastcode[pp->lencode + 1] = '\0'; /* Terminate for printf(). */

#ifdef PRE_NTP420
	/* We don't use the micro-/milli- second part... */
	pp->usec = 0;
	pp->msec = 0;
#else
	/* We don't use the nano-second part... */
	pp->nsec = 0;
#endif	
	/* Validate format and numbers. */
	if (pp->a_lastcode[0] != 'o'
		|| !get2(pp->a_lastcode + 1, &pp->hour)
		|| !get2(pp->a_lastcode + 3, &pp->minute)
		|| !get2(pp->a_lastcode + 5, &pp->second)
		|| !get1(pp->a_lastcode + 7, &wday)
		|| !get2(pp->a_lastcode + 8, &pp->day)
		|| !get2(pp->a_lastcode + 10, &month)
		|| !get2(pp->a_lastcode + 12, &pp->year)) {
#ifdef DEBUG
		/* Would expect to have caught major problems already... */
		if(debug) { printf("arc: badly formatted data.\n"); }
#endif
		pp->lencode = 0;
		refclock_report(peer, CEVNT_BADREPLY);
		return;
	}
	flags = pp->a_lastcode[14];
	status = pp->a_lastcode[15];
#ifdef DEBUG
	if(debug) { printf("arc: status 0x%.2x flags 0x%.2x\n", flags, status); }
#endif
	n = 9;

	/*
	  Validate received values at least enough to prevent internal
	  array-bounds problems, etc.
	*/
	if((pp->hour < 0) || (pp->hour > 23) ||
	   (pp->minute < 0) || (pp->minute > 59) ||
	   (pp->second < 0) || (pp->second > 60) /*Allow for leap seconds.*/ ||
	   (wday < 1) || (wday > 7) ||
	   (pp->day < 1) || (pp->day > 31) ||
	   (month < 1) || (month > 12) ||
	   (pp->year < 0) || (pp->year > 99)) {
		/* Data out of range. */
		pp->lencode = 0;
		refclock_report(peer, CEVNT_BADREPLY);
		return;
	}


	if(peer->MODE == 0) { /* compatiblity to original version */
		int bst = flags;
		/* Check that BST/UTC bits are the complement of one another. */
		if(!(bst & 2) == !(bst & 4)) {
			pp->lencode = 0;
			refclock_report(peer, CEVNT_BADREPLY);
			return;
		}
	}
	if(status & 0x8) { msyslog(LOG_NOTICE, "ARCRON: battery low"); }

	/* Year-2000 alert! */
	/* Attempt to wrap 2-digit date into sensible window. */
	if(pp->year < YEAR_PIVOT) { pp->year += 100; }		/* Y2KFixes */
	pp->year += 1900;	/* use full four-digit year */	/* Y2KFixes */
	/*
	  Attempt to do the right thing by screaming that the code will
	  soon break when we get to the end of its useful life.  What a
	  hero I am...  PLEASE FIX LEAP-YEAR AND WRAP CODE IN 209X!
	*/
	if(pp->year >= YEAR_PIVOT+2000-2 ) {  			/* Y2KFixes */
		/*This should get attention B^> */
		msyslog(LOG_NOTICE,
			"ARCRON: fix me!  EITHER YOUR DATE IS BADLY WRONG or else I will break soon!");
	}
#ifdef DEBUG
	if(debug) {
		printf("arc: n=%d %02d:%02d:%02d %02d/%02d/%04d %1d %1d\n",
		       n,
		       pp->hour, pp->minute, pp->second,
		       pp->day, month, pp->year, flags, status);
	}
#endif

	/*
	  The status value tested for is not strictly supported by the
	  clock spec since the value of bit 2 (0x4) is claimed to be
	  undefined for MSF, yet does seem to indicate if the last resync
	  was successful or not.
	*/
	pp->leap = LEAP_NOWARNING;
	status &= 0x7;
	if(status == 0x3) {
		if(status != up->status)
		{ msyslog(LOG_NOTICE, "ARCRON: signal acquired"); }
	} else {
		if(status != up->status) {
			msyslog(LOG_NOTICE, "ARCRON: signal lost");
			pp->leap = LEAP_NOTINSYNC; /* MSF clock is free-running. */
			up->status = status;
			pp->lencode = 0;
			refclock_report(peer, CEVNT_FAULT);
			return;
		}
	}
	up->status = status;

	if (peer->MODE == 0) { /* compatiblity to original version */
		int bst = flags;

		pp->day += moff[month - 1];

		if(isleap_4(pp->year) && month > 2) { pp->day++; }/* Y2KFixes */

		/* Convert to UTC if required */
		if(bst & 2) {
			pp->hour--;
			if (pp->hour < 0) {
				pp->hour = 23;
				pp->day--;
				/* If we try to wrap round the year
				 * (BST on 1st Jan), reject.*/
				if(pp->day < 0) {
					pp->lencode = 0;
					refclock_report(peer, CEVNT_BADTIME);
					return;
				}
			}
		}
	}

	if(peer->MODE > 0) {
		if(pp->sloppyclockflag & CLK_FLAG1) {
			struct tm  local;
			struct tm *gmtp;
			time_t	   unixtime;

			/*
			 * Convert to GMT for sites that distribute localtime.
			 * This means we have to do Y2K conversion on the
			 * 2-digit year; otherwise, we get the time wrong.
			 */

			memset(&local, 0, sizeof(local));

			local.tm_year  = pp->year-1900;
			local.tm_mon   = month-1;
			local.tm_mday  = pp->day;
			local.tm_hour  = pp->hour;
			local.tm_min   = pp->minute;
			local.tm_sec   = pp->second;
			switch (peer->MODE) {
			    case 1:
				local.tm_isdst = (flags & 2);
				break;
			    case 2:
				local.tm_isdst = (flags & 2);
				break;
			    case 3:
				switch (flags & 3) {
				    case 0: /* It is unclear exactly when the 
					       Arcron changes from DST->ST and 
					       ST->DST. Testing has shown this
					       to be irregular. For the time 
					       being, let the OS decide. */
					local.tm_isdst = 0;
#ifdef DEBUG
					if (debug)
					    printf ("arc: DST = 00 (0)\n"); 
#endif
					break;
				    case 1: /* dst->st time */
					local.tm_isdst = -1;
#ifdef DEBUG
					if (debug) 
					    printf ("arc: DST = 01 (1)\n"); 
#endif
					break;
				    case 2: /* st->dst time */
					local.tm_isdst = -1;
#ifdef DEBUG
					if (debug) 
					    printf ("arc: DST = 10 (2)\n"); 
#endif
					break;
				    case 3: /* dst time */
				        local.tm_isdst = 1;
#ifdef DEBUG
					if (debug) 
					    printf ("arc: DST = 11 (3)\n"); 
#endif
					break;
				}
				break;
			    default:
				msyslog(LOG_NOTICE, "ARCRON: Invalid mode %d",
					peer->MODE);
				return;
				break;
			}
			unixtime = mktime (&local);
			if ((gmtp = gmtime (&unixtime)) == NULL)
			{
				pp->lencode = 0;
				refclock_report (peer, CEVNT_FAULT);
				return;
			}
			pp->year = gmtp->tm_year+1900;
			month = gmtp->tm_mon+1;
			pp->day = ymd2yd(pp->year,month,gmtp->tm_mday);
			/* pp->day = gmtp->tm_yday; */
			pp->hour = gmtp->tm_hour;
			pp->minute = gmtp->tm_min;
			pp->second = gmtp->tm_sec;
#ifdef DEBUG
			if (debug)
			{
				printf ("arc: time is %04d/%02d/%02d %02d:%02d:%02d UTC\n",
					pp->year,month,gmtp->tm_mday,pp->hour,pp->minute,
					pp->second);
			}
#endif
		} else 
		{
			/*
			* For more rational sites distributing UTC
			*/
			pp->day    = ymd2yd(pp->year,month,pp->day);
		}
	}

	if (peer->MODE == 0) { /* compatiblity to original version */
				/* If clock signal quality is 
				 * unknown, revert to default PRECISION...*/
		if(up->quality == QUALITY_UNKNOWN) { 
			peer->precision = PRECISION; 
		} else { /* ...else improve precision if flag3 is set... */
			peer->precision = ((pp->sloppyclockflag & CLK_FLAG3) ?
					   HIGHPRECISION : PRECISION);
		}
	} else {
		if ((status == 0x3) && (pp->sloppyclockflag & CLK_FLAG2)) {
			peer->precision = ((pp->sloppyclockflag & CLK_FLAG3) ?
					   HIGHPRECISION : PRECISION);
		} else if (up->quality == QUALITY_UNKNOWN) {
			peer->precision = PRECISION;
		} else {
			peer->precision = ((pp->sloppyclockflag & CLK_FLAG3) ?
					   HIGHPRECISION : PRECISION);
		}
	}

	/* Notice and log any change (eg from initial defaults) for flags. */
	if(up->saved_flags != pp->sloppyclockflag) {
#ifdef DEBUG
		msyslog(LOG_NOTICE, "ARCRON: flags enabled: %s%s%s%s",
			((pp->sloppyclockflag & CLK_FLAG1) ? "1" : "."),
			((pp->sloppyclockflag & CLK_FLAG2) ? "2" : "."),
			((pp->sloppyclockflag & CLK_FLAG3) ? "3" : "."),
			((pp->sloppyclockflag & CLK_FLAG4) ? "4" : "."));
		/* Note effects of flags changing... */
		if(debug) {
			printf("arc: PRECISION = %d.\n", peer->precision);
		}
#endif
		up->saved_flags = pp->sloppyclockflag;
	}

	/* Note time of last believable timestamp. */
	pp->lastrec = up->lastrec;

#ifdef ARCRON_LEAPSECOND_KEEN
	/* Find out if a leap-second might just have happened...
	   (ie is this the first hour of the first day of Jan or Jul?)
	*/
	if((pp->hour == 0) &&
	   (pp->day == 1) &&
	   ((month == 1) || (month == 7))) {
		if(possible_leap >= 0) {
			/* A leap may have happened, and no resync has started yet...*/
			possible_leap = 1;
		}
	} else {
		/* Definitely not leap-second territory... */
		possible_leap = 0;
	}
#endif

	if (!refclock_process(pp)) {
		pp->lencode = 0;
		refclock_report(peer, CEVNT_BADTIME);
		return;
	}
	record_clock_stats(&peer->srcadr, pp->a_lastcode);
	refclock_receive(peer);
}
Пример #20
0
/*
 * audio_gain - adjust codec gains and port
 */
int
audio_gain(
	int gain,		/* volume level (gain) 0-255 */
	int mongain,		/* input to output mix (monitor gain) 0-255 */
	int port		/* selected I/O port: 1 mic/2 line in */
	)
{
	int rval;
	static int o_mongain = -1;
	static int o_port = -1;

#ifdef PCM_STYLE_SOUND
	int l, r;

	rval = 0;

	r = l = 100 * gain / 255;	/* Normalize to 0-100 */
# ifdef DEBUG
	if (debug > 1)
		printf("audio_gain: gain %d/%d\n", gain, l);
# endif
#if 0	/* not a good idea to do this; connector wiring dependency */
	/* figure out what channel(s) to use. just nuke right for now. */
	r = 0 ; /* setting to zero nicely mutes the channel */
#endif
	l |= r << 8;
	if (cf_agc[0] != '\0')
		rval = ioctl(ctl_fd, agc, &l);
	else
		if (2 == port)
			rval = ioctl(ctl_fd, SOUND_MIXER_WRITE_LINE, &l);
		else
			rval = ioctl(ctl_fd, SOUND_MIXER_WRITE_MIC, &l);
	if (-1 == rval) {
		printf("audio_gain: agc write: %s\n", strerror(errno));
		return rval;
	}

	if (o_mongain != mongain) {
		r = l = 100 * mongain / 255;    /* Normalize to 0-100 */
# ifdef DEBUG
		if (debug > 1)
			printf("audio_gain: mongain %d/%d\n", mongain, l);
# endif
		l |= r << 8;
		if (cf_monitor[0] != '\0')
			rval = ioctl(ctl_fd, monitor, &l );
		else 
			rval = ioctl(ctl_fd, SOUND_MIXER_WRITE_VOLUME,
				     &l);
		if (-1 == rval) {
			printf("audio_gain: mongain write: %s\n",
			       strerror(errno));
			return (rval);
		}
		o_mongain = mongain;
	}

	if (o_port != port) {
# ifdef DEBUG
		if (debug > 1)
			printf("audio_gain: port %d\n", port);
# endif
		l = (1 << ((port == 2) ? SOUND_MIXER_LINE : SOUND_MIXER_MIC));
		rval = ioctl(ctl_fd, SOUND_MIXER_WRITE_RECSRC, &l);
		if (rval == -1) {
			printf("SOUND_MIXER_WRITE_RECSRC: %s\n",
			       strerror(errno));
			return (rval);
		}
# ifdef DEBUG
		if (debug > 1) {
			if (ioctl(ctl_fd, SOUND_MIXER_READ_RECSRC, &l) == -1)
				printf("SOUND_MIXER_WRITE_RECSRC: %s\n",
				       strerror(errno));
			else
				printf("audio_gain: recsrc is %d\n", l);
		}
# endif
		o_port = port;
	}
#else /* not PCM_STYLE_SOUND */
	ioctl(ctl_fd, (int)AUDIO_GETINFO, (char *)&info);
	info.record.encoding = AUDIO_ENCODING_ULAW;
	info.record.error = 0;
	info.record.gain = gain;
	if (o_mongain != mongain)
		o_mongain = info.monitor_gain = mongain;
	if (o_port != port)
		o_port = info.record.port = port;
	rval = ioctl(ctl_fd, (int)AUDIO_SETINFO, (char *)&info);
	if (rval < 0) {
		msyslog(LOG_ERR, "audio_gain: %m");
		return (rval);
	}
	rval = info.record.error;
#endif /* not PCM_STYLE_SOUND */
	return (rval);
}
Пример #21
0
static int
neoclock4x_start(int unit,
		 struct peer *peer)
{
  struct neoclock4x_unit *up;
  struct refclockproc *pp;
  int fd;
  char dev[20];
  int sl232;
#if defined(HAVE_TERMIOS)
  struct termios termsettings;
#endif
#if !defined(NEOCLOCK4X_FIRMWARE)
  int tries;
#endif

  (void) snprintf(dev, sizeof(dev)-1, "/dev/neoclock4x-%d", unit);

  /* LDISC_STD, LDISC_RAW
   * Open serial port. Use CLK line discipline, if available.
   */
  fd = refclock_open(dev, B2400, LDISC_STD);
  if(fd <= 0)
    {
      return (0);
    }

#if defined(HAVE_TERMIOS)

#if 1
  if(tcgetattr(fd, &termsettings) < 0)
    {
      msyslog(LOG_CRIT, "NeoClock4X(%d): (tcgetattr) can't query serial port settings: %m", unit);
      (void) close(fd);
      return (0);
    }

  /* 2400 Baud 8N2 */
  termsettings.c_iflag = IGNBRK | IGNPAR | ICRNL;
  termsettings.c_oflag = 0;
  termsettings.c_cflag = CS8 | CSTOPB | CLOCAL | CREAD;
  (void)cfsetispeed(&termsettings, (u_int)B2400);
  (void)cfsetospeed(&termsettings, (u_int)B2400);

  if(tcsetattr(fd, TCSANOW, &termsettings) < 0)
    {
      msyslog(LOG_CRIT, "NeoClock4X(%d): (tcsetattr) can't set serial port 2400 8N2: %m", unit);
      (void) close(fd);
      return (0);
    }

#else
  if(tcgetattr(fd, &termsettings) < 0)
    {
      msyslog(LOG_CRIT, "NeoClock4X(%d): (tcgetattr) can't query serial port settings: %m", unit);
      (void) close(fd);
      return (0);
    }

  /* 2400 Baud 8N2 */
  termsettings.c_cflag &= ~PARENB;
  termsettings.c_cflag |= CSTOPB;
  termsettings.c_cflag &= ~CSIZE;
  termsettings.c_cflag |= CS8;

  if(tcsetattr(fd, TCSANOW, &termsettings) < 0)
    {
      msyslog(LOG_CRIT, "NeoClock4X(%d): (tcsetattr) can't set serial port 2400 8N2: %m", unit);
      (void) close(fd);
      return (0);
    }
#endif

#elif defined(HAVE_SYSV_TTYS)
  if(ioctl(fd, TCGETA, &termsettings) < 0)
    {
      msyslog(LOG_CRIT, "NeoClock4X(%d): (TCGETA) can't query serial port settings: %m", unit);
      (void) close(fd);
      return (0);
    }

  /* 2400 Baud 8N2 */
  termsettings.c_cflag &= ~PARENB;
  termsettings.c_cflag |= CSTOPB;
  termsettings.c_cflag &= ~CSIZE;
  termsettings.c_cflag |= CS8;

  if(ioctl(fd, TCSETA, &termsettings) < 0)
    {
      msyslog(LOG_CRIT, "NeoClock4X(%d): (TSGETA) can't set serial port 2400 8N2: %m", unit);
      (void) close(fd);
      return (0);
    }
#else
  msyslog(LOG_EMERG, "NeoClock4X(%d): don't know how to set port to 2400 8N2 with this OS!", unit);
  (void) close(fd);
  return (0);
#endif

#if defined(TIOCMSET) && (defined(TIOCM_RTS) || defined(CIOCM_RTS))
  /* turn on RTS, and DTR for power supply */
  /* NeoClock4x is powered from serial line */
  if(ioctl(fd, TIOCMGET, (caddr_t)&sl232) == -1)
    {
      msyslog(LOG_CRIT, "NeoClock4X(%d): can't query RTS/DTR state: %m", unit);
      (void) close(fd);
      return (0);
    }
#ifdef TIOCM_RTS
  sl232 = sl232 | TIOCM_DTR | TIOCM_RTS;	/* turn on RTS, and DTR for power supply */
#else
  sl232 = sl232 | CIOCM_DTR | CIOCM_RTS;	/* turn on RTS, and DTR for power supply */
#endif
  if(ioctl(fd, TIOCMSET, (caddr_t)&sl232) == -1)
    {
      msyslog(LOG_CRIT, "NeoClock4X(%d): can't set RTS/DTR to power neoclock4x: %m", unit);
      (void) close(fd);
      return (0);
    }
#else
  msyslog(LOG_EMERG, "NeoClock4X(%d): don't know how to set DTR/RTS to power NeoClock4X with this OS!",
	  unit);
  (void) close(fd);
  return (0);
#endif

  up = (struct neoclock4x_unit *) emalloc(sizeof(struct neoclock4x_unit));
  if(!(up))
    {
      msyslog(LOG_ERR, "NeoClock4X(%d): can't allocate memory for: %m",unit);
      (void) close(fd);
      return (0);
    }

  memset((char *)up, 0, sizeof(struct neoclock4x_unit));
  pp = peer->procptr;
  pp->clockdesc = "NeoClock4X";
  pp->unitptr = up;
  pp->io.clock_recv = neoclock4x_receive;
  pp->io.srcclock = peer;
  pp->io.datalen = 0;
  pp->io.fd = fd;
  /*
   * no fudge time is given by user!
   * use 169.583333 ms to compensate the serial line delay
   * formula is:
   * 2400 Baud / 11 bit = 218.18 charaters per second
   *  (NeoClock4X timecode len)
   */
  pp->fudgetime1 = (NEOCLOCK4X_TIMECODELEN * 11) / 2400.0;

  /*
   * Initialize miscellaneous variables
   */
  peer->precision = -10;
  memcpy((char *)&pp->refid, "neol", 4);

  up->leap_status = 0;
  up->unit = unit;
  strlcpy(up->firmware, "?", sizeof(up->firmware));
  up->firmwaretag = '?';
  strlcpy(up->serial, "?", sizeof(up->serial));
  strlcpy(up->radiosignal, "?", sizeof(up->radiosignal));
  up->timesource  = '?';
  up->dststatus   = '?';
  up->quarzstatus = '?';
  up->antenna1    = -1;
  up->antenna2    = -1;
  up->utc_year    = 0;
  up->utc_month   = 0;
  up->utc_day     = 0;
  up->utc_hour    = 0;
  up->utc_minute  = 0;
  up->utc_second  = 0;
  up->utc_msec    = 0;

#if defined(NEOCLOCK4X_FIRMWARE)
#if NEOCLOCK4X_FIRMWARE == NEOCLOCK4X_FIRMWARE_VERSION_A
  strlcpy(up->firmware, "(c) 2002 NEOL S.A. FRANCE / L0.01 NDF:A:* (compile time)",
	  sizeof(up->firmware));
  up->firmwaretag = 'A';
#else
  msyslog(LOG_EMERG, "NeoClock4X(%d): unknown firmware defined at compile time for NeoClock4X",
	  unit);
  (void) close(fd);
  pp->io.fd = -1;
  free(pp->unitptr);
  pp->unitptr = NULL;
  return (0);
#endif
#else
  for(tries=0; tries < 5; tries++)
    {
      NLOG(NLOG_CLOCKINFO)
	msyslog(LOG_INFO, "NeoClock4X(%d): checking NeoClock4X firmware version (%d/5)", unit, tries);
      /* wait 3 seconds for receiver to power up */
      sleep(3);
      if(neol_query_firmware(pp->io.fd, up->unit, up->firmware, sizeof(up->firmware)))
	{
	  break;
	}
    }

  /* can I handle this firmware version? */
  if(!neol_check_firmware(up->unit, up->firmware, &up->firmwaretag))
    {
      (void) close(fd);
      pp->io.fd = -1;
      free(pp->unitptr);
      pp->unitptr = NULL;
      return (0);
    }
#endif

  if(!io_addclock(&pp->io))
    {
      msyslog(LOG_ERR, "NeoClock4X(%d): error add peer to ntpd: %m", unit);
      (void) close(fd);
      pp->io.fd = -1;
      free(pp->unitptr);
      pp->unitptr = NULL;
      return (0);
    }

  NLOG(NLOG_CLOCKINFO)
    msyslog(LOG_INFO, "NeoClock4X(%d): receiver setup successful done", unit);

  return (1);
}
Пример #22
0
Файл: main.c Проект: happyj/qcn
int
handle_pkt (
    int rpktl,
    struct pkt *rpkt,
    struct addrinfo *host
)
{
    struct timeval tv_dst;
    int sw_case, digits;
    char *hostname = NULL, *ref, *ts_str = NULL;
    double offset, precision, root_dispersion;
    char addr_buf[INET6_ADDRSTRLEN];
    char *p_SNTP_PRETEND_TIME;
    time_t pretend_time;

    if(rpktl > 0)
        sw_case = 1;
    else
        sw_case = rpktl;

    switch(sw_case) {
    case SERVER_UNUSEABLE:
        return -1;
        break;

    case PACKET_UNUSEABLE:
        break;

    case SERVER_AUTH_FAIL:
        break;

    case KOD_DEMOBILIZE:
        /* Received a DENY or RESTR KOD packet */
        hostname = addrinfo_to_str(host);
        ref = (char *)&rpkt->refid;
        add_entry(hostname, ref);

        if (ENABLED_OPT(NORMALVERBOSE))
            printf("sntp handle_pkt: Received KOD packet with code: %c%c%c%c from %s, demobilizing all connections\n",
                   ref[0], ref[1], ref[2], ref[3],
                   hostname);

        msyslog(LOG_WARNING, "Received a KOD packet with code %c%c%c%c from %s, demobilizing all connections",
                ref[0], ref[1], ref[2], ref[3], hostname);
        break;

    case KOD_RATE:
        /* Hmm... probably we should sleep a bit here */
        break;

    case 1:
        if (ENABLED_OPT(NORMALVERBOSE)) {
            getnameinfo(host->ai_addr, host->ai_addrlen, addr_buf,
                        sizeof(addr_buf), NULL, 0, NI_NUMERICHOST);
            printf("sntp handle_pkt: Received %i bytes from %s\n", rpktl, addr_buf);
        }

        GETTIMEOFDAY(&tv_dst, (struct timezone *)NULL);

        p_SNTP_PRETEND_TIME = getenv("SNTP_PRETEND_TIME");
        if (p_SNTP_PRETEND_TIME) {
#if SIZEOF_TIME_T == 4
            sscanf(p_SNTP_PRETEND_TIME, "%ld", &pretend_time);
#elif SIZEOF_TIME_T == 8
            sscanf(p_SNTP_PRETEND_TIME, "%lld", &pretend_time);
#else
# include "GRONK: unexpected value for SIZEOF_TIME_T"
#endif
            tv_dst.tv_sec = pretend_time;
        }

        offset_calculation(rpkt, rpktl, &tv_dst, &offset,
                           &precision, &root_dispersion);

        for (digits = 0; (precision *= 10.) < 1.; ++digits)
            /* empty */ ;
        if (digits > 6)
            digits = 6;

        ts_str = tv_to_str(&tv_dst);
        printf("%s ", ts_str);
        if (offset > 0)
            printf("+");
        printf("%.*f", digits, offset);
        if (root_dispersion > 0.)
            printf(" +/- %f secs", root_dispersion);
        printf("\n");
        free(ts_str);

        if (p_SNTP_PRETEND_TIME)
            return 0;

        if (ENABLED_OPT(SETTOD) || ENABLED_OPT(ADJTIME))
            return set_time(offset);

        return 0;
    }

    return 1;
}
Пример #23
0
static void
neoclock4x_control(int unit,
		   const struct refclockstat *in,
		   struct refclockstat *out,
		   struct peer *peer)
{
  struct neoclock4x_unit *up;
  struct refclockproc *pp;

  if(NULL == peer)
    {
      msyslog(LOG_ERR, "NeoClock4X(%d): control: unit invalid/inactive", unit);
      return;
    }

  pp = peer->procptr;
  if(NULL == pp)
    {
      msyslog(LOG_ERR, "NeoClock4X(%d): control: unit invalid/inactive", unit);
      return;
    }

  up = pp->unitptr;
  if(NULL == up)
    {
      msyslog(LOG_ERR, "NeoClock4X(%d): control: unit invalid/inactive", unit);
      return;
    }

  if(NULL != in)
    {
      /* check to see if a user supplied time offset is given */
      if(in->haveflags & CLK_HAVETIME1)
	{
	  pp->fudgetime1 = in->fudgetime1;
	  NLOG(NLOG_CLOCKINFO)
	    msyslog(LOG_NOTICE, "NeoClock4X(%d): using fudgetime1 with %0.5fs from ntp.conf.",
		    unit, pp->fudgetime1);
	}

      /* notify */
      if(pp->sloppyclockflag & CLK_FLAG1)
	{
	  NLOG(NLOG_CLOCKINFO)
	    msyslog(LOG_NOTICE, "NeoClock4X(%d): quartz clock is used to synchronize time if radio clock has no reception.", unit);
	}
      else
	{
	  NLOG(NLOG_CLOCKINFO)
	    msyslog(LOG_NOTICE, "NeoClock4X(%d): time is only adjusted with radio signal reception.", unit);
	}
    }

  if(NULL != out)
    {
      char *tt;
      char tmpbuf[80];

      out->kv_list = (struct ctl_var *)0;
      out->type    = REFCLK_NEOCLOCK4X;

      snprintf(tmpbuf, sizeof(tmpbuf)-1,
	       "%04d-%02d-%02d %02d:%02d:%02d.%03d",
	       up->utc_year, up->utc_month, up->utc_day,
	       up->utc_hour, up->utc_minute, up->utc_second,
	       up->utc_msec);
      tt = add_var(&out->kv_list, sizeof(tmpbuf)-1, RO|DEF);
      snprintf(tt, sizeof(tmpbuf)-1, "calc_utc=\"%s\"", tmpbuf);

      tt = add_var(&out->kv_list, 40, RO|DEF);
      snprintf(tt, 39, "radiosignal=\"%s\"", up->radiosignal);
      tt = add_var(&out->kv_list, 40, RO|DEF);
      snprintf(tt, 39, "antenna1=\"%d\"", up->antenna1);
      tt = add_var(&out->kv_list, 40, RO|DEF);
      snprintf(tt, 39, "antenna2=\"%d\"", up->antenna2);
      tt = add_var(&out->kv_list, 40, RO|DEF);
      if('A' == up->timesource)
	snprintf(tt, 39, "timesource=\"radio\"");
      else if('C' == up->timesource)
	snprintf(tt, 39, "timesource=\"quartz\"");
      else
	snprintf(tt, 39, "timesource=\"unknown\"");
      tt = add_var(&out->kv_list, 40, RO|DEF);
      if('I' == up->quarzstatus)
	snprintf(tt, 39, "quartzstatus=\"synchronized\"");
      else if('X' == up->quarzstatus)
        snprintf(tt, 39, "quartzstatus=\"not synchronized\"");
      else
	snprintf(tt, 39, "quartzstatus=\"unknown\"");
      tt = add_var(&out->kv_list, 40, RO|DEF);
      if('S' == up->dststatus)
        snprintf(tt, 39, "dststatus=\"summer\"");
      else if('W' == up->dststatus)
        snprintf(tt, 39, "dststatus=\"winter\"");
      else
        snprintf(tt, 39, "dststatus=\"unknown\"");
      tt = add_var(&out->kv_list, 80, RO|DEF);
      snprintf(tt, 79, "firmware=\"%s\"", up->firmware);
      tt = add_var(&out->kv_list, 40, RO|DEF);
      snprintf(tt, 39, "firmwaretag=\"%c\"", up->firmwaretag);
      tt = add_var(&out->kv_list, 80, RO|DEF);
      snprintf(tt, 79, "driver version=\"%s\"", NEOCLOCK4X_DRIVER_VERSION);
      tt = add_var(&out->kv_list, 80, RO|DEF);
      snprintf(tt, 79, "serialnumber=\"%s\"", up->serial);
    }
}
Пример #24
0
Файл: main.c Проект: happyj/qcn
/*
 * The actual main function.
 */
int
sntp_main (
    int argc,
    char **argv
)
{
    register int c;
    struct kod_entry *reason = NULL;
    int optct;
    /* boolean, u_int quiets gcc4 signed overflow warning */
    u_int sync_data_suc;
    struct addrinfo **bcastaddr = NULL;
    struct addrinfo **resh = NULL;
    struct addrinfo *ai;
    int resc;
    int kodc;
    int ow_ret;
    int bcast = 0;
    char *hostname;

    optct = optionProcess(&sntpOptions, argc, argv);
    argc -= optct;
    argv += optct;

    /* Initialize logging system */
    init_logging();
    if (HAVE_OPT(LOGFILE))
        open_logfile(OPT_ARG(LOGFILE));

    msyslog(LOG_NOTICE, "Started sntp");

    /* IPv6 available? */
    if (isc_net_probeipv6() != ISC_R_SUCCESS) {
        ai_fam_pref = AF_INET;
#ifdef DEBUG
        printf("No ipv6 support available, forcing ipv4\n");
#endif
    } else {
        /* Check for options -4 and -6 */
        if (HAVE_OPT(IPV4))
            ai_fam_pref = AF_INET;
        else if (HAVE_OPT(IPV6))
            ai_fam_pref = AF_INET6;
    }

    /* Parse config file if declared TODO */

    /*
     * If there's a specified KOD file init KOD system.  If not use
     * default file.  For embedded systems with no writable
     * filesystem, -K /dev/null can be used to disable KoD storage.
     */
    if (HAVE_OPT(KOD))
        kod_init_kod_db(OPT_ARG(KOD));
    else
        kod_init_kod_db("/var/db/ntp-kod");

    if (HAVE_OPT(KEYFILE))
        auth_init(OPT_ARG(KEYFILE), &keys);

#ifdef EXERCISE_KOD_DB
    add_entry("192.168.169.170", "DENY");
    add_entry("192.168.169.171", "DENY");
    add_entry("192.168.169.172", "DENY");
    add_entry("192.168.169.173", "DENY");
    add_entry("192.168.169.174", "DENY");
    delete_entry("192.168.169.174", "DENY");
    delete_entry("192.168.169.172", "DENY");
    delete_entry("192.168.169.170", "DENY");
    if ((kodc = search_entry("192.168.169.173", &reason)) == 0)
        printf("entry for 192.168.169.173 not found but should have been!\n");
    else
        free(reason);
#endif

    /* Considering employing a variable that prevents functions of doing anything until
     * everything is initialized properly
     */
    resc = resolve_hosts((const char **)argv, argc, &resh, ai_fam_pref);
    if (resc < 1) {
        printf("Unable to resolve hostname(s)\n");
        return -1;
    }
    bcast = ENABLED_OPT(BROADCAST);
    if (bcast) {
        const char * myargv[2];

        myargv[0] = OPT_ARG(BROADCAST);
        myargv[1] = NULL;
        bcast = resolve_hosts(myargv, 1, &bcastaddr, ai_fam_pref);
    }

    /* Select a certain ntp server according to simple criteria? For now
     * let's just pay attention to previous KoDs.
     */
    sync_data_suc = FALSE;
    for (c = 0; c < resc && !sync_data_suc; c++) {
        ai = resh[c];
        do {
            hostname = addrinfo_to_str(ai);
            if ((kodc = search_entry(hostname, &reason)) == 0) {
                if (is_reachable(ai)) {
                    ow_ret = on_wire(ai, bcast ? bcastaddr[0] : NULL);
                    if (0 == ow_ret)
                        sync_data_suc = TRUE;
                }
            } else {
                printf("%d prior KoD%s for %s, skipping.\n",
                       kodc, (kodc > 1) ? "s" : "", hostname);
                free(reason);
            }
            free(hostname);
            ai = ai->ai_next;
        } while (NULL != ai);
        freeaddrinfo(resh[c]);
    }
    free(resh);

    if (!sync_data_suc)
        return 1;
    return 0;
}
Пример #25
0
/*
 * getCmdOpts - get command line options
 */
void
getCmdOpts(
	int argc,
	char *argv[]
	)
{
	extern const char *config_file;
	int errflg;
	tOptions *myOptions = &ntpdOptions;

	/*
	 * Initialize, initialize
	 */
	errflg = 0;

	if (HAVE_OPT( IPV4 ))
		default_ai_family = AF_INET;
	else if (HAVE_OPT( IPV6 ))
		default_ai_family = AF_INET6;

	if (HAVE_OPT( AUTHREQ ))
		proto_config(PROTO_AUTHENTICATE, 1, 0., NULL);
	else if (HAVE_OPT( AUTHNOREQ ))
		proto_config(PROTO_AUTHENTICATE, 0, 0., NULL);

	if (HAVE_OPT( BCASTSYNC ))
		proto_config(PROTO_BROADCLIENT, 1, 0., NULL);

	if (HAVE_OPT( CONFIGFILE )) {
		config_file = OPT_ARG( CONFIGFILE );
#ifdef HAVE_NETINFO
		check_netinfo = 0;
#endif
	}

	if (HAVE_OPT( DRIFTFILE ))
		stats_config(STATS_FREQ_FILE, OPT_ARG( DRIFTFILE ));

	if (HAVE_OPT( PANICGATE ))
		allow_panic = TRUE;

#ifdef HAVE_DROPROOT
	if (HAVE_OPT( JAILDIR )) {
		droproot = 1;
		chrootdir = OPT_ARG( JAILDIR );
	}
#endif

	if (HAVE_OPT( KEYFILE ))
		getauthkeys(OPT_ARG( KEYFILE ));

	if (HAVE_OPT( PIDFILE ))
		stats_config(STATS_PID_FILE, OPT_ARG( PIDFILE ));

	if (HAVE_OPT( QUIT ))
		mode_ntpdate = TRUE;

	if (HAVE_OPT( PROPAGATIONDELAY ))
		do {
			double tmp;
			const char *my_ntp_optarg = OPT_ARG( PROPAGATIONDELAY );

			if (sscanf(my_ntp_optarg, "%lf", &tmp) != 1) {
				msyslog(LOG_ERR,
					"command line broadcast delay value %s undecodable",
					my_ntp_optarg);
			} else {
				proto_config(PROTO_BROADDELAY, 0, tmp, NULL);
			}
		} while (0);

	if (HAVE_OPT( STATSDIR ))
		stats_config(STATS_STATSDIR, OPT_ARG( STATSDIR ));

	if (HAVE_OPT( TRUSTEDKEY )) {
		int		ct = STACKCT_OPT(  TRUSTEDKEY );
		const char**	pp = STACKLST_OPT( TRUSTEDKEY );

		do  {
			u_long tkey;
			const char* p = *pp++;

			tkey = (int)atol(p);
			if (tkey == 0 || tkey > NTP_MAXKEY) {
				msyslog(LOG_ERR,
				    "command line trusted key %s is invalid",
				    p);
			} else {
				authtrust(tkey, 1);
			}
		} while (--ct > 0);
	}

#ifdef HAVE_DROPROOT
	if (HAVE_OPT( USER )) {
		droproot = 1;
		user = estrdup(OPT_ARG( USER ));
		group = rindex(user, ':');
		if (group)
			*group++ = '\0'; /* get rid of the ':' */
	}
#endif

	if (HAVE_OPT( VAR )) {
		int		ct = STACKCT_OPT(  VAR );
		const char**	pp = STACKLST_OPT( VAR );

		do  {
			const char* my_ntp_optarg = *pp++;

			set_sys_var(my_ntp_optarg, strlen(my_ntp_optarg)+1,
			    (u_short) (RW));
		} while (--ct > 0);
	}

	if (HAVE_OPT( DVAR )) {
		int		ct = STACKCT_OPT(  DVAR );
		const char**	pp = STACKLST_OPT( DVAR );

		do  {
			const char* my_ntp_optarg = *pp++;

			set_sys_var(my_ntp_optarg, strlen(my_ntp_optarg)+1,
			    (u_short) (RW | DEF));
		} while (--ct > 0);
	}

	if (HAVE_OPT( SLEW )) {
		clock_max = 600;
		kern_enable = 0;
	}
	if (HAVE_OPT( UPDATEINTERVAL )) {
		long val = OPT_VALUE_UPDATEINTERVAL;
			  
		if (val >= 0)
			interface_interval = val;
		else {
			fprintf(stderr, 
				"command line interface update interval %ld must not be negative\n",
				val);
			msyslog(LOG_ERR, 
				"command line interface update interval %ld must not be negative",
				val);
			errflg++;
		}
	}
#ifdef SIM

	/* SK:
	 * The simulator no longer takes any command line arguments. Hence,
	 * all the code that was here has been removed.
	 */

#endif /* SIM */

	if (errflg || argc) {
		if (argc)
			fprintf(stderr, "argc after processing is <%d>\n", argc);
		optionUsage(myOptions, 2);
	}
	return;
}
Пример #26
0
Файл: main.c Проект: happyj/qcn
/* The heart of (S)NTP, exchange NTP packets and compute values to correct the local clock */
int
on_wire (
    struct addrinfo *host,
    struct addrinfo *bcast
)
{
    char addr_buf[INET6_ADDRSTRLEN];
    register int try;
    SOCKET sock;
    struct key *pkt_key = NULL;
    int key_id = 0;
    struct timeval tv_xmt;
    struct pkt x_pkt;
    int error, rpktl, handle_pkt_res;


    if (ENABLED_OPT(AUTHENTICATION)) {
        key_id = (int) OPT_ARG(AUTHENTICATION);
        get_key(key_id, &pkt_key);
    }
    for (try=0; try<5; try++) {
                    memset(&r_pkt, 0, sizeof rbuf);

                    error = GETTIMEOFDAY(&tv_xmt, (struct timezone *)NULL);
                    tv_xmt.tv_sec += JAN_1970;

#ifdef DEBUG
                    printf("sntp on_wire: Current time sec: %i msec: %i\n", (unsigned int) tv_xmt.tv_sec,
                           (unsigned int) tv_xmt.tv_usec);
#endif

                    if (bcast) {
                        create_socket(&sock, (sockaddr_u *)bcast->ai_addr);
                        rpktl = recv_bcst_pkt(sock, &r_pkt, sizeof rbuf, (sockaddr_u *)bcast->ai_addr);
                        closesocket(sock);
                    } else {
                        int pkt_len = generate_pkt(&x_pkt, &tv_xmt, key_id, pkt_key);

                        create_socket(&sock, (sockaddr_u *)host->ai_addr);
                        sendpkt(sock, (sockaddr_u *)host->ai_addr, &x_pkt, pkt_len);
                        rpktl = recvpkt(sock, &r_pkt, sizeof rbuf, &x_pkt);
                        closesocket(sock);
                    }

                    handle_pkt_res = handle_pkt(rpktl, &r_pkt, host);
                    if (handle_pkt_res < 1)
                        return handle_pkt_res;
                }

    getnameinfo(host->ai_addr, host->ai_addrlen, addr_buf, sizeof(addr_buf), NULL, 0, NI_NUMERICHOST);
    msyslog(LOG_DEBUG, "Received no useable packet from %s!", addr_buf);

    return -1;
}

/* Compute the 8 bits for li_vn_mode */
void
set_li_vn_mode (
    struct pkt *spkt,
    char leap,
    char version,
    char mode
)
{
    if (leap > 3) {
        msyslog(LOG_DEBUG, "set_li_vn_mode: leap > 3 using max. 3");
        leap = 3;
    }

    if (mode > 7) {
        msyslog(LOG_DEBUG, "set_li_vn_mode: mode > 7, using client mode 3");
        mode = 3;
    }

    spkt->li_vn_mode  = leap << 6;
    spkt->li_vn_mode |= version << 3;
    spkt->li_vn_mode |= mode;
}

/* set_time corrects the local clock by offset with either settimeofday() or by default
 * with adjtime()/adjusttimeofday().
 */
int
set_time(
    double offset
)
{
    struct timeval tp;

    if (ENABLED_OPT(SETTOD)) {
        GETTIMEOFDAY(&tp, NULL);

        tp.tv_sec += (long)offset;
        tp.tv_usec += 1e6 * (offset - (long)offset);
        NORMALIZE_TIMEVAL(tp);

        if (SETTIMEOFDAY(&tp, NULL) < 0) {
            msyslog(LOG_ERR, "Time not set: settimeofday(): %m");
            return -1;
        }
        return 0;
    }

    tp.tv_sec = (long)offset;
    tp.tv_usec = 1e6 * (offset - (long)offset);
    NORMALIZE_TIMEVAL(tp);

    if (ADJTIMEOFDAY(&tp, NULL) < 0) {
        msyslog(LOG_ERR, "Time not set: adjtime(): %m");
        return -1;
    }
    return 0;
}
Пример #27
0
/*
 * Main program.  Initialize us, disconnect us from the tty if necessary,
 * and loop waiting for I/O and/or timer expiries.
 */
int
ntpdmain(
	int argc,
	char *argv[]
	)
{
	l_fp now;
	struct recvbuf *rbuf;
#ifdef _AIX			/* HMS: ifdef SIGDANGER? */
	struct sigaction sa;
#endif

	progname = argv[0];
	initializing = 1;		/* mark that we are initializing */
	process_commandline_opts(&argc, &argv);
	init_logging(progname, 1);	/* Open the log file */

	char *error = NULL;
	if (sandbox_init("ntpd", SANDBOX_NAMED, &error) == -1) {
		msyslog(LOG_ERR, "sandbox_init(ntpd, SANDBOX_NAMED) failed: %s", error);
		sandbox_free_error(error);
	}
#ifdef HAVE_UMASK
	{
		mode_t uv;

		uv = umask(0);
		if(uv)
			(void) umask(uv);
		else
			(void) umask(022);
	}
#endif

#if defined(HAVE_GETUID) && !defined(MPE) /* MPE lacks the concept of root */
	{
		uid_t uid;

		uid = getuid();
		if (uid && !HAVE_OPT( SAVECONFIGQUIT )) {
			msyslog(LOG_ERR, "ntpd: must be run as root, not uid %ld", (long)uid);
			printf("must be run as root, not uid %ld\n", (long)uid);
			exit(1);
		}
	}
#endif

	/* getstartup(argc, argv); / * startup configuration, may set debug */

#ifdef DEBUG
	debug = DESC(DEBUG_LEVEL).optOccCt;
	DPRINTF(1, ("%s\n", Version));
#endif

	/* honor -l/--logfile option to log to a file */
	setup_logfile();

/*
 * Enable the Multi-Media Timer for Windows?
 */
#ifdef SYS_WINNT
	if (HAVE_OPT( MODIFYMMTIMER ))
		set_mm_timer(MM_TIMER_HIRES);
#endif

	if (HAVE_OPT( NOFORK ) || HAVE_OPT( QUIT )
#ifdef DEBUG
	    || debug
#endif
	    || HAVE_OPT( SAVECONFIGQUIT ))
		nofork = 1;

	if (HAVE_OPT( NOVIRTUALIPS ))
		listen_to_virtual_ips = 0;

	/*
	 * --interface, listen on specified interfaces
	 */
	if (HAVE_OPT( INTERFACE )) {
		int	ifacect = STACKCT_OPT( INTERFACE );
		const char**	ifaces  = STACKLST_OPT( INTERFACE );
		isc_netaddr_t	netaddr;

		while (ifacect-- > 0) {
			add_nic_rule(
				is_ip_address(*ifaces, &netaddr)
					? MATCH_IFADDR
					: MATCH_IFNAME,
				*ifaces, -1, ACTION_LISTEN);
			ifaces++;
		}
	}

	if (HAVE_OPT( NICE ))
		priority_done = 0;

#if defined(HAVE_SCHED_SETSCHEDULER)
	if (HAVE_OPT( PRIORITY )) {
		config_priority = OPT_VALUE_PRIORITY;
		config_priority_override = 1;
		priority_done = 0;
	}
#endif

#ifdef SYS_WINNT
	/*
	 * Start interpolation thread, must occur before first
	 * get_systime()
	 */
	init_winnt_time();
#endif
	/*
	 * Initialize random generator and public key pair
	 */
	get_systime(&now);

	ntp_srandom((int)(now.l_i * now.l_uf));

#if !defined(VMS)
# ifndef NODETACH
	/*
	 * Detach us from the terminal.  May need an #ifndef GIZMO.
	 */
	if (!nofork) {

		/*
		 * Install trap handlers to log errors and assertion
		 * failures.  Default handlers print to stderr which 
		 * doesn't work if detached.
		 */
		isc_assertion_setcallback(assertion_failed);
		isc_error_setfatal(library_fatal_error);
		isc_error_setunexpected(library_unexpected_error);

#  ifndef SYS_WINNT
#   ifdef HAVE_DAEMON
		daemon(0, 0);
#   else /* not HAVE_DAEMON */
		if (fork())	/* HMS: What about a -1? */
			exit(0);

		{
#if !defined(F_CLOSEM)
			u_long s;
			int max_fd;
#endif /* !FCLOSEM */
			if (syslog_file != NULL) {
				fclose(syslog_file);
				syslog_file = NULL;
			}
#if defined(F_CLOSEM)
			/*
			 * From 'Writing Reliable AIX Daemons,' SG24-4946-00,
			 * by Eric Agar (saves us from doing 32767 system
			 * calls)
			 */
			if (fcntl(0, F_CLOSEM, 0) == -1)
			    msyslog(LOG_ERR, "ntpd: failed to close open files(): %m");
#else  /* not F_CLOSEM */

# if defined(HAVE_SYSCONF) && defined(_SC_OPEN_MAX)
			max_fd = sysconf(_SC_OPEN_MAX);
# else /* HAVE_SYSCONF && _SC_OPEN_MAX */
			max_fd = getdtablesize();
# endif /* HAVE_SYSCONF && _SC_OPEN_MAX */
			for (s = 0; s < max_fd; s++)
				(void) close((int)s);
#endif /* not F_CLOSEM */
			(void) open("/", 0);
			(void) dup2(0, 1);
			(void) dup2(0, 2);

			init_logging(progname, 0);
			/* we lost our logfile (if any) daemonizing */
			setup_logfile();

#ifdef SYS_DOMAINOS
			{
				uid_$t puid;
				status_$t st;

				proc2_$who_am_i(&puid);
				proc2_$make_server(&puid, &st);
			}
#endif /* SYS_DOMAINOS */
#if defined(HAVE_SETPGID) || defined(HAVE_SETSID)
# ifdef HAVE_SETSID
			if (setsid() == (pid_t)-1)
				msyslog(LOG_ERR, "ntpd: setsid(): %m");
# else
			if (setpgid(0, 0) == -1)
				msyslog(LOG_ERR, "ntpd: setpgid(): %m");
# endif
#else /* HAVE_SETPGID || HAVE_SETSID */
			{
# if defined(TIOCNOTTY)
				int fid;

				fid = open("/dev/tty", 2);
				if (fid >= 0)
				{
					(void) ioctl(fid, (u_long) TIOCNOTTY, (char *) 0);
					(void) close(fid);
				}
# endif /* defined(TIOCNOTTY) */
# ifdef HAVE_SETPGRP_0
				(void) setpgrp();
# else /* HAVE_SETPGRP_0 */
				(void) setpgrp(0, getpid());
# endif /* HAVE_SETPGRP_0 */
			}
#endif /* HAVE_SETPGID || HAVE_SETSID */
#ifdef _AIX
			/* Don't get killed by low-on-memory signal. */
			sa.sa_handler = catch_danger;
			sigemptyset(&sa.sa_mask);
			sa.sa_flags = SA_RESTART;

			(void) sigaction(SIGDANGER, &sa, NULL);
#endif /* _AIX */
		}
#   endif /* not HAVE_DAEMON */
#  endif /* SYS_WINNT */
	}
# endif /* NODETACH */
#endif /* VMS */

#ifdef SCO5_CLOCK
	/*
	 * SCO OpenServer's system clock offers much more precise timekeeping
	 * on the base CPU than the other CPUs (for multiprocessor systems),
	 * so we must lock to the base CPU.
	 */
	{
	    int fd = open("/dev/at1", O_RDONLY);
	    if (fd >= 0) {
		int zero = 0;
		if (ioctl(fd, ACPU_LOCK, &zero) < 0)
		    msyslog(LOG_ERR, "cannot lock to base CPU: %m");
		close( fd );
	    } /* else ...
	       *   If we can't open the device, this probably just isn't
	       *   a multiprocessor system, so we're A-OK.
	       */
	}
#endif

#if defined(HAVE_MLOCKALL) && defined(MCL_CURRENT) && defined(MCL_FUTURE)
# ifdef HAVE_SETRLIMIT
	/*
	 * Set the stack limit to something smaller, so that we don't lock a lot
	 * of unused stack memory.
	 */
	{
	    struct rlimit rl;

	    /* HMS: must make the rlim_cur amount configurable */
	    if (getrlimit(RLIMIT_STACK, &rl) != -1
		&& (rl.rlim_cur = 50 * 4096) < rl.rlim_max)
	    {
		    if (setrlimit(RLIMIT_STACK, &rl) == -1)
		    {
			    msyslog(LOG_ERR,
				"Cannot adjust stack limit for mlockall: %m");
		    }
	    }
#  ifdef RLIMIT_MEMLOCK
	    /*
	     * The default RLIMIT_MEMLOCK is very low on Linux systems.
	     * Unless we increase this limit malloc calls are likely to
	     * fail if we drop root privlege.  To be useful the value
	     * has to be larger than the largest ntpd resident set size.
	     */
	    rl.rlim_cur = rl.rlim_max = 32*1024*1024;
	    if (setrlimit(RLIMIT_MEMLOCK, &rl) == -1) {
		msyslog(LOG_ERR, "Cannot set RLIMIT_MEMLOCK: %m");
	    }
#  endif /* RLIMIT_MEMLOCK */
	}
# endif /* HAVE_SETRLIMIT */
	/*
	 * lock the process into memory
	 */
	if (mlockall(MCL_CURRENT|MCL_FUTURE) < 0)
		msyslog(LOG_ERR, "mlockall(): %m");
#else /* not (HAVE_MLOCKALL && MCL_CURRENT && MCL_FUTURE) */
# ifdef HAVE_PLOCK
#  ifdef PROCLOCK
#   ifdef _AIX
	/*
	 * set the stack limit for AIX for plock().
	 * see get_aix_stack() for more info.
	 */
	if (ulimit(SET_STACKLIM, (get_aix_stack() - 8*4096)) < 0)
	{
		msyslog(LOG_ERR,"Cannot adjust stack limit for plock on AIX: %m");
	}
#   endif /* _AIX */
	/*
	 * lock the process into memory
	 */
	if (plock(PROCLOCK) < 0)
		msyslog(LOG_ERR, "plock(PROCLOCK): %m");
#  else /* not PROCLOCK */
#   ifdef TXTLOCK
	/*
	 * Lock text into ram
	 */
	if (plock(TXTLOCK) < 0)
		msyslog(LOG_ERR, "plock(TXTLOCK) error: %m");
#   else /* not TXTLOCK */
	msyslog(LOG_ERR, "plock() - don't know what to lock!");
#   endif /* not TXTLOCK */
#  endif /* not PROCLOCK */
# endif /* HAVE_PLOCK */
#endif /* not (HAVE_MLOCKALL && MCL_CURRENT && MCL_FUTURE) */

	/*
	 * Set up signals we pay attention to locally.
	 */
#ifdef SIGDIE1
	(void) signal_no_reset(SIGDIE1, finish);
#endif	/* SIGDIE1 */
#ifdef SIGDIE2
	(void) signal_no_reset(SIGDIE2, finish);
#endif	/* SIGDIE2 */
#ifdef SIGDIE3
	(void) signal_no_reset(SIGDIE3, finish);
#endif	/* SIGDIE3 */
#ifdef SIGDIE4
	(void) signal_no_reset(SIGDIE4, finish);
#endif	/* SIGDIE4 */

#ifdef SIGBUS
	(void) signal_no_reset(SIGBUS, finish);
#endif /* SIGBUS */

#if !defined(SYS_WINNT) && !defined(VMS)
# ifdef DEBUG
	(void) signal_no_reset(MOREDEBUGSIG, moredebug);
	(void) signal_no_reset(LESSDEBUGSIG, lessdebug);
# else
	(void) signal_no_reset(MOREDEBUGSIG, no_debug);
	(void) signal_no_reset(LESSDEBUGSIG, no_debug);
# endif /* DEBUG */
#endif /* !SYS_WINNT && !VMS */

	/*
	 * Set up signals we should never pay attention to.
	 */
#if defined SIGPIPE
	(void) signal_no_reset(SIGPIPE, SIG_IGN);
#endif	/* SIGPIPE */

	/*
	 * Call the init_ routines to initialize the data structures.
	 *
	 * Exactly what command-line options are we expecting here?
	 */
	init_auth();
	init_util();
	init_restrict();
	init_mon();
	init_timer();
	init_lib();
	init_request();
	init_control();
	init_peer();
#ifdef REFCLOCK
	init_refclock();
#endif
	set_process_priority();
	init_proto();		/* Call at high priority */
	init_io();
	init_loopfilter();
	mon_start(MON_ON);	/* monitor on by default now	  */
				/* turn off in config if unwanted */

	/*
	 * Get the configuration.  This is done in a separate module
	 * since this will definitely be different for the gizmo board.
	 */
	getconfig(argc, argv);
	NLOG(NLOG_SYSINFO) /* 'if' clause for syslog */
	msyslog(LOG_NOTICE, "%s", Version);
	report_event(EVNT_SYSRESTART, NULL, NULL);
	loop_config(LOOP_DRIFTCOMP, old_drift);
	initializing = 0;

#ifdef HAVE_DROPROOT
	if( droproot ) {
		/* Drop super-user privileges and chroot now if the OS supports this */

#ifdef HAVE_LINUX_CAPABILITIES
		/* set flag: keep privileges accross setuid() call (we only really need cap_sys_time): */
		if (prctl( PR_SET_KEEPCAPS, 1L, 0L, 0L, 0L ) == -1) {
			msyslog( LOG_ERR, "prctl( PR_SET_KEEPCAPS, 1L ) failed: %m" );
			exit(-1);
		}
#else
		/* we need a user to switch to */
		if (user == NULL) {
			msyslog(LOG_ERR, "Need user name to drop root privileges (see -u flag!)" );
			exit(-1);
		}
#endif /* HAVE_LINUX_CAPABILITIES */

		if (user != NULL) {
			if (isdigit((unsigned char)*user)) {
				sw_uid = (uid_t)strtoul(user, &endp, 0);
				if (*endp != '\0')
					goto getuser;

				if ((pw = getpwuid(sw_uid)) != NULL) {
					user = strdup(pw->pw_name);
					if (NULL == user) {
						msyslog(LOG_ERR, "strdup() failed: %m");
						exit (-1);
					}
					sw_gid = pw->pw_gid;
				} else {
					errno = 0;
					msyslog(LOG_ERR, "Cannot find user ID %s", user);
					exit (-1);
				}

			} else {
getuser:
				errno = 0;
				if ((pw = getpwnam(user)) != NULL) {
					sw_uid = pw->pw_uid;
					sw_gid = pw->pw_gid;
				} else {
					if (errno)
					    msyslog(LOG_ERR, "getpwnam(%s) failed: %m", user);
					else
					    msyslog(LOG_ERR, "Cannot find user `%s'", user);
					exit (-1);
				}
			}
		}
		if (group != NULL) {
			if (isdigit((unsigned char)*group)) {
				sw_gid = (gid_t)strtoul(group, &endp, 0);
				if (*endp != '\0')
					goto getgroup;
			} else {
getgroup:
				if ((gr = getgrnam(group)) != NULL) {
					sw_gid = gr->gr_gid;
				} else {
					errno = 0;
					msyslog(LOG_ERR, "Cannot find group `%s'", group);
					exit (-1);
				}
			}
		}

		if (chrootdir ) {
			/* make sure cwd is inside the jail: */
			if (chdir(chrootdir)) {
				msyslog(LOG_ERR, "Cannot chdir() to `%s': %m", chrootdir);
				exit (-1);
			}
			if (chroot(chrootdir)) {
				msyslog(LOG_ERR, "Cannot chroot() to `%s': %m", chrootdir);
				exit (-1);
			}
			if (chdir("/")) {
				msyslog(LOG_ERR, "Cannot chdir() to`root after chroot(): %m");
				exit (-1);
			}
		}
		if (user && initgroups(user, sw_gid)) {
			msyslog(LOG_ERR, "Cannot initgroups() to user `%s': %m", user);
			exit (-1);
		}
		if (group && setgid(sw_gid)) {
			msyslog(LOG_ERR, "Cannot setgid() to group `%s': %m", group);
			exit (-1);
		}
		if (group && setegid(sw_gid)) {
			msyslog(LOG_ERR, "Cannot setegid() to group `%s': %m", group);
			exit (-1);
		}
		if (user && setuid(sw_uid)) {
			msyslog(LOG_ERR, "Cannot setuid() to user `%s': %m", user);
			exit (-1);
		}
		if (user && seteuid(sw_uid)) {
			msyslog(LOG_ERR, "Cannot seteuid() to user `%s': %m", user);
			exit (-1);
		}

#ifndef HAVE_LINUX_CAPABILITIES
		/*
		 * for now assume that the privilege to bind to privileged ports
		 * is associated with running with uid 0 - should be refined on
		 * ports that allow binding to NTP_PORT with uid != 0
		 */
		disable_dynamic_updates |= (sw_uid != 0);  /* also notifies routing message listener */
#endif

		if (disable_dynamic_updates && interface_interval) {
			interface_interval = 0;
			msyslog(LOG_INFO, "running in unprivileged mode disables dynamic interface tracking");
		}

#ifdef HAVE_LINUX_CAPABILITIES
		do {
			/*
			 *  We may be running under non-root uid now, but we still hold full root privileges!
			 *  We drop all of them, except for the crucial one or two: cap_sys_time and
			 *  cap_net_bind_service if doing dynamic interface tracking.
			 */
			cap_t caps;
			char *captext = (interface_interval)
				? "cap_sys_time,cap_net_bind_service=ipe"
				: "cap_sys_time=ipe";
			if( ! ( caps = cap_from_text( captext ) ) ) {
				msyslog( LOG_ERR, "cap_from_text() failed: %m" );
				exit(-1);
			}
			if( cap_set_proc( caps ) == -1 ) {
				msyslog( LOG_ERR, "cap_set_proc() failed to drop root privileges: %m" );
				exit(-1);
			}
			cap_free( caps );
		} while(0);
#endif /* HAVE_LINUX_CAPABILITIES */

	}    /* if( droproot ) */
#endif /* HAVE_DROPROOT */

	/*
	 * Use select() on all on all input fd's for unlimited
	 * time.  select() will terminate on SIGALARM or on the
	 * reception of input.	Using select() means we can't do
	 * robust signal handling and we get a potential race
	 * between checking for alarms and doing the select().
	 * Mostly harmless, I think.
	 */
	/* On VMS, I suspect that select() can't be interrupted
	 * by a "signal" either, so I take the easy way out and
	 * have select() time out after one second.
	 * System clock updates really aren't time-critical,
	 * and - lacking a hardware reference clock - I have
	 * yet to learn about anything else that is.
	 */
#if defined(HAVE_IO_COMPLETION_PORT)

	for (;;) {
		GetReceivedBuffers();
#else /* normal I/O */

	BLOCK_IO_AND_ALARM();
	was_alarmed = 0;
	for (;;)
	{
# if !defined(HAVE_SIGNALED_IO)
		extern fd_set activefds;
		extern int maxactivefd;

		fd_set rdfdes;
		int nfound;
# endif

		if (alarm_flag)		/* alarmed? */
		{
			was_alarmed = 1;
			alarm_flag = 0;
		}

		if (!was_alarmed && has_full_recv_buffer() == ISC_FALSE)
		{
			/*
			 * Nothing to do.  Wait for something.
			 */
# ifndef HAVE_SIGNALED_IO
			rdfdes = activefds;
#  if defined(VMS) || defined(SYS_VXWORKS)
			/* make select() wake up after one second */
			{
				struct timeval t1;

				t1.tv_sec = 1; t1.tv_usec = 0;
				nfound = select(maxactivefd+1, &rdfdes, (fd_set *)0,
						(fd_set *)0, &t1);
			}
#  else
			nfound = select(maxactivefd+1, &rdfdes, (fd_set *)0,
					(fd_set *)0, (struct timeval *)0);
#  endif /* VMS */
			if (nfound > 0)
			{
				l_fp ts;

				get_systime(&ts);

				(void)input_handler(&ts);
			}
			else if (nfound == -1 && errno != EINTR)
				msyslog(LOG_ERR, "select() error: %m");
#  ifdef DEBUG
			else if (debug > 5)
				msyslog(LOG_DEBUG, "select(): nfound=%d, error: %m", nfound);
#  endif /* DEBUG */
# else /* HAVE_SIGNALED_IO */

			wait_for_signal();
# endif /* HAVE_SIGNALED_IO */
			if (alarm_flag)		/* alarmed? */
			{
				was_alarmed = 1;
				alarm_flag = 0;
			}
		}

		if (was_alarmed)
		{
			UNBLOCK_IO_AND_ALARM();
			/*
			 * Out here, signals are unblocked.  Call timer routine
			 * to process expiry.
			 */
			timer();
			was_alarmed = 0;
			BLOCK_IO_AND_ALARM();
		}

#endif /* ! HAVE_IO_COMPLETION_PORT */

#ifdef DEBUG_TIMING
		{
			l_fp pts;
			l_fp tsa, tsb;
			int bufcount = 0;

			get_systime(&pts);
			tsa = pts;
#endif
			rbuf = get_full_recv_buffer();
			while (rbuf != NULL)
			{
				if (alarm_flag)
				{
					was_alarmed = 1;
					alarm_flag = 0;
				}
				UNBLOCK_IO_AND_ALARM();

				if (was_alarmed)
				{	/* avoid timer starvation during lengthy I/O handling */
					timer();
					was_alarmed = 0;
				}

				/*
				 * Call the data procedure to handle each received
				 * packet.
				 */
				if (rbuf->receiver != NULL)	/* This should always be true */
				{
#ifdef DEBUG_TIMING
					l_fp dts = pts;

					L_SUB(&dts, &rbuf->recv_time);
					DPRINTF(2, ("processing timestamp delta %s (with prec. fuzz)\n", lfptoa(&dts, 9)));
					collect_timing(rbuf, "buffer processing delay", 1, &dts);
					bufcount++;
#endif
					(rbuf->receiver)(rbuf);
				} else {
					msyslog(LOG_ERR, "receive buffer corruption - receiver found to be NULL - ABORTING");
					abort();
				}

				BLOCK_IO_AND_ALARM();
				freerecvbuf(rbuf);
				rbuf = get_full_recv_buffer();
			}
#ifdef DEBUG_TIMING
			get_systime(&tsb);
			L_SUB(&tsb, &tsa);
			if (bufcount) {
				collect_timing(NULL, "processing", bufcount, &tsb);
				DPRINTF(2, ("processing time for %d buffers %s\n", bufcount, lfptoa(&tsb, 9)));
			}
		}
#endif

		/*
		 * Go around again
		 */

#ifdef HAVE_DNSREGISTRATION
		if (mdnsreg && (current_time - mdnsreg ) > 60 && mdnstries && sys_leap != LEAP_NOTINSYNC) {
			mdnsreg = current_time;
			msyslog(LOG_INFO, "Attemping to register mDNS");
			if ( DNSServiceRegister (&mdns, 0, 0, NULL, "_ntp._udp", NULL, NULL, 
			    htons(NTP_PORT), 0, NULL, NULL, NULL) != kDNSServiceErr_NoError ) {
				if (!--mdnstries) {
					msyslog(LOG_ERR, "Unable to register mDNS, giving up.");
				} else {	
					msyslog(LOG_INFO, "Unable to register mDNS, will try later.");
				}
			} else {
				msyslog(LOG_INFO, "mDNS service registered.");
				mdnsreg = 0;
			}
		}
#endif /* HAVE_DNSREGISTRATION */

	}
	UNBLOCK_IO_AND_ALARM();
	return 1;
}


#ifdef SIGDIE2
/*
 * finish - exit gracefully
 */
static RETSIGTYPE
finish(
	int sig
	)
{
	msyslog(LOG_NOTICE, "ntpd exiting on signal %d", sig);
#ifdef HAVE_DNSREGISTRATION
	if (mdns != NULL)
		DNSServiceRefDeallocate(mdns);
#endif
	switch (sig) {
# ifdef SIGBUS
	case SIGBUS:
		printf("\nfinish(SIGBUS)\n");
		exit(0);
# endif
	case 0:			/* Should never happen... */
		return;

	default:
		exit(0);
	}
}
Пример #28
0
/*
 * local_clock - the NTP logical clock loop filter.
 *
 * Return codes:
 * -1	update ignored: exceeds panic threshold
 * 0	update ignored: popcorn or exceeds step threshold
 * 1	clock was slewed
 * 2	clock was stepped
 *
 * LOCKCLOCK: The only thing this routine does is set the
 * sys_rootdisp variable equal to the peer dispersion.
 */
int
local_clock(
	struct	peer *peer,	/* synch source peer structure */
	double	fp_offset	/* clock offset (s) */
	)
{
	int	rval;		/* return code */
	int	osys_poll;	/* old system poll */
	double	mu;		/* interval since last update */
	double	clock_frequency; /* clock frequency */
	double	dtemp, etemp;	/* double temps */
	char	tbuf[80];	/* report buffer */

	/*
	 * If the loop is opened or the NIST LOCKCLOCK is in use,
	 * monitor and record the offsets anyway in order to determine
	 * the open-loop response and then go home.
	 */
#ifdef LOCKCLOCK
	return (0);

#else /* LOCKCLOCK */
	if (!ntp_enable) {
		record_loop_stats(fp_offset, drift_comp, clock_jitter,
		    clock_stability, sys_poll);
		return (0);
	}

	/*
	 * If the clock is way off, panic is declared. The clock_panic
	 * defaults to 1000 s; if set to zero, the panic will never
	 * occur. The allow_panic defaults to FALSE, so the first panic
	 * will exit. It can be set TRUE by a command line option, in
	 * which case the clock will be set anyway and time marches on.
	 * But, allow_panic will be set FALSE when the update is less
	 * than the step threshold; so, subsequent panics will exit.
	 */
	if (fabs(fp_offset) > clock_panic && clock_panic > 0 &&
	    !allow_panic) {
		snprintf(tbuf, sizeof(tbuf),
		    "%+.0f s; set clock manually within %.0f s.",
		    fp_offset, clock_panic);
		report_event(EVNT_SYSFAULT, NULL, tbuf);
		return (-1);
	}

	/*
	 * This section simulates ntpdate. If the offset exceeds the
	 * step threshold (128 ms), step the clock to that time and
	 * exit. Othewise, slew the clock to that time and exit. Note
	 * that the slew will persist and eventually complete beyond the
	 * life of this program. Note that while ntpdate is active, the
	 * terminal does not detach, so the termination message prints
	 * directly to the terminal.
	 */
	if (mode_ntpdate) {
		if (fabs(fp_offset) > clock_max && clock_max > 0) {
			step_systime(fp_offset);
			msyslog(LOG_NOTICE, "ntpd: time set %+.6f s",
	   		    fp_offset);
			printf("ntpd: time set %+.6fs\n", fp_offset);
		} else {
			adj_systime(fp_offset);
			msyslog(LOG_NOTICE, "ntpd: time slew %+.6f s",
			    fp_offset);
			printf("ntpd: time slew %+.6fs\n", fp_offset);
		}
		record_loop_stats(fp_offset, drift_comp, clock_jitter,
		    clock_stability, sys_poll);
		exit (0);
	}

	/*
	 * The huff-n'-puff filter finds the lowest delay in the recent
	 * interval. This is used to correct the offset by one-half the
	 * difference between the sample delay and minimum delay. This
	 * is most effective if the delays are highly assymetric and
	 * clockhopping is avoided and the clock frequency wander is
	 * relatively small.
	 */
	if (sys_huffpuff != NULL) {
		if (peer->delay < sys_huffpuff[sys_huffptr])
			sys_huffpuff[sys_huffptr] = peer->delay;
		if (peer->delay < sys_mindly)
			sys_mindly = peer->delay;
		if (fp_offset > 0)
			dtemp = -(peer->delay - sys_mindly) / 2;
		else
			dtemp = (peer->delay - sys_mindly) / 2;
		fp_offset += dtemp;
#ifdef DEBUG
		if (debug)
			printf(
		    "local_clock: size %d mindly %.6f huffpuff %.6f\n",
			    sys_hufflen, sys_mindly, dtemp);
#endif
	}

	/*
	 * Clock state machine transition function which defines how the
	 * system reacts to large phase and frequency excursion. There
	 * are two main regimes: when the offset exceeds the step
	 * threshold (128 ms) and when it does not. Under certain
	 * conditions updates are suspended until the stepout theshold
	 * (900 s) is exceeded. See the documentation on how these
	 * thresholds interact with commands and command line options. 
	 *
	 * Note the kernel is disabled if step is disabled or greater
	 * than 0.5 s or in ntpdate mode. 
	 */
	osys_poll = sys_poll;
	if (sys_poll < peer->minpoll)
		sys_poll = peer->minpoll;
	if (sys_poll > peer->maxpoll)
		sys_poll = peer->maxpoll;
	mu = current_time - clock_epoch;
	clock_frequency = drift_comp;
	rval = 1;
	if (fabs(fp_offset) > clock_max && clock_max > 0) {
		switch (state) {

		/*
		 * In SYNC state we ignore the first outlyer and switch
		 * to SPIK state.
		 */
		case EVNT_SYNC:
			snprintf(tbuf, sizeof(tbuf), "%+.6f s",
			    fp_offset);
			report_event(EVNT_SPIK, NULL, tbuf);
			state = EVNT_SPIK;
			return (0);

		/*
		 * In FREQ state we ignore outlyers and inlyers. At the
		 * first outlyer after the stepout threshold, compute
		 * the apparent frequency correction and step the phase.
		 */
		case EVNT_FREQ:
			if (mu < clock_minstep)
				return (0);

			clock_frequency = direct_freq(fp_offset);

			/* fall through to S_SPIK */

		/*
		 * In SPIK state we ignore succeeding outlyers until
		 * either an inlyer is found or the stepout threshold is
		 * exceeded.
		 */
		case EVNT_SPIK:
			if (mu < clock_minstep)
				return (0);

			/* fall through to default */

		/*
		 * We get here by default in NSET and FSET states and
		 * from above in FREQ or SPIK states.
		 *
		 * In NSET state an initial frequency correction is not
		 * available, usually because the frequency file has not
		 * yet been written. Since the time is outside the step
		 * threshold, the clock is stepped. The frequency will
		 * be set directly following the stepout interval.
		 *
		 * In FSET state the initial frequency has been set from
		 * the frequency file. Since the time is outside the
		 * step threshold, the clock is stepped immediately,
		 * rather than after the stepout interval. Guys get
		 * nervous if it takes 15 minutes to set the clock for
		 * the first time.
		 *
		 * In FREQ and SPIK states the stepout threshold has
		 * expired and the phase is still above the step
		 * threshold. Note that a single spike greater than the
		 * step threshold is always suppressed, even with a
		 * long time constant.
		 */ 
		default:
			snprintf(tbuf, sizeof(tbuf), "%+.6f s",
			    fp_offset);
			report_event(EVNT_CLOCKRESET, NULL, tbuf);
			step_systime(fp_offset);
			reinit_timer();
			tc_counter = 0;
			clock_jitter = LOGTOD(sys_precision);
			rval = 2;
			if (state == EVNT_NSET || (current_time -
			    last_step) < clock_minstep * 2) {
				rstclock(EVNT_FREQ, 0);
				return (rval);
			}
			last_step = current_time;
			break;
		}
		rstclock(EVNT_SYNC, 0);
	} else {

		/*
		 * The offset is less than the step threshold. Calculate
		 * the jitter as the exponentially weighted offset
		 * differences.
 	      	 */
		etemp = SQUARE(clock_jitter);
		dtemp = SQUARE(max(fabs(fp_offset - last_offset),
		    LOGTOD(sys_precision)));
		clock_jitter = SQRT(etemp + (dtemp - etemp) /
		    CLOCK_AVG);
		switch (state) {

		/*
		 * In NSET state this is the first update received and
		 * the frequency has not been initialized. Adjust the
		 * phase, but do not adjust the frequency until after
		 * the stepout threshold.
		 */
		case EVNT_NSET:
			rstclock(EVNT_FREQ, fp_offset);
			break;

		/*
		 * In FSET state this is the first update received and
		 * the frequency has been initialized. Adjust the phase,
		 * but do not adjust the frequency until the next
		 * update.
		 */
		case EVNT_FSET:
			rstclock(EVNT_SYNC, fp_offset);
			break;

		/*
		 * In FREQ state ignore updates until the stepout
		 * threshold. After that, compute the new frequency, but
		 * do not adjust the phase or frequency until the next
		 * update.
		 */
		case EVNT_FREQ:
			if (mu < clock_minstep)
				return (0);

			clock_frequency = direct_freq(fp_offset);
			rstclock(EVNT_SYNC, 0);
			break;


		/*
		 * We get here by default in SYNC and SPIK states. Here
		 * we compute the frequency update due to PLL and FLL
		 * contributions.
		 */
		default:
			allow_panic = FALSE;

			/*
			 * The FLL and PLL frequency gain constants
			 * depend on the time constant and Allan
			 * intercept. The PLL is always used, but
			 * becomes ineffective above the Allan intercept
			 * where the FLL becomes effective.
			 */
			if (sys_poll >= allan_xpt)
				clock_frequency += (fp_offset -
				    clock_offset) /
				    max(ULOGTOD(sys_poll), mu) *
				    CLOCK_FLL;

			/*
			 * The PLL frequency gain (numerator) depends on
			 * the minimum of the update interval and Allan
			 * intercept. This reduces the PLL gain when the 
			 * FLL becomes effective.
			 */ 
			etemp = min(ULOGTOD(allan_xpt), mu);
			dtemp = 4 * CLOCK_PLL * ULOGTOD(sys_poll);
			clock_frequency += fp_offset * etemp / (dtemp *
			    dtemp);
			rstclock(EVNT_SYNC, fp_offset);
			break;
		}
	}

#ifdef KERNEL_PLL
	/*
	 * This code segment works when clock adjustments are made using
	 * precision time kernel support and the ntp_adjtime() system
	 * call. This support is available in Solaris 2.6 and later,
	 * Digital Unix 4.0 and later, FreeBSD, Linux and specially
	 * modified kernels for HP-UX 9 and Ultrix 4. In the case of the
	 * DECstation 5000/240 and Alpha AXP, additional kernel
	 * modifications provide a true microsecond clock and nanosecond
	 * clock, respectively.
	 *
	 * Important note: The kernel discipline is used only if the
	 * step threshold is less than 0.5 s, as anything higher can
	 * lead to overflow problems. This might occur if some misguided
	 * lad set the step threshold to something ridiculous.
	 */
	if (pll_control && kern_enable) {

		/*
		 * We initialize the structure for the ntp_adjtime()
		 * system call. We have to convert everything to
		 * microseconds or nanoseconds first. Do not update the
		 * system variables if the ext_enable flag is set. In
		 * this case, the external clock driver will update the
		 * variables, which will be read later by the local
		 * clock driver. Afterwards, remember the time and
		 * frequency offsets for jitter and stability values and
		 * to update the frequency file.
		 */
		memset(&ntv,  0, sizeof(ntv));
		if (ext_enable) {
			ntv.modes = MOD_STATUS;
		} else {
#ifdef STA_NANO
			ntv.modes = MOD_BITS | MOD_NANO;
#else /* STA_NANO */
			ntv.modes = MOD_BITS;
#endif /* STA_NANO */
			if (clock_offset < 0)
				dtemp = -.5;
			else
				dtemp = .5;
#ifdef STA_NANO
			ntv.offset = (int32)(clock_offset * 1e9 +
			    dtemp);
			ntv.constant = sys_poll;
#else /* STA_NANO */
			ntv.offset = (int32)(clock_offset * 1e6 +
			    dtemp);
			ntv.constant = sys_poll - 4;
#endif /* STA_NANO */
			ntv.esterror = (u_int32)(clock_jitter * 1e6);
			ntv.maxerror = (u_int32)((sys_rootdelay / 2 +
			    sys_rootdisp) * 1e6);
			ntv.status = STA_PLL;

			/*
			 * Enable/disable the PPS if requested.
			 */
			if (pps_enable) {
				if (!(pll_status & STA_PPSTIME))
					report_event(EVNT_KERN,
					    NULL, "PPS enabled");
				ntv.status |= STA_PPSTIME | STA_PPSFREQ;
			} else {
				if (pll_status & STA_PPSTIME)
					report_event(EVNT_KERN,
					    NULL, "PPS disabled");
				ntv.status &= ~(STA_PPSTIME |
				    STA_PPSFREQ);
			}
			if (sys_leap == LEAP_ADDSECOND)
				ntv.status |= STA_INS;
			else if (sys_leap == LEAP_DELSECOND)
				ntv.status |= STA_DEL;
		}

		/*
		 * Pass the stuff to the kernel. If it squeals, turn off
		 * the pps. In any case, fetch the kernel offset,
		 * frequency and jitter.
		 */
		if (ntp_adjtime(&ntv) == TIME_ERROR) {
			if (!(ntv.status & STA_PPSSIGNAL))
				report_event(EVNT_KERN, NULL,
				    "PPS no signal");
		}
		pll_status = ntv.status;
#ifdef STA_NANO
		clock_offset = ntv.offset / 1e9;
#else /* STA_NANO */
		clock_offset = ntv.offset / 1e6;
#endif /* STA_NANO */
		clock_frequency = FREQTOD(ntv.freq);

		/*
		 * If the kernel PPS is lit, monitor its performance.
		 */
		if (ntv.status & STA_PPSTIME) {
#ifdef STA_NANO
			clock_jitter = ntv.jitter / 1e9;
#else /* STA_NANO */
			clock_jitter = ntv.jitter / 1e6;
#endif /* STA_NANO */
		}

#if defined(STA_NANO) && NTP_API == 4
		/*
		 * If the TAI changes, update the kernel TAI.
		 */
		if (loop_tai != sys_tai) {
			loop_tai = sys_tai;
			ntv.modes = MOD_TAI;
			ntv.constant = sys_tai;
			ntp_adjtime(&ntv);
		}
#endif /* STA_NANO */
	}
#endif /* KERNEL_PLL */

	/*
	 * Clamp the frequency within the tolerance range and calculate
	 * the frequency difference since the last update.
	 */
	if (fabs(clock_frequency) > NTP_MAXFREQ)
		msyslog(LOG_NOTICE,
		    "frequency error %.0f PPM exceeds tolerance %.0f PPM",
		    clock_frequency * 1e6, NTP_MAXFREQ * 1e6);
	dtemp = SQUARE(clock_frequency - drift_comp);
	if (clock_frequency > NTP_MAXFREQ)
		drift_comp = NTP_MAXFREQ;
	else if (clock_frequency < -NTP_MAXFREQ)
		drift_comp = -NTP_MAXFREQ;
	else
		drift_comp = clock_frequency;

	/*
	 * Calculate the wander as the exponentially weighted RMS
	 * frequency differences. Record the change for the frequency
	 * file update.
	 */
	etemp = SQUARE(clock_stability);
	clock_stability = SQRT(etemp + (dtemp - etemp) / CLOCK_AVG);
	drift_file_sw = TRUE;

	/*
	 * Here we adjust the timeconstan by comparing the current
	 * offset with the clock jitter. If the offset is less than the
	 * clock jitter times a constant, then the averaging interval is
	 * increased, otherwise it is decreased. A bit of hysteresis
	 * helps calm the dance. Works best using burst mode.
	 */
	if (fabs(clock_offset) < CLOCK_PGATE * clock_jitter) {
		tc_counter += sys_poll;
		if (tc_counter > CLOCK_LIMIT) {
			tc_counter = CLOCK_LIMIT;
			if (sys_poll < peer->maxpoll) {
				tc_counter = 0;
				sys_poll++;
			}
		}
	} else {
		tc_counter -= sys_poll << 1;
		if (tc_counter < -CLOCK_LIMIT) {
			tc_counter = -CLOCK_LIMIT;
			if (sys_poll > peer->minpoll) {
				tc_counter = 0;
				sys_poll--;
			}
		}
	}

	/*
	 * If the time constant has changed, update the poll variables.
	 */
	if (osys_poll != sys_poll)
		poll_update(peer, sys_poll);

	/*
	 * Yibbidy, yibbbidy, yibbidy; that'h all folks.
	 */
	record_loop_stats(clock_offset, drift_comp, clock_jitter,
	    clock_stability, sys_poll);
#ifdef DEBUG
	if (debug)
		printf(
		    "local_clock: offset %.9f jit %.9f freq %.3f stab %.3f poll %d\n",
		    clock_offset, clock_jitter, drift_comp * 1e6,
		    clock_stability * 1e6, sys_poll);
#endif /* DEBUG */
	return (rval);
#endif /* LOCKCLOCK */
}
Пример #29
0
static void
fork_blocking_child(
	blocking_child *	c
	)
{
	static int	atexit_installed;
	static int	blocking_pipes[4] = { -1, -1, -1, -1 };
	int		rc;
	int		was_pipe;
	int		is_pipe;
	int		saved_errno = 0;
	int		childpid;
	int		keep_fd;
	int		fd;

	/*
	 * parent and child communicate via a pair of pipes.
	 * 
	 * 0 child read request
	 * 1 parent write request
	 * 2 parent read response
	 * 3 child write response
	 */
	if (-1 == c->req_write_pipe) {
		rc = pipe_socketpair(&blocking_pipes[0], &was_pipe);
		if (0 != rc) {
			saved_errno = errno;
		} else {
			rc = pipe_socketpair(&blocking_pipes[2], &is_pipe);
			if (0 != rc) {
				saved_errno = errno;
				close(blocking_pipes[0]);
				close(blocking_pipes[1]);
			} else {
				INSIST(was_pipe == is_pipe);
			}
		}
		if (0 != rc) {
			errno = saved_errno;
			msyslog(LOG_ERR, "unable to create worker pipes: %m");
			exit(1);
		}

		/*
		 * Move the descriptors the parent will keep open out of the
		 * low descriptors preferred by C runtime buffered FILE *.
		 */
		c->req_write_pipe = move_fd(blocking_pipes[1]);
		c->resp_read_pipe = move_fd(blocking_pipes[2]);
		/*
		 * wake any worker child on orderly shutdown of the
		 * daemon so that it can notice the broken pipes and
		 * go away promptly.
		 */
		if (!atexit_installed) {
			atexit(&send_worker_home_atexit);
			atexit_installed = TRUE;
		}
	}

#if defined(HAVE_DROPROOT) && !defined(NEED_EARLY_FORK)
	/* defer the fork until after root is dropped */
	if (droproot && !root_dropped)
		return;
#endif
	if (syslog_file != NULL)
		fflush(syslog_file);
	fflush(stdout);
	fflush(stderr);

	/* [BUG 3050] setting SIGCHLD to SIG_IGN likely causes unwanted
	 * or undefined effects. We don't do it and leave SIGCHLD alone.
	 */
	/* signal_no_reset(SIGCHLD, SIG_IGN); */

	childpid = fork();
	if (-1 == childpid) {
		msyslog(LOG_ERR, "unable to fork worker: %m");
		exit(1);
	}

	if (childpid) {
		/* this is the parent */
		TRACE(1, ("forked worker child (pid %d)\n", childpid));
		c->pid = childpid;
		c->ispipe = is_pipe;

		/* close the child's pipe descriptors. */
		close(blocking_pipes[0]);
		close(blocking_pipes[3]);

		memset(blocking_pipes, -1, sizeof(blocking_pipes));

		/* wire into I/O loop */
		(*addremove_io_fd)(c->resp_read_pipe, is_pipe, FALSE);

		return;		/* parent returns */
	}

	/*
	 * The parent gets the child pid as the return value of fork().
	 * The child must work for it.
	 */
	c->pid = getpid();
	worker_process = TRUE;

	/*
	 * In the child, close all files except stdin, stdout, stderr,
	 * and the two child ends of the pipes.
	 */
	DEBUG_INSIST(-1 == c->req_read_pipe);
	DEBUG_INSIST(-1 == c->resp_write_pipe);
	c->req_read_pipe = blocking_pipes[0];
	c->resp_write_pipe = blocking_pipes[3];

	kill_asyncio(0);
	closelog();
	if (syslog_file != NULL) {
		fclose(syslog_file);
		syslog_file = NULL;
		syslogit = TRUE;
	}
	keep_fd = max(c->req_read_pipe, c->resp_write_pipe);
	for (fd = 3; fd < keep_fd; fd++)
		if (fd != c->req_read_pipe && 
		    fd != c->resp_write_pipe)
			close(fd);
	close_all_beyond(keep_fd);
	/*
	 * We get signals from refclock serial I/O on NetBSD in the
	 * worker if we do not reset SIGIO's handler to the default.
	 * It is not conditionalized for NetBSD alone because on
	 * systems where it is not needed, it is harmless, and that
	 * allows us to handle unknown others with NetBSD behavior.
	 * [Bug 1386]
	 */
#if defined(USE_SIGIO)
	signal_no_reset(SIGIO, SIG_DFL);
#elif defined(USE_SIGPOLL)
	signal_no_reset(SIGPOLL, SIG_DFL);
#endif
	signal_no_reset(SIGHUP, worker_sighup);
	init_logging("ntp_intres", 0, FALSE);
	setup_logfile(NULL);

	/*
	 * And now back to the portable code
	 */
	exit_worker(blocking_child_common(c));
}
Пример #30
0
static void
hopfserial_receive (
	struct recvbuf *rbufp
	)
{
	struct hopfclock_unit *up;
	struct refclockproc *pp;
	struct peer *peer;

	int		synch;	/* synchhronization indicator */
	int		DoW;	/* Dow */

	int	day, month;	/* ddd conversion */

	/*
	 * Initialize pointers and read the timecode and timestamp.
	 */
	peer = (struct peer *)rbufp->recv_srcclock;
	pp = peer->procptr;
	up = (struct hopfclock_unit *)pp->unitptr;

	if (up->rpt_next == 0 )
		return;


	up->rpt_next = 0; /* wait until next poll interval occur */

	pp->lencode = (u_short)refclock_gtlin(rbufp, pp->a_lastcode, BMAX, &pp->lastrec);

	if (pp->lencode  == 0)
		return;

	sscanf(pp->a_lastcode,
#if 1
	       "%1x%1x%2d%2d%2d%2d%2d%2d",   /* ...cr,lf */
#else
	       "%*c%1x%1x%2d%2d%2d%2d%2d%2d", /* stx...cr,lf,etx */
#endif
	       &synch,
	       &DoW,
	       &pp->hour,
	       &pp->minute,
	       &pp->second,
	       &day,
	       &month,
	       &pp->year);


	/*
	  Validate received values at least enough to prevent internal
	  array-bounds problems, etc.
	*/
	if((pp->hour < 0) || (pp->hour > 23) ||
	   (pp->minute < 0) || (pp->minute > 59) ||
	   (pp->second < 0) || (pp->second > 60) /*Allow for leap seconds.*/ ||
	   (day < 1) || (day > 31) ||
	   (month < 1) || (month > 12) ||
	   (pp->year < 0) || (pp->year > 99)) {
		/* Data out of range. */
		refclock_report(peer, CEVNT_BADREPLY);
		return;
	}
	/*
	  some preparations
	*/
	pp->day    = ymd2yd(pp->year,month,day);
	pp->leap=0;

	/* Year-2000 check! */
	/* wrap 2-digit date into 4-digit */

	if(pp->year < YEAR_PIVOT) { pp->year += 100; }		/* < 98 */
	pp->year += 1900;

	/* preparation for timecode ntpq rl command ! */

#if 0
	snprintf(pp->a_lastcode, sizeof(pp->a_lastcode),
		 "STATUS: %1X%1X, DATE: %02d.%02d.%04d  TIME: %02d:%02d:%02d",
		 synch,
		 DoW,
		 day,
		 month,
		 pp->year,
		 pp->hour,
		 pp->minute,
		 pp->second);

	pp->lencode = strlen(pp->a_lastcode);
	if ((synch && 0xc) == 0 ){  /* time ok? */
		refclock_report(peer, CEVNT_BADTIME);
		pp->leap = LEAP_NOTINSYNC;
		return;
	}
#endif
	/*
	 * If clock has no valid status then report error and exit
	 */
	if ((synch & HOPF_OPMODE) == HOPF_INVALID ){  /* time ok? */
		refclock_report(peer, CEVNT_BADTIME);
		pp->leap = LEAP_NOTINSYNC;
		return;
	}

	/*
	 * Test if time is running on internal quarz
	 * if CLK_FLAG1 is set, sychronize even if no radio operation
	 */

	if ((synch & HOPF_OPMODE) == HOPF_INTERNAL){
		if ((pp->sloppyclockflag & CLK_FLAG1) == 0) {
			refclock_report(peer, CEVNT_BADTIME);
			pp->leap = LEAP_NOTINSYNC;
			return;
		}
	}


	if (!refclock_process(pp)) {
		refclock_report(peer, CEVNT_BADTIME);
		return;
	}
	pp->lastref = pp->lastrec;
	refclock_receive(peer);

#if 0
	msyslog(LOG_ERR, " D:%x  D:%d D:%d",synch,pp->minute,pp->second);
#endif

	record_clock_stats(&peer->srcadr, pp->a_lastcode);

	return;
}