]> git.ipfire.org Git - thirdparty/dhcpcd.git/commitdiff
Add a control socket so that interfaces can be dynamically re-set.
authorRoy Marples <roy@marples.name>
Wed, 3 Sep 2008 16:49:28 +0000 (16:49 +0000)
committerRoy Marples <roy@marples.name>
Wed, 3 Sep 2008 16:49:28 +0000 (16:49 +0000)
This requires the event loop argument being changed to void *
so we can send arguments other than an interface.

16 files changed:
Makefile
arp.c
arp.h
bind.c
bind.h
config.h
control.c [new file with mode: 0644]
control.h [new file with mode: 0644]
dhcpcd.8.in
dhcpcd.c
dhcpcd.h
eloop.c
eloop.h
if-options.c
ipv4ll.c
ipv4ll.h

index 58ca6ba0fcf25afbb0a7adf32a9c1e344b2cd879..691f6b923922082cee7689fb3647280659cce858 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -3,7 +3,7 @@
 # Copyright 2008 Roy Marples <roy@marples.name>
 
 PROG=          dhcpcd
-SRCS=          arp.c bind.c common.c dhcp.c dhcpcd.c duid.c eloop.c
+SRCS=          arp.c bind.c common.c control.c dhcp.c dhcpcd.c duid.c eloop.c
 SRCS+=         if-options.c ipv4ll.c logger.c net.c signals.c
 SRCS+=         configure.c
 SRCS+=         ${SRC_IF} ${SRC_PF}
diff --git a/arp.c b/arp.c
index 71431dc824d48d3931807bd15d5bbaecc7456627..8935ea65e71e16e54c684ba6e936582c4615553f 100644 (file)
--- a/arp.c
+++ b/arp.c
@@ -52,9 +52,10 @@ handle_arp_failure(struct interface *iface)
        add_timeout_sec(DHCP_ARP_FAIL, start_interface, iface);
 }
 
-void
-handle_arp_packet(struct interface *iface)
+static void
+handle_arp_packet(void *arg)
 {
+       struct interface *iface = arg;
        struct arphdr reply;
        uint32_t reply_s;
        uint32_t reply_t;
@@ -123,8 +124,9 @@ handle_arp_packet(struct interface *iface)
 }
 
 void
-send_arp_announce(struct interface *iface)
+send_arp_announce(void *arg)
 {
+       struct interface *iface = arg;
        struct if_state *state = iface->state;
        struct timeval tv;
 
@@ -167,8 +169,9 @@ send_arp_announce(struct interface *iface)
 }
 
 void
-send_arp_probe(struct interface *iface)
+send_arp_probe(void *arg)
 {
+       struct interface *iface = arg;
        struct if_state *state = iface->state;
        struct in_addr addr;
        struct timeval tv;
diff --git a/arp.h b/arp.h
index 3cfe55a79efe4b0a3a13aa8caccc29b447b74ff3..c9bc9e4964499f2dd2aa9fd2dc7e3aa6d131f9f7 100644 (file)
--- a/arp.h
+++ b/arp.h
@@ -28,8 +28,6 @@
 #ifndef ARP_H
 #define ARP_H
 
-#include "dhcpcd.h"
-
 /* These are for IPV4LL, RFC 3927.
  * We put them here as we use the timings for all ARP foo. */
 #define PROBE_WAIT              1
@@ -43,7 +41,6 @@
 #define RATE_LIMIT_INTERVAL    60
 #define DEFEND_INTERVAL                10
 
-void send_arp_announce(struct interface *);
-void send_arp_probe(struct interface *);
-void handle_arp_packet(struct interface *);
+void send_arp_announce(void *);
+void send_arp_probe(void *);
 #endif
diff --git a/bind.c b/bind.c
index 452738cd38d302f59f7feecdfb3e974a20ee2055..22cfd045e6ff23fc25e54593852ed0b9ba23c6de 100644 (file)
--- a/bind.c
+++ b/bind.c
@@ -98,8 +98,10 @@ daemonise(void)
 }
 #endif
 
