You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
165 lines
3.8 KiB
165 lines
3.8 KiB
#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;
|
|
}
|
|
|
|
if (swaynag->detailed) {
|
|
if (pipe(swaynag->fd) != 0) {
|
|
sway_log(SWAY_ERROR, "Failed to create pipe for swaynag");
|
|
return false;
|
|
}
|
|
if (!sway_set_cloexec(swaynag->fd[1], true)) {
|
|
goto failed;
|
|
}
|
|
}
|
|
|
|
int sockets[2];
|
|
if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockets) != 0) {
|
|
sway_log_errno(SWAY_ERROR, "socketpair failed");
|
|
goto failed;
|
|
}
|
|
if (!sway_set_cloexec(sockets[0], true) || !sway_set_cloexec(sockets[1], true)) {
|
|
goto failed;
|
|
}
|
|
|
|
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");
|
|
goto failed;
|
|
} else if (pid == 0) {
|
|
restore_nofile_limit();
|
|
|
|
pid = fork();
|
|
if (pid < 0) {
|
|
sway_log_errno(SWAY_ERROR, "fork failed");
|
|
_exit(EXIT_FAILURE);
|
|
} else if (pid == 0) {
|
|
if (!sway_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);
|
|
execlp("sh", "sh", "-c", cmd, NULL);
|
|
sway_log_errno(SWAY_ERROR, "execlp failed");
|
|
_exit(EXIT_FAILURE);
|
|
}
|
|
_exit(EXIT_SUCCESS);
|
|
}
|
|
|
|
if (swaynag->detailed) {
|
|
if (close(swaynag->fd[0]) != 0) {
|
|
sway_log_errno(SWAY_ERROR, "close failed");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
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,
|
|
const char *fmt, ...) {
|
|
if (!swaynag_command) {
|
|
return;
|
|
}
|
|
|
|
if (!swaynag->detailed) {
|
|
sway_log(SWAY_ERROR, "Attempting to write to non-detailed swaynag inst");
|
|
return;
|
|
}
|
|
|
|
if (swaynag->client == NULL && !swaynag_spawn(swaynag_command, swaynag)) {
|
|
return;
|
|
}
|
|
|
|
va_list args;
|
|
va_start(args, fmt);
|
|
char *str = vformat_str(fmt, args);
|
|
va_end(args);
|
|
if (!str) {
|
|
sway_log(SWAY_ERROR, "Failed to allocate buffer for swaynag log entry.");
|
|
return;
|
|
}
|
|
|
|
write(swaynag->fd[1], str, strlen(str));
|
|
|
|
free(str);
|
|
}
|
|
|
|
void swaynag_show(struct swaynag_instance *swaynag) {
|
|
if (swaynag->detailed && swaynag->client != NULL) {
|
|
close(swaynag->fd[1]);
|
|
}
|
|
}
|
|
|