mirror of
https://codeberg.org/dnkl/foot.git
synced 2026-02-08 10:06:22 -05:00
client: send overrides for everything that is publicly visible in the conf
Send a generic “overrides” list to the server, containing options in text, on the format “section.key=value”. This reduces the size of the base client/server protocol packet, as well as opens up for a generic -o,--override command line option (not yet implemented).
This commit is contained in:
parent
fa5cde6ce1
commit
136d60606a
4 changed files with 109 additions and 141 deletions
|
|
@ -4,32 +4,23 @@
|
|||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
|
||||
struct client_argv {
|
||||
struct client_string {
|
||||
uint16_t len;
|
||||
/* char arg[static len]; */
|
||||
/* char str[static len]; */
|
||||
};
|
||||
|
||||
struct client_data {
|
||||
unsigned width;
|
||||
unsigned height;
|
||||
uint8_t size_type:1; // Values correspond to enum conf_size_type
|
||||
uint8_t maximized:1;
|
||||
uint8_t fullscreen:1;
|
||||
uint8_t hold:1;
|
||||
uint8_t login_shell:1;
|
||||
uint8_t no_wait:1;
|
||||
bool hold:1;
|
||||
bool no_wait:1;
|
||||
uint8_t reserved:6;
|
||||
|
||||
uint16_t cwd_len;
|
||||
uint16_t term_len;
|
||||
uint16_t title_len;
|
||||
uint16_t app_id_len;
|
||||
|
||||
uint16_t override_count;
|
||||
uint16_t argc;
|
||||
|
||||
/* char cwd[static cwd_len]; */
|
||||
/* char term[static term_len]; */
|
||||
/* char title[static title_len]; */
|
||||
/* char app_id[static app_id_len]; */
|
||||
/* struct client_string overrides[static override_count]; */
|
||||
/* struct client_string argv[static argc]; */
|
||||
} __attribute__((packed));
|
||||
|
||||
/* struct client_argv argv[static argc]; */
|
||||
};
|
||||
_Static_assert(sizeof(struct client_data) == 7, "protocol struct size error");
|
||||
|
|
|
|||
140
client.c
140
client.c
|
|
@ -12,6 +12,8 @@
|
|||
#include <sys/un.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <tllist.h>
|
||||
|
||||
#define LOG_MODULE "foot-client"
|
||||
#define LOG_ENABLE_DBG 0
|
||||
#include "log.h"
|
||||
|
|
@ -96,22 +98,22 @@ main(int argc, char *const *argv)
|
|||
{NULL, no_argument, NULL, 0},
|
||||
};
|
||||
|
||||
const char *term = "";
|
||||
const char *title = "";
|
||||
const char *app_id = "";
|
||||
tll(char *) overrides = tll_init();
|
||||
|
||||
const char *custom_cwd = NULL;
|
||||
unsigned size_type = 0; // enum conf_size_type (without pulling in tllist/fcft via config.h)
|
||||
unsigned width = 0;
|
||||
unsigned height = 0;
|
||||
const char *server_socket_path = NULL;
|
||||
enum log_class log_level = LOG_CLASS_INFO;
|
||||
enum log_colorize log_colorize = LOG_COLORIZE_AUTO;
|
||||
bool login_shell = false;
|
||||
bool maximized = false;
|
||||
bool fullscreen = false;
|
||||
bool hold = false;
|
||||
bool no_wait = false;
|
||||
|
||||
char buf[1024];
|
||||
|
||||
/* malloc:ed and needs to be in scope of all goto's */
|
||||
char *_cwd = NULL;
|
||||
struct client_string *coverrides = NULL;
|
||||
struct client_string *cargv = NULL;
|
||||
|
||||
while (true) {
|
||||
int c = getopt_long(argc, argv, "+t:T:a:w:W:mFLD:s:HNd:l::vh", longopts, NULL);
|
||||
if (c == -1)
|
||||
|
|
@ -119,55 +121,62 @@ main(int argc, char *const *argv)
|
|||
|
||||
switch (c) {
|
||||
case 't':
|
||||
term = optarg;
|
||||
snprintf(buf, sizeof(buf), "term=%s", optarg);
|
||||
tll_push_back(overrides, xstrdup(buf));
|
||||
break;
|
||||
|
||||
case 'T':
|
||||
title = optarg;
|
||||
snprintf(buf, sizeof(buf), "title=%s", optarg);
|
||||
tll_push_back(overrides, xstrdup(buf));
|
||||
break;
|
||||
|
||||
case 'a':
|
||||
app_id = optarg;
|
||||
snprintf(buf, sizeof(buf), "app-id=%s", optarg);
|
||||
tll_push_back(overrides, xstrdup(buf));
|
||||
break;
|
||||
|
||||
case 'L':
|
||||
login_shell = true;
|
||||
tll_push_back(overrides, xstrdup("login-shell=yes"));
|
||||
break;
|
||||
|
||||
case 'D': {
|
||||
struct stat st;
|
||||
if (stat(optarg, &st) < 0 || !(st.st_mode & S_IFDIR)) {
|
||||
fprintf(stderr, "error: %s: not a directory\n", optarg);
|
||||
return ret;
|
||||
goto err;
|
||||
}
|
||||
custom_cwd = optarg;
|
||||
break;
|
||||
}
|
||||
|
||||
case 'w':
|
||||
case 'w': {
|
||||
unsigned width, height;
|
||||
if (sscanf(optarg, "%ux%u", &width, &height) != 2 || width == 0 || height == 0) {
|
||||
fprintf(stderr, "error: invalid window-size-pixels: %s\n", optarg);
|
||||
return ret;
|
||||
}
|
||||
size_type = 0; // CONF_SIZE_PX
|
||||
snprintf(buf, sizeof(buf), "initial-window-size-pixels=%ux%u", width, height);
|
||||
tll_push_back(overrides, xstrdup(buf));
|
||||
break;
|
||||
}
|
||||
|
||||
case 'W':
|
||||
case 'W': {
|
||||
unsigned width, height;
|
||||
if (sscanf(optarg, "%ux%u", &width, &height) != 2 || width == 0 || height == 0) {
|
||||
fprintf(stderr, "error: invalid window-size-chars: %s\n", optarg);
|
||||
return ret;
|
||||
goto err;
|
||||
}
|
||||
size_type = 1; // CONF_SIZE_CELLS
|
||||
snprintf(buf, sizeof(buf), "initial-window-size-chars=%ux%u", width, height);
|
||||
tll_push_back(overrides, xstrdup(buf));
|
||||
break;
|
||||
}
|
||||
|
||||
case 'm':
|
||||
maximized = true;
|
||||
fullscreen = false;
|
||||
tll_push_back(overrides, xstrdup("initial-window-mode=maximized"));
|
||||
break;
|
||||
|
||||
case 'F':
|
||||
fullscreen = true;
|
||||
maximized = false;
|
||||
tll_push_back(overrides, xstrdup("initial-window-mode=fullscreen"));
|
||||
break;
|
||||
|
||||
case 's':
|
||||
|
|
@ -190,7 +199,7 @@ main(int argc, char *const *argv)
|
|||
"-d,--log-level: %s: argument must be one of %s\n",
|
||||
optarg,
|
||||
log_level_string_hint());
|
||||
return ret;
|
||||
goto err;
|
||||
}
|
||||
log_level = lvl;
|
||||
break;
|
||||
|
|
@ -205,20 +214,22 @@ main(int argc, char *const *argv)
|
|||
log_colorize = LOG_COLORIZE_ALWAYS;
|
||||
else {
|
||||
fprintf(stderr, "%s: argument must be one of 'never', 'always' or 'auto'\n", optarg);
|
||||
return ret;
|
||||
goto err;
|
||||
}
|
||||
break;
|
||||
|
||||
case 'v':
|
||||
printf("footclient %s\n", version_and_features());
|
||||
return EXIT_SUCCESS;
|
||||
ret = EXIT_SUCCESS;
|
||||
goto err;
|
||||
|
||||
case 'h':
|
||||
print_usage(prog_name);
|
||||
return EXIT_SUCCESS;
|
||||
ret = EXIT_SUCCESS;
|
||||
goto err;
|
||||
|
||||
case '?':
|
||||
return ret;
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -227,10 +238,6 @@ main(int argc, char *const *argv)
|
|||
|
||||
log_init(log_colorize, false, LOG_FACILITY_USER, log_level);
|
||||
|
||||
/* malloc:ed and needs to be in scope of all goto's */
|
||||
char *_cwd = NULL;
|
||||
struct client_argv *cargv = NULL;
|
||||
|
||||
int fd = socket(AF_UNIX, SOCK_STREAM, 0);
|
||||
if (fd == -1) {
|
||||
LOG_ERRNO("failed to create socket");
|
||||
|
|
@ -290,33 +297,36 @@ main(int argc, char *const *argv)
|
|||
|
||||
/* String lengths, including NULL terminator */
|
||||
const size_t cwd_len = strlen(cwd) + 1;
|
||||
const size_t term_len = strlen(term) + 1;
|
||||
const size_t title_len = strlen(title) + 1;
|
||||
const size_t app_id_len = strlen(app_id) + 1;
|
||||
const size_t override_count = tll_length(overrides);
|
||||
|
||||
const struct client_data data = {
|
||||
.width = width,
|
||||
.height = height,
|
||||
.size_type = size_type,
|
||||
.maximized = maximized,
|
||||
.fullscreen = fullscreen,
|
||||
.hold = hold,
|
||||
.login_shell = login_shell,
|
||||
.no_wait = no_wait,
|
||||
.cwd_len = cwd_len,
|
||||
.term_len = term_len,
|
||||
.title_len = title_len,
|
||||
.app_id_len = app_id_len,
|
||||
.override_count = override_count,
|
||||
.argc = argc,
|
||||
};
|
||||
|
||||
/* Total packet length, not (yet) including argv[] */
|
||||
uint64_t total_len = (
|
||||
sizeof(data) +
|
||||
cwd_len +
|
||||
term_len +
|
||||
title_len +
|
||||
app_id_len);
|
||||
/* Total packet length, not (yet) including overrides or argv[] */
|
||||
uint64_t total_len = sizeof(data) + cwd_len;
|
||||
|
||||
/* Add overrides to total packet length */
|
||||
coverrides = xmalloc(override_count * sizeof(coverrides[0]));
|
||||
{
|
||||
size_t i = 0;
|
||||
tll_foreach(overrides, it) {
|
||||
const size_t len = strlen(it->item) + 1;
|
||||
|
||||
if (len >= 1 << (8 * sizeof(coverrides[i].len))) {
|
||||
LOG_ERR("override length overflow");
|
||||
goto err;
|
||||
}
|
||||
|
||||
coverrides[i].len = len;
|
||||
total_len += sizeof(coverrides[i]) + coverrides[i].len;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
cargv = xmalloc(argc * sizeof(cargv[0]));
|
||||
|
||||
|
|
@ -336,9 +346,7 @@ main(int argc, char *const *argv)
|
|||
/* Check for size overflows */
|
||||
if (total_len >= 1llu << (8 * sizeof(uint32_t)) ||
|
||||
cwd_len >= 1 << (8 * sizeof(data.cwd_len)) ||
|
||||
term_len >= 1 << (8 * sizeof(data.term_len)) ||
|
||||
title_len >= 1 << (8 * sizeof(data.title_len)) ||
|
||||
app_id_len >= 1 << (8 * sizeof(data.app_id_len)) ||
|
||||
override_count > (size_t)(unsigned int)data.override_count ||
|
||||
argc > (int)(unsigned int)data.argc)
|
||||
{
|
||||
LOG_ERR("size overflow");
|
||||
|
|
@ -348,21 +356,33 @@ main(int argc, char *const *argv)
|
|||
/* Send everything except argv[] */
|
||||
if (send(fd, &(uint32_t){total_len}, sizeof(uint32_t), 0) != sizeof(uint32_t) ||
|
||||
send(fd, &data, sizeof(data), 0) != sizeof(data) ||
|
||||
send(fd, cwd, cwd_len, 0) != cwd_len ||
|
||||
send(fd, term, term_len, 0) != term_len ||
|
||||
send(fd, title, title_len, 0) != title_len ||
|
||||
send(fd, app_id, app_id_len, 0) != app_id_len)
|
||||
send(fd, cwd, cwd_len, 0) != cwd_len)
|
||||
{
|
||||
LOG_ERRNO("failed to send setup packet to server");
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Send overrides */
|
||||
{
|
||||
size_t i = 0;
|
||||
tll_foreach(overrides, it) {
|
||||
if (send(fd, &coverrides[i], sizeof(coverrides[i]), 0) != sizeof(coverrides[i]) ||
|
||||
send(fd, it->item, coverrides[i].len, 0) != coverrides[i].len)
|
||||
{
|
||||
LOG_ERRNO("failed to send setup packet (overrides) to server");
|
||||
goto err;
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Send argv[] */
|
||||
for (size_t i = 0; i < argc; i++) {
|
||||
if (send(fd, &cargv[i], sizeof(cargv[i]), 0) != sizeof(cargv[i]) ||
|
||||
send(fd, argv[i], cargv[i].len, 0) != cargv[i].len)
|
||||
{
|
||||
LOG_ERRNO("failed to send setup packet to server");
|
||||
LOG_ERRNO("failed to send setup packet (argv) to server");
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
|
@ -386,7 +406,9 @@ main(int argc, char *const *argv)
|
|||
ret = exit_code;
|
||||
|
||||
err:
|
||||
tll_free_and_free(overrides, free);
|
||||
free(cargv);
|
||||
free(coverrides);
|
||||
free(_cwd);
|
||||
if (fd != -1)
|
||||
close(fd);
|
||||
|
|
|
|||
|
|
@ -211,6 +211,7 @@ executable(
|
|||
'macros.h',
|
||||
'util.h',
|
||||
version,
|
||||
dependencies: [tllist],
|
||||
link_with: common,
|
||||
install: true)
|
||||
|
||||
|
|
|
|||
80
server.c
80
server.c
|
|
@ -240,6 +240,7 @@ fdm_client(struct fdm *fdm, int fd, int events, void *data)
|
|||
|
||||
uint8_t *p = client->buffer.data;
|
||||
const uint8_t *end = &client->buffer.data[client->buffer.idx];
|
||||
config_override_t overrides = tll_init();
|
||||
|
||||
struct client_data cdata;
|
||||
CHECK_BUF(sizeof(cdata));
|
||||
|
|
@ -250,22 +251,23 @@ fdm_client(struct fdm *fdm, int fd, int events, void *data)
|
|||
const char *cwd = (const char *)p; p += cdata.cwd_len;
|
||||
LOG_DBG("CWD = %.*s", cdata.cwd_len, cwd);
|
||||
|
||||
CHECK_BUF_AND_NULL(cdata.term_len);
|
||||
const char *term_env = (const char *)p; p += cdata.term_len;
|
||||
LOG_DBG("TERM = %.*s", cdata.term_len, term_env);
|
||||
/* Overrides */
|
||||
for (uint16_t i = 0; i < cdata.override_count; i++) {
|
||||
const struct client_string *arg = (const struct client_string *)p;
|
||||
CHECK_BUF(sizeof(*arg));
|
||||
p += sizeof(*arg);
|
||||
|
||||
CHECK_BUF_AND_NULL(cdata.title_len);
|
||||
const char *title = (const char *)p; p += cdata.title_len;
|
||||
LOG_DBG("title = %.*s", cdata.title_len, title);
|
||||
CHECK_BUF_AND_NULL(arg->len);
|
||||
const char *str = (const char *)p;
|
||||
p += arg->len;
|
||||
|
||||
CHECK_BUF_AND_NULL(cdata.app_id_len);
|
||||
const char *app_id = (const char *)p; p += cdata.app_id_len;
|
||||
LOG_DBG("app-id = %.*s", cdata.app_id_len, app_id);
|
||||
tll_push_back(overrides, xstrdup(str));
|
||||
}
|
||||
|
||||
/* argv */
|
||||
argv = xcalloc(cdata.argc + 1, sizeof(argv[0]));
|
||||
|
||||
for (uint16_t i = 0; i < cdata.argc; i++) {
|
||||
struct client_argv arg;
|
||||
struct client_string arg;
|
||||
CHECK_BUF(sizeof(arg));
|
||||
memcpy(&arg, p, sizeof(arg));
|
||||
p += sizeof(arg);
|
||||
|
|
@ -282,63 +284,14 @@ fdm_client(struct fdm *fdm, int fd, int events, void *data)
|
|||
struct terminal_instance *instance = malloc(sizeof(struct terminal_instance));
|
||||
|
||||
const bool need_to_clone_conf =
|
||||
strlen(term_env) > 0 ||
|
||||
strlen(title) > 0 ||
|
||||
strlen(app_id) > 0 ||
|
||||
tll_length(overrides)> 0 ||
|
||||
cdata.hold != server->conf->hold_at_exit ||
|
||||
cdata.login_shell != server->conf->login_shell ||
|
||||
cdata.no_wait != server->conf->no_wait ||
|
||||
(cdata.maximized && server->conf->startup_mode != STARTUP_MAXIMIZED) ||
|
||||
(cdata.fullscreen && server->conf->startup_mode != STARTUP_FULLSCREEN) ||
|
||||
(cdata.width > 0 && cdata.height > 0);
|
||||
cdata.no_wait != server->conf->no_wait;
|
||||
|
||||
struct config *conf = NULL;
|
||||
if (need_to_clone_conf) {
|
||||
conf = config_clone(server->conf);
|
||||
|
||||
char buf[1024];
|
||||
config_override_t overrides = tll_init();
|
||||
|
||||
if (strlen(term_env) > 0) {
|
||||
snprintf(buf, sizeof(buf), "term=%s", term_env);
|
||||
tll_push_back(overrides, xstrdup(buf));
|
||||
}
|
||||
|
||||
if (strlen(title) > 0) {
|
||||
snprintf(buf, sizeof(buf), "title=%s", title);
|
||||
tll_push_back(overrides, xstrdup(buf));
|
||||
}
|
||||
|
||||
if (strlen(app_id)> 0) {
|
||||
snprintf(buf, sizeof(buf), "app-id=%s", app_id);
|
||||
tll_push_back(overrides, xstrdup(buf));
|
||||
}
|
||||
|
||||
if (cdata.login_shell != server->conf->login_shell)
|
||||
tll_push_back(overrides, xstrdup("login-shell=yes"));
|
||||
|
||||
if (cdata.maximized && server->conf->startup_mode != STARTUP_MAXIMIZED)
|
||||
tll_push_back(overrides, xstrdup("initial-window-mode=maximized"));
|
||||
|
||||
if (cdata.fullscreen && server->conf->startup_mode != STARTUP_FULLSCREEN)
|
||||
tll_push_back(overrides, xstrdup("initial-window-mode=fullscreen"));
|
||||
|
||||
if (cdata.width > 0 && cdata.height > 0) {
|
||||
switch (cdata.size_type) {
|
||||
case CONF_SIZE_PX:
|
||||
snprintf(buf, sizeof(buf), "initial-window-size-pixels=%ux%u",
|
||||
cdata.width, cdata.height);
|
||||
tll_push_back(overrides, xstrdup(buf));
|
||||
break;
|
||||
|
||||
case CONF_SIZE_CELLS:
|
||||
snprintf(buf, sizeof(buf), "initial-window-size-chars=%ux%u",
|
||||
cdata.width, cdata.height);
|
||||
tll_push_back(overrides, xstrdup(buf));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (cdata.no_wait != server->conf->no_wait)
|
||||
conf->no_wait = cdata.no_wait;
|
||||
|
||||
|
|
@ -346,7 +299,6 @@ fdm_client(struct fdm *fdm, int fd, int events, void *data)
|
|||
conf->hold_at_exit = cdata.hold;
|
||||
|
||||
config_override_apply(conf, &overrides, false);
|
||||
tll_free_and_free(overrides, free);
|
||||
}
|
||||
|
||||
*instance = (struct terminal_instance) {
|
||||
|
|
@ -377,6 +329,7 @@ fdm_client(struct fdm *fdm, int fd, int events, void *data)
|
|||
instance->client = client;
|
||||
client->instance = instance;
|
||||
free(argv);
|
||||
tll_free_and_free(overrides, free);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
@ -385,6 +338,7 @@ shutdown:
|
|||
LOG_DBG("client FD=%d: disconnected", client->fd);
|
||||
|
||||
free(argv);
|
||||
tll_free_and_free(overrides, free);
|
||||
fdm_del(fdm, fd);
|
||||
client->fd = -1;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue