aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--common/util.c19
-rw-r--r--include/sway/swaynag.h8
-rw-r--r--include/util.h2
-rw-r--r--sway/config.c21
-rw-r--r--sway/config/output.c19
-rw-r--r--sway/main.c2
-rw-r--r--sway/swaynag.c124
-rw-r--r--swaynag/swaynag.c23
8 files changed, 147 insertions, 71 deletions
diff --git a/common/util.c b/common/util.c
index c43c5ddf..3a807edb 100644
--- a/common/util.c
+++ b/common/util.c
@@ -1,5 +1,6 @@
#define _POSIX_C_SOURCE 200809L
#include <float.h>
+#include <fcntl.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>
@@ -75,3 +76,21 @@ const char *sway_wl_output_subpixel_to_string(enum wl_output_subpixel subpixel)
sway_assert(false, "Unknown value for wl_output_subpixel.");
return NULL;
}
+
+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;
+}
diff --git a/include/sway/swaynag.h b/include/sway/swaynag.h
index 5a178739..74d9ea18 100644
--- a/include/sway/swaynag.h
+++ b/include/sway/swaynag.h
@@ -1,9 +1,12 @@
#ifndef _SWAY_SWAYNAG_H
#define _SWAY_SWAYNAG_H
+#include <wayland-server-core.h>
struct swaynag_instance {
+ struct wl_client *client;
+ struct wl_listener client_destroy;
+
const char *args;
- pid_t pid;
int fd[2];
bool detailed;
};
@@ -15,9 +18,6 @@ struct swaynag_instance {
bool swaynag_spawn(const char *swaynag_command,
struct swaynag_instance *swaynag);
-// Kill the swaynag instance
-void swaynag_kill(struct swaynag_instance *swaynag);
-
// Write a log message to swaynag->fd[1]. This will fail when swaynag->detailed
// is false.
void swaynag_log(const char *swaynag_command, struct swaynag_instance *swaynag,
diff --git a/include/util.h b/include/util.h
index 6a668fd6..6d9454e0 100644
--- a/include/util.h
+++ b/include/util.h
@@ -32,4 +32,6 @@ float parse_float(const char *value);
const char *sway_wl_output_subpixel_to_string(enum wl_output_subpixel subpixel);
+bool set_cloexec(int fd, bool cloexec);
+
#endif
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]);
}
}
diff --git a/swaynag/swaynag.c b/swaynag/swaynag.c
index eb31da57..26411ab3 100644
--- a/swaynag/swaynag.c
+++ b/swaynag/swaynag.c
@@ -45,17 +45,24 @@ static void swaynag_button_execute(struct swaynag *swaynag,
swaynag->details.visible = !swaynag->details.visible;
render_frame(swaynag);
} else {
- if (fork() == 0) {
+ pid_t pid = fork();
+ if (pid < 0) {
+ sway_log_errno(SWAY_DEBUG, "Failed to fork");
+ return;
+ } else if (pid == 0) {
// Child process. Will be used to prevent zombie processes
- setsid();
- if (fork() == 0) {
+ pid = fork();
+ if (pid < 0) {
+ sway_log_errno(SWAY_DEBUG, "Failed to fork");
+ return;
+ } else if (pid == 0) {
// Child of the child. Will be reparented to the init process
char *terminal = getenv("TERMINAL");
if (button->terminal && terminal && strlen(terminal)) {
sway_log(SWAY_DEBUG, "Found $TERMINAL: %s", terminal);
if (!terminal_execute(terminal, button->action)) {
swaynag_destroy(swaynag);
- exit(EXIT_FAILURE);
+ _exit(EXIT_FAILURE);
}
} else {
if (button->terminal) {
@@ -63,12 +70,16 @@ static void swaynag_button_execute(struct swaynag *swaynag,
"$TERMINAL not found. Running directly");
}
execl("/bin/sh", "/bin/sh", "-c", button->action, NULL);
+ sway_log_errno(SWAY_DEBUG, "execl failed");
+ _exit(EXIT_FAILURE);
}
}
- exit(EXIT_SUCCESS);
+ _exit(EXIT_SUCCESS);
+ }
+ if (waitpid(pid, NULL, 0) < 0) {
+ sway_log_errno(SWAY_DEBUG, "waitpid failed");
}
}
- wait(0);
}
static void layer_surface_configure(void *data,