/* * dhcpcd - DHCP client daemon * Copyright 2006-2008 Roy Marples <roy@marples.name> * All rights reserved * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifdef __APPLE__ # include <mach/mach_time.h> # include <mach/kern_return.h> #endif #include <sys/param.h> #include <sys/time.h> #include <errno.h> #include <fcntl.h> #ifdef BSD # include <paths.h> #endif #include <stdint.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h> #include <unistd.h> #include "common.h" #include "logger.h" #ifndef _PATH_DEVNULL # define _PATH_DEVNULL "/dev/null" #endif int clock_monotonic = 0; /* Handy routine to read very long lines in text files. * This means we read the whole line and avoid any nasty buffer overflows. */ ssize_t get_line(char **line, size_t *len, FILE *fp) { char *p; size_t last = 0; while(!feof(fp)) { if (*line == NULL || last != 0) { *len += BUFSIZ; *line = xrealloc(*line, *len); } p = *line + last; memset(p, 0, BUFSIZ); fgets(p, BUFSIZ, fp); last += strlen(p); if (last && (*line)[last - 1] == '\n') { (*line)[last - 1] = '\0'; break; } } return last; } /* Simple hack to return a random number without arc4random */ #ifndef HAVE_ARC4RANDOM uint32_t arc4random(void) { int fd; static unsigned long seed = 0; if (!seed) { fd = open("/dev/urandom", 0); if (fd == -1 || read(fd, &seed, sizeof(seed)) == -1) seed = time(0); if (fd >= 0) close(fd); srandom(seed); } return (uint32_t)random(); } #endif /* strlcpy is nice, shame glibc does not define it */ #if HAVE_STRLCPY #else size_t strlcpy(char *dst, const char *src, size_t size) { const char *s = src; size_t n = size; if (n && --n) do { if (!(*dst++ = *src++)) break; } while (--n); if (!n) { if (size) *dst = '\0'; while (*src++); } return src - s - 1; } #endif #if HAVE_CLOSEFROM #else int closefrom(int fd) { int max = getdtablesize(); int i; int r = 0; for (i = fd; i < max; i++) r += close(i); return r; } #endif /* Close our fd's */ int close_fds(void) { int fd; if ((fd = open(_PATH_DEVNULL, O_RDWR)) == -1) return -1; dup2(fd, fileno(stdin)); dup2(fd, fileno(stdout)); dup2(fd, fileno(stderr)); if (fd > 2) close(fd); return 0; } int set_cloexec(int fd) { int flags; if ((flags = fcntl(fd, F_GETFD, 0)) == -1 || fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1) { logger(LOG_ERR, "fcntl: %s", strerror(errno)); return -1; } return 0; } int set_nonblock(int fd) { int flags; if ((flags = fcntl(fd, F_GETFL, 0)) == -1 || fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) { logger(LOG_ERR, "fcntl: %s", strerror(errno)); return -1; } return 0; } /* Handy function to get the time. * We only care about time advancements, not the actual time itself * Which is why we use CLOCK_MONOTONIC, but it is not available on all * platforms. */ #define NO_MONOTONIC "host does not support a monotonic clock - timing can skew" int get_monotonic(struct timeval *tp) { static int posix_clock_set = 0; #if defined(_POSIX_MONOTONIC_CLOCK) && defined(CLOCK_MONOTONIC) struct timespec ts; static clockid_t posix_clock; if (posix_clock_set == 0) { if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) { posix_clock = CLOCK_MONOTONIC; clock_monotonic = 1; } posix_clock_set = 1; } if (clock_monotonic) { if (clock_gettime(posix_clock, &ts) == 0) { tp->tv_sec = ts.tv_sec; tp->tv_usec = ts.tv_nsec / 1000; return 0; } } #elif defined(__APPLE__) #define NSEC_PER_SEC 1000000000 /* We can use mach kernel functions here. * This is crap though - why can't they implement clock_gettime?*/ static struct mach_timebase_info info = { 0, 0 }; static double factor = 0.0; uint64_t nano; long rem; if (posix_clock_set == 0) { if (mach_timebase_info(&info) == KERN_SUCCESS) { factor = (double)info.numer / (double)info.denom; clock_monotonic = 1; } posix_clock_set = 1; } if (clock_monotonic) { nano = mach_absolute_time(); if ((info.denom != 1 || info.numer != 1) && factor != 0.0) nano *= factor; tp->tv_sec = nano / NSEC_PER_SEC; rem = nano % NSEC_PER_SEC; if (rem < 0) { tp->tv_sec--; rem += NSEC_PER_SEC; } tp->tv_usec = rem / 1000; return 0; } #endif /* Something above failed, so fall back to gettimeofday */ if (!posix_clock_set) { logger(LOG_WARNING, NO_MONOTONIC); posix_clock_set = 1; } return gettimeofday(tp, NULL); } time_t uptime(void) { struct timeval tv; if (get_monotonic(&tv) == -1) return -1; return tv.tv_sec; } int writepid(int fd, pid_t pid) { char spid[16]; ssize_t len; if (ftruncate(fd, (off_t)0) == -1) return -1; snprintf(spid, sizeof(spid), "%u\n", pid); len = pwrite(fd, spid, strlen(spid), (off_t)0); if (len != (ssize_t)strlen(spid)) return -1; return 0; } void * xmalloc(size_t s) { void *value = malloc(s); if (value) return value; logger(LOG_ERR, "memory exhausted"); exit (EXIT_FAILURE); /* NOTREACHED */ } void * xzalloc(size_t s) { void *value = xmalloc(s); memset(value, 0, s); return value; } void * xrealloc(void *ptr, size_t s) { void *value = realloc(ptr, s); if (value) return (value); logger(LOG_ERR, "memory exhausted"); exit(EXIT_FAILURE); /* NOTREACHED */ } char * xstrdup(const char *str) { char *value; if (!str) return NULL; if ((value = strdup(str))) return value; logger(LOG_ERR, "memory exhausted"); exit(EXIT_FAILURE); /* NOTREACHED */ }