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 @@ | |||
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 | } |