|  |  |  | @ -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]); | 
			
		
	
		
			
				
					|  |  |  |  | 	} | 
			
		
	
		
			
				
					|  |  |  |  | } | 
			
		
	
	
		
			
				
					|  |  |  | 
 |