Home | History | Annotate | Download | only in dhcpcd
      1 /*
      2  * dhcpcd - DHCP client daemon
      3  * Copyright 2006-2008 Roy Marples <roy (at) 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
     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 		if (fgets(p, BUFSIZ, fp) == NULL)
     73 			break;
     74 		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
     85 uint32_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
    106 size_t
    107 strlcpy(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
    130 int
    131 closefrom(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 */
    144 int
    145 close_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 
    160 int
    161 set_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 
    174 int
    175 set_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"
    194 int
    195 get_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;
    205 			clock_monotonic = posix_clock_set = 1;
    206 		}
    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 = posix_clock_set = 1;
    229 		}
    230 	}
    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 
    254 time_t
    255 uptime(void)
    256 {
    257 	struct timeval tv;
    258 
    259 	if (get_monotonic(&tv) == -1)
    260 		return -1;
    261 	return tv.tv_sec;
    262 }
    263 
    264 int
    265 writepid(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 
    279 void *
    280 xmalloc(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 
    291 void *
    292 xzalloc(size_t s)
    293 {
    294 	void *value = xmalloc(s);
    295 
    296 	memset(value, 0, s);
    297 	return value;
    298 }
    299 
    300 void *
    301 xrealloc(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 
    312 char *
    313 xstrdup(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 }
    327