blob: da22a5cd59529ec44782190dfa27d0bcc37059ca [file] [log] [blame]
The Android Open Source Projectf7c54212009-03-03 19:29:22 -08001/*
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
55int 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. */
59ssize_t
60get_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);
Dmitry Shmidt938bc382010-01-08 10:47:26 -080072 if (fgets(p, BUFSIZ, fp) == NULL)
73 break;
The Android Open Source Projectf7c54212009-03-03 19:29:22 -080074 last += strlen(p);
75 if (last && (*line)[last - 1] == '\n') {
76 (*line)[last - 1] = '\0';
77 break;
78 }
79 }
80 return last;
81}
82
83/* Simple hack to return a random number without arc4random */
84#ifndef HAVE_ARC4RANDOM
85uint32_t arc4random(void)
86{
87 int fd;
88 static unsigned long seed = 0;
89
90 if (!seed) {
91 fd = open("/dev/urandom", 0);
92 if (fd == -1 || read(fd, &seed, sizeof(seed)) == -1)
93 seed = time(0);
94 if (fd >= 0)
95 close(fd);
96 srandom(seed);
97 }
98
99 return (uint32_t)random();
100}
101#endif
102
103/* strlcpy is nice, shame glibc does not define it */
104#if HAVE_STRLCPY
105#else
106size_t
107strlcpy(char *dst, const char *src, size_t size)
108{
109 const char *s = src;
110 size_t n = size;
111
112 if (n && --n)
113 do {
114 if (!(*dst++ = *src++))
115 break;
116 } while (--n);
117
118 if (!n) {
119 if (size)
120 *dst = '\0';
121 while (*src++);
122 }
123
124 return src - s - 1;
125}
126#endif
127
128#if HAVE_CLOSEFROM
129#else
130int
131closefrom(int fd)
132{
133 int max = getdtablesize();
134 int i;
135 int r = 0;
136
137 for (i = fd; i < max; i++)
138 r += close(i);
139 return r;
140}
141#endif
142
143/* Close our fd's */
144int
145close_fds(void)
146{
147 int fd;
148
149 if ((fd = open(_PATH_DEVNULL, O_RDWR)) == -1)
150 return -1;
151
152 dup2(fd, fileno(stdin));
153 dup2(fd, fileno(stdout));
154 dup2(fd, fileno(stderr));
155 if (fd > 2)
156 close(fd);
157 return 0;
158}
159
160int
161set_cloexec(int fd)
162{
163 int flags;
164
165 if ((flags = fcntl(fd, F_GETFD, 0)) == -1
166 || fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1)
167 {
168 logger(LOG_ERR, "fcntl: %s", strerror(errno));
169 return -1;
170 }
171 return 0;
172}
173
174int
175set_nonblock(int fd)
176{
177 int flags;
178
179 if ((flags = fcntl(fd, F_GETFL, 0)) == -1
180 || fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1)
181 {
182 logger(LOG_ERR, "fcntl: %s", strerror(errno));
183 return -1;
184 }
185 return 0;
186}
187
188/* Handy function to get the time.
189 * We only care about time advancements, not the actual time itself
190 * Which is why we use CLOCK_MONOTONIC, but it is not available on all
191 * platforms.
192 */
193#define NO_MONOTONIC "host does not support a monotonic clock - timing can skew"
194int
195get_monotonic(struct timeval *tp)
196{
197 static int posix_clock_set = 0;
198#if defined(_POSIX_MONOTONIC_CLOCK) && defined(CLOCK_MONOTONIC)
199 struct timespec ts;
200 static clockid_t posix_clock;
201
202 if (posix_clock_set == 0) {
203 if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) {
204 posix_clock = CLOCK_MONOTONIC;
Dmitry Shmidt938bc382010-01-08 10:47:26 -0800205 clock_monotonic = posix_clock_set = 1;
The Android Open Source Projectf7c54212009-03-03 19:29:22 -0800206 }
The Android Open Source Projectf7c54212009-03-03 19:29:22 -0800207 }
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;
Dmitry Shmidt938bc382010-01-08 10:47:26 -0800228 clock_monotonic = posix_clock_set = 1;
The Android Open Source Projectf7c54212009-03-03 19:29:22 -0800229 }
The Android Open Source Projectf7c54212009-03-03 19:29:22 -0800230 }
231 if (clock_monotonic) {
232 nano = mach_absolute_time();
233 if ((info.denom != 1 || info.numer != 1) && factor != 0.0)
234 nano *= factor;
235 tp->tv_sec = nano / NSEC_PER_SEC;
236 rem = nano % NSEC_PER_SEC;
237 if (rem < 0) {
238 tp->tv_sec--;
239 rem += NSEC_PER_SEC;
240 }
241 tp->tv_usec = rem / 1000;
242 return 0;
243 }
244#endif
245
246 /* Something above failed, so fall back to gettimeofday */
247 if (!posix_clock_set) {
248 logger(LOG_WARNING, NO_MONOTONIC);
249 posix_clock_set = 1;
250 }
251 return gettimeofday(tp, NULL);
252}
253
254time_t
255uptime(void)
256{
257 struct timeval tv;
258
259 if (get_monotonic(&tv) == -1)
260 return -1;
261 return tv.tv_sec;
262}
263
264int
265writepid(int fd, pid_t pid)
266{
267 char spid[16];
268 ssize_t len;
269
270 if (ftruncate(fd, (off_t)0) == -1)
271 return -1;
272 snprintf(spid, sizeof(spid), "%u\n", pid);
273 len = pwrite(fd, spid, strlen(spid), (off_t)0);
274 if (len != (ssize_t)strlen(spid))
275 return -1;
276 return 0;
277}
278
279void *
280xmalloc(size_t s)
281{
282 void *value = malloc(s);
283
284 if (value)
285 return value;
286 logger(LOG_ERR, "memory exhausted");
287 exit (EXIT_FAILURE);
288 /* NOTREACHED */
289}
290
291void *
292xzalloc(size_t s)
293{
294 void *value = xmalloc(s);
295
296 memset(value, 0, s);
297 return value;
298}
299
300void *
301xrealloc(void *ptr, size_t s)
302{
303 void *value = realloc(ptr, s);
304
305 if (value)
306 return (value);
307 logger(LOG_ERR, "memory exhausted");
308 exit(EXIT_FAILURE);
309 /* NOTREACHED */
310}
311
312char *
313xstrdup(const char *str)
314{
315 char *value;
316
317 if (!str)
318 return NULL;
319
320 if ((value = strdup(str)))
321 return value;
322
323 logger(LOG_ERR, "memory exhausted");
324 exit(EXIT_FAILURE);
325 /* NOTREACHED */
326}