• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * dhcpcd - DHCP client daemon
3  * Copyright 2006-2008 Roy Marples <roy@marples.name>
4  * All rights reserved
5 
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  */
27 
28 #ifdef __APPLE__
29 #  include <mach/mach_time.h>
30 #  include <mach/kern_return.h>
31 #endif
32 
33 #include <sys/param.h>
34 #include <sys/time.h>
35 
36 #include <errno.h>
37 #include <fcntl.h>
38 #ifdef BSD
39 #  include <paths.h>
40 #endif
41 #include <stdint.h>
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <string.h>
45 #include <time.h>
46 #include <unistd.h>
47 
48 #include "common.h"
49 #include "logger.h"
50 
51 #ifndef _PATH_DEVNULL
52 #  define _PATH_DEVNULL "/dev/null"
53 #endif
54 
55 int clock_monotonic = 0;
56 
57 /* Handy routine to read very long lines in text files.
58  * This means we read the whole line and avoid any nasty buffer overflows. */
59 ssize_t
get_line(char ** line,size_t * len,FILE * fp)60 get_line(char **line, size_t *len, FILE *fp)
61 {
62 	char *p;
63 	size_t last = 0;
64 
65 	while(!feof(fp)) {
66 		if (*line == NULL || last != 0) {
67 			*len += BUFSIZ;
68 			*line = xrealloc(*line, *len);
69 		}
70 		p = *line + last;
71 		memset(p, 0, BUFSIZ);
72 		fgets(p, BUFSIZ, fp);
73 		last += strlen(p);
74 		if (last && (*line)[last - 1] == '\n') {
75 			(*line)[last - 1] = '\0';
76 			break;
77 		}
78 	}
79 	return last;
80 }
81 
82 /* Simple hack to return a random number without arc4random */
83 #ifndef HAVE_ARC4RANDOM
arc4random(void)84 uint32_t arc4random(void)
85 {
86 	int fd;
87 	static unsigned long seed = 0;
88 
89 	if (!seed) {
90 		fd = open("/dev/urandom", 0);
91 		if (fd == -1 || read(fd,  &seed, sizeof(seed)) == -1)
92 			seed = time(0);
93 		if (fd >= 0)
94 			close(fd);
95 		srandom(seed);
96 	}
97 
98 	return (uint32_t)random();
99 }
100 #endif
101 
102 /* strlcpy is nice, shame glibc does not define it */
103 #if HAVE_STRLCPY
104 #else
105 size_t
strlcpy(char * dst,const char * src,size_t size)106 strlcpy(char *dst, const char *src, size_t size)
107 {
108 	const char *s = src;
109 	size_t n = size;
110 
111 	if (n && --n)
112 		do {
113 			if (!(*dst++ = *src++))
114 				break;
115 		} while (--n);
116 
117 	if (!n) {
118 		if (size)
119 			*dst = '\0';
120 		while (*src++);
121 	}
122 
123 	return src - s - 1;
124 }
125 #endif
126 
127 #if HAVE_CLOSEFROM
128 #else
129 int
closefrom(int fd)130 closefrom(int fd)
131 {
132 	int max = getdtablesize();
133 	int i;
134 	int r = 0;
135 
136 	for (i = fd; i < max; i++)
137 		r += close(i);
138 	return r;
139 }
140 #endif
141 
142 /* Close our fd's */
143 int
close_fds(void)144 close_fds(void)
145 {
146 	int fd;
147 
148 	if ((fd = open(_PATH_DEVNULL, O_RDWR)) == -1)
149 		return -1;
150 
151 	dup2(fd, fileno(stdin));
152 	dup2(fd, fileno(stdout));
153 	dup2(fd, fileno(stderr));
154 	if (fd > 2)
155 		close(fd);
156 	return 0;
157 }
158 
159 int
set_cloexec(int fd)160 set_cloexec(int fd)
161 {
162 	int flags;
163 
164 	if ((flags = fcntl(fd, F_GETFD, 0)) == -1
165 	    || fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1)
166 	{
167 		logger(LOG_ERR, "fcntl: %s", strerror(errno));
168 		return -1;
169 	}
170 	return 0;
171 }
172 
173 int
set_nonblock(int fd)174 set_nonblock(int fd)
175 {
176 	int flags;
177 
178 	if ((flags = fcntl(fd, F_GETFL, 0)) == -1
179 	    || fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1)
180 	{
181 		logger(LOG_ERR, "fcntl: %s", strerror(errno));
182 		return -1;
183 	}
184 	return 0;
185 }
186 
187 /* Handy function to get the time.
188  * We only care about time advancements, not the actual time itself
189  * Which is why we use CLOCK_MONOTONIC, but it is not available on all
190  * platforms.
191  */
192 #define NO_MONOTONIC "host does not support a monotonic clock - timing can skew"
193 int
get_monotonic(struct timeval * tp)194 get_monotonic(struct timeval *tp)
195 {
196 	static int posix_clock_set = 0;
197 #if defined(_POSIX_MONOTONIC_CLOCK) && defined(CLOCK_MONOTONIC)
198 	struct timespec ts;
199 	static clockid_t posix_clock;
200 
201 	if (posix_clock_set == 0) {
202 		if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) {
203 			posix_clock = CLOCK_MONOTONIC;
204 			clock_monotonic = 1;
205 		}
206 		posix_clock_set = 1;
207 	}
208 
209 	if (clock_monotonic) {
210 		if (clock_gettime(posix_clock, &ts) == 0) {
211 			tp->tv_sec = ts.tv_sec;
212 			tp->tv_usec = ts.tv_nsec / 1000;
213 			return 0;
214 		}
215 	}
216 #elif defined(__APPLE__)
217 #define NSEC_PER_SEC 1000000000
218 	/* We can use mach kernel functions here.
219 	 * This is crap though - why can't they implement clock_gettime?*/
220 	static struct mach_timebase_info info = { 0, 0 };
221 	static double factor = 0.0;
222 	uint64_t nano;
223 	long rem;
224 
225 	if (posix_clock_set == 0) {
226 		if (mach_timebase_info(&info) == KERN_SUCCESS) {
227 			factor = (double)info.numer / (double)info.denom;
228 			clock_monotonic = 1;
229 		}
230 		posix_clock_set = 1;
231 	}
232 	if (clock_monotonic) {
233 		nano = mach_absolute_time();
234 		if ((info.denom != 1 || info.numer != 1) && factor != 0.0)
235 			nano *= factor;
236 		tp->tv_sec = nano / NSEC_PER_SEC;
237 		rem = nano % NSEC_PER_SEC;
238 		if (rem < 0) {
239 			tp->tv_sec--;
240 			rem += NSEC_PER_SEC;
241 		}
242 		tp->tv_usec = rem / 1000;
243 		return 0;
244 	}
245 #endif
246 
247 	/* Something above failed, so fall back to gettimeofday */
248 	if (!posix_clock_set) {
249 		logger(LOG_WARNING, NO_MONOTONIC);
250 		posix_clock_set = 1;
251 	}
252 	return gettimeofday(tp, NULL);
253 }
254 
255 time_t
uptime(void)256 uptime(void)
257 {
258 	struct timeval tv;
259 
260 	if (get_monotonic(&tv) == -1)
261 		return -1;
262 	return tv.tv_sec;
263 }
264 
265 int
writepid(int fd,pid_t pid)266 writepid(int fd, pid_t pid)
267 {
268 	char spid[16];
269 	ssize_t len;
270 
271 	if (ftruncate(fd, (off_t)0) == -1)
272 		return -1;
273 	snprintf(spid, sizeof(spid), "%u\n", pid);
274 	len = pwrite(fd, spid, strlen(spid), (off_t)0);
275 	if (len != (ssize_t)strlen(spid))
276 		return -1;
277 	return 0;
278 }
279 
280 void *
xmalloc(size_t s)281 xmalloc(size_t s)
282 {
283 	void *value = malloc(s);
284 
285 	if (value)
286 		return value;
287 	logger(LOG_ERR, "memory exhausted");
288 	exit (EXIT_FAILURE);
289 	/* NOTREACHED */
290 }
291 
292 void *
xzalloc(size_t s)293 xzalloc(size_t s)
294 {
295 	void *value = xmalloc(s);
296 
297 	memset(value, 0, s);
298 	return value;
299 }
300 
301 void *
xrealloc(void * ptr,size_t s)302 xrealloc(void *ptr, size_t s)
303 {
304 	void *value = realloc(ptr, s);
305 
306 	if (value)
307 		return (value);
308 	logger(LOG_ERR, "memory exhausted");
309 	exit(EXIT_FAILURE);
310 	/* NOTREACHED */
311 }
312 
313 char *
xstrdup(const char * str)314 xstrdup(const char *str)
315 {
316 	char *value;
317 
318 	if (!str)
319 		return NULL;
320 
321 	if ((value = strdup(str)))
322 		return value;
323 
324 	logger(LOG_ERR, "memory exhausted");
325 	exit(EXIT_FAILURE);
326 	/* NOTREACHED */
327 }
328