1/* 2 * dhcpcd - DHCP client daemon 3 * Copyright (c) 2006-2012 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/* Needed define to get at getline for glibc and FreeBSD */ 29#ifndef _GNU_SOURCE 30# define _GNU_SOURCE 31#endif 32 33#include <sys/cdefs.h> 34 35#ifdef __APPLE__ 36# include <mach/mach_time.h> 37# include <mach/kern_return.h> 38#endif 39 40#include <sys/param.h> 41#include <sys/time.h> 42 43#include <errno.h> 44#include <fcntl.h> 45#include <limits.h> 46#ifdef BSD 47# include <paths.h> 48#endif 49#include <stdint.h> 50#include <stdio.h> 51#include <stdlib.h> 52#include <string.h> 53#include <syslog.h> 54#include <time.h> 55#include <unistd.h> 56 57#include "common.h" 58 59#ifndef _PATH_DEVNULL 60# define _PATH_DEVNULL "/dev/null" 61#endif 62 63int clock_monotonic; 64static char *lbuf; 65static size_t lbuf_len; 66#ifdef DEBUG_MEMORY 67static char lbuf_set; 68#endif 69 70#ifdef DEBUG_MEMORY 71static void 72free_lbuf(void) 73{ 74 free(lbuf); 75 lbuf = NULL; 76} 77#endif 78 79/* Handy routine to read very long lines in text files. 80 * This means we read the whole line and avoid any nasty buffer overflows. 81 * We strip leading space and avoid comment lines, making the code that calls 82 * us smaller. 83 * As we don't use threads, this API is clean too. */ 84char * 85get_line(FILE * __restrict fp) 86{ 87 char *p; 88 ssize_t bytes; 89 90#ifdef DEBUG_MEMORY 91 if (lbuf_set == 0) { 92 atexit(free_lbuf); 93 lbuf_set = 1; 94 } 95#endif 96 97 do { 98 bytes = getline(&lbuf, &lbuf_len, fp); 99 if (bytes == -1) 100 return NULL; 101 for (p = lbuf; *p == ' ' || *p == '\t'; p++) 102 ; 103 } while (*p == '\0' || *p == '\n' || *p == '#' || *p == ';'); 104 if (lbuf[--bytes] == '\n') 105 lbuf[bytes] = '\0'; 106 return p; 107} 108 109int 110set_cloexec(int fd) 111{ 112 int flags; 113 114 if ((flags = fcntl(fd, F_GETFD, 0)) == -1 || 115 fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1) 116 { 117 syslog(LOG_ERR, "fcntl: %m"); 118 return -1; 119 } 120 return 0; 121} 122 123int 124set_nonblock(int fd) 125{ 126 int flags; 127 128 if ((flags = fcntl(fd, F_GETFL, 0)) == -1 || 129 fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) 130 { 131 syslog(LOG_ERR, "fcntl: %m"); 132 return -1; 133 } 134 return 0; 135} 136 137/* Handy function to get the time. 138 * We only care about time advancements, not the actual time itself 139 * Which is why we use CLOCK_MONOTONIC, but it is not available on all 140 * platforms. 141 */ 142#define NO_MONOTONIC "host does not support a monotonic clock - timing can skew" 143int 144get_monotonic(struct timeval *tp) 145{ 146 static int posix_clock_set = 0; 147#if defined(_POSIX_MONOTONIC_CLOCK) && defined(CLOCK_MONOTONIC) 148 struct timespec ts; 149 static clockid_t posix_clock; 150 151 if (!posix_clock_set) { 152 if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) { 153 posix_clock = CLOCK_MONOTONIC; 154 clock_monotonic = posix_clock_set = 1; 155 } 156 } 157 158 if (clock_monotonic) { 159 if (clock_gettime(posix_clock, &ts) == 0) { 160 tp->tv_sec = ts.tv_sec; 161 tp->tv_usec = ts.tv_nsec / 1000; 162 return 0; 163 } 164 } 165#elif defined(__APPLE__) 166#define NSEC_PER_SEC 1000000000 167 /* We can use mach kernel functions here. 168 * This is crap though - why can't they implement clock_gettime?*/ 169 static struct mach_timebase_info info = { 0, 0 }; 170 static double factor = 0.0; 171 uint64_t nano; 172 long rem; 173 174 if (!posix_clock_set) { 175 if (mach_timebase_info(&info) == KERN_SUCCESS) { 176 factor = (double)info.numer / (double)info.denom; 177 clock_monotonic = posix_clock_set = 1; 178 } 179 } 180 if (clock_monotonic) { 181 nano = mach_absolute_time(); 182 if ((info.denom != 1 || info.numer != 1) && factor != 0.0) 183 nano *= factor; 184 tp->tv_sec = nano / NSEC_PER_SEC; 185 rem = nano % NSEC_PER_SEC; 186 if (rem < 0) { 187 tp->tv_sec--; 188 rem += NSEC_PER_SEC; 189 } 190 tp->tv_usec = rem / 1000; 191 return 0; 192 } 193#endif 194 195 /* Something above failed, so fall back to gettimeofday */ 196 if (!posix_clock_set) { 197 syslog(LOG_WARNING, NO_MONOTONIC); 198 posix_clock_set = 1; 199 } 200 return gettimeofday(tp, NULL); 201} 202 203ssize_t 204setvar(char ***e, const char *prefix, const char *var, const char *value) 205{ 206 size_t len = strlen(var) + strlen(value) + 3; 207 208 if (prefix) 209 len += strlen(prefix) + 1; 210 **e = xmalloc(len); 211 if (prefix) 212 snprintf(**e, len, "%s_%s=%s", prefix, var, value); 213 else 214 snprintf(**e, len, "%s=%s", var, value); 215 (*e)++; 216 return len; 217} 218 219ssize_t 220setvard(char ***e, const char *prefix, const char *var, int value) 221{ 222 char buffer[32]; 223 224 snprintf(buffer, sizeof(buffer), "%d", value); 225 return setvar(e, prefix, var, buffer); 226} 227 228 229time_t 230uptime(void) 231{ 232 struct timeval tv; 233 234 if (get_monotonic(&tv) == -1) 235 return -1; 236 return tv.tv_sec; 237} 238 239int 240writepid(int fd, pid_t pid) 241{ 242 char spid[16]; 243 ssize_t len; 244 245 if (ftruncate(fd, (off_t)0) == -1) 246 return -1; 247 snprintf(spid, sizeof(spid), "%u\n", pid); 248 len = pwrite(fd, spid, strlen(spid), (off_t)0); 249 if (len != (ssize_t)strlen(spid)) 250 return -1; 251 return 0; 252} 253 254void * 255xmalloc(size_t s) 256{ 257 void *value = malloc(s); 258 259 if (value != NULL) 260 return value; 261 syslog(LOG_ERR, "memory exhausted (xalloc %zu bytes)", s); 262 exit (EXIT_FAILURE); 263 /* NOTREACHED */ 264} 265 266void * 267xzalloc(size_t s) 268{ 269 void *value = xmalloc(s); 270 271 memset(value, 0, s); 272 return value; 273} 274 275void * 276xrealloc(void *ptr, size_t s) 277{ 278 void *value = realloc(ptr, s); 279 280 if (value != NULL) 281 return value; 282 syslog(LOG_ERR, "memory exhausted (xrealloc %zu bytes)", s); 283 exit(EXIT_FAILURE); 284 /* NOTREACHED */ 285} 286 287char * 288xstrdup(const char *str) 289{ 290 char *value; 291 292 if (str == NULL) 293 return NULL; 294 295 if ((value = strdup(str)) != NULL) 296 return value; 297 298 syslog(LOG_ERR, "memory exhausted (xstrdup)"); 299 exit(EXIT_FAILURE); 300 /* NOTREACHED */ 301} 302