#include "config.h"
#include "dhcpcd.h"
+#ifdef HAS_GETTEXT
+#include <libintl.h>
#define _ gettext
+#else
+#define _(a) (a)
+#endif
#ifndef SUN_LEN
#define SUN_LEN(su) \
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;
* 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) {
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
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;
return dhcpcd_get_value(i, pvar);
}
-static bool strtobool(const char *var)
+static bool
+strtobool(const char *var)
{
if (var == NULL)
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) {
}
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)
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') {
} 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;
}
else
con->interfaces = i;
i->next = NULL;
+ i->last_message = NULL;
} else
free(i->data);
/* Sort! */
n = nl = NULL;
p = orderdup;
+ addedi = false;
while ((o = strsep(&p, " ")) != NULL) {
for (ti = 0; dhcpcd_types[ti]; ti++) {
l = NULL;
}
if (e == NULL)
continue;
+ if (i == e)
+ addedi = true;
if (l)
l->next = e->next;
else
while (con->interfaces) {
e = con->interfaces->next;
free(con->interfaces->data);
+ free(con->interfaces->last_message);
free(con->interfaces);
con->interfaces = e;
}
con->interfaces = n;
- return i;
+ return addedi ? i : NULL;
}
static DHCPCD_IF *
/* Have to call update_status last as it could
* cause the interface to be destroyed. */
- update_status(con);
+ update_status(con, NULL);
}
DHCPCD_CONNECTION *
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
#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
return con->listen_fd;
}
+bool
+dhcpcd_privileged(DHCPCD_CONNECTION *con)
+{
+
+ assert(con);
+ return con->privileged;
+}
+
const char *
dhcpcd_status(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;
}
}
}
+void
+dhcpcd_free(DHCPCD_CONNECTION *con)
+{
+
+ assert(con);
+ free(con);
+}
+
DHCPCD_CONNECTION *
dhcpcd_if_connection(DHCPCD_IF *i)
{
}
char *
-dhcpcd_if_message(const DHCPCD_IF *i)
+dhcpcd_if_message(DHCPCD_IF *i, bool *new_msg)
{
const char *ip, *iplen, *pfx;
char *msg, *p;
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");
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);
- return msg;
-}
+ snprintf(p, len - (size_t)(p - msg), " %s", ip);
-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);
- 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;
+ if (new_msg) {
+ if (i->last_message == NULL || strcmp(i->last_message, msg))
+ *new_msg = true;
+ else
+ *new_msg = false;
}
- free(con);
+ free(i->last_message);
+ i->last_message = strdup(msg);
+
+ return msg;
}