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