diff options
Diffstat (limited to 'sway')
-rw-r--r-- | sway/config.c | 21 | ||||
-rw-r--r-- | sway/config/output.c | 19 | ||||
-rw-r--r-- | sway/main.c | 2 | ||||
-rw-r--r-- | sway/swaynag.c | 124 |
4 files changed, 105 insertions, 61 deletions
diff --git a/sway/config.c b/sway/config.c index d5bfe105..4944ec02 100644 --- a/sway/config.c +++ b/sway/config.c @@ -175,15 +175,13 @@ static void set_color(float dest[static 4], uint32_t color) { static void config_defaults(struct sway_config *config) { if (!(config->swaynag_command = strdup("swaynag"))) goto cleanup; - config->swaynag_config_errors = (struct swaynag_instance){ - .args = "--type error " + config->swaynag_config_errors = (struct swaynag_instance){0}; + config->swaynag_config_errors.args = "--type error " "--message 'There are errors in your config file' " "--detailed-message " - "--button 'Exit sway' 'swaymsg exit' " - "--button 'Reload sway' 'swaymsg reload'", - .pid = -1, - .detailed = true, - }; + "--button-no-terminal 'Exit sway' 'swaymsg exit' " + "--button-no-terminal 'Reload sway' 'swaymsg reload'"; + config->swaynag_config_errors.detailed = true; if (!(config->symbols = create_list())) goto cleanup; if (!(config->modes = create_list())) goto cleanup; @@ -411,10 +409,9 @@ bool load_main_config(const char *file, bool is_active, bool validating) { config->reloading = true; config->active = true; - swaynag_kill(&old_config->swaynag_config_errors); - memcpy(&config->swaynag_config_errors, - &old_config->swaynag_config_errors, - sizeof(struct swaynag_instance)); + if (old_config->swaynag_config_errors.client != NULL) { + wl_client_destroy(old_config->swaynag_config_errors.client); + } input_manager_reset_all_inputs(); } @@ -486,7 +483,7 @@ bool load_main_config(const char *file, bool is_active, bool validating) { spawn_swaybg(); config->reloading = false; - if (config->swaynag_config_errors.pid > 0) { + if (config->swaynag_config_errors.client != NULL) { swaynag_show(&config->swaynag_config_errors); } diff --git a/sway/config/output.c b/sway/config/output.c index 747ab28b..fb8a9ee5 100644 --- a/sway/config/output.c +++ b/sway/config/output.c @@ -1,6 +1,5 @@ #define _POSIX_C_SOURCE 200809L #include <assert.h> -#include <fcntl.h> #include <stdbool.h> #include <string.h> #include <sys/socket.h> @@ -488,24 +487,6 @@ static void handle_swaybg_client_destroy(struct wl_listener *listener, config->swaybg_client = NULL; } -static bool set_cloexec(int fd, bool cloexec) { - int flags = fcntl(fd, F_GETFD); - if (flags == -1) { - sway_log_errno(SWAY_ERROR, "fcntl failed"); - return false; - } - if (cloexec) { - flags = flags | FD_CLOEXEC; - } else { - flags = flags & ~FD_CLOEXEC; - } - if (fcntl(fd, F_SETFD, flags) == -1) { - sway_log_errno(SWAY_ERROR, "fcntl failed"); - return false; - } - return true; -} - static bool _spawn_swaybg(char **command) { if (config->swaybg_client != NULL) { wl_client_destroy(config->swaybg_client); diff --git a/sway/main.c b/sway/main.c index ba4e2562..96f67b36 100644 --- a/sway/main.c +++ b/sway/main.c @@ -391,7 +391,7 @@ int main(int argc, char **argv) { load_swaybars(); run_deferred_commands(); - if (config->swaynag_config_errors.pid > 0) { + if (config->swaynag_config_errors.client != NULL) { swaynag_show(&config->swaynag_config_errors); } 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]); } } |