Home | History | Annotate | Download | only in dhcpcd
      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