1 /*
2  * This file contains functions to deal with compatibility issues across OSes.
3  *
4  * The initial version of this file is a near-verbatim concatenation of the
5  * following three source files:
6  *     clock_gettime.c
7  *     daemon.c
8  *     strl.c
9  * History of this code prior to the creation of this file can be found
10  * in the histories of those files.
11  *
12  * This file is Copyright (c)2017-2019 by the GPSD project
13  * SPDX-License-Identifier: BSD-2-clause
14  */
15 
16 #include "gpsd_config.h"  /* must be before all includes */
17 
18 #include "os_compat.h"
19 
20 #ifndef HAVE_CLOCK_GETTIME
21 
22 /* Simulate ANSI/POSIX clock_gettime() on platforms that don't have it */
23 
24 #include <time.h>
25 #include <sys/time.h>
26 
27 /*
28  * Note that previous versions of this code made use of clock_get_time()
29  * on OSX, as a way to get time of day with nanosecond resolution.  But
30  * it turns out that clock_get_time() only has microsecond resolution,
31  * in spite of the data format, and it's also substantially slower than
32  * gettimeofday().  Thus, it makes no sense to do anything special for OSX.
33  */
34 
clock_gettime(clockid_t clk_id,struct timespec * ts)35 int clock_gettime(clockid_t clk_id, struct timespec *ts)
36 {
37     (void) clk_id;
38     struct timeval tv;
39     if (gettimeofday(&tv, NULL) < 0)
40 	return -1;
41     ts->tv_sec = tv.tv_sec;
42     ts->tv_nsec = tv.tv_usec * 1000;
43     return 0;
44 }
45 #endif /* HAVE_CLOCK_GETTIME */
46 
47 /* End of clock_gettime section */
48 
49 #ifndef HAVE_DAEMON
50 /* Simulate Linux/BSD daemon() on platforms that don't have it */
51 
52 #ifdef HAVE_FORK
53 
54 #include <stdlib.h>
55 #include <sys/types.h>
56 #include <sys/stat.h>
57 #include <fcntl.h>
58 #include <unistd.h>
59 
60 #if defined (HAVE_PATH_H)
61 #include <paths.h>
62 #else
63 #if !defined (_PATH_DEVNULL)
64 #define _PATH_DEVNULL    "/dev/null"
65 #endif
66 #endif
67 
os_daemon(int nochdir,int noclose)68 int os_daemon(int nochdir, int noclose)
69 /* compatible with the daemon(3) found on Linuxes and BSDs */
70 {
71     int fd;
72 
73     switch (fork()) {
74     case -1:
75 	return -1;
76     case 0:			/* child side */
77 	break;
78     default:			/* parent side */
79 	exit(EXIT_SUCCESS);
80     }
81 
82     if (setsid() == -1)
83 	return -1;
84     if ((nochdir==0) && (chdir("/") == -1))
85 	return -1;
86     if ((noclose==0) && (fd = open(_PATH_DEVNULL, O_RDWR, 0)) != -1) {
87 	(void)dup2(fd, STDIN_FILENO);
88 	(void)dup2(fd, STDOUT_FILENO);
89 	(void)dup2(fd, STDERR_FILENO);
90 	if (fd > 2)
91 	    (void)close(fd);
92     }
93     /* coverity[leaked_handle] Intentional handle duplication */
94     return 0;
95 }
96 #else /* !HAVE_FORK */
97 
98 #include <errno.h>
99 
os_daemon(int nochdir,int noclose)100 int os_daemon(int nochdir, int noclose)
101 {
102     (void) nochdir; (void) noclose;
103     errno = EPERM;
104     return -1;
105 }
106 
107 #endif /* !HAVE_FORK */
108 
109 #else /* HAVE_DAEMON */
110 
111 #if defined (__linux__) || defined (__GLIBC__)
112 
113 #include <unistd.h>      /* for daemon() */
114 
115 #elif defined(__APPLE__) /* !__linux__ */
116 
117 /*
118  * Avoid the OSX deprecation warning.
119  *
120  * Note that on OSX, real daemons like gpsd should run via launchd rather than
121  * self-daemonizing, but we use daemon() for other tools as well.
122  *
123  * There doesn't seem to be an easy way to avoid the warning other than by
124  * providing our own declaration to override the deprecation-flagged version.
125  * Fortunately, the function signature is pretty well frozen at this point.
126  *
127  * Until we fix the kludge where all this code has to be additionally compiled
128  * as C++ for the Qt library, we need this to be compilable as C++ as well.
129  */
130 #ifdef __cplusplus
131 extern "C" {
132 #endif
133 
134 int daemon(int nochdir, int noclose);
135 
136 #ifdef __cplusplus
137 }
138 #endif
139 
140 #else /* !__linux__ && !__APPLE__ */
141 
142 #include <stdlib.h>
143 
144 #endif /* !__linux__ && !__APPLE__ */
145 
os_daemon(int nochdir,int noclose)146 int os_daemon(int nochdir, int noclose)
147 {
148     return daemon(nochdir, noclose);
149 }
150 
151 #endif /* HAVE_DAEMON */
152 
153 /* End of daemon section */
154 
155 /* Provide syslog() on platforms that don't have it */
156 
157 #ifndef HAVE_SYSLOG_H
158 #include "compiler.h"
159 #include <stdarg.h>
160 #include <stdio.h>
161 /*
162  * Minimal syslog() fallback to print to stderr
163  *
164  */
syslog(int priority UNUSED,const char * format,...)165 PRINTF_FUNC(2, 3) void syslog(int priority UNUSED, const char *format, ...)
166 {
167   /* ATM ignore priority (i.e. don't even both prepending to output) */
168   char buf[BUFSIZ];
169   va_list ap;
170   va_start(ap, format);
171   /* Always append a new line to the message */
172   (void)vsnprintf(buf, sizeof(buf) - 2, format, ap);
173   (void)fprintf(stderr, "%s\n", buf);
174   va_end(ap);
175 }
176 
openlog(const char * __ident UNUSED,int __option UNUSED,int __facility UNUSED)177 void openlog (const char *__ident UNUSED, int __option UNUSED, int __facility UNUSED)
178 {
179   (void)fprintf(stderr, "Warning openlog() not available\n");
180 }
181 
closelog(void)182 void closelog (void)
183 {
184 }
185 #endif /* !HAVE_SYSLOG_H */
186 
187 /* End of syslog section */
188 
189 /*
190  * Provide BSD strlcat()/strlcpy() on platforms that don't have it
191  *
192  * These versions use memcpy and strlen() because they are often
193  * heavily optimized down to assembler level. Thus, likely to be
194  * faster even with the function call overhead.
195  */
196 
197 #ifndef HAVE_STRLCAT
198 
199 #include <string.h>
200 
201 /*
202  * Appends src to string dst of size siz (unlike strncat, siz is the
203  * full size of dst, not space left).  At most siz-1 characters
204  * will be copied.  Always NUL terminates (unless siz <= strlen(dst)).
205  * Returns strlen(src) + MIN(siz, strlen(initial dst)).
206  * If retval >= siz, truncation occurred.
207  */
strlcat(char * dst,const char * src,size_t siz)208 size_t strlcat(char *dst, const char *src, size_t siz)
209 {
210     size_t slen = strlen(src);
211     size_t dlen = strlen(dst);
212     if (siz != 0) {
213 	if (dlen + slen < siz)
214 	    memcpy(dst + dlen, src, slen + 1);
215 	else {
216 	    memcpy(dst + dlen, src, siz - dlen - 1);
217 	    dst[siz - 1] = '\0';
218 	}
219     }
220     return dlen + slen;
221 }
222 
223 #ifdef __UNUSED__
224 /*	$OpenBSD: strlcat.c,v 1.13 2005/08/08 08:05:37 espie Exp $	*/
225 
226 /*
227  * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
228  *
229  * Permission to use, copy, modify, and distribute this software for any
230  * purpose with or without fee is hereby granted, provided that the above
231  * copyright notice and this permission notice appear in all copies.
232  *
233  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
234  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
235  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
236  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
237  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
238  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
239  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
240  */
241 
strlcat(char * dst,const char * src,size_t siz)242 size_t strlcat(char *dst, const char *src, size_t siz)
243 {
244     char *d = dst;
245     const char *s = src;
246     size_t n = siz;
247     size_t dlen;
248 
249     /* Find the end of dst and adjust bytes left but don't go past end */
250     while (n-- != 0 && *d != '\0')
251 	d++;
252     dlen = (size_t) (d - dst);
253     n = siz - dlen;
254 
255     if (n == 0)
256 	return (dlen + strlen(s));
257     while (*s != '\0') {
258 	if (n != 1) {
259 	    *d++ = *s;
260 	    n--;
261 	}
262 	s++;
263     }
264     *d = '\0';
265 
266     return (dlen + (s - src));	/* count does not include NUL */
267 }
268 #endif /* __UNUSED__ */
269 #endif /* !HAVE_STRLCAT */
270 
271 #ifndef HAVE_STRLCPY
272 
273 #include <string.h>
274 
275 /*
276  * Copy src to string dst of size siz.  At most siz-1 characters
277  * will be copied.  Always NUL terminates (unless siz == 0).
278  * Returns strlen(src); if retval >= siz, truncation occurred.
279  */
strlcpy(char * dst,const char * src,size_t siz)280 size_t strlcpy(char *dst, const char *src, size_t siz)
281 {
282     size_t len = strlen(src);
283     if (siz != 0) {
284 	if (len >= siz) {
285 	    memcpy(dst, src, siz - 1);
286 	    dst[siz - 1] = '\0';
287 	} else
288 	    memcpy(dst, src, len + 1);
289     }
290     return len;
291 }
292 
293 #endif /* !HAVE_STRLCPY */
294 
295 /* End of strlcat()/strlcpy() section */
296 
297 /*
298  * Provide sincos() on platforms that don't have it.
299  * This just uses the usual sin() and cos(), with no speed benefit.
300  * It doesn't worry about the corner case where the +-infinity argument
301  * may raise the "invalid" exception before storing both NaN results.
302  */
303 
304 #ifndef HAVE_SINCOS
305 
306 #include <math.h>
307 
sincos(double x,double * sinp,double * cosp)308 void sincos(double x, double *sinp, double *cosp)
309 {
310     *sinp = sin(x);
311     *cosp = cos(x);
312 }
313 
314 #endif /* !HAVE_SINCOS */
315 
316 /* End of sincos() section. */
317