1 /* 2 * dhcpcd - DHCP client daemon 3 * Copyright (c) 2006-2012 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 /* 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 63 int clock_monotonic; 64 static char *lbuf; 65 static size_t lbuf_len; 66 #ifdef DEBUG_MEMORY 67 static char lbuf_set; 68 #endif 69 70 #ifdef DEBUG_MEMORY 71 static void 72 free_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. */ 84 char * 85 get_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 109 int 110 set_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 123 int 124 set_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" 143 int 144 get_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 203 ssize_t 204 setvar(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 219 ssize_t 220 setvard(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 229 time_t 230 uptime(void) 231 { 232 struct timeval tv; 233 234 if (get_monotonic(&tv) == -1) 235 return -1; 236 return tv.tv_sec; 237 } 238 239 int 240 writepid(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 254 void * 255 xmalloc(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 266 void * 267 xzalloc(size_t s) 268 { 269 void *value = xmalloc(s); 270 271 memset(value, 0, s); 272 return value; 273 } 274 275 void * 276 xrealloc(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 287 char * 288 xstrdup(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