1 /* 2 * dhcpcd - DHCP client daemon 3 * Copyright 2006-2008 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 #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 55 int 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. */ 59 ssize_t 60 get_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 85 uint32_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 106 size_t 107 strlcpy(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 130 int 131 closefrom(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 */ 144 int 145 close_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 160 int 161 set_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 174 int 175 set_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" 194 int 195 get_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 254 time_t 255 uptime(void) 256 { 257 struct timeval tv; 258 259 if (get_monotonic(&tv) == -1) 260 return -1; 261 return tv.tv_sec; 262 } 263 264 int 265 writepid(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 279 void * 280 xmalloc(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 291 void * 292 xzalloc(size_t s) 293 { 294 void *value = xmalloc(s); 295 296 memset(value, 0, s); 297 return value; 298 } 299 300 void * 301 xrealloc(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 312 char * 313 xstrdup(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