X-Git-Url: https://roy.marples.name/git diff --git a/src/libdhcpcd/dhcpcd.c b/src/libdhcpcd/dhcpcd.c index 7c79e8c..508137c 100644 --- a/src/libdhcpcd/dhcpcd.c +++ b/src/libdhcpcd/dhcpcd.c @@ -48,7 +48,12 @@ #include "config.h" #include "dhcpcd.h" +#ifdef HAS_GETTEXT +#include #define _ gettext +#else +#define _(a) (a) +#endif #ifndef SUN_LEN #define SUN_LEN(su) \ @@ -60,9 +65,9 @@ static const char * const dhcpcd_types[] = static ssize_t dhcpcd_command_fd(DHCPCD_CONNECTION *con, - int fd, const char *cmd, char **buffer) + int fd, bool progname, const char *cmd, char **buffer) { - size_t len; + size_t pl, cl, len; ssize_t bytes; char buf[1024], *p; char *nbuf; @@ -71,15 +76,28 @@ dhcpcd_command_fd(DHCPCD_CONNECTION *con, * Each argument is NULL seperated. * We may need to send a space one day, so the API * in this function may need to be improved */ - len = strlen(cmd) + 1; + cl = strlen(cmd); + if (progname) { + pl = strlen(con->progname); + len = pl + 1 + cl + 1; + } else { + pl = 0; + len = cl + 1; + } if (con->terminate_commands) len++; if (len > sizeof(buf)) { errno = ENOBUFS; return -1; } - strlcpy(buf, cmd, sizeof(buf)); p = buf; + if (progname) { + memcpy(buf, con->progname, pl); + buf[pl] = '\0'; + p = buf + pl + 1; + } + memcpy(p, cmd, cl); + p[cl] = '\0'; while ((p = strchr(p, ' ')) != NULL) *p++ = '\0'; if (con->terminate_commands) { @@ -110,7 +128,14 @@ ssize_t dhcpcd_command(DHCPCD_CONNECTION *con, const char *cmd, char **buffer) { - return dhcpcd_command_fd(con, con->command_fd, cmd, buffer); + return dhcpcd_command_fd(con, con->command_fd, true, cmd, buffer); +} + +static ssize_t +dhcpcd_ctrl_command(DHCPCD_CONNECTION *con, const char *cmd, char **buffer) +{ + + return dhcpcd_command_fd(con, con->command_fd, false, cmd, buffer); } bool @@ -136,31 +161,36 @@ dhcpcd_command_arg(DHCPCD_CONNECTION *con, const char *cmd, const char *arg, size_t cmdlen, len; cmdlen = strlen(cmd); - len = cmdlen + strlen(arg) + 2; + if (arg) + len = cmdlen + strlen(arg) + 2; + else + len = cmdlen + 1; if (!dhcpcd_realloc(con, len)) return -1; strlcpy(con->buf, cmd, con->buflen); - con->buf[cmdlen] = ' '; - strlcpy(con->buf + cmdlen + 1, arg, con->buflen - 1 - cmdlen); + if (arg) { + con->buf[cmdlen] = ' '; + strlcpy(con->buf + cmdlen + 1, arg, con->buflen - 1 - cmdlen); + } - return dhcpcd_command_fd(con, con->command_fd, con->buf, buffer); + return dhcpcd_command_fd(con, con->command_fd, true, con->buf, buffer); } static int -dhcpcd_connect(void) +dhcpcd_connect(const char *path, int opts) { int fd; socklen_t len; struct sockaddr_un sun; - fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0); + fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | opts, 0); if (fd == -1) return -1; memset(&sun, 0, sizeof(sun)); sun.sun_family = AF_UNIX; - strlcpy(sun.sun_path, DHCPCD_SOCKET, sizeof(sun.sun_path)); + strlcpy(sun.sun_path, path, sizeof(sun.sun_path)); len = (socklen_t)SUN_LEN(&sun); if (connect(fd, (struct sockaddr *)&sun, len) == 0) return fd; @@ -220,7 +250,8 @@ dhcpcd_get_prefix_value(const DHCPCD_IF *i, const char *prefix, const char *var) return dhcpcd_get_value(i, pvar); } -static bool strtobool(const char *var) +static bool +strtobool(const char *var) { if (var == NULL) @@ -238,9 +269,15 @@ get_status(DHCPCD_CONNECTION *con) const char *status; assert(con); - if (con->command_fd == -1 || con->listen_fd == -1) + if (con->command_fd == -1) return "down"; + if (con->listen_fd == -1) + return "opened"; + + if (con->interfaces == NULL) + return "initialised"; + status = "disconnected"; for (i = con->interfaces; i; i = i->next) { if (i->up) { @@ -255,12 +292,12 @@ get_status(DHCPCD_CONNECTION *con) } static void -update_status(DHCPCD_CONNECTION *con) +update_status(DHCPCD_CONNECTION *con, const char *nstatus) { - const char *nstatus; assert(con); - nstatus = get_status(con); + if (nstatus == NULL) + nstatus = get_status(con); if (con->status == NULL || strcmp(nstatus, con->status)) { con->status = nstatus; if (con->status_cb) @@ -296,6 +333,7 @@ dhcpcd_new_if(DHCPCD_CONNECTION *con, char *data, size_t len) char *orderdup, *o, *p; DHCPCD_IF *e, *i, *l, *n, *nl; int ti; + bool addedi; ifname = get_value(data, len, "interface="); if (ifname == NULL || *ifname == '\0') { @@ -362,7 +400,7 @@ dhcpcd_new_if(DHCPCD_CONNECTION *con, char *data, size_t len) } else if (strcmp(type, "link")) { /* If link is down, ignore it */ e = dhcpcd_get_if(con, ifname, "link"); - if (e && strcmp(e->reason, "NOCARRIER") == 0) + if (e && !e->up) return NULL; } @@ -420,6 +458,7 @@ dhcpcd_new_if(DHCPCD_CONNECTION *con, char *data, size_t len) /* Sort! */ n = nl = NULL; p = orderdup; + addedi = false; while ((o = strsep(&p, " ")) != NULL) { for (ti = 0; dhcpcd_types[ti]; ti++) { l = NULL; @@ -431,6 +470,8 @@ dhcpcd_new_if(DHCPCD_CONNECTION *con, char *data, size_t len) } if (e == NULL) continue; + if (i == e) + addedi = true; if (l) l->next = e->next; else @@ -455,7 +496,7 @@ dhcpcd_new_if(DHCPCD_CONNECTION *con, char *data, size_t len) } con->interfaces = n; - return i; + return addedi ? i : NULL; } static DHCPCD_IF * @@ -516,7 +557,7 @@ dhcpcd_dispatch(DHCPCD_CONNECTION *con) /* Have to call update_status last as it could * cause the interface to be destroyed. */ - update_status(con); + update_status(con, NULL); } DHCPCD_CONNECTION * @@ -526,9 +567,27 @@ dhcpcd_new(void) con = calloc(1, sizeof(*con)); con->command_fd = con->listen_fd = -1; + con->open = false; + con->progname = "libdhcpcd"; return con; } +void +dhcpcd_set_progname(DHCPCD_CONNECTION *con, const char *progname) +{ + + assert(con); + con->progname = progname; +} + +const char * +dhcpcd_get_progname(const DHCPCD_CONNECTION *con) +{ + + assert(con); + return con->progname; +} + #ifndef __GLIBC__ /* Good enough for our needs */ static int @@ -555,60 +614,60 @@ strverscmp(const char *s1, const char *s2) #endif int -dhcpcd_open(DHCPCD_CONNECTION *con) +dhcpcd_open(DHCPCD_CONNECTION *con, bool privileged) { + const char *path = privileged ? DHCPCD_SOCKET : DHCPCD_UNPRIV_SOCKET; char cmd[128]; ssize_t bytes; size_t nifs, n; - DHCPCD_IF *i; assert(con); - if (con->listen_fd != -1) - return con->listen_fd; - con->command_fd = dhcpcd_connect(); - if (con->command_fd == -1) { - update_status(con); + if (con->open) { + if (con->listen_fd != -1) + return con->listen_fd; + errno = EISCONN; return -1; } + /* We need to block the command fd */ + con->command_fd = dhcpcd_connect(path, 0); + if (con->command_fd == -1) + goto err_exit; con->terminate_commands = false; - if (dhcpcd_command(con, "--version", &con->version) <= 0) - return -1; + if (dhcpcd_ctrl_command(con, "--version", &con->version) <= 0) + goto err_exit; con->terminate_commands = strverscmp(con->version, "6.4.1") >= 0 ? true : false; - if (dhcpcd_command(con, "--getconfigfile", &con->cffile) <= 0) - return -1; + if (dhcpcd_ctrl_command(con, "--getconfigfile", &con->cffile) <= 0) + goto err_exit; - con->listen_fd = dhcpcd_connect(); - if (con->listen_fd == -1) { - close(con->command_fd); - con->command_fd = -1; - update_status(con); - return -1; - } - dhcpcd_command_fd(con, con->listen_fd, "--listen", NULL); + con->open = true; + con->privileged = privileged; + update_status(con, NULL); - dhcpcd_command_fd(con, con->command_fd, "--getinterfaces", NULL); + con->listen_fd = dhcpcd_connect(path, SOCK_NONBLOCK); + if (con->listen_fd == -1) + goto err_exit; + + dhcpcd_command_fd(con, con->listen_fd, false, "--listen", NULL); + dhcpcd_command_fd(con, con->command_fd, false, "--getinterfaces", NULL); bytes = read(con->command_fd, cmd, sizeof(nifs)); - if (bytes != sizeof(nifs)) { - close(con->command_fd); - con->command_fd = -1; - close(con->listen_fd); - con->listen_fd = -1; - } else { - memcpy(&nifs, cmd, sizeof(nifs)); - /* We don't dispatch each interface here as that - * causes too much notification spam when the GUI starts */ - for (n = 0; n < nifs; n++) { - i = dhcpcd_read_if(con, con->command_fd); - if (i) - dhcpcd_wpa_if_event(i); - } - } - update_status(con); + if (bytes != sizeof(nifs)) + goto err_exit; + memcpy(&nifs, cmd, sizeof(nifs)); + /* We don't dispatch each interface here as that + * causes too much notification spam when the GUI starts */ + for (n = 0; n < nifs; n++) + dhcpcd_read_if(con, con->command_fd); + + update_status(con, NULL); return con->listen_fd; + +err_exit: + dhcpcd_close(con); + return -1; } int @@ -619,6 +678,14 @@ dhcpcd_get_fd(DHCPCD_CONNECTION *con) return con->listen_fd; } +bool +dhcpcd_privileged(DHCPCD_CONNECTION *con) +{ + + assert(con); + return con->privileged; +} + const char * dhcpcd_status(DHCPCD_CONNECTION *con) { @@ -666,21 +733,48 @@ dhcpcd_set_status_callback(DHCPCD_CONNECTION *con, void dhcpcd_close(DHCPCD_CONNECTION *con) { - DHCPCD_WPA *wpa; + DHCPCD_IF *nif; + DHCPCD_WPA *nwpa; + DHCPCD_WI_HIST *nh; assert(con); + con->open = false; + /* Shut down WPA listeners as they aren't much good without dhcpcd. * They'll be restarted anyway when dhcpcd comes back up. */ - for (wpa = con->wpa; wpa; wpa = wpa->next) + while (con->wpa) { + nwpa = con->wpa->next; dhcpcd_wpa_close(con->wpa); + free(con->wpa); + con->wpa = nwpa; + } + while (con->wi_history) { + nh = con->wi_history->next; + free(con->wi_history); + con->wi_history = nh; + } + while (con->interfaces) { + nif = con->interfaces->next; + free(con->interfaces->data); + free(con->interfaces->last_message); + free(con->interfaces); + con->interfaces = nif; + } - if (con->command_fd != -1) { + if (con->command_fd != -1) shutdown(con->command_fd, SHUT_RDWR); + if (con->listen_fd != -1) + shutdown(con->listen_fd, SHUT_RDWR); + + update_status(con, "down"); + + if (con->command_fd != -1) { + close(con->command_fd); con->command_fd = -1; } if (con->listen_fd != -1) { - shutdown(con->listen_fd, SHUT_RDWR); + close(con->listen_fd); con->listen_fd = -1; } @@ -699,6 +793,14 @@ dhcpcd_close(DHCPCD_CONNECTION *con) } } +void +dhcpcd_free(DHCPCD_CONNECTION *con) +{ + + assert(con); + free(con); +} + DHCPCD_CONNECTION * dhcpcd_if_connection(DHCPCD_IF *i) { @@ -740,7 +842,9 @@ dhcpcd_if_message(DHCPCD_IF *i, bool *new_msg) reason = _("Not associated"); } else reason = _("Cable unplugged"); - } else if (strcmp(i->reason, "UNKNOWN") == 0) + } else if (strcmp(i->reason, "DEPARTED") == 0) + reason = _("Departed"); + else if (strcmp(i->reason, "UNKNOWN") == 0) reason = _("Unknown link state"); else if (strcmp(i->reason, "FAIL") == 0) reason = _("Automatic configuration not possible"); @@ -783,9 +887,9 @@ dhcpcd_if_message(DHCPCD_IF *i, bool *new_msg) if (showssid) p += snprintf(p, len - (size_t)(p - msg), " %s", i->ssid); if (iplen) - p += snprintf(p, len - (size_t)(p - msg), " %s/%s", ip, iplen); + snprintf(p, len - (size_t)(p - msg), " %s/%s", ip, iplen); else if (ip) - p += snprintf(p, len - (size_t)(p - msg), " %s", ip); + snprintf(p, len - (size_t)(p - msg), " %s", ip); if (new_msg) { if (i->last_message == NULL || strcmp(i->last_message, msg)) @@ -798,32 +902,3 @@ dhcpcd_if_message(DHCPCD_IF *i, bool *new_msg) return msg; } - -void -dhcpcd_free(DHCPCD_CONNECTION *con) -{ - DHCPCD_IF *nif; - DHCPCD_WPA *nwpa; - DHCPCD_WI_HIST *nh; - - assert(con); - while (con->interfaces) { - nif = con->interfaces->next; - free(con->interfaces->data); - free(con->interfaces->last_message); - free(con->interfaces); - con->interfaces = nif; - } - while (con->wpa) { - nwpa = con->wpa->next; - dhcpcd_wpa_close(con->wpa); - free(con->wpa); - con->wpa = nwpa; - } - while (con->wi_history) { - nh = con->wi_history->next; - free(con->wi_history); - con->wi_history = nh; - } - free(con); -}