summaryrefslogtreecommitdiff
path: root/ntpmon.c
blob: 7899fd77be09b2992147be9ce45ae346331303c1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
/* ntpmon.c -- monitor the inner end of an ntpshm connection
 *
 * This file is Copyright (c) 2010 by the GPSD project
 * BSD terms apply: see the file COPYING in the distribution root for details.
 *
 */
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
#ifndef S_SPLINT_S
#include <unistd.h>
#endif /* S_SPLINT_S */

#include "ntpshm.h"

#define NTPSEGMENTS	256	/* NTPx for x any byte */

static struct shmTime *segments[NTPSEGMENTS + 1];
static struct timespec tick[NTPSEGMENTS + 1];

static void shm_shutdown(void)
/* shut down all active segments */
{
    struct shmTime **pp;

    for (pp = segments; pp < segments + NTPSEGMENTS; pp++)
	if (*pp != NULL)
	    (void)shmdt((void *)(*pp));
}

int main(int argc, char **argv)
{
    int units = 0;
    int option;
    int	i;
    bool verbose = false;

#define USAGE	"usage: ntpmon [-s] [-v] [-h]\n"
    while ((option = getopt(argc, argv, "hsv")) != -1) {
	switch (option) {
	case 's':
	    if (units > 0) {
		shm_shutdown();
		exit(EXIT_SUCCESS);
	    } else {
		fprintf(stderr, "ntpmon: zero units declared.\n");
		exit(EXIT_FAILURE);
	    }
	    //0break;
	case 'v':
	    verbose = true;
	    break;
	case 'h':
	default:
	    fprintf(stderr, USAGE);
	    break;
	}
    }

    /* grab all segments, keep the non-null ones */
    for (i = 0; i < NTPSEGMENTS; i++) {
	segments[i] = shm_get(i, false, true);
	if (verbose && segments[i] != NULL)
	    fprintf(stderr, "unit %d opened\n", i);
    }
    (void)printf("ntpmon version 1\n");

    for (;;) {
	struct shm_stat_t	shm_stat;

	for (i = 0; i < NTPSEGMENTS; i++) {
	    enum segstat_t status = shm_query(segments[i], &shm_stat);
	    if (verbose)
		fprintf(stderr, "unit %d status %d\n", i, status);
	    switch(status)
	    {
	    case OK:
		/*@-mustfreefresh -formattype@*/
		/*@-type@*//* splint is confused about struct timespec */
		if (shm_stat.tvc.tv_sec != tick[i].tv_sec || shm_stat.tvc.tv_nsec != tick[i].tv_nsec) {
		    printf("sample %s %ld.%09ld %ld.%09ld %ld.%09ld %d %3d\n",
			   shm_name(i),
			   shm_stat.tvc.tv_sec, shm_stat.tvc.tv_nsec,
			   shm_stat.tvr.tv_sec, shm_stat.tvr.tv_nsec,
			   shm_stat.tvt.tv_sec, shm_stat.tvt.tv_nsec,
			   shm_stat.leap, shm_stat.precision);
		    tick[i] = shm_stat.tvc;
		}
		/*@+type@*/
		/*@+mustfreefresh +formattype@*/
		break;
	    case NO_SEGMENT:
		break;
	    case NOT_READY:
		/* do nothing, data not ready, wait another cycle */
		break;
	    case BAD_MODE:
		/*@-mustfreefresh@*/
		fprintf(stderr, "ntpmon: unknown mode %d on segment %s\n",
			shm_stat.status, shm_name(i));
		/*@+mustfreefresh@*/
		break;
	    case CLASH:
		/* do nothing, data is corrupt, wait another cycle */
		break;
	    default:
		/*@-mustfreefresh@*/
		fprintf(stderr, "ntpmon: unknown status %d on segment %s\n",
			status, shm_name(i));
		/*@+mustfreefresh@*/
		break;
	    }
	}
 
	/*
	 * Even on a 1 Hz PPS, a sleep(1) may end up
         * being sleep(1.1) and missing a beat.  Since
	 * we're ignoring duplicates via timestamp, polling
	 * at interval < 1 sec shouldn't be a problem.
	 */
	(void)usleep(1000);
    }

    //exit(EXIT_SUCCESS);
}

/* end */