This enables us to query states via the control socket.
struct if_options *ifo = state->options;
struct dhcp_lease *lease = &state->lease;
struct timeval tv;
- const char *reason = NULL;
+ state->reason = NULL;
delete_timeout(handle_exit_timeout, NULL);
if (clock_monotonic)
get_monotonic(&lease->boundtime);
iface->name, inet_ntoa(lease->addr));
lease->leasetime = ~0U;
lease->net.s_addr = ifo->request_netmask.s_addr;
- reason = "STATIC";
+ state->reason = "STATIC";
} else if (IN_LINKLOCAL(htonl(state->new->yiaddr))) {
syslog(LOG_INFO, "%s: using IPv4LL address %s",
iface->name, inet_ntoa(lease->addr));
lease->leasetime = ~0U;
- reason = "IPV4LL";
+ state->reason = "IPV4LL";
} else if (ifo->options & DHCPCD_INFORM) {
if (ifo->request_address.s_addr != 0)
lease->addr.s_addr = ifo->request_address.s_addr;
syslog(LOG_INFO, "%s: received approval for %s", iface->name,
inet_ntoa(lease->addr));
lease->leasetime = ~0U;
- reason = "INFORM";
+ state->reason = "INFORM";
} else {
if (gettimeofday(&tv, NULL) == 0)
lease->leasedfrom = tv.tv_sec;
else if (lease->frominfo)
- reason = "TIMEOUT";
+ state->reason = "TIMEOUT";
if (lease->leasetime == ~0U) {
lease->renewaltime = lease->rebindtime = lease->leasetime;
syslog(LOG_INFO, "%s: leased %s for infinity",
inet_ntoa(lease->addr), lease->leasetime);
}
}
- if (reason == NULL) {
+ if (options & DHCPCD_TEST) {
+ state->reason = "TEST";
+ run_script(iface);
+ exit(EXIT_SUCCESS);
+ }
+ if (state->reason == NULL) {
if (state->old) {
if (state->old->yiaddr == state->new->yiaddr &&
lease->server.s_addr)
- reason = "RENEW";
+ state->reason = "RENEW";
else
- reason = "REBIND";
+ state->reason = "REBIND";
} else if (state->state == DHS_REBOOT)
- reason = "REBOOT";
+ state->reason = "REBOOT";
else
- reason = "BOUND";
- }
- if (options & DHCPCD_TEST) {
- run_script(iface, "TEST");
- exit(EXIT_SUCCESS);
+ state->reason = "BOUND";
}
if (lease->leasetime == ~0U)
lease->renewaltime = lease->rebindtime = lease->leasetime;
add_timeout_sec(lease->rebindtime, start_rebind, iface);
add_timeout_sec(lease->leasetime, start_expire, iface);
}
- configure(iface, reason);
+ configure(iface);
daemonise();
state->state = DHS_BOUND;
if (ifo->options & DHCPCD_ARP) {
return len;
}
-int
-run_script(const struct interface *iface, const char *reason)
+static ssize_t
+make_env(const struct interface *iface, char ***argv)
{
- char *const argv[2] = { UNCONST(iface->state->options->script), NULL };
- char **env = NULL, **ep;
- char *path, *p, *bigenv;
+ char **env, *p;
ssize_t e, elen, l;
- pid_t pid;
- int status = 0;
const struct if_options *ifo = iface->state->options;
const struct interface *ifp;
- const struct fd_list *fd;
- struct iovec iov[2];
-
- syslog(LOG_DEBUG, "%s: executing `%s', reason %s",
- iface->name, argv[0], reason);
/* Make our env */
- elen = 6;
+ elen = 5;
env = xmalloc(sizeof(char *) * (elen + 1));
- path = getenv("PATH");
- if (path) {
- e = strlen("PATH") + strlen(path) + 2;
- env[0] = xmalloc(e);
- snprintf(env[0], e, "PATH=%s", path);
- } else
- env[0] = xstrdup(DEFAULT_PATH);
e = strlen("interface") + strlen(iface->name) + 2;
+ env[0] = xmalloc(e);
+ snprintf(env[0], e, "interface=%s", iface->name);
+ e = strlen("reason") + strlen(iface->state->reason) + 2;
env[1] = xmalloc(e);
- snprintf(env[1], e, "interface=%s", iface->name);
- e = strlen("reason") + strlen(reason) + 2;
- env[2] = xmalloc(e);
- snprintf(env[2], e, "reason=%s", reason);
+ snprintf(env[1], e, "reason=%s", iface->state->reason);
e = 20;
+ env[2] = xmalloc(e);
+ snprintf(env[2], e, "pid=%d", getpid());
env[3] = xmalloc(e);
- snprintf(env[3], e, "pid=%d", getpid());
- env[4] = xmalloc(e);
- snprintf(env[4], e, "metric=%d", iface->metric);
+ snprintf(env[3], e, "metric=%d", iface->metric);
l = e = strlen("interface_order=");
for (ifp = ifaces; ifp; ifp = ifp->next)
e += strlen(ifp->name) + 1;
- p = env[5] = xmalloc(e);
+ p = env[4] = xmalloc(e);
strlcpy(p, "interface_order=", e);
e -= l;
p += l;
}
env[elen] = '\0';
+ *argv = env;
+ return elen;
+}
+
+int
+send_state(int fd, const struct interface *iface)
+{
+ char **env, **ep, *s;
+ ssize_t elen;
+ struct iovec iov[2];
+ int retval;
+
+ retval = 0;
+ make_env(iface, &env);
+ elen = arraytostr((const char *const *)env, &s);
+ iov[0].iov_base = &elen;
+ iov[0].iov_len = sizeof(ssize_t);
+ iov[1].iov_base = s;
+ iov[1].iov_len = elen;
+ retval = writev(fd, iov, 2);
+ ep = env;
+ while (*ep)
+ free(*ep++);
+ free(env);
+ free(s);
+ return retval;
+}
+
+int
+run_script(const struct interface *iface)
+{
+ char *const argv[2] = { UNCONST(iface->state->options->script), NULL };
+ char **env = NULL, **ep;
+ char *path, *bigenv;
+ ssize_t e, elen = 0;
+ pid_t pid;
+ int status = 0;
+ const struct fd_list *fd;
+ struct iovec iov[2];
+
+ syslog(LOG_DEBUG, "%s: executing `%s', reason %s",
+ iface->name, argv[0], iface->state->reason);
+
+ /* Make our env */
+ elen = make_env(iface, &env);
+ env = xrealloc(env, sizeof(char *) * (elen + 2));
+ /* Add path to it */
+ path = getenv("PATH");
+ if (path) {
+ e = strlen("PATH") + strlen(path) + 2;
+ env[elen] = xmalloc(e);
+ snprintf(env[elen], e, "PATH=%s", path);
+ } else
+ env[elen] = xstrdup(DEFAULT_PATH);
+ env[++elen] = '\0';
+
pid = exec_script(argv, env);
if (pid == -1)
status = -1;
elen = arraytostr((const char *const *)env,
&bigenv);
iov[0].iov_base = &elen;
- iov[0].iov_len = sizeof(size_t);
+ iov[0].iov_len = sizeof(ssize_t);
iov[1].iov_base = bigenv;
iov[1].iov_len = elen;
}
}
int
-configure(struct interface *iface, const char *reason)
+configure(struct interface *iface)
{
struct dhcp_message *dhcp = iface->state->new;
struct dhcp_lease *lease = &iface->state->lease;
build_routes();
delete_address(iface);
}
- run_script(iface, reason);
+ run_script(iface);
return 0;
}
!(iface->state->options->options & DHCPCD_INFORM))
if (write_lease(iface, dhcp) == -1)
syslog(LOG_ERR, "write_lease: %m");
- run_script(iface, reason);
+ run_script(iface);
return 0;
}
#include "net.h"
-int run_script(const struct interface *, const char *);
-int configure(struct interface *, const char *);
+int send_state(int, const struct interface *);
+int run_script(const struct interface *);
+int configure(struct interface *);
#endif
free(iface->state->old);
iface->state->old = iface->state->new;
iface->state->new = NULL;
- configure(iface, reason);
+ if (reason == NULL)
+ iface->state->reason = "EXPIRE";
+ else
+ iface->state->reason = reason;
+ configure(iface);
}
iface->state->lease.addr.s_addr = 0;
}
state->old = state->new;
state->new = state->offer;
state->offer = NULL;
- run_script(iface, "TEST");
+ state->reason = "TEST";
+ run_script(iface);
exit(EXIT_SUCCESS);
}
delete_timeout(send_discover, iface);
ifs = iface->state = xzalloc(sizeof(*ifs));
ifs->state = DHS_INIT;
+ ifs->reason = "PREINIT";
ifs->nakoff = 1;
configure_interface(iface, argc, argv);
if (ifn)
continue;
init_state(ifp, 2, UNCONST(argv));
- run_script(ifp, "PREINIT");
+ run_script(ifp);
start_interface(ifp);
if (ifl)
ifl->next = ifp;
struct interface *ifs, *ifp, *ifl, *ifn, *ift;
int do_exit = 0, do_release = 0, do_reboot = 0, opt, oi = 0;
char *s, *p;
- size_t l, len;
+ ssize_t l, len;
+ struct iovec iov[2];
if (fd != NULL) {
+ /* Special commands for our control socket */
if (strcmp(*argv, "--version") == 0) {
write(fd->fd, VERSION, strlen(VERSION));
return 0;
- } else if (strcmp(*argv, "--listinterfaces") == 0) {
+ } else if (strcmp(*argv, "--getinterfaces") == 0) {
l = 0;
for (ifp = ifaces; ifp; ifp = ifp->next)
l += strlen(ifp->name) + 1;
*p++ = ' ';
}
*--p = '\0';
- write(fd->fd, s, l);
+ iov[0].iov_base = &l;
+ iov[0].iov_len = sizeof(ssize_t);
+ iov[1].iov_base = s;
+ iov[1].iov_len = l;
+ writev(fd->fd, iov, 2);
free(s);
return 0;
+ } else if (strcmp(*argv, "--getstates") == 0) {
+ l = 0;
+ for (ifp = ifaces; ifp; ifp = ifp->next)
+ l++;
+ write(fd->fd, &l, sizeof(l));
+ for (ifp = ifaces; ifp; ifp = ifp->next)
+ send_state(fd->fd, ifp);
+ return 0;
} else if (strcmp(*argv, "--listen") == 0) {
fd->listener = 1;
return 0;
} else {
ifp->next = NULL;
init_state(ifp, argc, argv);
- run_script(ifp, "PREINIT");
+ run_script(ifp);
start_interface(ifp);
if (ifl)
ifl->next = ifp;
sort_interfaces();
for (iface = ifaces; iface; iface = iface->next) {
if (!(options & DHCPCD_TEST))
- run_script(iface, "PREINIT");
+ run_script(iface);
start_interface(iface);
}
start_eloop();
struct dhcp_message *new;
struct dhcp_message *old;
struct dhcp_lease lease;
+ const char *reason;
time_t interval;
time_t nakoff;
uint32_t xid;