| /* |
| * 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 */ |
| } |