diff options
author | Brian Ashworth <bosrsf04@gmail.com> | 2019-04-14 00:27:47 -0400 |
---|---|---|
committer | Simon Ser <contact@emersion.fr> | 2019-04-14 12:41:59 +0300 |
commit | 6961bf2e4ce2c116e41a8db158691f6c993707ce (patch) | |
tree | a381146599a5f19e565006cafeb23edc04247d2b | |
parent | swaynag: fix pointer management (diff) | |
download | sway-6961bf2e4ce2c116e41a8db158691f6c993707ce.tar.gz sway-6961bf2e4ce2c116e41a8db158691f6c993707ce.tar.zst sway-6961bf2e4ce2c116e41a8db158691f6c993707ce.zip |
Spawn swaynag as a wayland client
This spawns swaynag as a wayland client similar to how swaybar and
swaybg are already done
-rw-r--r-- | common/util.c | 19 | ||||
-rw-r--r-- | include/sway/swaynag.h | 8 | ||||
-rw-r--r-- | include/util.h | 2 | ||||
-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 | ||||
-rw-r--r-- | swaynag/swaynag.c | 23 |
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 | |||
80 | bool 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 | ||
4 | struct swaynag_instance { | 5 | struct 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 { | |||
15 | bool swaynag_spawn(const char *swaynag_command, | 18 | bool swaynag_spawn(const char *swaynag_command, |
16 | struct swaynag_instance *swaynag); | 19 | struct swaynag_instance *swaynag); |
17 | 20 | ||
18 | // Kill the swaynag instance | ||
19 | void 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. |
23 | void swaynag_log(const char *swaynag_command, struct swaynag_instance *swaynag, | 23 | 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); | |||
32 | 32 | ||
33 | const char *sway_wl_output_subpixel_to_string(enum wl_output_subpixel subpixel); | 33 | const char *sway_wl_output_subpixel_to_string(enum wl_output_subpixel subpixel); |
34 | 34 | ||
35 | bool 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 | ||
176 | static void config_defaults(struct sway_config *config) { | 176 | static 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 | ||
491 | static 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 | |||
509 | static bool _spawn_swaybg(char **command) { | 490 | static 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 | |||
15 | static 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 | ||
12 | bool swaynag_spawn(const char *swaynag_command, | 24 | bool 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 | ||
56 | void swaynag_kill(struct swaynag_instance *swaynag) { | 114 | return true; |
57 | if (swaynag->pid > 0) { | 115 | |
58 | kill(swaynag->pid, SIGTERM); | 116 | failed: |
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 | ||
63 | void swaynag_log(const char *swaynag_command, struct swaynag_instance *swaynag, | 129 | 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, | |||
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 | ||
98 | void swaynag_show(struct swaynag_instance *swaynag) { | 164 | void 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 | ||
74 | static void layer_surface_configure(void *data, | 85 | static void layer_surface_configure(void *data, |