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