aboutsummaryrefslogtreecommitdiffstats
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 @@
1#define _POSIX_C_SOURCE 200809L 1#define _POSIX_C_SOURCE 200809L
2#include <float.h> 2#include <float.h>
3#include <fcntl.h>
3#include <math.h> 4#include <math.h>
4#include <stdlib.h> 5#include <stdlib.h>
5#include <string.h> 6#include <string.h>
@@ -75,3 +76,21 @@ const char *sway_wl_output_subpixel_to_string(enum wl_output_subpixel subpixel)
75 sway_assert(false, "Unknown value for wl_output_subpixel."); 76 sway_assert(false, "Unknown value for wl_output_subpixel.");
76 return NULL; 77 return NULL;
77} 78}
79
80bool set_cloexec(int fd, bool cloexec) {
81 int flags = fcntl(fd, F_GETFD);
82 if (flags == -1) {
83 sway_log_errno(SWAY_ERROR, "fcntl failed");
84 return false;
85 }
86 if (cloexec) {
87 flags = flags | FD_CLOEXEC;
88 } else {
89 flags = flags & ~FD_CLOEXEC;
90 }
91 if (fcntl(fd, F_SETFD, flags) == -1) {
92 sway_log_errno(SWAY_ERROR, "fcntl failed");
93 return false;
94 }
95 return true;
96}
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 @@
1#ifndef _SWAY_SWAYNAG_H 1#ifndef _SWAY_SWAYNAG_H
2#define _SWAY_SWAYNAG_H 2#define _SWAY_SWAYNAG_H
3#include <wayland-server-core.h>
3 4
4struct swaynag_instance { 5struct swaynag_instance {
6 struct wl_client *client;
7 struct wl_listener client_destroy;
8
5 const char *args; 9 const char *args;
6 pid_t pid;
7 int fd[2]; 10 int fd[2];
8 bool detailed; 11 bool detailed;
9}; 12};
@@ -15,9 +18,6 @@ struct swaynag_instance {
15bool swaynag_spawn(const char *swaynag_command, 18bool swaynag_spawn(const char *swaynag_command,
16 struct swaynag_instance *swaynag); 19 struct swaynag_instance *swaynag);
17 20
18// Kill the swaynag instance
19void swaynag_kill(struct swaynag_instance *swaynag);
20
21// Write a log message to swaynag->fd[1]. This will fail when swaynag->detailed 21// Write a log message to swaynag->fd[1]. This will fail when swaynag->detailed
22// is false. 22// is false.
23void swaynag_log(const char *swaynag_command, struct swaynag_instance *swaynag, 23void 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);
32 32
33const char *sway_wl_output_subpixel_to_string(enum wl_output_subpixel subpixel); 33const char *sway_wl_output_subpixel_to_string(enum wl_output_subpixel subpixel);
34 34
35bool set_cloexec(int fd, bool cloexec);
36
35#endif 37#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) {
175 175
176static void config_defaults(struct sway_config *config) { 176static void config_defaults(struct sway_config *config) {
177 if (!(config->swaynag_command = strdup("swaynag"))) goto cleanup; 177 if (!(config->swaynag_command = strdup("swaynag"))) goto cleanup;
178 config->swaynag_config_errors = (struct swaynag_instance){ 178 config->swaynag_config_errors = (struct swaynag_instance){0};
179 .args = "--type error " 179 config->swaynag_config_errors.args = "--type error "
180 "--message 'There are errors in your config file' " 180 "--message 'There are errors in your config file' "
181 "--detailed-message " 181 "--detailed-message "
182 "--button 'Exit sway' 'swaymsg exit' " 182 "--button-no-terminal 'Exit sway' 'swaymsg exit' "
183 "--button 'Reload sway' 'swaymsg reload'", 183 "--button-no-terminal 'Reload sway' 'swaymsg reload'";
184 .pid = -1, 184 config->swaynag_config_errors.detailed = true;
185 .detailed = true,
186 };
187 185
188 if (!(config->symbols = create_list())) goto cleanup; 186 if (!(config->symbols = create_list())) goto cleanup;
189 if (!(config->modes = create_list())) goto cleanup; 187 if (!(config->modes = create_list())) goto cleanup;
@@ -411,10 +409,9 @@ bool load_main_config(const char *file, bool is_active, bool validating) {
411 config->reloading = true; 409 config->reloading = true;
412 config->active = true; 410 config->active = true;
413 411
414 swaynag_kill(&old_config->swaynag_config_errors); 412 if (old_config->swaynag_config_errors.client != NULL) {
415 memcpy(&config->swaynag_config_errors, 413 wl_client_destroy(old_config->swaynag_config_errors.client);
416 &old_config->swaynag_config_errors, 414 }
417 sizeof(struct swaynag_instance));
418 415
419 input_manager_reset_all_inputs(); 416 input_manager_reset_all_inputs();
420 } 417 }
@@ -486,7 +483,7 @@ bool load_main_config(const char *file, bool is_active, bool validating) {
486 spawn_swaybg(); 483 spawn_swaybg();
487 484
488 config->reloading = false; 485 config->reloading = false;
489 if (config->swaynag_config_errors.pid > 0) { 486 if (config->swaynag_config_errors.client != NULL) {
490 swaynag_show(&config->swaynag_config_errors); 487 swaynag_show(&config->swaynag_config_errors);
491 } 488 }
492 489
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 @@
1#define _POSIX_C_SOURCE 200809L 1#define _POSIX_C_SOURCE 200809L
2#include <assert.h> 2#include <assert.h>
3#include <fcntl.h>
4#include <stdbool.h> 3#include <stdbool.h>
5#include <string.h> 4#include <string.h>
6#include <sys/socket.h> 5#include <sys/socket.h>
@@ -488,24 +487,6 @@ static void handle_swaybg_client_destroy(struct wl_listener *listener,
488 config->swaybg_client = NULL; 487 config->swaybg_client = NULL;
489} 488}
490 489
491static bool set_cloexec(int fd, bool cloexec) {
492 int flags = fcntl(fd, F_GETFD);
493 if (flags == -1) {
494 sway_log_errno(SWAY_ERROR, "fcntl failed");
495 return false;
496 }
497 if (cloexec) {
498 flags = flags | FD_CLOEXEC;
499 } else {
500 flags = flags & ~FD_CLOEXEC;
501 }
502 if (fcntl(fd, F_SETFD, flags) == -1) {
503 sway_log_errno(SWAY_ERROR, "fcntl failed");
504 return false;
505 }
506 return true;
507}
508
509static bool _spawn_swaybg(char **command) { 490static bool _spawn_swaybg(char **command) {
510 if (config->swaybg_client != NULL) { 491 if (config->swaybg_client != NULL) {
511 wl_client_destroy(config->swaybg_client); 492 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) {
391 load_swaybars(); 391 load_swaybars();
392 run_deferred_commands(); 392 run_deferred_commands();
393 393
394 if (config->swaynag_config_errors.pid > 0) { 394 if (config->swaynag_config_errors.client != NULL) {
395 swaynag_show(&config->swaynag_config_errors); 395 swaynag_show(&config->swaynag_config_errors);
396 } 396 }
397 397
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 @@
1#define _POSIX_C_SOURCE 200809L 1#define _POSIX_C_SOURCE 200809L
2#include <fcntl.h>
3#include <signal.h> 2#include <signal.h>
4#include <stdbool.h> 3#include <stdbool.h>
5#include <stdlib.h> 4#include <stdlib.h>
6#include <stdio.h> 5#include <stdio.h>
6#include <sys/socket.h>
7#include <sys/types.h> 7#include <sys/types.h>
8#include <sys/wait.h>
8#include <unistd.h> 9#include <unistd.h>
9#include "log.h" 10#include "log.h"
11#include "sway/server.h"
10#include "sway/swaynag.h" 12#include "sway/swaynag.h"
13#include "util.h"
14
15static void handle_swaynag_client_destroy(struct wl_listener *listener,
16 void *data) {
17 struct swaynag_instance *swaynag =
18 wl_container_of(listener, swaynag, client_destroy);
19 wl_list_remove(&swaynag->client_destroy.link);
20 wl_list_init(&swaynag->client_destroy.link);
21 swaynag->client = NULL;
22}
11 23
12bool swaynag_spawn(const char *swaynag_command, 24bool swaynag_spawn(const char *swaynag_command,
13 struct swaynag_instance *swaynag) { 25 struct swaynag_instance *swaynag) {
26 if (swaynag->client != NULL) {
27 wl_client_destroy(swaynag->client);
28 }
29
14 if (!swaynag_command) { 30 if (!swaynag_command) {
15 return true; 31 return true;
16 } 32 }
@@ -20,44 +36,94 @@ bool swaynag_spawn(const char *swaynag_command,
20 sway_log(SWAY_ERROR, "Failed to create pipe for swaynag"); 36 sway_log(SWAY_ERROR, "Failed to create pipe for swaynag");
21 return false; 37 return false;
22 } 38 }
23 fcntl(swaynag->fd[1], F_SETFD, FD_CLOEXEC); 39 if (!set_cloexec(swaynag->fd[1], true)) {
40 goto failed;
41 }
24 } 42 }
25 43
26 pid_t pid; 44 int sockets[2];
27 if ((pid = fork()) == 0) { 45 if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockets) != 0) {
28 if (swaynag->detailed) { 46 sway_log_errno(SWAY_ERROR, "socketpair failed");
29 close(swaynag->fd[1]); 47 goto failed;
30 dup2(swaynag->fd[0], STDIN_FILENO); 48 }
31 close(swaynag->fd[0]); 49 if (!set_cloexec(sockets[0], true) || !set_cloexec(sockets[1], true)) {
32 } 50 goto failed;
51 }
33 52
34 size_t length = strlen(swaynag_command) + strlen(swaynag->args) + 2; 53 swaynag->client = wl_client_create(server.wl_display, sockets[0]);
35 char *cmd = malloc(length); 54 if (swaynag->client == NULL) {
36 snprintf(cmd, length, "%s %s", swaynag_command, swaynag->args); 55 sway_log_errno(SWAY_ERROR, "wl_client_create failed");
37 execl("/bin/sh", "/bin/sh", "-c", cmd, NULL); 56 goto failed;
38 _exit(0); 57 }
39 } else if (pid < 0) { 58
59 swaynag->client_destroy.notify = handle_swaynag_client_destroy;
60 wl_client_add_destroy_listener(swaynag->client, &swaynag->client_destroy);
61
62 pid_t pid = fork();
63 if (pid < 0) {
40 sway_log(SWAY_ERROR, "Failed to create fork for swaynag"); 64 sway_log(SWAY_ERROR, "Failed to create fork for swaynag");
41 if (swaynag->detailed) { 65 goto failed;
42 close(swaynag->fd[0]); 66 } else if (pid == 0) {
43 close(swaynag->fd[1]); 67 pid = fork();
68 if (pid < 0) {
69 sway_log_errno(SWAY_ERROR, "fork failed");
70 _exit(EXIT_FAILURE);
71 } else if (pid == 0) {
72 if (!set_cloexec(sockets[1], false)) {
73 _exit(EXIT_FAILURE);
74 }
75
76 if (swaynag->detailed) {
77 close(swaynag->fd[1]);
78 dup2(swaynag->fd[0], STDIN_FILENO);
79 close(swaynag->fd[0]);
80 }
81
82 char wayland_socket_str[16];
83 snprintf(wayland_socket_str, sizeof(wayland_socket_str),
84 "%d", sockets[1]);
85 setenv("WAYLAND_SOCKET", wayland_socket_str, true);
86
87 size_t length = strlen(swaynag_command) + strlen(swaynag->args) + 2;
88 char *cmd = malloc(length);
89 snprintf(cmd, length, "%s %s", swaynag_command, swaynag->args);
90 execl("/bin/sh", "/bin/sh", "-c", cmd, NULL);
91 sway_log_errno(SWAY_ERROR, "execl failed");
92 _exit(EXIT_FAILURE);
44 } 93 }
45 return false; 94 _exit(EXIT_SUCCESS);
46 } 95 }
47 96
48 if (swaynag->detailed) { 97 if (swaynag->detailed) {
49 close(swaynag->fd[0]); 98 if (close(swaynag->fd[0]) != 0) {
99 sway_log_errno(SWAY_ERROR, "close failed");
100 return false;
101 }
50 } 102 }
51 swaynag->pid = pid;
52 return true;
53}
54 103
104 if (close(sockets[1]) != 0) {
105 sway_log_errno(SWAY_ERROR, "close failed");
106 return false;
107 }
108
109 if (waitpid(pid, NULL, 0) < 0) {
110 sway_log_errno(SWAY_ERROR, "waitpid failed");
111 return false;
112 }
55 113
56void swaynag_kill(struct swaynag_instance *swaynag) { 114 return true;
57 if (swaynag->pid > 0) { 115
58 kill(swaynag->pid, SIGTERM); 116failed:
59 swaynag->pid = -1; 117 if (swaynag->detailed) {
118 if (close(swaynag->fd[0]) != 0) {
119 sway_log_errno(SWAY_ERROR, "close failed");
120 return false;
121 }
122 if (close(swaynag->fd[1]) != 0) {
123 sway_log_errno(SWAY_ERROR, "close failed");
124 }
60 } 125 }
126 return false;
61} 127}
62 128
63void swaynag_log(const char *swaynag_command, struct swaynag_instance *swaynag, 129void 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,
71 return; 137 return;
72 } 138 }
73 139
74 if (swaynag->pid <= 0 && !swaynag_spawn(swaynag_command, swaynag)) { 140 if (swaynag->client == NULL && !swaynag_spawn(swaynag_command, swaynag)) {
75 return; 141 return;
76 } 142 }
77 143
@@ -96,7 +162,7 @@ void swaynag_log(const char *swaynag_command, struct swaynag_instance *swaynag,
96} 162}
97 163
98void swaynag_show(struct swaynag_instance *swaynag) { 164void swaynag_show(struct swaynag_instance *swaynag) {
99 if (swaynag->detailed && swaynag->pid > 0) { 165 if (swaynag->detailed && swaynag->client != NULL) {
100 close(swaynag->fd[1]); 166 close(swaynag->fd[1]);
101 } 167 }
102} 168}
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,
45 swaynag->details.visible = !swaynag->details.visible; 45 swaynag->details.visible = !swaynag->details.visible;
46 render_frame(swaynag); 46 render_frame(swaynag);
47 } else { 47 } else {
48 if (fork() == 0) { 48 pid_t pid = fork();
49 if (pid < 0) {
50 sway_log_errno(SWAY_DEBUG, "Failed to fork");
51 return;
52 } else if (pid == 0) {
49 // Child process. Will be used to prevent zombie processes 53 // Child process. Will be used to prevent zombie processes
50 setsid(); 54 pid = fork();
51 if (fork() == 0) { 55 if (pid < 0) {
56 sway_log_errno(SWAY_DEBUG, "Failed to fork");
57 return;
58 } else if (pid == 0) {
52 // Child of the child. Will be reparented to the init process 59 // Child of the child. Will be reparented to the init process
53 char *terminal = getenv("TERMINAL"); 60 char *terminal = getenv("TERMINAL");
54 if (button->terminal && terminal && strlen(terminal)) { 61 if (button->terminal && terminal && strlen(terminal)) {
55 sway_log(SWAY_DEBUG, "Found $TERMINAL: %s", terminal); 62 sway_log(SWAY_DEBUG, "Found $TERMINAL: %s", terminal);
56 if (!terminal_execute(terminal, button->action)) { 63 if (!terminal_execute(terminal, button->action)) {
57 swaynag_destroy(swaynag); 64 swaynag_destroy(swaynag);
58 exit(EXIT_FAILURE); 65 _exit(EXIT_FAILURE);
59 } 66 }
60 } else { 67 } else {
61 if (button->terminal) { 68 if (button->terminal) {
@@ -63,12 +70,16 @@ static void swaynag_button_execute(struct swaynag *swaynag,
63 "$TERMINAL not found. Running directly"); 70 "$TERMINAL not found. Running directly");
64 } 71 }
65 execl("/bin/sh", "/bin/sh", "-c", button->action, NULL); 72 execl("/bin/sh", "/bin/sh", "-c", button->action, NULL);
73 sway_log_errno(SWAY_DEBUG, "execl failed");
74 _exit(EXIT_FAILURE);
66 } 75 }
67 } 76 }
68 exit(EXIT_SUCCESS); 77 _exit(EXIT_SUCCESS);
78 }
79 if (waitpid(pid, NULL, 0) < 0) {
80 sway_log_errno(SWAY_DEBUG, "waitpid failed");
69 } 81 }
70 } 82 }
71 wait(0);
72} 83}
73 84
74static void layer_surface_configure(void *data, 85static void layer_surface_configure(void *data,