NetBSD/dist/ntp/clockstuff/clktest.c

415 lines
7.1 KiB
C

/* $NetBSD: clktest.c,v 1.3 2007/01/06 19:45:21 kardel Exp $ */
/* clktest.c,v 3.1 1993/07/06 01:05:23 jbj Exp
* clktest - test the clock line discipline
*
* usage: clktest -b bps -f -t timeo -s cmd -c char1 -a char2 /dev/whatever
*/
#include "clktest-opts.h"
#define STREQ(a, b) (*(a) == *(b) && strcmp((a), (b)) == 0)
#if defined(ULT_2_0_SUCKS)
#ifndef sigmask
#define sigmask(m) (1<<(m))
#endif
#endif
#ifndef STREAM
# ifndef CLKLDISC
CLOCK_LINE_DISCIPLINE_NEEDED_BY_THIS_PROGRAM;
# endif
#else
# ifdef CLKLDISC
ONLY_ONE_CLOCK_LINE_DISCIPLINE_FOR_THIS_PROGRAM;
# endif
#endif
/*
* Mask for blocking SIGIO and SIGALRM
*/
#define BLOCKSIGMASK (sigmask(SIGIO)|sigmask(SIGALRM))
#define progname clktestOptions.pzProgName
struct timeval timeout = { 0 };
char *cmd = NULL;
int cmdlen;
#ifdef CLKLDISC
u_long magic1 = DEFMAGIC;
u_long magic2 = DEFMAGIC;
#endif
int speed = B9600;
int ttflags = RAW|EVENP|ODDP;
volatile int wasalarmed;
volatile int iosig;
struct timeval lasttv;
extern u_long ustotslo[];
extern u_long ustotsmid[];
extern u_long ustotshi[];
int alarming();
int ioready();
/*
* main - parse arguments and handle options
*/
int
main(
int argc,
char *argv[]
)
{
int fd;
struct sgttyb ttyb;
struct itimerval itimer;
#ifdef STREAM
magic[0] = 0;
#endif
{
int ct = optionProcess( &clktestOptions, argc, argv );
if (HAVE_OPT(COMMAND) && (strlen(OPT_ARG(COMMAND)) == 0)) {
fputs( "The command option string must not be empty\n", stderr );
USAGE( EXIT_FAILURE );
}
if ((argc -= ct) != 1) {
fputs( "Missing tty device name\n", stderr );
USAGE( EXIT_FAILURE );
}
argv += ct;
}
#ifdef STREAM
if (!strlen(magic))
strcpy(magic,DEFMAGIC);
#endif
fd = open(*argv, HAVE_OPT(TIMEOUT) ? O_RDWR : O_RDONLY, 0777);
if (fd == -1) {
fprintf(stderr, "%s: open(%s): ", progname, *argv);
perror("");
exit(1);
}
if (ioctl(fd, TIOCEXCL, (char *)0) < 0) {
(void) fprintf(stderr, "%s: ioctl(TIOCEXCL): ", progname);
perror("");
exit(1);
}
/*
* If we have the clock discipline, set the port to raw. Otherwise
* we run cooked.
*/
ttyb.sg_ispeed = ttyb.sg_ospeed = speed;
#ifdef CLKLDISC
ttyb.sg_erase = (char)magic1;
ttyb.sg_kill = (char)magic2;
#endif
ttyb.sg_flags = (short)ttflags;
if (ioctl(fd, TIOCSETP, (char *)&ttyb) < 0) {
(void) fprintf(stderr, "%s: ioctl(TIOCSETP): ", progname);
perror("");
exit(1);
}
if (fcntl(fd, F_SETOWN, getpid()) == -1) {
(void) fprintf(stderr, "%s: fcntl(F_SETOWN): ", progname);
perror("");
exit(1);
}
#ifdef CLKLDISC
{
int ldisc;
ldisc = CLKLDISC;
if (ioctl(fd, TIOCSETD, (char *)&ldisc) < 0) {
(void) fprintf(stderr, "%s: ioctl(TIOCSETD): ", progname);
perror("");
exit(1);
}
}
#endif
#ifdef STREAM
if (ioctl(fd, I_POP, 0) >=0 ) ;
if (ioctl(fd, I_PUSH, "clk") < 0) {
(void) fprintf(stderr, "%s: ioctl(I_PUSH): ", progname);
perror("");
exit(1);
}
if (ioctl(fd, CLK_SETSTR, magic) < 0) {
(void) fprintf(stderr, "%s: ioctl(CLK_SETSTR): ", progname);
perror("");
exit(1);
}
#endif
(void) gettimeofday(&lasttv, (struct timezone *)0);
if (HAVE_OPT(TIMEOUT)) {
/*
* set non-blocking, async I/O on the descriptor
*/
iosig = 0;
(void) signal(SIGIO, ioready);
if (fcntl(fd, F_SETFL, FNDELAY|FASYNC) < 0) {
(void) fprintf(stderr, "%s: fcntl(F_SETFL): ",
progname);
perror("");
exit(1);
}
/*
* Set up the alarm interrupt.
*/
wasalarmed = 0;
(void) signal(SIGALRM, alarming);
timeout.tv_sec = OPT_VALUE_TIMEOUT;
itimer.it_interval = itimer.it_value = timeout;
setitimer(ITIMER_REAL, &itimer, (struct itimerval *)0);
doboth(fd);
}
doioonly(fd);
}
/*
* doboth - handle both I/O and alarms via SIGIO
*/
int
doboth(
int fd
)
{
int n;
int sawalarm;
int sawiosig;
int omask;
fd_set fds;
struct timeval tvzero;
sawalarm = 0;
sawiosig = 0;
FD_ZERO(&fds);
for (;;) {
omask = sigblock(BLOCKSIGMASK);
if (wasalarmed) { /* alarmed? */
sawalarm = 1;
wasalarmed = 0;
}
if (iosig) {
sawiosig = 1;
iosig = 0;
}
if (!sawalarm && !sawiosig) {
/*
* Nothing to do. Wait for something.
*/
sigpause(omask);
if (wasalarmed) { /* alarmed? */
sawalarm = 1;
wasalarmed = 0;
}
if (iosig) {
sawiosig = 1;
iosig = 0;
}
}
(void)sigsetmask(omask);
if (sawiosig) {
do {
tvzero.tv_sec = tvzero.tv_usec = 0;
FD_SET(fd, &fds);
n = select(fd+1, &fds, (fd_set *)0,
(fd_set *)0, &tvzero);
if (n > 0)
doio(fd);
} while (n > 0);
if (n == -1) {
(void) fprintf(stderr, "%s: select: ",
progname);
perror("");
exit(1);
}
sawiosig = 0;
}
if (sawalarm) {
doalarm(fd);
sawalarm = 0;
}
}
}
/*
* doioonly - do I/O. This avoids the use of signals
*/
int
doioonly(
int fd
)
{
int n;
fd_set fds;
FD_ZERO(&fds);
for (;;) {
FD_SET(fd, &fds);
n = select(fd+1, &fds, (fd_set *)0, (fd_set *)0,
(struct timeval *)0);
if (n > 0)
doio(fd);
}
}
/*
* doio - read a buffer full of stuff and print it out
*/
int
doio(
int fd
)
{
register char *rp, *rpend;
register char *cp;
register int i;
char raw[512];
struct timeval tv, tvd;
int rlen;
int ind;
char cooked[2049];
static char *digits = "0123456789abcdef";
rlen = read(fd, raw, sizeof(raw));
if (rlen < 0) {
(void) fprintf(stderr, "%s: read(): ", progname);
perror("");
return;
}
if (rlen == 0) {
(void) printf("Zero length read\n");
return;
}
cp = cooked;
rp = raw;
rpend = &raw[rlen];
ind = 0;
while (rp < rpend) {
ind = 1;
if (isprint(*rp))
*cp++ = *rp;
else {
*cp++ = '<';
*cp++ = digits[((*rp)>>4) & 0xf];
*cp++ = digits[*rp & 0xf];
*cp++ = '>';
}
if (
#ifdef CLKLDISC
(*rp == (char)magic1 || *rp == (char)magic2)
#else
( strchr( magic, *rp) != NULL )
#endif
) {
rp++;
ind = 0;
*cp = '\0';
if ((rpend - rp) < sizeof(struct timeval)) {
(void)printf(
"Too little data (%d): %s\n",
rpend-rp, cooked);
return;
}
tv.tv_sec = 0;
for (i = 0; i < 4; i++) {
tv.tv_sec <<= 8;
tv.tv_sec |= ((long)*rp++) & 0xff;
}
tv.tv_usec = 0;
for (i = 0; i < 4; i++) {
tv.tv_usec <<= 8;
tv.tv_usec |= ((long)*rp++) & 0xff;
}
tvd.tv_sec = tv.tv_sec - lasttv.tv_sec;
tvd.tv_usec = tv.tv_usec - lasttv.tv_usec;
if (tvd.tv_usec < 0) {
tvd.tv_usec += 1000000;
tvd.tv_sec--;
}
(void)printf("%lu.%06lu %lu.%06lu %s\n",
tv.tv_sec, tv.tv_usec, tvd.tv_sec, tvd.tv_usec,
cooked);
lasttv = tv;
} else {
rp++;
}
}
if (ind) {
*cp = '\0';
(void)printf("Incomplete data: %s\n", cooked);
}
}
/*
* doalarm - send a string out the port, if we have one.
*/
int
doalarm(
int fd
)
{
int n;
if (! HAVE_OPT(COMMAND))
return;
n = write(fd, cmd, cmdlen);
if (n < 0) {
(void) fprintf(stderr, "%s: write(): ", progname);
perror("");
} else if (n < cmdlen) {
(void) printf("Short write (%d bytes, should be %d)\n",
n, cmdlen);
}
}
/*
* alarming - receive alarm interupt
*/
void
alarming(void)
{
wasalarmed = 1;
}
/*
* ioready - handle SIGIO interrupt
*/
void
ioready(void)
{
iosig = 1;
}