mirror of
https://github.com/swaywm/sway.git
synced 2026-04-22 06:46:27 -04:00
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:
parent
b7f62c9d7a
commit
27c67cc2b3
4 changed files with 151 additions and 0 deletions
|
|
@ -307,4 +307,6 @@ sway_cmd cmd_ipc_cmd;
|
|||
sway_cmd cmd_ipc_events;
|
||||
sway_cmd cmd_ipc_event_cmd;
|
||||
|
||||
sway_cmd cmd_sandbox_socket;
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -81,6 +81,7 @@ static const struct cmd_handler handlers[] = {
|
|||
{ "no_focus", cmd_no_focus },
|
||||
{ "output", cmd_output },
|
||||
{ "popup_during_fullscreen", cmd_popup_during_fullscreen },
|
||||
{ "sandbox_socket", cmd_sandbox_socket },
|
||||
{ "seat", cmd_seat },
|
||||
{ "set", cmd_set },
|
||||
{ "show_marks", cmd_show_marks },
|
||||
|
|
|
|||
147
sway/commands/sandbox_socket.c
Normal file
147
sway/commands/sandbox_socket.c
Normal 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);
|
||||
}
|
||||
}
|
||||
|
|
@ -86,6 +86,7 @@ sway_sources = files(
|
|||
'commands/reload.c',
|
||||
'commands/rename.c',
|
||||
'commands/resize.c',
|
||||
'commands/sandbox_socket.c',
|
||||
'commands/scratchpad.c',
|
||||
'commands/seat.c',
|
||||
'commands/seat/attach.c',
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue