From: Roy Marples Date: Tue, 4 Sep 2007 12:48:40 +0000 (+0000) Subject: Many thanks to Michael Durrant for testing the below changes. X-Git-Tag: v3.2.3~203 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=3e120d46a8dc084b5404f04cf98bf90cc0ba32cc;p=thirdparty%2Fdhcpcd.git Many thanks to Michael Durrant for testing the below changes. Compile and work on OSX/Darwin. If we have no fork then we re-exec ourselves with --daemonised. Improved the build system so we automatically detect if we need librt or libresolv and if fork() works or not. Move back to using librt for clock_gettime on Linux systems. --- diff --git a/ChangeLog b/ChangeLog index 29d009cb..ef958b2b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +Many thanks to Michael Durrant for testing the below changes. +Compile and work on OSX/Darwin. +If we have no fork then we re-exec ourselves with --daemonised. +Improved the build system so we automatically detect if we need +librt or libresolv and if fork() works or not. +Move back to using librt for clock_gettime on Linux systems. + dhcpcd-3.1.5 Fix the flushing of addresses on BSD systems. Rework get_time so that we don't link to librt on Linux. diff --git a/INSTALL b/INSTALL index c5687c15..272fedc1 100644 --- a/INSTALL +++ b/INSTALL @@ -3,8 +3,6 @@ Edit config.h to match your building requirements. Take special note of ENABLE_DUID and unset it if the target media is volatile, like say a LiveCD. -Darwin users should edit the Makefile and enable dhcpcd_LIBS = -lresolv - Then just make; make install man dhcpcd for command line options diff --git a/Makefile b/Makefile index 53b77e8f..56ede2b5 100644 --- a/Makefile +++ b/Makefile @@ -1,17 +1,71 @@ # Should work for both GNU make and BSD make -VERSION = 3.1.5 -CFLAGS ?= -O2 -pipe +# NOTE: I really don't like autotools, but we do need to work a few things out +# such as the need to link to libresolv and/or librt so please forgive the +# embedded code :) -# Saying that, this function only works with GNU Make :/ -check_gcc=$(shell if $(CC) $(1) -S -o /dev/null -xc /dev/null >/dev/null 2>&1; \ - then echo "$(1)"; else echo "$(2)"; fi) +VERSION = 3.1.6_pre6 +CFLAGS += -O2 -pipe + +INSTALL ?= install +DESTDIR = +SBINDIR = $(DESTDIR)/sbin +MANDIR = $(DESTDIR)/usr/share/man +LIBDIR = $(DESTDIR)/var/lib + +SBIN_TARGETS = dhcpcd +MAN8_TARGETS = dhcpcd.8 +TARGET = $(SBIN_TARGETS) -# Luckily we can do this more long winded thing with pmake used by the BSDs -WEXTRA != for x in -Wdeclaration-after-statement -Wsequence-point -Wextra ; do \ +# Work out if we need -lresolv or not +_LIBRESOLV_SH = printf '\#include \n\#include \nint main (void) { return (res_init ()); }\n' > .res_init.c; \ + if $(CC) .res_init.c -o .res_init >/dev/null 2>&1 ; then \ + echo ""; \ + elif $(CC) .res_init.c -lresolv -o .res_init >/dev/null 2>&1 ; then \ + echo "-lresolv"; \ + else \ + echo "Cannot work out how to get res_init to link" >&2; \ + exit 1; \ + fi; \ + rm -f .res_init.c .res_init +_LIBRESOLV != $(_LIBRESOLV_SH) +LIBRESOLV = $(_LIBRESOLV)$(shell $(_LIBRESOLV_SH)) + +# Work out if we need -lrt or not +_LIBRT_SH = printf '\#include \nint main (void) { struct timespec ts; return (clock_gettime (CLOCK_MONOTONIC, &ts)); }\n' > .clock_gettime.c; \ + if $(CC) .clock_gettime.c -o .clock_gettime >/dev/null 2>&1; then \ + echo ""; \ + elif $(CC) .clock_gettime.c -lrt -o .clock_gettime >/dev/null 2>&1 ; then \ + echo "-lrt"; \ + else \ + echo "Cannot work out how to get clock_gettime to link" >&2; \ + exit 1; \ + fi; \ + rm -f .clock_gettime.c .clock_gettime +_LIBRT != $(_LIBRT_SH) +LIBRT = $(_LIBRT)$(shell $(_LIBRT_SH)) + +# Work out if our fork() works or not +_HAVE_FORK_SH = printf '\#include \n\#include \nint main (void) { pid_t pid = fork(); if (pid == -1) exit (-1); exit (0); }\n' > .fork.c; \ + $(CC) .fork.c -o .fork >/dev/null 2>&1; \ + if ./.fork; then \ + echo ""; \ + else \ + echo "-DTHERE_IS_NO_FORK"; \ + fi; \ + rm -f .fork.c .fork +_HAVE_FORK != $(_HAVE_FORK_SH) +HAVE_FORK = $(_HAVE_FORK)$(shell $(_HAVE_FORK_SH)) + +# pmake check for extra cflags +WEXTRA != for x in -Wdeclaration-after-statement -Wsequence-point -Wextra; do \ if $(CC) -Wdeclaration-after-statement -S -o /dev/null -xc /dev/null >/dev/null 2>&1; \ then echo -n "$$x "; fi \ done +# gmake function for similar, but called below +check_gcc=$(shell if $(CC) $(1) -S -o /dev/null -xc /dev/null >/dev/null 2>&1; \ + then echo "$(1)"; else echo "$(2)"; fi) + # Loads of nice flags to ensure our code is good # IMPORTANT: We should be using c99 instead of gnu99 but for some reason # generic linux headers as of 2.6.19 don't allow this in asm/types.h @@ -28,36 +82,29 @@ CFLAGS += -pedantic -std=gnu99 \ # have buggy headers from time to time, so you may need to comment this out #CFLAGS += -Werror -# We define _BSD_SOURCE as GNU supports BSD too - which is nice :) -CDEFS = -D_BSD_SOURCE - -INSTALL ?= install -DESTDIR = -SBINDIR = $(DESTDIR)/sbin -MANDIR = $(DESTDIR)/usr/share/man -LIBDIR = $(DESTDIR)/var/lib - -SBIN_TARGETS = dhcpcd -MAN8_TARGETS = dhcpcd.8 -TARGET = $(SBIN_TARGETS) +all: $(TARGET) dhcpcd_H = version.h dhcpcd_OBJS = arp.o client.o common.o configure.o dhcp.o dhcpcd.o duid.o \ info.o interface.o ipv4ll.o logger.o signals.o socket.o -# Darwin needs this, but we have no way of detecting this atm -#LIBRESOLV = -lresolv +$(dhcpcd_OBJS): + $(CC) $(HAVE_FORK) $(CFLAGS) -c $*.c -dhcpcd: $(dhcpcd_H) $(dhcpcd_OBJS) - $(CC) $(LDFLAGS) $(dhcpcd_OBJS) $(LIBRESOLV) -o dhcpcd +dhcpcd: $(dhcpcd_H) .depend $(dhcpcd_OBJS) + $(CC) $(LDFLAGS) $(dhcpcd_OBJS) $(LIBRESOLV) $(LIBRT) -o dhcpcd version.h: echo '#define VERSION "$(VERSION)"' > version.h -$(dhcpcd_OBJS): - $(CC) $(CDEFS) $(CFLAGS) -c $*.c +.PHONY: clean install dist -all: $(TARGET) +# We always need to have a .depend file as not all make implentations can work +# with each others way of optionally including a file +clean: + echo > .depend + touch -r Makefile .depend + rm -f $(TARGET) $(dhcpcd_H) *.o *~ *.core *.bz2 install: $(TARGET) $(INSTALL) -m 0755 -d $(SBINDIR) @@ -66,9 +113,6 @@ install: $(TARGET) $(INSTALL) -m 0644 $(MAN8_TARGETS) $(MANDIR)/man8 $(INSTALL) -m 0755 -d $(LIBDIR) -clean: - rm -f $(TARGET) $(dhcpcd_H) *.o *~ *.core *.bz2 - dist: $(INSTALL) -m 0755 -d /tmp/dhcpcd-$(VERSION) cp -RPp . /tmp/dhcpcd-$(VERSION) @@ -77,3 +121,10 @@ dist: tar cvjpf dhcpcd-$(VERSION).tar.bz2 -C /tmp dhcpcd-$(VERSION) rm -rf /tmp/dhcpcd-$(VERSION) ls -l dhcpcd-$(VERSION).tar.bz2 + +# Sucky, but I cannot find a way of optional including the .depend file +# that works for all make implementations :/ +include .depend +_DEPS != ls *.c *.h +.depend: $(dhcpcd_H) $(_DEPS)$(wildcard *.c *.h) + $(CC) $(CPPFLAGS) -MM *.c > .depend diff --git a/client.c b/client.c index 656fc6de..0c17d838 100644 --- a/client.c +++ b/client.c @@ -19,7 +19,9 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + #ifdef __linux__ +# define _BSD_SOURCE # define _XOPEN_SOURCE 500 /* needed for pwrite */ #endif @@ -66,6 +68,12 @@ # include "info.h" #endif +#ifdef THERE_IS_NO_FORK +# ifndef ENABLE_INFO +# error "Non MMU requires ENABLE_INFO to work" +# endif +#endif + /* We need this for our maximum timeout as FreeBSD's select cannot handle any higher than this. Is there a better way of working this out? */ #define SELECT_MAX 100000000 @@ -104,40 +112,68 @@ } #define DROP_CONFIG { \ - if (! options->persistent) \ + if (! persistent) \ configure (options, iface, dhcp, false); \ free_dhcp (dhcp); \ memset (dhcp, 0, sizeof (dhcp_t)); \ } -static bool daemonise (int *pidfd) +static pid_t daemonise (int *pidfd) { - char pid[16]; + pid_t pid; + char spid[16]; +#ifndef THERE_IS_NO_FORK logger (LOG_DEBUG, "forking to background"); - - if (daemon (0, 0) == -1) { - logger (LOG_ERR, "daemon: %s", strerror (errno)); - return (false); + if ((pid = fork()) == -1) { + logger (LOG_ERR, "fork: %s", strerror (errno)); + exit (EXIT_FAILURE); } - if (ftruncate (*pidfd, 0) == -1) { - logger (LOG_ERR, "ftruncate: %s", strerror (errno)); - return (false); + setsid (); + close_fds (); +#else + char **argv; + int i; + + logger (LOG_INFO, "forking to background"); + + /* We need to add --daemonise to our options */ + argv = xmalloc (sizeof (char *) * (dhcpcd_argc + 2)); + for (i = 0; i < dhcpcd_argc; i++) + argv[i] = dhcpcd_argv[i]; + argv[i] = (char *) "--daemonised"; + argv[i + 1] = NULL; + + switch (pid = vfork ()) { + case -1: + logger (LOG_ERR, "vfork: %s", strerror (errno)); + _exit (EXIT_FAILURE); + case 0: + execvp (dhcpcd, argv); + logger (LOG_ERR, "execl `%s': %s", dhcpcd, strerror (errno)); + _exit (EXIT_FAILURE); } - snprintf (pid, sizeof (pid), "%u", getpid()); - if (pwrite (*pidfd, pid, strlen(pid), 0) != (ssize_t) strlen (pid)) { - logger (LOG_ERR, "pwrite: %s", strerror (errno)); - return (false); + free (argv); +#endif + + if (pid != 0) { + if (ftruncate (*pidfd, 0) == -1) { + logger (LOG_ERR, "ftruncate: %s", strerror (errno)); + } else { + snprintf (spid, sizeof (spid), "%u", pid); + if (pwrite (*pidfd, spid, strlen (spid), 0) != (ssize_t) strlen (spid)) + logger (LOG_ERR, "pwrite: %s", strerror (errno)); + } } - - return (true); + + return (pid); } #ifdef ENABLE_INFO static bool get_old_lease (const options_t *options, interface_t *iface, - dhcp_t *dhcp, long *timeout) + dhcp_t *dhcp, time_t *timeout) { struct timeval tv; unsigned int offset = 0; @@ -201,7 +237,7 @@ int dhcp_run (const options_t *options, int *pidfd) int state = STATE_INIT; struct timeval tv; int xid = 0; - long timeout = 0; + time_t timeout = 0; fd_set rset; int maxfd; int retval; @@ -209,9 +245,10 @@ int dhcp_run (const options_t *options, int *pidfd) dhcp_t *dhcp; int type = DHCP_DISCOVER; int last_type = DHCP_DISCOVER; - bool daemonised = false; - unsigned long start = 0; - unsigned long last_send = 0; + bool daemonised = options->daemonised; + bool persistent = options->persistent; + time_t start = 0; + time_t last_send = 0; int sig; unsigned char *buffer = NULL; int buffer_len = 0; @@ -234,7 +271,7 @@ int dhcp_run (const options_t *options, int *pidfd) memset (dhcp, 0, sizeof (dhcp_t)); if (options->request_address.s_addr == 0 && - (options->doinform || options->dorequest)) + (options->doinform || options->dorequest || options->daemonised)) { #ifdef ENABLE_INFO if (! get_old_lease (options, iface, dhcp, NULL)) @@ -243,6 +280,35 @@ int dhcp_run (const options_t *options, int *pidfd) free (dhcp); return (-1); } + +#ifdef THERE_IS_NO_FORK + if (options->daemonised) { + state = STATE_BOUND; + timeout = dhcp->renewaltime; + iface->previous_address = dhcp->address; + iface->previous_netmask = dhcp->netmask; + + /* FIXME: Some routes may not be added for whatever reason. + * This is especially true on BSD platforms where we can only + * have one default route. */ + if (dhcp->routes) { + route_t *droute; + route_t *iroute; + + free_route (iface->previous_routes); + + iroute = iface->previous_routes = xmalloc (sizeof (route_t)); + for (droute = dhcp->routes; droute; droute = droute->next) { + memcpy (iroute, droute, sizeof (route_t)); + if (droute->next) { + iroute->next = xmalloc (sizeof (route_t)); + iroute = iroute->next; + } + } + } + } +#endif + } else { dhcp->address = options->request_address; dhcp->netmask = options->request_netmask; @@ -255,7 +321,7 @@ int dhcp_run (const options_t *options, int *pidfd) After all, we ARE a DHCP client whose job it is to configure the interface. We only do this on start, so persistent addresses can be added afterwards by the user if needed. */ - if (! options->test) { + if (! options->test && ! options->daemonised) { if (! options->doinform) flush_addresses (iface->name); else { @@ -308,7 +374,7 @@ int dhcp_run (const options_t *options, int *pidfd) SEND_MESSAGE (last_type); logger (LOG_DEBUG, "waiting on select for %ld seconds", - timeout); + (unsigned long) timeout); /* If we're waiting for a reply, then we re-send the last DHCP request periodically in-case of a bad line */ retval = 0; @@ -452,11 +518,18 @@ int dhcp_run (const options_t *options, int *pidfd) state = STATE_BOUND; if (! daemonised && options->daemonise) { - if ((daemonise (pidfd)) == -1) { - retval = EXIT_FAILURE; - goto eexit; + switch (daemonise (pidfd)) { + case -1: + retval = EXIT_FAILURE; + goto eexit; + case 0: + daemonised = true; + break; + default: + persistent = true; + retval = EXIT_SUCCESS; + goto eexit; } - daemonised = true; } timeout = dhcp->renewaltime; @@ -741,17 +814,26 @@ int dhcp_run (const options_t *options, int *pidfd) xid = 0; - if (configure (options, iface, dhcp, true) == -1 && ! daemonised) { + if (configure (options, iface, dhcp, true) == -1 && + ! daemonised) + { retval = EXIT_FAILURE; goto eexit; } if (! daemonised && options->daemonise) { - if ((daemonise (pidfd)) == -1 ) { - retval = EXIT_FAILURE; - goto eexit; + switch (daemonise (pidfd)) { + case -1: + retval = EXIT_FAILURE; + goto eexit; + case 0: + daemonised = true; + break; + default: + persistent = true; + retval = EXIT_SUCCESS; + goto eexit; } - daemonised = true; } } else if (type == DHCP_OFFER) logger (LOG_INFO, "got subsequent offer of %s, ignoring ", @@ -778,8 +860,7 @@ eexit: free (dhcp); if (iface) { - if (iface->previous_routes) - free_route (iface->previous_routes); + free_route (iface->previous_routes); free (iface); } @@ -791,10 +872,8 @@ eexit: *pidfd = -1; } - logger (LOG_INFO, "exiting"); - - /* Unlink our pidfile */ - unlink (options->pidfile); + if (daemonised) + unlink (options->pidfile); return retval; } diff --git a/common.c b/common.c index 1c3951b2..517ab677 100644 --- a/common.c +++ b/common.c @@ -21,9 +21,12 @@ #include #include +#include +#include #include #include #include +#include #include "common.h" #include "logger.h" @@ -31,14 +34,13 @@ /* OK, this should be in dhcpcd.c * It's here to make dhcpcd more readable */ #ifdef __linux__ -#include -#include -void srandomdev (void) { +void srandomdev (void) +{ int fd; unsigned long seed; fd = open ("/dev/urandom", 0); - if (fd == -1 || read (fd, &seed, sizeof(seed)) == -1) { + if (fd == -1 || read (fd, &seed, sizeof (seed)) == -1) { logger (LOG_WARNING, "Could not load seed from /dev/urandom: %s", strerror (errno)); seed = time (0); @@ -67,8 +69,7 @@ size_t strlcpy (char *dst, const char *src, size_t size) if (! n) { if (size) *dst = '\0'; - while (*src++) - ; + while (*src++); } return (src - s - 1); @@ -76,57 +77,31 @@ size_t strlcpy (char *dst, const char *src, size_t size) # endif #endif -/* This requires us to link to rt on glibc, so we use sysinfo instead */ -#ifdef __linux__ -#include -/* Avoid clock_gettime as it requires librt on Linux */ -#undef CLOCK_MONOTONIC -long uptime (void) -{ - struct sysinfo info; - - sysinfo (&info); - return info.uptime; -} -#elif CLOCK_MONOTONIC -long uptime (void) -{ - struct timespec tp; - - if (clock_gettime (CLOCK_MONOTONIC, &tp) == -1) { - logger (LOG_ERR, "clock_gettime: %s", strerror (errno)); - return -1; - } - - return tp.tv_sec; -} -#else -/* Darwin doesn't appear to have an uptime, so try and make one ourselves */ -long uptime (void) +/* Close our fd's */ +void close_fds (void) { - struct timeval tv; - static long start = 0; + int fd; - if (gettimeofday (&tv, NULL) == -1) { - logger (LOG_ERR, "gettimeofday: %s", strerror (errno)); - return -1; + if ((fd = open ("/dev/null", O_RDWR)) == -1) { + logger (LOG_ERR, "open `/dev/null': %s", strerror (errno)); + return; } - if (start == 0) - start = tv.tv_sec; - - return tv.tv_sec - start; + dup2 (fd, fileno (stdin)); + dup2 (fd, fileno (stdout)); + dup2 (fd, fileno (stderr)); + if (fd > 2) + close (fd); } -#endif /* Handy function to get the time. * We only care about time advancements, not the actual time itself * Which is why we use CLOCK_MONOTONIC, but it is not available on all * platforms. */ -#ifdef CLOCK_MONOTONIC int get_time (struct timeval *tp) { +#ifdef CLOCK_MONOTONIC struct timespec ts; if (clock_gettime (CLOCK_MONOTONIC, &ts) == -1) { @@ -137,17 +112,24 @@ int get_time (struct timeval *tp) tp->tv_sec = ts.tv_sec; tp->tv_usec = ts.tv_nsec / 1000; return (0); -} #else -int get_time (struct timeval *tp) -{ if (gettimeofday (tp, NULL) == -1) { logger (LOG_ERR, "gettimeofday: %s", strerror (errno)); return (-1); } return (0); -} #endif +} + +time_t uptime (void) +{ + struct timeval tp; + + if (get_time (&tp) == -1) + return (-1); + + return (tp.tv_sec); +} void *xmalloc (size_t s) { diff --git a/common.h b/common.h index 79940997..1c817087 100644 --- a/common.h +++ b/common.h @@ -37,8 +37,9 @@ size_t strlcpy (char *dst, const char *src, size_t size); void srandomdev (void); #endif +void close_fds (void); int get_time (struct timeval *tp); -long uptime (void); +time_t uptime (void); void *xmalloc (size_t size); char *xstrdup (const char *str); diff --git a/config.h b/config.h index 4d3ee0b6..050d4dc6 100644 --- a/config.h +++ b/config.h @@ -43,6 +43,11 @@ * See RFC 3315 for details on this. */ #define ENABLE_DUID +/* Some systems do not have a working fork. + * The Makefile will attempt to work it out, but if it fails to feel free to + * define it here. */ +// #define THERE_IS_NO_FORK + /* Packname name and pathname definitions. * NOTE: The service restart commands are Gentoo specific and will * probably need to be adapted for your OS. */ diff --git a/configure.c b/configure.c index f0194bfa..eb751bc0 100644 --- a/configure.c +++ b/configure.c @@ -28,7 +28,7 @@ #include #ifdef __linux__ -#include +# include #endif #include #include @@ -43,7 +43,7 @@ #include "configure.h" #include "dhcp.h" #ifdef ENABLE_INFO -#include "info.h" +# include "info.h" #endif #include "interface.h" #include "dhcpcd.h" @@ -62,11 +62,7 @@ static int exec_cmd (const char *cmd, const char *args, ...) while (va_arg (va, char *) != NULL) n++; va_end (va); - argv = alloca ((n + 1) * sizeof (*argv)); - if (argv == NULL) { - errno = ENOMEM; - return (-1); - } + argv = xmalloc (sizeof (char *) * (n + 2)); va_start (va, args); n = 2; @@ -81,9 +77,13 @@ static int exec_cmd (const char *cmd, const char *args, ...) logger (LOG_ERR, "error executing \"%s\": %s", cmd, strerror (errno)); _exit (0); - } else if (pid == -1) + } else if (pid == -1) { logger (LOG_ERR, "vfork: %s", strerror (errno)); + free (argv); + return (-1); + } + free (argv); return (0); } diff --git a/dhcp.c b/dhcp.c index 80ca8b51..c180ed6b 100644 --- a/dhcp.c +++ b/dhcp.c @@ -67,7 +67,7 @@ size_t send_message (const interface_t *iface, const dhcp_t *dhcp, unsigned long l; struct in_addr from; struct in_addr to; - long up = uptime() - iface->start_uptime; + time_t up = uptime() - iface->start_uptime; uint32_t ul; uint16_t sz; unsigned int message_length; @@ -106,7 +106,7 @@ size_t send_message (const interface_t *iface, const dhcp_t *dhcp, case ARPHRD_IEEE1394: case ARPHRD_INFINIBAND: if (message.ciaddr == 0) - message.flags = htons (BROADCAST_FLAG); + message.flags = (int16_t) htons (BROADCAST_FLAG); message.hwlen = 0; break; default: diff --git a/dhcp.h b/dhcp.h index e47113be..a11286ce 100644 --- a/dhcp.h +++ b/dhcp.h @@ -22,11 +22,11 @@ #ifndef DHCP_H #define DHCP_H -#include #include #include #include #include +#include #include "dhcpcd.h" #include "interface.h" diff --git a/dhcpcd.c b/dhcpcd.c index 63f922da..b54cbd2f 100644 --- a/dhcpcd.c +++ b/dhcpcd.c @@ -21,6 +21,7 @@ /* We need to define this to get kill on GNU systems */ #ifdef __linux__ +#define _BSD_SOURCE #define _POSIX_SOURCE #endif @@ -61,6 +62,12 @@ _int = (int) _number; \ } +#ifdef THERE_IS_NO_FORK +char dhcpcd[PATH_MAX]; +char **dhcpcd_argv = NULL; +int dhcpcd_argc = 0; +#endif + static pid_t read_pid (const char *pidfile) { FILE *fp; @@ -128,6 +135,9 @@ int main(int argc, char **argv) {"nonis", no_argument, NULL, 'Y'}, {"help", no_argument, &dohelp, 1}, {"version", no_argument, &doversion, 1}, +#ifdef THERE_IS_NO_FORK + {"daemonised", no_argument, NULL, 'f'}, +#endif {NULL, 0, NULL, 0} }; @@ -185,6 +195,12 @@ int main(int argc, char **argv) break; } break; +#ifdef THERE_IS_NO_FORK + case 'f': + options.daemonised = true; + close_fds (); + break; +#endif case 'h': if (! optarg) memset (options.hostname, 0, sizeof (options.hostname)); @@ -228,6 +244,7 @@ int main(int argc, char **argv) break; case 's': options.doinform = true; + options.doarp = false; if (! optarg || strlen (optarg) == 0) { options.request_address.s_addr = 0; break; @@ -238,11 +255,11 @@ int main(int argc, char **argv) /* nullify the slash, so the -r option can read the * address */ *slash++ = '\0'; - if (sscanf (slash, "%d", &cidr) != 1) { + if (sscanf (slash, "%d", &cidr) != 1 || + inet_cidrtoaddr (cidr, &options.request_netmask) != 0) { logger (LOG_ERR, "`%s' is not a valid CIDR", slash); exit (EXIT_FAILURE); } - options.request_netmask = inet_cidrtoaddr (cidr); } /* fall through */ } @@ -368,6 +385,24 @@ int main(int argc, char **argv) if (dohelp) usage (); +#ifdef THERE_IS_NO_FORK + dhcpcd_argv = argv; + dhcpcd_argc = argc; + + /* We need the full path to the dhcpcd */ + if (*argv[0] == '/') + strlcpy (dhcpcd, argv[0], sizeof (dhcpcd)); + else { + char pwd[PATH_MAX]; + if (! getcwd (pwd, PATH_MAX)) { + logger (LOG_ERR, "getcwd: %s", strerror (errno)); + exit (EXIT_FAILURE); + } + snprintf (dhcpcd, sizeof (dhcpcd), "%s/%s", pwd, argv[0]); + } + +#endif + if (optind < argc) { if (strlen (argv[optind]) > IF_NAMESIZE) { logger (LOG_ERR, "`%s' is too long for an interface name (max=%d)", @@ -408,7 +443,7 @@ int main(int argc, char **argv) chdir ("/"); umask (022); - + if (mkdir (CONFIGDIR, S_IRUSR |S_IWUSR |S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH) && errno != EEXIST ) { @@ -440,7 +475,7 @@ int main(int argc, char **argv) } } - if (sig != 0 ) { + if (sig != 0) { int killed = -1; pid = read_pid (options.pidfile); if (pid != 0) @@ -459,7 +494,7 @@ int main(int argc, char **argv) exit (EXIT_FAILURE); } - if (! options.test) { + if (! options.test && ! options.daemonised) { if ((pid = read_pid (options.pidfile)) > 0 && kill (pid, 0) == 0) { logger (LOG_ERR, ""PACKAGE" already running on pid %d (%s)", pid, options.pidfile); @@ -489,12 +524,14 @@ int main(int argc, char **argv) /* Seed random */ srandomdev (); - if (dhcp_run (&options, &pidfd)) { - if (pidfd > -1) - close (pidfd); - unlink (options.pidfile); - exit (EXIT_FAILURE); - } + i = EXIT_FAILURE; + if (dhcp_run (&options, &pidfd) == 0) + i = EXIT_SUCCESS; + + logger (LOG_INFO, "exiting"); + + if (pidfd > -1) + close (pidfd); - exit (EXIT_SUCCESS); + exit (i); } diff --git a/dhcpcd.h b/dhcpcd.h index 235149ca..fe0dbcdf 100644 --- a/dhcpcd.h +++ b/dhcpcd.h @@ -36,6 +36,12 @@ #define CLIENT_ID_MAX_LEN 48 #define USERCLASS_MAX_LEN 255 +#ifndef HAVE_FORK +extern char dhcpcd[PATH_MAX]; +extern char **dhcpcd_argv; +extern int dhcpcd_argc; +#endif + typedef struct options_t { char interface[IF_NAMESIZE]; char hostname[MAXHOSTNAMELEN]; @@ -69,6 +75,7 @@ typedef struct options_t { bool persistent; bool keep_address; bool daemonise; + bool daemonised; bool test; char *script; diff --git a/duid.c b/duid.c index 8ddbf2ca..160b131c 100644 --- a/duid.c +++ b/duid.c @@ -19,6 +19,7 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#include #include #include #include diff --git a/interface.c b/interface.c index 3502fecc..9a87687b 100644 --- a/interface.c +++ b/interface.c @@ -58,9 +58,6 @@ void free_address (address_t *addresses) address_t *p = addresses; address_t *n = NULL; - if (! addresses) - return; - while (p) { n = p->next; free (p); @@ -73,9 +70,6 @@ void free_route (route_t *routes) route_t *p = routes; route_t *n = NULL; - if (! routes) - return; - while (p) { n = p->next; free (p); @@ -96,29 +90,23 @@ int inet_ntocidr (struct in_addr address) return (cidr); } -struct in_addr inet_cidrtoaddr (int cidr) { - struct in_addr addr; +int inet_cidrtoaddr (int cidr, struct in_addr *addr) { int ocets; - if (cidr == 0) - ocets = 0; - else if (cidr < 9) - ocets = 1; - else if (cidr < 17) - ocets = 2; - else if (cidr < 25) - ocets = 3; - else - ocets = 4; + if (cidr < 0 || cidr > 32) { + errno = EINVAL; + return (-1); + } + ocets = (cidr + 7) / 8; - memset (&addr, 0, sizeof (struct in_addr)); + memset (addr, 0, sizeof (struct in_addr)); if (ocets > 0) { - memset (&addr.s_addr, 255, ocets - 1); - memset ((unsigned char *) &addr.s_addr + (ocets - 1), + memset (&addr->s_addr, 255, ocets - 1); + memset ((unsigned char *) &addr->s_addr + (ocets - 1), (256 - (1 << (32 - cidr) % 8)), 1); } - return (addr); + return (0); } unsigned long get_netmask (unsigned long addr) @@ -498,6 +486,15 @@ static void log_route( #if defined(__FreeBSD__) || defined(__NetBSD__) || defined (__OpenBSD__) \ || defined(__APPLE__) + +/* Darwin doesn't define this for some very odd reason */ +#ifndef SA_SIZE +# define SA_SIZE(sa) \ + ( (!(sa) || ((struct sockaddr *)(sa))->sa_len == 0) ? \ + sizeof(long) : \ + 1 + ( (((struct sockaddr *)(sa))->sa_len - 1) | (sizeof(long) - 1) ) ) +#endif + static int do_address (const char *ifname, struct in_addr address, struct in_addr netmask, struct in_addr broadcast, int del) { diff --git a/interface.h b/interface.h index eae71dd5..f3bf0505 100644 --- a/interface.h +++ b/interface.h @@ -90,7 +90,7 @@ typedef struct interface_t struct in_addr previous_netmask; route_t *previous_routes; - long start_uptime; + time_t start_uptime; #ifdef ENABLE_DUID unsigned char duid[DUID_LEN]; @@ -124,6 +124,6 @@ int del_route (const char *ifname, struct in_addr destination, struct in_addr netmask, struct in_addr gateway, int metric); int inet_ntocidr (struct in_addr address); -struct in_addr inet_cidrtoaddr (int cidr); +int inet_cidrtoaddr (int cidr, struct in_addr *addr); #endif diff --git a/ipv4ll.h b/ipv4ll.h index f05d188e..db5cb78b 100644 --- a/ipv4ll.h +++ b/ipv4ll.h @@ -29,7 +29,9 @@ #define LINKLOCAL_MASK 0xffff0000 #define LINKLOCAL_BRDC 0xa9feffff -#define IN_LINKLOCAL(addr) ((ntohl (addr) & IN_CLASSB_NET) == LINKLOCAL_ADDR) +#ifndef IN_LINKLOCAL +# define IN_LINKLOCAL(addr) ((ntohl (addr) & IN_CLASSB_NET) == LINKLOCAL_ADDR) +#endif int ipv4ll_get_address (interface_t *iface, dhcp_t *dhcp); diff --git a/socket.c b/socket.c index b1b87cb2..832c0ab8 100644 --- a/socket.c +++ b/socket.c @@ -19,6 +19,8 @@ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ +#define _BSD_SOURCE + #include #include #include