diff --git a/client/powerline.c b/client/powerline.c index d6858770..cafd3d62 100644 --- a/client/powerline.c +++ b/client/powerline.c @@ -42,6 +42,26 @@ void do_write(int sd, const char *raw, size_t len) { } } +inline size_t true_sun_len(const struct sockaddr_un *ptr) { +#ifdef __linux__ + /* Because SUN_LEN uses strlen and abstract namespace paths begin + * with a null byte, SUN_LEN is broken for these. Passing the full + * struct size also fails on Linux, so compute manually. The + * abstract namespace is Linux-only. */ + if (ptr->sun_path[0] == '\0') { + return sizeof(ptr->sun_family) + strlen(ptr->sun_path + 1) + 1; + } +#endif +#ifdef SUN_LEN + /* If the vendor provided SUN_LEN, we may as well use it. */ + return SUN_LEN(ptr); +#else + /* SUN_LEN is not POSIX, so if it was not provided, use the struct + * size as a fallback. */ + return sizeof(struct sockaddr_un); +#endif +} + #ifdef __linux__ # define ADDRESS_TEMPLATE "powerline-ipc-%d" # define A +1 @@ -91,7 +111,7 @@ int main(int argc, char *argv[]) { server.sun_family = AF_UNIX; strncpy(server.sun_path A, address, strlen(address)); - if (connect(sd, (struct sockaddr *) &server, (socklen_t) (sizeof(server.sun_family) + strlen(address) A)) < 0) { + if (connect(sd, (struct sockaddr *) &server, true_sun_len(&server)) < 0) { close(sd); /* We failed to connect to the daemon, execute powerline instead */ argc = (argc < NEW_ARGV_SIZE - 1) ? argc : NEW_ARGV_SIZE - 1;