-void bind_interface(struct interface *iface)
+void
+bind_interface(void *arg)
 {
+       struct interface *iface = arg;
        struct if_state *state = iface->state;
        struct if_options *ifo = state->options;
        struct dhcp_lease *lease = &state->lease;
diff --git a/bind.h b/bind.h
index 5aaabf70eab78a7e4c974d9ca1bb88cb33ffbbc6..f64d1c66d3f22ea2ce767870bbeba63901809f10 100644 (file)
--- a/bind.h
+++ b/bind.h
@@ -29,7 +29,6 @@
 #define BIND_H
 
 #include "config.h"
-#include "dhcpcd.h"
 #ifdef THERE_IS_NO_FORK
 #define daemonise() {}
 #else
@@ -37,5 +36,5 @@ pid_t daemonise(void);
 #endif
 
 extern int can_daemonise;
-void bind_interface(struct interface *);
+void bind_interface(void *);
 #endif
index 801c89cd442bb6c2c2c768e7d75a3bfe4dafba77..7315fa025eccab456df8f2256a4668eed08c3d08 100644 (file)
--- a/config.h
+++ b/config.h
@@ -71,5 +71,8 @@
 #ifndef PIDFILE
 # define PIDFILE               RUNDIR "/" PACKAGE "%s%s.pid"
 #endif
+#ifndef CONTROLSOCKET
+# define CONTROLSOCKET         RUNDIR "/" PACKAGE ".sock"
+#endif
 
 #endif
diff --git a/control.c b/control.c
new file mode 100644 (file)
index 0000000..6b0f1a1
--- /dev/null
+++ b/control.c
@@ -0,0 +1,163 @@
+/* 
+ * dhcpcd - DHCP client daemon
+ * Copyright 2006-2008 Roy Marples <roy@marples.name>
+ * All rights reserved
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/stat.h>
+#include <sys/un.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "config.h"
+#include "common.h"
+#include "control.h"
+#include "eloop.h"
+#include "dhcpcd.h"
+
+static int fd = -1;
+struct sockaddr_un sun;
+static char buffer[1024];
+static char *argvp[255];
+
+static void
+handle_control_data(void *arg)
+{
+       ssize_t bytes;
+       int argc, s = (int)arg;
+       char *e, *p;
+       char **ap;
+
+       for (;;) {
+               bytes = read(s, buffer, sizeof(buffer));
+               if (bytes == -1 || bytes == 0) {
+                       close(s);
+                       delete_event(s);
+                       return;
+               }
+               p = buffer;
+               e = buffer + bytes;
+               argc = 0;
+               ap = argvp;
+               while (p < e && (size_t)argc < sizeof(argvp)) {
+                       argc++;
+                       *ap++ = p;
+                       p += strlen(p) + 1;
+               }
+               handle_args(argc, argvp);
+       }
+}
+
+static void
+handle_control(_unused void *arg)
+{
+       struct sockaddr_un run;
+       socklen_t len;
+       int s;
+
+       len = sizeof(run);
+       if ((s = accept(fd, (struct sockaddr *)&run, &len)) == -1)
+               return;
+       add_event(s, handle_control_data, (void *)s);
+}
+
+static int
+make_sock(void)
+{
+       if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
+               return -1;
+       memset(&sun, 0, sizeof(sun));
+       sun.sun_family = AF_UNIX;
+       strlcpy(sun.sun_path, CONTROLSOCKET, sizeof(sun.sun_path));
+       return sizeof(sun.sun_family) + strlen(sun.sun_path) + 1;
+}
+
+int
+start_control(void)
+{
+       int len;
+
+       if ((len = make_sock()) == -1)
+               return -1;
+       unlink(CONTROLSOCKET);
+       if (bind(fd, (struct sockaddr *)&sun, len) == -1 ||
+           chmod(CONTROLSOCKET, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP) == -1 ||
+           set_cloexec(fd) == -1 ||
+           set_nonblock(fd) == -1 ||
+           listen(fd, 0) == -1)
+       {
+               close(fd);
+               return -1;
+       }
+       add_event(fd, handle_control, NULL);
+       return fd;
+}
+
+int
+stop_control(void)
+{
+       int retval = 0;
+       if (close(fd) == -1)
+               retval = 1;
+       if (unlink(CONTROLSOCKET) == -1)
+               retval = -1;
+       return retval;
+}
+
+int
+open_control(void)
+{
+       int len;
+
+       if ((len = make_sock()) == -1)
+               return -1;
+       return connect(fd, (struct sockaddr *)&sun, len);
+}
+
+int
+send_control(int argc, char * const *argv)
+{
+       char *p = buffer;
+       int i;
+       size_t len;
+
+       if (argc > 255) {
+               errno = ENOBUFS;
+               return -1;
+       }
+       for (i = 0; i < argc; i++) {
+               len = strlen(argv[i]) + 1;
+               if ((p - buffer) + len > sizeof(buffer)) {
+                       errno = ENOBUFS;
+                       return -1;
+               }
+               memcpy(p, argv[i], len);
+               p += len;
+       }
+       return write(fd, buffer, p - buffer);
+}
diff --git a/control.h b/control.h
new file mode 100644 (file)
index 0000000..4440690
--- /dev/null
+++ b/control.h
@@ -0,0 +1,38 @@
+/* 
+ * dhcpcd - DHCP client daemon
+ * Copyright 2006-2008 Roy Marples <roy@marples.name>
+ * All rights reserved
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef CONTROL_H
+#define CONTROL_H
+
+#include "dhcpcd.h"
+
+int start_control(void);
+int stop_control(void);
+int open_control(void);
+int send_control(int, char * const *);
+
+#endif
index 68d7f9509f9416892ac6c184b2eca52f0f00a237..aba3b86644ae9503d317f416f169f3cd510f9698 100644 (file)
@@ -22,7 +22,7 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.Dd September 1, 2008
+.Dd September 3, 2008
 .Dt DHCPCD 8 SMM
 .Sh NAME
 .Nm dhcpcd
@@ -436,9 +436,10 @@ RFC 3442, RFC 3927, RFC 4361, RFC 4390, RFC 4702.
 .Sh AUTHORS
 .An Roy Marples <roy@marples.name>
 .Sh BUGS
-You cannot release a lease - this will be fixed before the first release.
-.Pp
-You cannot dynamically add or remove interfaces either manually or detected.
+.Nm
+does not wait for commands to complete when sending them to the master
+.Nm
+process.
 .Pp
 One of the goals for one instance managing multiple interfaces is more
 intelligent route and configuration management.
index 96d8cf709ae4f3aa417326a6694fc4dd66340ff5..c84164eb0348751f72b4d669ec9f4a3ef25cbfd9 100644 (file)
--- a/dhcpcd.c
+++ b/dhcpcd.c
@@ -50,6 +50,7 @@ const char copyright[] = "Copyright (c) 2006-2008 Roy Marples";
 #include "config.h"
 #include "common.h"
 #include "configure.h"
+#include "control.h"
 #include "dhcpcd.h"
 #include "dhcpf.h"
 #include "duid.h"
@@ -63,13 +64,13 @@ const char copyright[] = "Copyright (c) 2006-2008 Roy Marples";
 /* We should define a maximum for the NAK exponential backoff */ 
 #define NAKOFF_MAX              60
 
+int master = 0;
 int pidfd = -1;
 static int linkfd = -1;
 static char cffile[PATH_MAX];
 static char pidfile[PATH_MAX] = { '\0' };
 static struct interface *ifaces = NULL;
 
-
 struct dhcp_op {
        uint8_t value;
        const char *name;
@@ -140,13 +141,18 @@ cleanup(void)
        if (linkfd != -1)
                close(linkfd);
        if (pidfd > -1) {
+               if (master) {
+                       if (stop_control() == -1)
+                               logger(LOG_ERR, "stop_control: %s",
+                                      strerror(errno));
+               }
                close(pidfd);
                unlink(pidfile);
        }
 }
 
 void
-handle_exit_timeout(_unused struct interface *iface)
+handle_exit_timeout(_unused void *arg)
 {
        logger(LOG_ERR, "timed out");
        exit(EXIT_FAILURE);
@@ -186,7 +192,7 @@ close_sockets(struct interface *iface)
 
 static void
 send_message(struct interface *iface, int type,
-            void (*function)(struct interface *))
+            void (*callback)(void *))
 {
        struct if_state *state = iface->state;
        struct dhcp_message *dhcp;
@@ -196,7 +202,7 @@ send_message(struct interface *iface, int type,
        in_addr_t a = 0;
        struct timeval tv;
 
-       if (!function)
+       if (!callback)
                logger(LOG_DEBUG, "%s: sending %s with xid 0x%x",
                       iface->name, get_dhcp_op(type), state->xid);
        else {
@@ -243,31 +249,33 @@ send_message(struct interface *iface, int type,
                               iface->name, strerror(errno));
        }
        free(dhcp);
-       if (function)
-               add_timeout_tv(&tv, function, iface);
+       if (callback)
+               add_timeout_tv(&tv, callback, iface);
 }
 
 static void
-send_discover(struct interface *iface)
+send_discover(void *arg)
 {
-       send_message(iface, DHCP_DISCOVER, send_discover);
+       send_message((struct interface *)arg, DHCP_DISCOVER, send_discover);
 }
 
 void
-send_request(struct interface *iface)
+send_request(void *arg)
 {
-       send_message(iface, DHCP_REQUEST, send_request);
+       send_message((struct interface *)arg, DHCP_REQUEST, send_request);
 }
 
 static void
-send_renew(struct interface *iface)
+send_renew(void *arg)
 {
-       send_message(iface, DHCP_REQUEST, send_renew);
+       send_message((struct interface *)arg, DHCP_REQUEST, send_renew);
 }
 
 void
-start_renew(struct interface *iface)
+start_renew(void *arg)
 {
+       struct interface *iface = arg;
+
        logger(LOG_INFO, "%s: renewing lease of %s",
                        iface->name, inet_ntoa(iface->state->lease.addr));
        iface->state->state = DHS_RENEWING;
@@ -276,14 +284,16 @@ start_renew(struct interface *iface)
 }
 
 static void
-send_rebind(struct interface *iface)
+send_rebind(void *arg)
 {
-       send_message(iface, DHCP_REQUEST, send_rebind);
+       send_message((struct interface *)arg, DHCP_REQUEST, send_rebind);
 }
 
 void
-start_rebind(struct interface *iface)
+start_rebind(void *arg)
 {
+       struct interface *iface = arg;
+
        logger(LOG_ERR, "%s: failed to renew, attmepting to rebind",
                        iface->name);
        iface->state->state = DHS_REBINDING;
@@ -293,8 +303,9 @@ start_rebind(struct interface *iface)
 }
 
 void
-start_expire(struct interface *iface)
+start_expire(void *arg)
 {
+       struct interface *iface = arg;
        int ll = IN_LINKLOCAL(htonl(iface->state->lease.addr.s_addr));
 
        logger(LOG_ERR, "%s: lease expired", iface->name);
@@ -468,8 +479,9 @@ handle_dhcp(struct interface *iface, struct dhcp_message **dhcpp)
 }
 
 static void
-handle_dhcp_packet(struct interface *iface)
+handle_dhcp_packet(void *arg)
 {
+       struct interface *iface = arg;
        uint8_t *packet;
        struct dhcp_message *dhcp = NULL;
        const uint8_t *pp;
@@ -552,8 +564,9 @@ open_sockets(struct interface *iface)
 }
 
 static void
-handle_link(struct interface *iface)
+handle_link(_unused void *arg)
 {
+       struct interface *iface;
        int retval;
 
        retval = link_changed(linkfd, ifaces);
@@ -593,8 +606,9 @@ handle_link(struct interface *iface)
 }
 
 void
-start_discover(struct interface *iface)
+start_discover(void *arg)
 {
+       struct interface *iface = arg;
        struct if_options *ifo = iface->state->options;
 
        iface->state->state = DHS_DISCOVERING;
@@ -630,9 +644,24 @@ start_reboot(struct interface *iface)
        send_rebind(iface);
 }
 
+static void
+send_release(struct interface *iface)
+{
+       if (iface->state->lease.addr.s_addr &&
+           !IN_LINKLOCAL(htonl(iface->state->lease.addr.s_addr)))
+       {
+               logger(LOG_INFO, "%s: releasing lease of %s",
+                               iface->name, inet_ntoa(iface->state->lease.addr));
+               open_sockets(iface);
+               send_message(iface, DHCP_RELEASE, NULL);
+       }
+}
+
 void
-start_interface(struct interface *iface)
+start_interface(void *arg)
 {
+       struct interface *iface = arg;
+
        iface->start_uptime = uptime();
        if (!iface->state->lease.addr.s_addr)
                start_discover(iface);
@@ -643,25 +672,18 @@ start_interface(struct interface *iface)
 }
 
 static void
-init_state(struct interface *iface, int argc, char **argv)
+configure_interface(struct interface *iface, int argc, char **argv)
 {
-       struct if_state *ifs;
+       struct if_state *ifs = iface->state;
        struct if_options *ifo;
        uint8_t *duid;
        size_t len = 0, ifl;
 
-       if (iface->state) {
-               ifs = iface->state;
-               free_options(ifs->options);
-       } else
-               ifs = iface->state = xzalloc(sizeof(*ifs));
-
-       ifs->state = DHS_INIT;
-       ifs->nakoff = 1;
+       free_options(ifs->options);
        ifo = ifs->options = read_config(cffile, iface->name);
        add_options(ifo, argc, argv);
 
-       if (ifo->metric)
+       if (ifo->metric != -1)
                iface->metric = ifo->metric;
 
        if (*ifo->clientid) {
@@ -696,10 +718,26 @@ init_state(struct interface *iface, int argc, char **argv)
                }
        }
 
-       if (!(ifo->options & DHCPCD_TEST))
+}
+
+static void
+init_state(struct interface *iface, int argc, char **argv)
+{
+       struct if_state *ifs;
+
+       if (iface->state) {
+               ifs = iface->state;
+       } else
+               ifs = iface->state = xzalloc(sizeof(*ifs));
+
+       ifs->state = DHS_INIT;
+       ifs->nakoff = 1;
+       configure_interface(iface, argc, argv);
+
+       if (!(ifs->options->options & DHCPCD_TEST))
                run_script(iface, "PREINIT");
 
-       if (ifo->options & DHCPCD_LINK) {
+       if (ifs->options->options & DHCPCD_LINK) {
                switch (carrier_status(iface->name)) {
                case 0:
                        ifs->carrier = LINK_DOWN;
@@ -719,9 +757,11 @@ init_state(struct interface *iface, int argc, char **argv)
 }
 
 static void
-handle_signal(struct interface *iface)
+handle_signal(_unused void *arg)
 {
+       struct interface *iface;
        int sig = signal_read();
+       int do_reboot = 0, do_release = 0;
 
        switch (sig) {
        case SIGINT:
@@ -730,6 +770,14 @@ handle_signal(struct interface *iface)
        case SIGTERM:
                logger(LOG_INFO, "received SIGTERM, stopping");
                break;
+       case SIGALRM:
+               logger(LOG_INFO, "received SIGALRM, rebinding lease");
+               do_reboot = 1;
+               break;
+       case SIGHUP:
+               logger(LOG_INFO, "received SIGHUP, releasing lease");
+               do_release = 1;
+               break;
        default:
                logger (LOG_ERR,
                        "received signal %d, but don't know what to do with it",
@@ -740,18 +788,97 @@ handle_signal(struct interface *iface)
        for (iface = ifaces; iface; iface = iface->next) {
                if (!iface->state)
                        continue;
-               if (!(iface->state->options->options & DHCPCD_PERSISTENT))
-                       drop_config(iface, "STOP");
+               if (do_reboot)
+                       start_reboot(iface);
+               else {
+                       if (do_release)
+                               send_release(iface);
+                       if (!(iface->state->options->options & DHCPCD_PERSISTENT))
+                               drop_config(iface, do_release ? "RELEASE" : "STOP");
+               }
        }
        exit(EXIT_FAILURE);
 }
 
+int
+handle_args(int argc, char **argv)
+{
+       struct interface *ifs, *ifp, *ifl = NULL, *ifn;
+       int do_exit = 0, do_release = 0, do_reboot = 0, opt, oi = 0;
+
+       optind = 0;
+       while ((opt = getopt_long(argc, argv, IF_OPTS, cf_options, &oi)) != -1)
+       {
+               switch (opt) {
+               case 'k':
+                       do_release = 1;
+                       break;
+               case 'n':
+                       do_reboot = 1;
+                       break;
+               case 'x':
+                       do_exit = 1;
+                       break;
+               }
+       }
+
+       /* We only deal with one interface here */
+       if (optind == argc) {
+               logger(LOG_ERR, "handle_args: no interface");
+               return -1;
+       }
+
+       if (do_release || do_reboot || do_exit) {
+               oi = optind;
+               while (oi < argc) {
+                       for (ifp = ifaces; ifp && (ifn = ifp->next, 1); ifp = ifn) {
+                               if (strcmp(ifp->name, argv[oi]) == 0) {
+                                       if (do_release)
+                                               send_release(ifp);
+                                       if (do_exit || do_release) {
+                                               drop_config(ifp, do_release ? "RELEASE" : "STOP");
+                                               close_sockets(ifp);
+                                               delete_timeout(NULL, ifp);
+                                               if (ifl)
+                                                       ifl->next = ifp->next;
+                                               else
+                                                       ifaces = ifp->next;
+                                               free_interface(ifp);
+                                               continue;
+                                       } else if (do_reboot) {
+                                               configure_interface(ifp, argc, argv);
+                                               start_reboot(ifp);
+                                       }
+                               }
+                               ifl = ifp;
+                       }
+                       oi++;
+               }
+               return 0;
+       }
+
+       if ((ifs = discover_interfaces(argc, argv))) {
+               argc += optind;
+               argv -= optind;
+               for (ifp = ifs; ifp; ifp = ifp->next)
+                       init_state(ifp, argc, argv);
+               if (ifaces) {
+                       ifp = ifaces;
+                       while (ifp->next)
+                               ifp = ifp->next;
+                       ifp->next = ifs;
+               } else
+                       ifaces = ifs;
+       }
+       return 0;
+}
+
 int
 main(int argc, char **argv)
 {
        struct if_options *ifo;
        struct interface *iface;
-       int opt, oi = 0, test = 0, signal_fd, sig = 0, i;
+       int opt, oi = 0, test = 0, signal_fd, sig = 0, i, control_fd;
        pid_t pid;
        struct timespec ts;
 
@@ -781,6 +908,12 @@ main(int argc, char **argv)
                case 'f':
                        strlcpy(cffile, optarg, sizeof(cffile));
                        break;
+               case 'k':
+                       sig = SIGHUP;
+                       break;
+               case 'n':
+                       sig = SIGALRM;
+                       break;
                case 'x':
                        sig = SIGTERM;
                        break;
@@ -803,27 +936,45 @@ main(int argc, char **argv)
                        usage();
                exit(EXIT_FAILURE);
        }
-       if (test)
-               ifo->options |= DHCPCD_TEST | DHCPCD_PERSISTENT;
-#ifdef THERE_IS_NO_FORK
-       ifo->options &= ~DHCPCD_DAEMONISE;
-#endif
 
        /* If we have any other args, we should run as a single dhcpcd instance
         * for that interface. */
        if (optind == argc - 1)
                snprintf(pidfile, sizeof(pidfile), PIDFILE, "-", argv[optind]);
-       else
+       else {
                snprintf(pidfile, sizeof(pidfile), PIDFILE, "", "");
-
-       if (geteuid())
-               logger(LOG_WARNING, PACKAGE " will not work correctly unless"
-                      " run as root");
+               master = 1;
+       }
+       
+       if (test)
+               ifo->options |= DHCPCD_TEST | DHCPCD_PERSISTENT;
+#ifdef THERE_IS_NO_FORK
+       ifo->options &= ~DHCPCD_DAEMONISE;
+#endif
 
        chdir("/");
        umask(022);
        atexit(cleanup);
 
+       if (!master) {
+               control_fd = open_control();
+               if (control_fd != -1) {
+                       logger(LOG_INFO, "sending commands to master dhcpcd process");
+                       i = send_control(argc, argv);
+                       if (i > 0) {
+                               logger(LOG_DEBUG, "send OK");
+                               exit(EXIT_SUCCESS);
+                       } else {
+                               logger(LOG_ERR, "failed to send commands");
+                               exit(EXIT_FAILURE);
+                       }
+               }
+       }
+
+       if (geteuid())
+               logger(LOG_WARNING, PACKAGE " will not work correctly unless"
+                      " run as root");
+
        if (sig != 0) {
                i = -1;
                pid = read_pid();
@@ -886,6 +1037,13 @@ main(int argc, char **argv)
                exit(EXIT_FAILURE);
        add_event(signal_fd, handle_signal, NULL);
 
+       if (master) {
+               if (start_control() == -1) {
+                       logger(LOG_ERR, "start_control: %s", strerror(errno));
+                       exit(EXIT_FAILURE);
+               }
+       }
+
        if (ifo->options & DHCPCD_LINK) {
                linkfd = open_link_socket();
                if (linkfd == -1)
index 86aa49598914d9f3b6273e74318fc0d41cd899c8..c2ea5c782de25a8ffbbad6854dedf78539701e96 100644 (file)
--- a/dhcpcd.h
+++ b/dhcpcd.h
@@ -28,7 +28,6 @@
 #ifndef DHCPCD_H
 #define DHCPCD_H
 
-#include <sys/socket.h>
 #include <net/if.h>
 
 #include <limits.h>
@@ -105,14 +104,15 @@ struct interface
 };
 
 extern int pidfd;
-void handle_exit_timeout(struct interface *);
-void send_request(struct interface *);
-void start_interface(struct interface *);
-void start_discover(struct interface *);
-void start_renew(struct interface *);
-void start_rebind(struct interface *);
+int handle_args(int, char **);
+void handle_exit_timeout(void *);
+void send_request(void *);
+void start_interface(void *);
+void start_discover(void *);
+void start_renew(void *);
+void start_rebind(void *);
 void start_reboot(struct interface *);
-void start_expire(struct interface *);
+void start_expire(void *);
 void send_decline(struct interface *);
 void close_sockets(struct interface *);
 void drop_config(struct interface *, const char *);
diff --git a/eloop.c b/eloop.c
index 6391416263d5a097e2ff7541ea64dd01099ea5e3..1fa75bc4109d0c3deae5eee51fd66bfbe94fc077 100644 (file)
--- a/eloop.c
+++ b/eloop.c
@@ -41,16 +41,16 @@ static struct timeval now = {0, 0};
 
 static struct event {
        int fd;
-       void (*callback)(struct interface *);
-       struct interface *iface;
+       void (*callback)(void *);
+       void *arg;
        struct event *next;
 } *events = NULL;
 static struct event *free_events = NULL;
 
 static struct timeout {
        struct timeval when;
-       void (*callback)(struct interface *);
-       struct interface *iface;
+       void (*callback)(void *);
+       void *arg;
        struct timeout *next;
 } *timeouts = NULL;
 static struct timeout *free_timeouts = NULL;
@@ -93,7 +93,7 @@ cleanup(void)
 #endif
 
 void
-add_event(int fd, void (*callback)(struct interface *), struct interface *iface)
+add_event(int fd, void (*callback)(void *), void *arg)
 {
        struct event *e, *last = NULL;
 
@@ -101,7 +101,7 @@ add_event(int fd, void (*callback)(struct interface *), struct interface *iface)
        for (e = events; e; e = e->next) {
                if (e->fd == fd) {
                        e->callback = callback;
-                       e->iface = iface;
+                       e->arg = arg;
                        return;
                }
                last = e;
@@ -115,7 +115,7 @@ add_event(int fd, void (*callback)(struct interface *), struct interface *iface)
                e = xmalloc(sizeof(*e));
        e->fd = fd;
        e->callback = callback;
-       e->iface = iface;
+       e->arg = arg;
        e->next = NULL;
        if (last)
                last->next = e;
@@ -144,7 +144,7 @@ delete_event(int fd)
 
 void
 add_timeout_tv(const struct timeval *when,
-              void (*callback)(struct interface *), struct interface *iface)
+              void (*callback)(void *), void *arg)
 {
        struct timeval w;
        struct timeout *t, *tt = NULL;
@@ -154,7 +154,7 @@ add_timeout_tv(const struct timeval *when,
 
        /* Remove existing timeout if present */
        for (t = timeouts; t; t = t->next) {
-               if (t->callback == callback && t->iface == iface) {
+               if (t->callback == callback && t->arg == arg) {
                        if (tt)
                                tt->next = t->next;
                        else
@@ -176,7 +176,7 @@ add_timeout_tv(const struct timeval *when,
        t->when.tv_sec = w.tv_sec;
        t->when.tv_usec = w.tv_usec;
        t->callback = callback;
-       t->iface = iface;
+       t->arg = arg;
 
        /* The timeout list should be in chronological order,
         * soonest first.
@@ -199,30 +199,30 @@ add_timeout_tv(const struct timeval *when,
 
 void
 add_timeout_sec(time_t when,
-               void (*callback)(struct interface *), struct interface *iface)
+               void (*callback)(void *), void *arg)
 {
        struct timeval tv;
 
        tv.tv_sec = when;
        tv.tv_usec = 0;
-       add_timeout_tv(&tv, callback, iface);
+       add_timeout_tv(&tv, callback, arg);
 }
 
 /* This deletes all timeouts for the interface EXCEPT for ones with the
  * callbacks given. Handy for deleting everything apart from the expire
  * timeout. */
 void
-delete_timeouts(struct interface *iface,
-               void (*callback)(struct interface *), ...)
+delete_timeouts(void *arg,
+               void (*callback)(void *), ...)
 {
        struct timeout *t, *tt, *last = NULL;
        va_list va;
-       void (*f)(struct interface *);
+       void (*f)(void *);
 
        for (t = timeouts; t && (tt = t->next, 1); t = tt) {
-               if (t->iface == iface && t->callback != callback) {
+               if (t->arg == arg && t->callback != callback) {
                        va_start(va, callback);
-                       while ((f = va_arg(va, void (*)(struct interface *))))
+                       while ((f = va_arg(va, void (*)(void *))))
                                if (f == t->callback)
                                        break;
                        va_end(va);
@@ -240,12 +240,12 @@ delete_timeouts(struct interface *iface,
 }
 
 void
-delete_timeout(void (*callback)(struct interface *), struct interface *iface)
+delete_timeout(void (*callback)(void *), void *arg)
 {
        struct timeout *t, *tt, *last = NULL;
 
        for (t = timeouts; t && (tt = t->next, 1); t = tt) {
-               if (t->iface == iface &&
+               if (t->arg == arg &&
                    (!callback || t->callback == callback))
                {
                        if (last)
@@ -281,7 +281,7 @@ start_eloop(void)
                        if (timercmp(&now, &timeouts->when, >)) {
                                t = timeouts;
                                timeouts = timeouts->next;
-                               t->callback(t->iface);
+                               t->callback(t->arg);
                                t->next = free_timeouts;
                                free_timeouts = t;
                                continue;
@@ -338,7 +338,7 @@ start_eloop(void)
                                continue;
                        for (e = events; e; e = e->next) {
                                if (e->fd == fds[i].fd) {
-                                       e->callback(e->iface);
+                                       e->callback(e->arg);
                                        break;
                                }
                        }
diff --git a/eloop.h b/eloop.h
index 18e64ee6fec9ca12cc95a58ce9a6caae505d8290..f29425bf7190c25b75482fb8490a2b2dc108272f 100644 (file)
--- a/eloop.h
+++ b/eloop.h
 
 #include "dhcpcd.h"
 
-void add_event(int fd, void (*)(struct interface *), struct interface *);
+void add_event(int fd, void (*)(void *), void *);
 void delete_event(int fd);
-void add_timeout_sec(time_t, void (*)(struct interface *), struct interface *);
-void add_timeout_tv(const struct timeval *,
-                   void (*)(struct interface *), struct interface *);
-void delete_timeout(void (*)(struct interface *), struct interface *);
-void delete_timeouts(struct interface *, void (*)(struct interface *), ...);
+void add_timeout_sec(time_t, void (*)(void *), void *);
+void add_timeout_tv(const struct timeval *, void (*)(void *), void *);
+void delete_timeout(void (*)(void *), void *);
+void delete_timeouts(void *, void (*)(void *), ...);
 void start_eloop(void);
 
 #endif
index 836bf8dee17c280030c8e30cc008a69e37049b22..f6f9140bdc36866049544fc4c05c986eb8bf6792 100644 (file)
@@ -293,6 +293,8 @@ parse_option(struct if_options *ifo, int opt, const char *arg)
                }
                *ifo->vendorclassid = (uint8_t)s;
                break;
+       case 'k':
+               break;
        case 'l':
                if (*arg == '-') {
                        logger(LOG_ERR,
@@ -313,6 +315,8 @@ parse_option(struct if_options *ifo, int opt, const char *arg)
                        return -1;
                }
                break;
+       case 'n':
+               break;
        case 'o':
                if (make_option_mask(ifo->requestmask, arg, 1) != 0) {
                        logger(LOG_ERR, "unknown option `%s'", arg);
@@ -557,6 +561,7 @@ read_config(const char *file, const char *ifname)
        ifo->options |= DHCPCD_CLIENTID | DHCPCD_GATEWAY | DHCPCD_DAEMONISE;
        ifo->options |= DHCPCD_ARP | DHCPCD_IPV4LL | DHCPCD_LINK;
        ifo->timeout = DEFAULT_TIMEOUT;
+       ifo->metric = -1;
        gethostname(ifo->hostname + 1, sizeof(ifo->hostname));
        if (strcmp(ifo->hostname + 1, "(none)") == 0 ||
            strcmp(ifo->hostname + 1, "localhost") == 0)
@@ -642,12 +647,14 @@ free_options(struct if_options *ifo)
 {
        size_t i;
 
-       if (ifo->environ) {
-               i = 0;
-               while (ifo->environ[i])
-                       free(ifo->environ[i++]);
-               free(ifo->environ);
+       if (ifo) {
+               if (ifo->environ) {
+                       i = 0;
+                       while (ifo->environ[i])
+                               free(ifo->environ[i++]);
+                       free(ifo->environ);
+               }
+               free(ifo->blacklist);
+               free(ifo);
        }
-       free(ifo->blacklist);
-       free(ifo);
 }
index 3e8786f0f0e0545dc77601ed899f85ef3f3ec1c0..c7b0586acd8b213cef4cd00727e925c0916d4349 100644 (file)
--- a/ipv4ll.c
+++ b/ipv4ll.c
@@ -73,8 +73,10 @@ make_ipv4ll_lease(uint32_t old_addr)
 }
 
 void
-start_ipv4ll(struct interface *iface)
+start_ipv4ll(void *arg)
 {
+       struct interface *iface = arg;
+
        iface->state->probes = 0;
        iface->state->claims = 0;
        if (iface->addr.s_addr) {
@@ -94,8 +96,9 @@ start_ipv4ll(struct interface *iface)
 }
 
 void
-handle_ipv4ll_failure(struct interface *iface)
+handle_ipv4ll_failure(void *arg)
 {
+       struct interface *iface = arg;
        time_t up;
 
        if (iface->state->fail.s_addr == iface->state->lease.addr.s_addr) {
index 82f8d59f700cb46045b6b8f9e7e5305104486669..8c1d7e524a5fd0a0000402499d7dd179260cf9ef 100644 (file)
--- a/ipv4ll.h
+++ b/ipv4ll.h
@@ -28,8 +28,6 @@
 #ifndef IPV4LL_H
 #define IPV4LL_H
 
-#include "net.h"
-
-void start_ipv4ll(struct interface *);
-void handle_ipv4ll_failure(struct interface *);
+void start_ipv4ll(void *);
+void handle_ipv4ll_failure(void *);
 #endif