diff options
Diffstat (limited to 'dhcpcd/common.c')
-rw-r--r-- | dhcpcd/common.c | 279 |
1 files changed, 279 insertions, 0 deletions
diff --git a/dhcpcd/common.c b/dhcpcd/common.c new file mode 100644 index 00000000..4bf52bad --- /dev/null +++ b/dhcpcd/common.c @@ -0,0 +1,279 @@ +/* + * dhcpcd - DHCP client daemon + * Copyright (c) 2006-2012 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. + */ + +/* Needed define to get at getline for glibc and FreeBSD */ +#ifndef _GNU_SOURCE +# define _GNU_SOURCE +#endif + +#include <sys/cdefs.h> + +#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> +#include <limits.h> +#ifdef BSD +# include <paths.h> +#endif +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <syslog.h> +#include <time.h> +#include <unistd.h> + +#include "common.h" + +#ifndef _PATH_DEVNULL +# define _PATH_DEVNULL "/dev/null" +#endif + +static char hostname_buffer[HOSTNAME_MAX_LEN + 1]; +int clock_monotonic; +static char *lbuf; +static size_t lbuf_len; +#ifdef DEBUG_MEMORY +static char lbuf_set; +#endif + +#ifdef DEBUG_MEMORY +static void +free_lbuf(void) +{ + free(lbuf); + lbuf = NULL; +} +#endif + +/* Handy routine to read very long lines in text files. + * This means we read the whole line and avoid any nasty buffer overflows. + * We strip leading space and avoid comment lines, making the code that calls + * us smaller. + * As we don't use threads, this API is clean too. */ +char * +get_line(FILE * __restrict fp) +{ + char *p; + ssize_t bytes; + +#ifdef DEBUG_MEMORY + if (lbuf_set == 0) { + atexit(free_lbuf); + lbuf_set = 1; + } +#endif + + do { + bytes = getline(&lbuf, &lbuf_len, fp); + if (bytes == -1) + return NULL; + for (p = lbuf; *p == ' ' || *p == '\t'; p++) + ; + } while (*p == '\0' || *p == '\n' || *p == '#' || *p == ';'); + if (lbuf[--bytes] == '\n') + lbuf[bytes] = '\0'; + return p; +} + +int +set_cloexec(int fd) +{ + int flags; + + if ((flags = fcntl(fd, F_GETFD, 0)) == -1 || + fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1) + { + syslog(LOG_ERR, "fcntl: %m"); + 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) + { + syslog(LOG_ERR, "fcntl: %m"); + return -1; + } + return 0; +} + +const char * +get_hostname(int short_hostname) +{ + char *p; + + gethostname(hostname_buffer, sizeof(hostname_buffer)); + hostname_buffer[sizeof(hostname_buffer) - 1] = '\0'; + if (strcmp(hostname_buffer, "(none)") == 0 || + strcmp(hostname_buffer, "localhost") == 0 || + strncmp(hostname_buffer, "localhost.", strlen("localhost.")) == 0 || + hostname_buffer[0] == '.') + return NULL; + + if (short_hostname) { + p = strchr(hostname_buffer, '.'); + if (p) + *p = '\0'; + } + + return hostname_buffer; +} + +/* 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) { + if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) { + posix_clock = CLOCK_MONOTONIC; + clock_monotonic = 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) { + if (mach_timebase_info(&info) == KERN_SUCCESS) { + factor = (double)info.numer / (double)info.denom; + clock_monotonic = 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) { + syslog(LOG_WARNING, NO_MONOTONIC); + posix_clock_set = 1; + } + return gettimeofday(tp, NULL); +} + +ssize_t +setvar(char ***e, const char *prefix, const char *var, const char *value) +{ + size_t len = strlen(var) + strlen(value) + 3; + + if (prefix) + len += strlen(prefix) + 1; + **e = malloc(len); + if (**e == NULL) { + syslog(LOG_ERR, "%s: %m", __func__); + return -1; + } + if (prefix) + snprintf(**e, len, "%s_%s=%s", prefix, var, value); + else + snprintf(**e, len, "%s=%s", var, value); + (*e)++; + return len; +} + +ssize_t +setvard(char ***e, const char *prefix, const char *var, int value) +{ + char buffer[32]; + + snprintf(buffer, sizeof(buffer), "%d", value); + return setvar(e, prefix, var, buffer); +} + + +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; +} |