mirror of
https://codeberg.org/dnkl/foot.git
synced 2026-03-27 07:58:07 -04:00
Make foot able to receive a socket from its parent
If the argument to --server is parsed as a number, consider it to be a file descriptor, and use that as a socket. This is necessary to be able to use socket activation with the server mode of foot.
This commit is contained in:
parent
bd5576825f
commit
88a0f7397c
1 changed files with 92 additions and 27 deletions
119
server.c
119
server.c
|
|
@ -1,6 +1,7 @@
|
||||||
#include "server.h"
|
#include "server.h"
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <fcntl.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|
||||||
|
|
@ -19,6 +20,7 @@
|
||||||
#include "client-protocol.h"
|
#include "client-protocol.h"
|
||||||
#include "shm.h"
|
#include "shm.h"
|
||||||
#include "terminal.h"
|
#include "terminal.h"
|
||||||
|
#include "util.h"
|
||||||
#include "wayland.h"
|
#include "wayland.h"
|
||||||
#include "xmalloc.h"
|
#include "xmalloc.h"
|
||||||
|
|
||||||
|
|
@ -425,44 +427,107 @@ err:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
prepare_socket(int fd)
|
||||||
|
{
|
||||||
|
int flags = fcntl(fd, F_GETFD);
|
||||||
|
if (flags < 0) {
|
||||||
|
LOG_ERRNO("failed to get file descriptors flag for passed socket");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1) {
|
||||||
|
LOG_ERRNO("failed to set FD_CLOEXEC for passed socket");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
flags = fcntl(fd, F_GETFL);
|
||||||
|
if (flags < 0) {
|
||||||
|
LOG_ERRNO("failed to get file status flags for passed socket");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) {
|
||||||
|
LOG_ERRNO("failed to set non-blocking mode on passed socket");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int const socket_options[] = { SO_DOMAIN, SO_ACCEPTCONN, SO_TYPE };
|
||||||
|
int const socket_options_values[] = { AF_UNIX, 1, SOCK_STREAM};
|
||||||
|
char const * const socket_options_names[] = { "SO_DOMAIN", "SO_ACCEPTCONN", "SO_TYPE" };
|
||||||
|
|
||||||
|
xassert(ALEN(socket_options) == ALEN(socket_options_values));
|
||||||
|
xassert(ALEN(socket_options) == ALEN(socket_options_names));
|
||||||
|
|
||||||
|
int socket_option = 0;
|
||||||
|
socklen_t len;
|
||||||
|
for (size_t i = 0; i < ALEN(socket_options) ; i++) {
|
||||||
|
len = sizeof(socket_option);
|
||||||
|
if (getsockopt(fd, SOL_SOCKET, socket_options[i], &socket_option, &len) == -1 ||
|
||||||
|
len != sizeof(socket_option)) {
|
||||||
|
LOG_ERRNO("failed to read socket option from passed file descriptor");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (socket_option != socket_options_values[i]) {
|
||||||
|
LOG_ERR("wrong socket value for socket option '%s' on passed file descriptor",
|
||||||
|
socket_options_names[i]);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
struct server *
|
struct server *
|
||||||
server_init(const struct config *conf, struct fdm *fdm, struct reaper *reaper,
|
server_init(const struct config *conf, struct fdm *fdm, struct reaper *reaper,
|
||||||
struct wayland *wayl)
|
struct wayland *wayl)
|
||||||
{
|
{
|
||||||
int fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);
|
int fd;
|
||||||
if (fd == -1) {
|
|
||||||
LOG_ERRNO("failed to create UNIX socket");
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct server *server = NULL;
|
struct server *server = NULL;
|
||||||
const char *sock_path = conf->server_socket_path;
|
const char *sock_path = conf->server_socket_path;
|
||||||
|
char *end;
|
||||||
|
|
||||||
switch (try_connect(sock_path)) {
|
errno = 0;
|
||||||
case CONNECT_FAIL:
|
fd = strtol(sock_path, &end, 10);
|
||||||
break;
|
if (*end == '\0' && *sock_path != '\0')
|
||||||
|
{
|
||||||
case CONNECT_SUCCESS:
|
if (!prepare_socket(fd))
|
||||||
LOG_ERR("%s is already accepting connections; is 'foot --server' already running", sock_path);
|
goto err;
|
||||||
/* FALLTHROUGH */
|
LOG_DBG("we've been started by socket activation, using passed socket");
|
||||||
|
sock_path = NULL;
|
||||||
case CONNECT_ERR:
|
|
||||||
goto err;
|
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
LOG_DBG("no suitable pre-existing socket found, creating our own");
|
||||||
|
fd = socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);
|
||||||
|
if (fd == -1) {
|
||||||
|
LOG_ERRNO("failed to create UNIX socket");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
unlink(sock_path);
|
switch (try_connect(sock_path)) {
|
||||||
|
case CONNECT_FAIL:
|
||||||
|
break;
|
||||||
|
|
||||||
struct sockaddr_un addr = {.sun_family = AF_UNIX};
|
case CONNECT_SUCCESS:
|
||||||
strncpy(addr.sun_path, sock_path, sizeof(addr.sun_path) - 1);
|
LOG_ERR("%s is already accepting connections; is 'foot --server' already running", sock_path);
|
||||||
|
/* FALLTHROUGH */
|
||||||
|
|
||||||
if (bind(fd, (const struct sockaddr *)&addr, sizeof(addr)) < 0) {
|
case CONNECT_ERR:
|
||||||
LOG_ERRNO("%s: failed to bind", addr.sun_path);
|
goto err;
|
||||||
goto err;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (listen(fd, 0) < 0) {
|
unlink(sock_path);
|
||||||
LOG_ERRNO("%s: failed to listen", addr.sun_path);
|
|
||||||
goto err;
|
struct sockaddr_un addr = {.sun_family = AF_UNIX};
|
||||||
|
strncpy(addr.sun_path, sock_path, sizeof(addr.sun_path) - 1);
|
||||||
|
|
||||||
|
if (bind(fd, (const struct sockaddr *)&addr, sizeof(addr)) < 0) {
|
||||||
|
LOG_ERRNO("%s: failed to bind", addr.sun_path);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (listen(fd, 0) < 0) {
|
||||||
|
LOG_ERRNO("%s: failed to listen", addr.sun_path);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
server = malloc(sizeof(*server));
|
server = malloc(sizeof(*server));
|
||||||
|
|
@ -487,7 +552,7 @@ server_init(const struct config *conf, struct fdm *fdm, struct reaper *reaper,
|
||||||
if (!fdm_add(fdm, fd, EPOLLIN, &fdm_server, server))
|
if (!fdm_add(fdm, fd, EPOLLIN, &fdm_server, server))
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
LOG_INFO("accepting connections on %s", sock_path);
|
LOG_INFO("accepting connections on %s", sock_path != NULL ? sock_path : "socket provided through socket activation");
|
||||||
|
|
||||||
return server;
|
return server;
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue