Add sandbox_socket command

This command can be used to create a new listening socket (suitable for use in
WAYLAND_DISPLAY) whose clients will all have a specific label.

Co-authored-by: Mykola Orliuk <virkony@gmail.com>
This commit is contained in:
Daniel De Graaf 2020-09-12 23:48:06 -04:00
parent b7f62c9d7a
commit 27c67cc2b3
4 changed files with 151 additions and 0 deletions

View file

@ -307,4 +307,6 @@ sway_cmd cmd_ipc_cmd;
sway_cmd cmd_ipc_events; sway_cmd cmd_ipc_events;
sway_cmd cmd_ipc_event_cmd; sway_cmd cmd_ipc_event_cmd;
sway_cmd cmd_sandbox_socket;
#endif #endif

View file

@ -81,6 +81,7 @@ static const struct cmd_handler handlers[] = {
{ "no_focus", cmd_no_focus }, { "no_focus", cmd_no_focus },
{ "output", cmd_output }, { "output", cmd_output },
{ "popup_during_fullscreen", cmd_popup_during_fullscreen }, { "popup_during_fullscreen", cmd_popup_during_fullscreen },
{ "sandbox_socket", cmd_sandbox_socket },
{ "seat", cmd_seat }, { "seat", cmd_seat },
{ "set", cmd_set }, { "set", cmd_set },
{ "show_marks", cmd_show_marks }, { "show_marks", cmd_show_marks },

View file

@ -0,0 +1,147 @@
#define _XOPEN_SOURCE 700 // for strdup
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <strings.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <wayland-server-core.h>
#include "sway/client_label.h"
#include "sway/commands.h"
#include "sway/tree/container.h"
#include "sway/tree/view.h"
#include "list.h"
#include "log.h"
#include "util.h"
struct sandbox_socket {
char* path;
struct wl_event_source *src;
int fd;
char* label;
};
static list_t *sandbox_sockets;
static int fd_accept(int srv_fd, uint32_t mask, void *data) {
struct sandbox_socket *sock = data;
int cli_fd = accept(srv_fd, NULL, NULL);
if (cli_fd < 0) {
if (errno == EINTR || errno == ECONNABORTED || errno == EAGAIN || errno == EWOULDBLOCK) {
return 1;
} else {
int i;
wl_event_source_remove(sock->src);
unlink(sock->path);
free(sock->path);
close(srv_fd);
for(i = 0; i < sandbox_sockets->length; ++i) {
if (sock != sandbox_sockets->items[i])
continue;
list_del(sandbox_sockets, i);
break;
}
free(sock);
return 0;
}
}
sway_set_cloexec(cli_fd, true);
struct wl_client* client = wl_client_create(server.wl_display, cli_fd);
if (client) {
wl_client_label_set(client, strdup(sock->label));
} else {
close(cli_fd);
}
return 1;
}
struct cmd_results *cmd_sandbox_socket(int argc, char **argv) {
struct cmd_results *error = NULL;
if ((error = checkarg(argc, "sandbox_socket", EXPECTED_AT_LEAST, 2))) {
return error;
}
if (!sandbox_sockets)
sandbox_sockets = create_list();
char* op = argv[0];
if (strcmp(op, "create") == 0) {
struct sockaddr_un name = {};
char* label = NULL;
int i = 1;
while (i < argc) {
if (strcmp(argv[i], "--label") == 0) {
if (i + 1 >= argc)
return cmd_results_new(CMD_INVALID, "--label requires an argument");
label = argv[i + 1];
i += 2;
} else if (strcmp(argv[i], "--") == 0) { // after this any argument should be treated as positional
++i;
break;
} else if (strncmp(argv[i], "-", 1) == 0) {
return cmd_results_new(CMD_INVALID, "Unknown option to sandbox_socket");
} else {
break; // end of options, now only positional arguments
}
}
if ((error = checkarg(argc, "sandbox_socket", EXPECTED_EQUAL_TO, i + 1))) {
return error;
}
char *path = argv[i];
size_t path_len = strlen(path) + 1;
if (path_len > sizeof(name.sun_path)) {
return cmd_results_new(CMD_INVALID, "Invalid socket path: %s", path);
}
unlink(path);
name.sun_family = AF_UNIX;
memcpy(name.sun_path, path, path_len);
size_t name_len = offsetof(struct sockaddr_un, sun_path) + path_len;
int srv_fd = socket(AF_UNIX, SOCK_STREAM, 0);
if (srv_fd < 0 ||
!sway_set_cloexec(srv_fd, true) ||
fcntl(srv_fd, F_SETFL, O_NONBLOCK) != 0 ||
bind(srv_fd, (struct sockaddr *)&name, name_len) != 0 ||
listen(srv_fd, 5) != 0) {
close(srv_fd);
return cmd_results_new(CMD_FAILURE, "Error creating socket: %s", strerror(errno));
}
struct sandbox_socket *sock = calloc(1, sizeof(*sock));
sock->path = strdup(path);
sock->src = wl_event_loop_add_fd(server.wl_event_loop, srv_fd, WL_EVENT_READABLE, fd_accept, sock);
sock->fd = srv_fd;
if (label)
sock->label = strdup(label);
list_add(sandbox_sockets, sock);
return cmd_results_new(CMD_SUCCESS, NULL);
} else if (strcmp(op, "delete") == 0) {
char* path = argv[1];
int i;
for(i = 0; i < sandbox_sockets->length; ++i) {
struct sandbox_socket *sock = sandbox_sockets->items[i];
if (strcmp(sock->path, path) == 0) {
wl_event_source_remove(sock->src);
unlink(path);
close(sock->fd);
free(sock->path);
free(sock->label);
free(sock);
list_del(sandbox_sockets, i);
return cmd_results_new(CMD_SUCCESS, NULL);
}
}
return cmd_results_new(CMD_FAILURE, "sandbox_socket: %s not found", path);
} else {
return cmd_results_new(CMD_INVALID, "Unknown command sandbox_socket %s", op);
}
}

View file

@ -86,6 +86,7 @@ sway_sources = files(
'commands/reload.c', 'commands/reload.c',
'commands/rename.c', 'commands/rename.c',
'commands/resize.c', 'commands/resize.c',
'commands/sandbox_socket.c',
'commands/scratchpad.c', 'commands/scratchpad.c',
'commands/seat.c', 'commands/seat.c',
'commands/seat/attach.c', 'commands/seat/attach.c',