diff options
Diffstat (limited to 'sway/swaynag.c')
-rw-r--r-- | sway/swaynag.c | 124 |
1 files changed, 95 insertions, 29 deletions
diff --git a/sway/swaynag.c b/sway/swaynag.c index 49027f5d..0fca6c71 100644 --- a/sway/swaynag.c +++ b/sway/swaynag.c @@ -1,16 +1,32 @@ #define _POSIX_C_SOURCE 200809L -#include <fcntl.h> #include <signal.h> #include <stdbool.h> #include <stdlib.h> #include <stdio.h> +#include <sys/socket.h> #include <sys/types.h> +#include <sys/wait.h> #include <unistd.h> #include "log.h" +#include "sway/server.h" #include "sway/swaynag.h" +#include "util.h" + +static void handle_swaynag_client_destroy(struct wl_listener *listener, + void *data) { + struct swaynag_instance *swaynag = + wl_container_of(listener, swaynag, client_destroy); + wl_list_remove(&swaynag->client_destroy.link); + wl_list_init(&swaynag->client_destroy.link); + swaynag->client = NULL; +} bool swaynag_spawn(const char *swaynag_command, struct swaynag_instance *swaynag) { + if (swaynag->client != NULL) { + wl_client_destroy(swaynag->client); + } + if (!swaynag_command) { return true; } @@ -20,44 +36,94 @@ bool swaynag_spawn(const char *swaynag_command, sway_log(SWAY_ERROR, "Failed to create pipe for swaynag"); return false; } - fcntl(swaynag->fd[1], F_SETFD, FD_CLOEXEC); + if (!set_cloexec(swaynag->fd[1], true)) { + goto failed; + } } - pid_t pid; - if ((pid = fork()) == 0) { - if (swaynag->detailed) { - close(swaynag->fd[1]); - dup2(swaynag->fd[0], STDIN_FILENO); - close(swaynag->fd[0]); - } + int sockets[2]; + if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockets) != 0) { + sway_log_errno(SWAY_ERROR, "socketpair failed"); + goto failed; + } + if (!set_cloexec(sockets[0], true) || !set_cloexec(sockets[1], true)) { + goto failed; + } - size_t length = strlen(swaynag_command) + strlen(swaynag->args) + 2; - char *cmd = malloc(length); - snprintf(cmd, length, "%s %s", swaynag_command, swaynag->args); - execl("/bin/sh", "/bin/sh", "-c", cmd, NULL); - _exit(0); - } else if (pid < 0) { + swaynag->client = wl_client_create(server.wl_display, sockets[0]); + if (swaynag->client == NULL) { + sway_log_errno(SWAY_ERROR, "wl_client_create failed"); + goto failed; + } + + swaynag->client_destroy.notify = handle_swaynag_client_destroy; + wl_client_add_destroy_listener(swaynag->client, &swaynag->client_destroy); + + pid_t pid = fork(); + if (pid < 0) { sway_log(SWAY_ERROR, "Failed to create fork for swaynag"); - if (swaynag->detailed) { - close(swaynag->fd[0]); - close(swaynag->fd[1]); + goto failed; + } else if (pid == 0) { + pid = fork(); + if (pid < 0) { + sway_log_errno(SWAY_ERROR, "fork failed"); + _exit(EXIT_FAILURE); + } else if (pid == 0) { + if (!set_cloexec(sockets[1], false)) { + _exit(EXIT_FAILURE); + } + + if (swaynag->detailed) { + close(swaynag->fd[1]); + dup2(swaynag->fd[0], STDIN_FILENO); + close(swaynag->fd[0]); + } + + char wayland_socket_str[16]; + snprintf(wayland_socket_str, sizeof(wayland_socket_str), + "%d", sockets[1]); + setenv("WAYLAND_SOCKET", wayland_socket_str, true); + + size_t length = strlen(swaynag_command) + strlen(swaynag->args) + 2; + char *cmd = malloc(length); + snprintf(cmd, length, "%s %s", swaynag_command, swaynag->args); + execl("/bin/sh", "/bin/sh", "-c", cmd, NULL); + sway_log_errno(SWAY_ERROR, "execl failed"); + _exit(EXIT_FAILURE); } - return false; + _exit(EXIT_SUCCESS); } if (swaynag->detailed) { - close(swaynag->fd[0]); + if (close(swaynag->fd[0]) != 0) { + sway_log_errno(SWAY_ERROR, "close failed"); + return false; + } } - swaynag->pid = pid; - return true; -} + if (close(sockets[1]) != 0) { + sway_log_errno(SWAY_ERROR, "close failed"); + return false; + } + + if (waitpid(pid, NULL, 0) < 0) { + sway_log_errno(SWAY_ERROR, "waitpid failed"); + return false; + } -void swaynag_kill(struct swaynag_instance *swaynag) { - if (swaynag->pid > 0) { - kill(swaynag->pid, SIGTERM); - swaynag->pid = -1; + return true; + +failed: + if (swaynag->detailed) { + if (close(swaynag->fd[0]) != 0) { + sway_log_errno(SWAY_ERROR, "close failed"); + return false; + } + if (close(swaynag->fd[1]) != 0) { + sway_log_errno(SWAY_ERROR, "close failed"); + } } + return false; } void swaynag_log(const char *swaynag_command, struct swaynag_instance *swaynag, @@ -71,7 +137,7 @@ void swaynag_log(const char *swaynag_command, struct swaynag_instance *swaynag, return; } - if (swaynag->pid <= 0 && !swaynag_spawn(swaynag_command, swaynag)) { + if (swaynag->client == NULL && !swaynag_spawn(swaynag_command, swaynag)) { return; } @@ -96,7 +162,7 @@ void swaynag_log(const char *swaynag_command, struct swaynag_instance *swaynag, } void swaynag_show(struct swaynag_instance *swaynag) { - if (swaynag->detailed && swaynag->pid > 0) { + if (swaynag->detailed && swaynag->client != NULL) { close(swaynag->fd[1]); } } |