1 /*
2  * timehint.c - put time information in SHM segment for ntpd, or to chrony
3  *
4  * Note that for easy debugging all logging from this file is prefixed
5  * with PPS or NTP.
6  *
7  * This file is Copyright (c)2010-2018 by the GPSD project
8  * SPDX-License-Identifier: BSD-2-clause
9  */
10 
11 #include "gpsd_config.h"  /* must be before all includes */
12 
13 #include <errno.h>
14 #include <libgen.h>
15 #include <math.h>
16 #include <stdbool.h>
17 #include <string.h>
18 #include <sys/socket.h>
19 #include <sys/stat.h>
20 #include <sys/types.h>
21 #include <sys/wait.h>
22 #include <time.h>        /* for timespec */
23 #include <unistd.h>
24 
25 #include "timespec.h"
26 #include "gpsd.h"
27 
28 #include "ntpshm.h"
29 
30 /* Note: you can start gpsd as non-root, and have it work with ntpd.
31  * However, it will then only use the ntpshm segments 2 3, and higher.
32  *
33  * Ntpd always runs as root (to be able to control the system clock).
34  * After that it often (depending on its host configuration) drops to run as
35  * user ntpd and group ntpd.
36  *
37  * As of February 2015 its rules for the creation of ntpshm segments are:
38  *
39  * Segments 0 and 1: permissions 0600, i.e. other programs can only
40  *                   read and write as root.
41  *
42  * Segments 2, 3, and higher:
43  *                   permissions 0666, i.e. other programs can read
44  *                   and write as any user.  I.e.: if ntpd has been
45  *                   configured to use these segments, any
46  *                   unprivileged user is allowed to provide data
47  *                   for synchronisation.
48  *
49  * By default ntpd creates 0 segments (though the documentation is
50  * written in such a way as to suggest it creates 4).  It can be
51  * configured to create up to 217.  gpsd creates two segments for each
52  * device it can drive; by default this is 8 segments for 4
53  * devices,but can be higher if it was compiled with a larger value of
54  * MAX_DEVICES.
55  *
56  * Started as root, gpsd does as ntpd when attaching (creating) the
57  * segments.  In contrast to ntpd, which only attaches (creates)
58  * configured segments, gpsd creates all segments.  Thus a gpsd will
59  * by default create eight segments 0-7 that an ntpd with default
60  * configuration does not watch.
61  *
62  * Started as non-root, gpsd will only attach (create) segments 2 and
63  * above, with permissions 0666.  As the permissions are for any user,
64  * the creator does not matter.
65  *
66  * For each GPS module gpsd controls, it will use the attached ntpshm
67  * segments in pairs (for coarse clock and pps source, respectively)
68  * starting from the first found segments.  I.e. started as root, one
69  * GPS will deliver data on all segments including 0 and 1; started as
70  * non-root, gpsd will be deliver data only on segments 2 and higher.
71  *
72  * Segments are allocated to activated devices on a first-come-first-served
73  * basis. A device's segment is marked unused when the device is closed and
74  * may be re-used by devices connected later.
75  *
76  * To debug, try looking at the live segments this way:
77  *
78  *  ipcs -m
79  *
80  * results  should look like this:
81  * ------ Shared Memory Segments --------
82  *  key        shmid      owner      perms      bytes      nattch     status
83  *  0x4e545030 0          root       700        96         2
84  *  0x4e545031 32769      root       700        96         2
85  *  0x4e545032 163842     root       666        96         1
86  *  0x4e545033 196611     root       666        96         1
87  *  0x4e545034 253555     root       666        96         1
88  *  0x4e545035 367311     root       666        96         1
89  *
90  * For a bit more data try this:
91  *  cat /proc/sysvipc/shm
92  *
93  * If gpsd can not open the segments be sure you are not running SELinux
94  * or apparmor.
95  *
96  * if you see the shared segments (keys 1314148400 -- 1314148405), and
97  * no gpsd or ntpd is running, you can remove them like this:
98  *
99  * ipcrm  -M 0x4e545030
100  * ipcrm  -M 0x4e545031
101  * ipcrm  -M 0x4e545032
102  * ipcrm  -M 0x4e545033
103  * ipcrm  -M 0x4e545034
104  * ipcrm  -M 0x4e545035
105  *
106  * Removing these segments is usually not necessary, as the operating system
107  * garbage-collects them when they have no attached processes.
108  */
109 
getShmTime(struct gps_context_t * context,int unit)110 static volatile struct shmTime *getShmTime(struct gps_context_t *context, int unit)
111 {
112     int shmid;
113     unsigned int perms;
114     volatile struct shmTime *p;
115     // set the SHM perms the way ntpd does
116     if (unit < 2) {
117 	// we are root, be careful
118 	perms = 0600;
119     } else {
120 	// we are not root, try to work anyway
121 	perms = 0666;
122     }
123 
124     /*
125      * Note: this call requires root under BSD, and possibly on
126      * well-secured Linux systems.  This is why ntpshm_context_init() has to be
127      * called before privilege-dropping.
128      */
129     shmid = shmget((key_t) (NTPD_BASE + unit),
130 		   sizeof(struct shmTime), (int)(IPC_CREAT | perms));
131     if (shmid == -1) {
132 	GPSD_LOG(LOG_ERROR, &context->errout,
133 		 "NTP: shmget(%ld, %zd, %o) fail: %s\n",
134 		 (long int)(NTPD_BASE + unit), sizeof(struct shmTime),
135 		 (int)perms, strerror(errno));
136 	return NULL;
137     }
138     p = (struct shmTime *)shmat(shmid, 0, 0);
139     if ((int)(long)p == -1) {
140 	GPSD_LOG(LOG_ERROR, &context->errout,
141 		 "NTP: shmat failed: %s\n",
142 		 strerror(errno));
143 	return NULL;
144     }
145     GPSD_LOG(LOG_PROG, &context->errout,
146 	     "NTP: shmat(%d,0,0) succeeded, segment %d\n",
147 	     shmid, unit);
148     return p;
149 }
150 
ntpshm_context_init(struct gps_context_t * context)151 void ntpshm_context_init(struct gps_context_t *context)
152 /* Attach all NTP SHM segments. Called once at startup, while still root. */
153 {
154     int i;
155 
156     for (i = 0; i < NTPSHMSEGS; i++) {
157 	// Only grab the first two when running as root.
158 	if (2 <= i || 0 == getuid()) {
159 	    context->shmTime[i] = getShmTime(context, i);
160 	}
161     }
162     memset(context->shmTimeInuse, 0, sizeof(context->shmTimeInuse));
163 }
164 
ntpshm_alloc(struct gps_context_t * context)165 static volatile struct shmTime *ntpshm_alloc(struct gps_context_t *context)
166 /* allocate NTP SHM segment.  return its segment number, or -1 */
167 {
168     int i;
169 
170     for (i = 0; i < NTPSHMSEGS; i++)
171 	if (context->shmTime[i] != NULL && !context->shmTimeInuse[i]) {
172 	    context->shmTimeInuse[i] = true;
173 
174 	    /*
175 	     * In case this segment gets sent to ntpd before an
176 	     * ephemeris is available, the LEAP_NOTINSYNC value will
177 	     * tell ntpd that this source is in a "clock alarm" state
178 	     * and should be ignored.  The goal is to prevent ntpd
179 	     * from declaring the GPS a falseticker before it gets
180 	     * all its marbles together.
181 	     */
182 	    memset((void *)context->shmTime[i], 0, sizeof(struct shmTime));
183 	    context->shmTime[i]->mode = 1;
184 	    context->shmTime[i]->leap = LEAP_NOTINSYNC;
185 	    context->shmTime[i]->precision = -20;/* initially 1 micro sec */
186 	    context->shmTime[i]->nsamples = 3;	/* stages of median filter */
187 
188 	    return context->shmTime[i];
189 	}
190 
191     return NULL;
192 }
193 
ntpshm_free(struct gps_context_t * context,volatile struct shmTime * s)194 static bool ntpshm_free(struct gps_context_t * context, volatile struct shmTime *s)
195 /* free NTP SHM segment */
196 {
197     int i;
198 
199     for (i = 0; i < NTPSHMSEGS; i++)
200 	if (s == context->shmTime[i]) {
201 	    context->shmTimeInuse[i] = false;
202 	    return true;
203 	}
204 
205     return false;
206 }
207 
ntpshm_session_init(struct gps_device_t * session)208 void ntpshm_session_init(struct gps_device_t *session)
209 {
210     /* mark NTPD shared memory segments as unused */
211     session->shm_clock = NULL;
212     session->shm_pps = NULL;
213 }
214 
215 /* put a received fix time into shared memory for NTP */
ntpshm_put(struct gps_device_t * session,volatile struct shmTime * shmseg,struct timedelta_t * td)216 int ntpshm_put(struct gps_device_t *session, volatile struct shmTime *shmseg,
217                struct timedelta_t *td)
218 {
219     char real_str[TIMESPEC_LEN];
220     char clock_str[TIMESPEC_LEN];
221 
222     /* Any NMEA will be about -1 or -2. Garmin GPS-18/USB is around -6 or -7. */
223     int precision = -20; /* default precision, 1 micro sec */
224 
225     if (shmseg == NULL) {
226 	GPSD_LOG(LOG_RAW, &session->context->errout, "NTP:PPS: missing shm\n");
227 	return 0;
228     }
229 
230     // FIXME: make NMEA precision -1
231     if (shmseg == session->shm_pps) {
232         /* precision is a floor so do not make it tight */
233         if ( source_usb == session->sourcetype ) {
234 	    /* if PPS over USB, then precision = -10, 1 milli sec  */
235 	    precision = -10;
236         } else {
237 	    /* likely PPS over serial, precision = -20, 1 micro sec */
238 	    precision = -20;
239         }
240     }
241 
242     ntp_write(shmseg, td, precision, session->context->leap_notify);
243 
244     GPSD_LOG(LOG_PROG, &session->context->errout,
245 	     "NTP: ntpshm_put(%s,%d) %s @ %s\n",
246 	     session->gpsdata.dev.path,
247 	     precision,
248              timespec_str(&td->real, real_str, sizeof(real_str)),
249              timespec_str(&td->clock, clock_str, sizeof(clock_str)));
250 
251     return 1;
252 }
253 
254 #define SOCK_MAGIC 0x534f434b
255 struct sock_sample {
256     struct timeval tv;
257     double offset;
258     int pulse;
259     int leap;    /* notify that a leap second is upcoming */
260     // cppcheck-suppress unusedStructMember
261     int _pad;
262     int magic;      /* must be SOCK_MAGIC */
263 };
264 
init_hook(struct gps_device_t * session)265 static void init_hook(struct gps_device_t *session)
266 /* for chrony SOCK interface, which allows nSec timekeeping */
267 {
268     /* open the chrony socket */
269     char chrony_path[GPS_PATH_MAX];
270 
271     session->chronyfd = -1;
272     if ( 0 == getuid() ) {
273 	/* this case will fire on command-line devices;
274 	 * they're opened before priv-dropping.  Matters because
275          * only root can use /var/run.
276 	 */
277 	(void)snprintf(chrony_path, sizeof (chrony_path),
278 		"/var/run/chrony.%s.sock", basename(session->gpsdata.dev.path));
279     } else {
280 	(void)snprintf(chrony_path, sizeof (chrony_path),
281 		"/tmp/chrony.%s.sock", 	basename(session->gpsdata.dev.path));
282     }
283 
284     if (access(chrony_path, F_OK) != 0) {
285 	GPSD_LOG(LOG_PROG, &session->context->errout,
286 		"PPS:%s chrony socket %s doesn't exist\n",
287 		session->gpsdata.dev.path, chrony_path);
288     } else {
289 	session->chronyfd = netlib_localsocket(chrony_path, SOCK_DGRAM);
290 	if (session->chronyfd < 0)
291 	    GPSD_LOG(LOG_PROG, &session->context->errout,
292 		     "PPS:%s connect chrony socket failed: %s, error: %d, errno: %d/%s\n",
293 		     session->gpsdata.dev.path,
294 		     chrony_path, session->chronyfd, errno, strerror(errno));
295 	else
296 	    GPSD_LOG(LOG_RAW, &session->context->errout,
297 		     "PPS:%s using chrony socket: %s\n",
298 		     session->gpsdata.dev.path, chrony_path);
299     }
300 }
301 
302 
303 /* td is the real time and clock time of the edge */
304 /* offset is actual_ts - clock_ts */
chrony_send(struct gps_device_t * session,struct timedelta_t * td)305 static void chrony_send(struct gps_device_t *session, struct timedelta_t *td)
306 {
307     char real_str[TIMESPEC_LEN];
308     char clock_str[TIMESPEC_LEN];
309     struct sock_sample sample;
310     struct tm tm;
311     int leap_notify = session->context->leap_notify;
312 
313     /*
314      * insist that leap seconds only happen in june and december
315      * GPS emits leap pending for 3 months prior to insertion
316      * NTP expects leap pending for only 1 month prior to insertion
317      * Per http://bugs.ntp.org/1090
318      *
319      * ITU-R TF.460-6, Section 2.1, says leap seconds can be primarily
320      * in Jun/Dec but may be in March or September
321      */
322     (void)gmtime_r( &(td->real.tv_sec), &tm);
323     if ( 5 != tm.tm_mon && 11 != tm.tm_mon ) {
324         /* Not june, not December, no way */
325         leap_notify = LEAP_NOWARNING;
326     }
327 
328 
329     /* chrony expects tv-sec since Jan 1970 */
330     sample.pulse = 0;
331     sample.leap = leap_notify;
332     sample.magic = SOCK_MAGIC;
333     /* chronyd wants a timeval, not a timspec, not to worry, it is
334      * just the top of the second */
335     TSTOTV(&sample.tv, &td->clock);
336     /* calculate the offset as a timespec to not lose precision */
337     /* if tv_sec greater than 2 then tv_nsec loses precision, but
338      * not a big deal as slewing will be required */
339     sample.offset = TS_SUB_D(&td->real, &td->clock);
340     sample._pad = 0;
341 
342     GPSD_LOG(LOG_RAW, &session->context->errout,
343 	     "PPS chrony_send %s @ %s Offset: %0.9f\n",
344              timespec_str(&td->real, real_str, sizeof(real_str)),
345              timespec_str(&td->clock, clock_str, sizeof(clock_str)),
346              sample.offset);
347     (void)send(session->chronyfd, &sample, sizeof (sample), 0);
348 }
349 
report_hook(volatile struct pps_thread_t * pps_thread,struct timedelta_t * td)350 static char *report_hook(volatile struct pps_thread_t *pps_thread,
351 					struct timedelta_t *td)
352 /* ship the time of a PPS event to ntpd and/or chrony */
353 {
354     char *log1;
355     struct gps_device_t *session = (struct gps_device_t *)pps_thread->context;
356 
357     /* PPS only source never get any serial info
358      * so no NTPTIME_IS or fixcnt */
359     if ( source_pps != session->sourcetype) {
360         /* FIXME! these two validations need to move back into ppsthread.c */
361 
362 	if ( !session->ship_to_ntpd)
363 	    return "skipped ship_to_ntp=0";
364 
365 	/*
366 	 * Only listen to PPS after several consecutive fixes,
367 	 * otherwise time may be inaccurate.  (We know this is
368 	 * required on all Garmin and u-blox; safest to do it
369 	 * for all cases as we have no other general way to know
370 	 * if PPS is good.
371 	 */
372 	if (session->fixcnt <= NTP_MIN_FIXES &&
373 	    (session->gpsdata.set & GOODTIME_IS) == 0)
374 	    return "no fix";
375     }
376 
377     /* FIXME?  how to log socket AND shm reported? */
378     log1 = "accepted";
379     if ( 0 <= session->chronyfd ) {
380 	log1 = "accepted chrony sock";
381 	chrony_send(session, td);
382     }
383     if (session->shm_pps != NULL)
384 	(void)ntpshm_put(session, session->shm_pps, td);
385 
386     /* session context might have a hook set, too */
387     if (session->context->pps_hook != NULL)
388 	session->context->pps_hook(session, td);
389 
390     return log1;
391 }
392 
ntpshm_link_deactivate(struct gps_device_t * session)393 void ntpshm_link_deactivate(struct gps_device_t *session)
394 /* release ntpshm storage for a session */
395 {
396     if (session->shm_clock != NULL) {
397 	(void)ntpshm_free(session->context, session->shm_clock);
398 	session->shm_clock = NULL;
399     }
400     if (session->shm_pps != NULL) {
401 	pps_thread_deactivate(&session->pps_thread);
402 	if (session->chronyfd != -1)
403 	    (void)close(session->chronyfd);
404 	(void)ntpshm_free(session->context, session->shm_pps);
405 	session->shm_pps = NULL;
406     }
407 }
408 
ntpshm_link_activate(struct gps_device_t * session)409 void ntpshm_link_activate(struct gps_device_t *session)
410 /* set up ntpshm storage for a session */
411 {
412     /* don't talk to NTP when we're running inside the test harness */
413     if (session->sourcetype == source_pty)
414 	return;
415 
416     if (session->sourcetype != source_pps ) {
417 	/* allocate a shared-memory segment for "NMEA" time data */
418 	session->shm_clock = ntpshm_alloc(session->context);
419 
420 	if (session->shm_clock == NULL) {
421 	    GPSD_LOG(LOG_WARN, &session->context->errout,
422 		     "NTP: ntpshm_alloc() failed\n");
423 	    return;
424         }
425     }
426 
427     if (session->sourcetype == source_usb
428             || session->sourcetype == source_rs232
429             || session->sourcetype == source_pps) {
430 	/* We also have the 1pps capability, allocate a shared-memory segment
431 	 * for the 1pps time data and launch a thread to capture the 1pps
432 	 * transitions
433 	 */
434 	if ((session->shm_pps = ntpshm_alloc(session->context)) == NULL) {
435 	    GPSD_LOG(LOG_WARN, &session->context->errout,
436 		     "PPS: ntpshm_alloc(1) failed\n");
437 	} else {
438 	    init_hook(session);
439 	    session->pps_thread.report_hook = report_hook;
440 	    #ifdef MAGIC_HAT_ENABLE
441 	    /*
442 	     * The HAT kludge. If we're using the HAT GPS on a
443 	     * Raspberry Pi or a workalike like the ODROIDC2, and
444 	     * there is a static "first PPS", and we have access because
445 	     * we're root, assume we want to use KPPS.
446 	     */
447 	    if (strcmp(session->pps_thread.devicename, MAGIC_HAT_GPS) == 0
448 		|| strcmp(session->pps_thread.devicename,
449 		          MAGIC_LINK_GPS) == 0) {
450 		char *first_pps = pps_get_first();
451 		if (access(first_pps, R_OK | W_OK) == 0)
452 			session->pps_thread.devicename = first_pps;
453 		}
454 	    #endif /* MAGIC_HAT_ENABLE */
455 	    pps_thread_activate(&session->pps_thread);
456 	}
457     }
458 }
459 
460 /* end */
461