mirror of
https://codeberg.org/dnkl/foot.git
synced 2026-03-27 07:58:07 -04:00
commit
bdef28c6d1
13 changed files with 177 additions and 48 deletions
|
|
@ -49,6 +49,10 @@
|
||||||
allows setting/saving/restoring/querying the keypad mode.
|
allows setting/saving/restoring/querying the keypad mode.
|
||||||
* Sixel support can be disabled by setting `[tweak].sixel=no`
|
* Sixel support can be disabled by setting `[tweak].sixel=no`
|
||||||
(https://codeberg.org/dnkl/foot/issues/950).
|
(https://codeberg.org/dnkl/foot/issues/950).
|
||||||
|
* footclient: `-E,--client-environment` command line option. When
|
||||||
|
used, the child process in the new terminal instance inherits the
|
||||||
|
environment from the footclient process instead of the server’s
|
||||||
|
(https://codeberg.org/dnkl/foot/issues/1004).
|
||||||
|
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
|
||||||
|
|
@ -19,11 +19,13 @@ struct client_data {
|
||||||
uint16_t cwd_len;
|
uint16_t cwd_len;
|
||||||
uint16_t override_count;
|
uint16_t override_count;
|
||||||
uint16_t argc;
|
uint16_t argc;
|
||||||
|
uint16_t env_count;
|
||||||
|
|
||||||
/* char cwd[static cwd_len]; */
|
/* char cwd[static cwd_len]; */
|
||||||
/* char token[static token_len]; */
|
/* char token[static token_len]; */
|
||||||
/* struct client_string overrides[static override_count]; */
|
/* struct client_string overrides[static override_count]; */
|
||||||
/* struct client_string argv[static argc]; */
|
/* struct client_string argv[static argc]; */
|
||||||
|
/* struct client_string envp[static env_count]; */
|
||||||
} __attribute__((packed));
|
} __attribute__((packed));
|
||||||
|
|
||||||
_Static_assert(sizeof(struct client_data) == 8, "protocol struct size error");
|
_Static_assert(sizeof(struct client_data) == 10, "protocol struct size error");
|
||||||
|
|
|
||||||
105
client.c
105
client.c
|
|
@ -25,11 +25,13 @@
|
||||||
#include "version.h"
|
#include "version.h"
|
||||||
#include "xmalloc.h"
|
#include "xmalloc.h"
|
||||||
|
|
||||||
struct override {
|
extern char **environ;
|
||||||
|
|
||||||
|
struct string {
|
||||||
size_t len;
|
size_t len;
|
||||||
char *str;
|
char *str;
|
||||||
};
|
};
|
||||||
typedef tll(struct override) override_list_t;
|
typedef tll(struct string) string_list_t;
|
||||||
|
|
||||||
static volatile sig_atomic_t aborted = 0;
|
static volatile sig_atomic_t aborted = 0;
|
||||||
|
|
||||||
|
|
@ -91,6 +93,7 @@ print_usage(const char *prog_name)
|
||||||
" -H,--hold remain open after child process exits\n"
|
" -H,--hold remain open after child process exits\n"
|
||||||
" -N,--no-wait detach the client process from the running terminal, exiting immediately\n"
|
" -N,--no-wait detach the client process from the running terminal, exiting immediately\n"
|
||||||
" -o,--override=[section.]key=value override configuration option\n"
|
" -o,--override=[section.]key=value override configuration option\n"
|
||||||
|
" -E, --client-environment exec shell using footclient's environment, instead of the server's\n"
|
||||||
" -d,--log-level={info|warning|error|none} log level (info)\n"
|
" -d,--log-level={info|warning|error|none} log level (info)\n"
|
||||||
" -l,--log-colorize=[{never|always|auto}] enable/disable colorization of log output on stderr\n"
|
" -l,--log-colorize=[{never|always|auto}] enable/disable colorization of log output on stderr\n"
|
||||||
" -v,--version show the version number and quit\n"
|
" -v,--version show the version number and quit\n"
|
||||||
|
|
@ -102,20 +105,45 @@ print_usage(const char *prog_name)
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool NOINLINE
|
static bool NOINLINE
|
||||||
push_override(override_list_t *overrides, const char *s, uint64_t *total_len)
|
push_string(string_list_t *string_list, const char *s, uint64_t *total_len)
|
||||||
{
|
{
|
||||||
size_t len = strlen(s) + 1;
|
size_t len = strlen(s) + 1;
|
||||||
if (len >= 1 << (8 * sizeof(struct client_string))) {
|
if (len >= 1 << (8 * sizeof(uint16_t))) {
|
||||||
LOG_ERR("override length overflow");
|
LOG_ERR("string length overflow");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct override o = {len, xstrdup(s)};
|
struct string o = {len, xstrdup(s)};
|
||||||
tll_push_back(*overrides, o);
|
tll_push_back(*string_list, o);
|
||||||
*total_len += sizeof(struct client_string) + o.len;
|
*total_len += sizeof(struct client_string) + o.len;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
free_string_list(string_list_t *string_list)
|
||||||
|
{
|
||||||
|
tll_foreach(*string_list, it) {
|
||||||
|
free(it->item.str);
|
||||||
|
tll_remove(*string_list, it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
send_string_list(int fd, const string_list_t *string_list)
|
||||||
|
{
|
||||||
|
tll_foreach(*string_list, it) {
|
||||||
|
const struct client_string s = {it->item.len};
|
||||||
|
if (sendall(fd, &s, sizeof(s)) < 0 ||
|
||||||
|
sendall(fd, it->item.str, s.len) < 0)
|
||||||
|
{
|
||||||
|
LOG_ERRNO("failed to send setup packet to server");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
main(int argc, char *const *argv)
|
main(int argc, char *const *argv)
|
||||||
{
|
{
|
||||||
|
|
@ -140,6 +168,7 @@ main(int argc, char *const *argv)
|
||||||
{"hold", no_argument, NULL, 'H'},
|
{"hold", no_argument, NULL, 'H'},
|
||||||
{"no-wait", no_argument, NULL, 'N'},
|
{"no-wait", no_argument, NULL, 'N'},
|
||||||
{"override", required_argument, NULL, 'o'},
|
{"override", required_argument, NULL, 'o'},
|
||||||
|
{"client-environment", no_argument, NULL, 'E'},
|
||||||
{"log-level", required_argument, NULL, 'd'},
|
{"log-level", required_argument, NULL, 'd'},
|
||||||
{"log-colorize", optional_argument, NULL, 'l'},
|
{"log-colorize", optional_argument, NULL, 'l'},
|
||||||
{"version", no_argument, NULL, 'v'},
|
{"version", no_argument, NULL, 'v'},
|
||||||
|
|
@ -152,6 +181,7 @@ main(int argc, char *const *argv)
|
||||||
enum log_class log_level = LOG_CLASS_INFO;
|
enum log_class log_level = LOG_CLASS_INFO;
|
||||||
enum log_colorize log_colorize = LOG_COLORIZE_AUTO;
|
enum log_colorize log_colorize = LOG_COLORIZE_AUTO;
|
||||||
bool hold = false;
|
bool hold = false;
|
||||||
|
bool client_environment = false;
|
||||||
|
|
||||||
/* Used to format overrides */
|
/* Used to format overrides */
|
||||||
bool no_wait = false;
|
bool no_wait = false;
|
||||||
|
|
@ -169,35 +199,36 @@ main(int argc, char *const *argv)
|
||||||
/* malloc:ed and needs to be in scope of all goto's */
|
/* malloc:ed and needs to be in scope of all goto's */
|
||||||
int fd = -1;
|
int fd = -1;
|
||||||
char *_cwd = NULL;
|
char *_cwd = NULL;
|
||||||
override_list_t overrides = tll_init();
|
|
||||||
struct client_string *cargv = NULL;
|
struct client_string *cargv = NULL;
|
||||||
|
string_list_t overrides = tll_init();
|
||||||
|
string_list_t envp = tll_init();
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
int c = getopt_long(argc, argv, "+t:T:a:w:W:mFLD:s:HNo:d:l::veh", longopts, NULL);
|
int c = getopt_long(argc, argv, "+t:T:a:w:W:mFLD:s:HNo:Ed:l::veh", longopts, NULL);
|
||||||
if (c == -1)
|
if (c == -1)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case 't':
|
case 't':
|
||||||
snprintf(buf, sizeof(buf), "term=%s", optarg);
|
snprintf(buf, sizeof(buf), "term=%s", optarg);
|
||||||
if (!push_override(&overrides, buf, &total_len))
|
if (!push_string(&overrides, buf, &total_len))
|
||||||
goto err;
|
goto err;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'T':
|
case 'T':
|
||||||
snprintf(buf, sizeof(buf), "title=%s", optarg);
|
snprintf(buf, sizeof(buf), "title=%s", optarg);
|
||||||
if (!push_override(&overrides, buf, &total_len))
|
if (!push_string(&overrides, buf, &total_len))
|
||||||
goto err;
|
goto err;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'a':
|
case 'a':
|
||||||
snprintf(buf, sizeof(buf), "app-id=%s", optarg);
|
snprintf(buf, sizeof(buf), "app-id=%s", optarg);
|
||||||
if (!push_override(&overrides, buf, &total_len))
|
if (!push_string(&overrides, buf, &total_len))
|
||||||
goto err;
|
goto err;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'L':
|
case 'L':
|
||||||
if (!push_override(&overrides, "login-shell=yes", &total_len))
|
if (!push_string(&overrides, "login-shell=yes", &total_len))
|
||||||
goto err;
|
goto err;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
@ -219,7 +250,7 @@ main(int argc, char *const *argv)
|
||||||
}
|
}
|
||||||
|
|
||||||
snprintf(buf, sizeof(buf), "initial-window-size-pixels=%ux%u", width, height);
|
snprintf(buf, sizeof(buf), "initial-window-size-pixels=%ux%u", width, height);
|
||||||
if (!push_override(&overrides, buf, &total_len))
|
if (!push_string(&overrides, buf, &total_len))
|
||||||
goto err;
|
goto err;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -232,18 +263,18 @@ main(int argc, char *const *argv)
|
||||||
}
|
}
|
||||||
|
|
||||||
snprintf(buf, sizeof(buf), "initial-window-size-chars=%ux%u", width, height);
|
snprintf(buf, sizeof(buf), "initial-window-size-chars=%ux%u", width, height);
|
||||||
if (!push_override(&overrides, buf, &total_len))
|
if (!push_string(&overrides, buf, &total_len))
|
||||||
goto err;
|
goto err;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'm':
|
case 'm':
|
||||||
if (!push_override(&overrides, "initial-window-mode=maximized", &total_len))
|
if (!push_string(&overrides, "initial-window-mode=maximized", &total_len))
|
||||||
goto err;
|
goto err;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'F':
|
case 'F':
|
||||||
if (!push_override(&overrides, "initial-window-mode=fullscreen", &total_len))
|
if (!push_string(&overrides, "initial-window-mode=fullscreen", &total_len))
|
||||||
goto err;
|
goto err;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
@ -260,10 +291,14 @@ main(int argc, char *const *argv)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'o':
|
case 'o':
|
||||||
if (!push_override(&overrides, optarg, &total_len))
|
if (!push_string(&overrides, optarg, &total_len))
|
||||||
goto err;
|
goto err;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'E':
|
||||||
|
client_environment = true;
|
||||||
|
break;
|
||||||
|
|
||||||
case 'd': {
|
case 'd': {
|
||||||
int lvl = log_level_from_string(optarg);
|
int lvl = log_level_from_string(optarg);
|
||||||
if (unlikely(lvl < 0)) {
|
if (unlikely(lvl < 0)) {
|
||||||
|
|
@ -373,9 +408,17 @@ main(int argc, char *const *argv)
|
||||||
cwd = _cwd;
|
cwd = _cwd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (client_environment) {
|
||||||
|
for (char **e = environ; *e != NULL; e++) {
|
||||||
|
if (!push_string(&envp, *e, &total_len))
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* String lengths, including NULL terminator */
|
/* String lengths, including NULL terminator */
|
||||||
const size_t cwd_len = strlen(cwd) + 1;
|
const size_t cwd_len = strlen(cwd) + 1;
|
||||||
const size_t override_count = tll_length(overrides);
|
const size_t override_count = tll_length(overrides);
|
||||||
|
const size_t env_count = tll_length(envp);
|
||||||
|
|
||||||
const struct client_data data = {
|
const struct client_data data = {
|
||||||
.hold = hold,
|
.hold = hold,
|
||||||
|
|
@ -385,6 +428,7 @@ main(int argc, char *const *argv)
|
||||||
.cwd_len = cwd_len,
|
.cwd_len = cwd_len,
|
||||||
.override_count = override_count,
|
.override_count = override_count,
|
||||||
.argc = argc,
|
.argc = argc,
|
||||||
|
.env_count = env_count,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Total packet length, not (yet) including argv[] */
|
/* Total packet length, not (yet) including argv[] */
|
||||||
|
|
@ -409,7 +453,8 @@ main(int argc, char *const *argv)
|
||||||
cwd_len >= 1 << (8 * sizeof(data.cwd_len)) ||
|
cwd_len >= 1 << (8 * sizeof(data.cwd_len)) ||
|
||||||
token_len >= 1 << (8 * sizeof(data.token_len)) ||
|
token_len >= 1 << (8 * sizeof(data.token_len)) ||
|
||||||
override_count > (size_t)(unsigned int)data.override_count ||
|
override_count > (size_t)(unsigned int)data.override_count ||
|
||||||
argc > (int)(unsigned int)data.argc)
|
argc > (int)(unsigned int)data.argc ||
|
||||||
|
env_count > (size_t)(unsigned int)data.env_count)
|
||||||
{
|
{
|
||||||
LOG_ERR("size overflow");
|
LOG_ERR("size overflow");
|
||||||
goto err;
|
goto err;
|
||||||
|
|
@ -434,16 +479,8 @@ main(int argc, char *const *argv)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Send overrides */
|
/* Send overrides */
|
||||||
tll_foreach(overrides, it) {
|
if (!send_string_list(fd, &overrides))
|
||||||
const struct override *o = &it->item;
|
goto err;
|
||||||
struct client_string s = {o->len};
|
|
||||||
if (sendall(fd, &s, sizeof(s)) < 0 ||
|
|
||||||
sendall(fd, o->str, o->len) < 0)
|
|
||||||
{
|
|
||||||
LOG_ERRNO("failed to send setup packet (overrides) to server");
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Send argv[] */
|
/* Send argv[] */
|
||||||
for (size_t i = 0; i < argc; i++) {
|
for (size_t i = 0; i < argc; i++) {
|
||||||
|
|
@ -455,6 +492,10 @@ main(int argc, char *const *argv)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Send environment */
|
||||||
|
if (!send_string_list(fd, &envp))
|
||||||
|
goto err;
|
||||||
|
|
||||||
struct sigaction sa = {.sa_handler = &sig_handler};
|
struct sigaction sa = {.sa_handler = &sig_handler};
|
||||||
sigemptyset(&sa.sa_mask);
|
sigemptyset(&sa.sa_mask);
|
||||||
if (sigaction(SIGINT, &sa, NULL) < 0 || sigaction(SIGTERM, &sa, NULL) < 0) {
|
if (sigaction(SIGINT, &sa, NULL) < 0 || sigaction(SIGTERM, &sa, NULL) < 0) {
|
||||||
|
|
@ -473,10 +514,8 @@ main(int argc, char *const *argv)
|
||||||
ret = exit_code;
|
ret = exit_code;
|
||||||
|
|
||||||
err:
|
err:
|
||||||
tll_foreach(overrides, it) {
|
free_string_list(&envp);
|
||||||
free(it->item.str);
|
free_string_list(&overrides);
|
||||||
tll_remove(overrides, it);
|
|
||||||
}
|
|
||||||
free(cargv);
|
free(cargv);
|
||||||
free(_cwd);
|
free(_cwd);
|
||||||
if (fd != -1)
|
if (fd != -1)
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ _footclient()
|
||||||
"--log-colorize"
|
"--log-colorize"
|
||||||
"--maximized"
|
"--maximized"
|
||||||
"--override"
|
"--override"
|
||||||
|
"--client-environment"
|
||||||
"--server-socket"
|
"--server-socket"
|
||||||
"--term"
|
"--term"
|
||||||
"--title"
|
"--title"
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ complete -c footclient -F -s s -l server-socket
|
||||||
complete -c footclient -s H -l hold -d "remain open after child process exits"
|
complete -c footclient -s H -l hold -d "remain open after child process exits"
|
||||||
complete -c footclient -s N -l no-wait -d "detach the client process from the running terminal, exiting immediately"
|
complete -c footclient -s N -l no-wait -d "detach the client process from the running terminal, exiting immediately"
|
||||||
complete -c footclient -x -s o -l override -d "configuration option to override, in form SECTION.KEY=VALUE"
|
complete -c footclient -x -s o -l override -d "configuration option to override, in form SECTION.KEY=VALUE"
|
||||||
|
complete -c footclient -s E -l client-environment -d "child process inherits footclient's environment, instead of the server's"
|
||||||
complete -c footclient -x -s d -l log-level -a "info warning error none" -d "log-level (info)"
|
complete -c footclient -x -s d -l log-level -a "info warning error none" -d "log-level (info)"
|
||||||
complete -c footclient -x -s l -l log-colorize -a "always never auto" -d "enable or disable colorization of log output on stderr"
|
complete -c footclient -x -s l -l log-colorize -a "always never auto" -d "enable or disable colorization of log output on stderr"
|
||||||
complete -c footclient -s v -l version -d "show the version number and quit"
|
complete -c footclient -s v -l version -d "show the version number and quit"
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ _arguments \
|
||||||
'(-H --hold)'{-H,--hold}'[remain open after child process exits]' \
|
'(-H --hold)'{-H,--hold}'[remain open after child process exits]' \
|
||||||
'(-N --no-wait)'{-N,--no-wait}'[detach the client process from the running terminal, exiting immediately]' \
|
'(-N --no-wait)'{-N,--no-wait}'[detach the client process from the running terminal, exiting immediately]' \
|
||||||
'(-o --override)'{-o,--override}'[configuration option to override, in form SECTION.KEY=VALUE]:()' \
|
'(-o --override)'{-o,--override}'[configuration option to override, in form SECTION.KEY=VALUE]:()' \
|
||||||
|
'(-E --client-environment)'{-E,--client-environment}"[child process inherits footclient's environment, instead of the server's]" \
|
||||||
'(-d --log-level)'{-d,--log-level}'[log level (info)]:loglevel:(info warning error none)' \
|
'(-d --log-level)'{-d,--log-level}'[log level (info)]:loglevel:(info warning error none)' \
|
||||||
'(-l --log-colorize)'{-l,--log-colorize}'[enable or disable colorization of log output on stderr]:logcolor:(never always auto)' \
|
'(-l --log-colorize)'{-l,--log-colorize}'[enable or disable colorization of log output on stderr]:logcolor:(never always auto)' \
|
||||||
'(-v --version)'{-v,--version}'[show the version number and quit]' \
|
'(-v --version)'{-v,--version}'[show the version number and quit]' \
|
||||||
|
|
|
||||||
|
|
@ -69,6 +69,10 @@ terminal has terminated.
|
||||||
Override an option set in the configuration file. If _SECTION_ is not
|
Override an option set in the configuration file. If _SECTION_ is not
|
||||||
given, defaults to _main_.
|
given, defaults to _main_.
|
||||||
|
|
||||||
|
*-E*,*--client-environment*
|
||||||
|
The child process in the new terminal instance will use
|
||||||
|
footclient's environment, instead of the server's.
|
||||||
|
|
||||||
*-d*,*--log-level*={*info*,*warning*,*error*,*none*}
|
*-d*,*--log-level*={*info*,*warning*,*error*,*none*}
|
||||||
Log level, used both for log output on stderr as well as
|
Log level, used both for log output on stderr as well as
|
||||||
syslog. Default: _info_.
|
syslog. Default: _info_.
|
||||||
|
|
|
||||||
2
main.c
2
main.c
|
|
@ -608,7 +608,7 @@ main(int argc, char *const *argv)
|
||||||
|
|
||||||
if (!as_server && (term = term_init(
|
if (!as_server && (term = term_init(
|
||||||
&conf, fdm, reaper, wayl, "foot", cwd, token,
|
&conf, fdm, reaper, wayl, "foot", cwd, token,
|
||||||
argc, argv,
|
argc, argv, NULL,
|
||||||
&term_shutdown_cb, &shutdown_ctx)) == NULL) {
|
&term_shutdown_cb, &shutdown_ctx)) == NULL) {
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
21
server.c
21
server.c
|
|
@ -146,6 +146,7 @@ fdm_client(struct fdm *fdm, int fd, int events, void *data)
|
||||||
|
|
||||||
char **argv = NULL;
|
char **argv = NULL;
|
||||||
config_override_t overrides = tll_init();
|
config_override_t overrides = tll_init();
|
||||||
|
char **envp = NULL;
|
||||||
|
|
||||||
if (events & EPOLLHUP)
|
if (events & EPOLLHUP)
|
||||||
goto shutdown;
|
goto shutdown;
|
||||||
|
|
@ -281,7 +282,21 @@ fdm_client(struct fdm *fdm, int fd, int events, void *data)
|
||||||
argv[i] = (char *)p; p += arg.len;
|
argv[i] = (char *)p; p += arg.len;
|
||||||
LOG_DBG("argv[%hu] = %.*s", i, arg.len, argv[i]);
|
LOG_DBG("argv[%hu] = %.*s", i, arg.len, argv[i]);
|
||||||
}
|
}
|
||||||
argv[cdata.argc] = NULL;
|
|
||||||
|
/* envp */
|
||||||
|
envp = cdata.env_count != 0
|
||||||
|
? xcalloc(cdata.env_count + 1, sizeof(envp[0]))
|
||||||
|
: NULL;
|
||||||
|
|
||||||
|
for (uint16_t i = 0; i < cdata.env_count; i++) {
|
||||||
|
struct client_string e;
|
||||||
|
CHECK_BUF(sizeof(e));
|
||||||
|
memcpy(&e, p, sizeof(e)); p += sizeof(e);
|
||||||
|
|
||||||
|
CHECK_BUF_AND_NULL(e.len);
|
||||||
|
envp[i] = (char *)p; p += e.len;
|
||||||
|
LOG_DBG("env[%hu] = %.*s", i, e.len, envp[i]);
|
||||||
|
}
|
||||||
|
|
||||||
#undef CHECK_BUF_AND_NULL
|
#undef CHECK_BUF_AND_NULL
|
||||||
#undef CHECK_BUF
|
#undef CHECK_BUF
|
||||||
|
|
@ -317,7 +332,7 @@ fdm_client(struct fdm *fdm, int fd, int events, void *data)
|
||||||
instance->terminal = term_init(
|
instance->terminal = term_init(
|
||||||
conf != NULL ? conf : server->conf,
|
conf != NULL ? conf : server->conf,
|
||||||
server->fdm, server->reaper, server->wayl, "footclient", cwd, token,
|
server->fdm, server->reaper, server->wayl, "footclient", cwd, token,
|
||||||
cdata.argc, argv, &term_shutdown_handler, instance);
|
cdata.argc, argv, envp, &term_shutdown_handler, instance);
|
||||||
|
|
||||||
if (instance->terminal == NULL) {
|
if (instance->terminal == NULL) {
|
||||||
LOG_ERR("failed to instantiate new terminal");
|
LOG_ERR("failed to instantiate new terminal");
|
||||||
|
|
@ -336,6 +351,7 @@ fdm_client(struct fdm *fdm, int fd, int events, void *data)
|
||||||
instance->client = client;
|
instance->client = client;
|
||||||
client->instance = instance;
|
client->instance = instance;
|
||||||
free(argv);
|
free(argv);
|
||||||
|
free(envp);
|
||||||
tll_free_and_free(overrides, free);
|
tll_free_and_free(overrides, free);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -345,6 +361,7 @@ shutdown:
|
||||||
LOG_DBG("client FD=%d: disconnected", client->fd);
|
LOG_DBG("client FD=%d: disconnected", client->fd);
|
||||||
|
|
||||||
free(argv);
|
free(argv);
|
||||||
|
free(envp);
|
||||||
tll_free_and_free(overrides, free);
|
tll_free_and_free(overrides, free);
|
||||||
fdm_del(fdm, fd);
|
fdm_del(fdm, fd);
|
||||||
client->fd = -1;
|
client->fd = -1;
|
||||||
|
|
|
||||||
72
slave.c
72
slave.c
|
|
@ -23,6 +23,65 @@
|
||||||
#include "tokenize.h"
|
#include "tokenize.h"
|
||||||
#include "xmalloc.h"
|
#include "xmalloc.h"
|
||||||
|
|
||||||
|
extern char **environ;
|
||||||
|
|
||||||
|
#if defined(__FreeBSD__)
|
||||||
|
static char *
|
||||||
|
find_file_in_path(const char *file)
|
||||||
|
{
|
||||||
|
if (strchr(file, '/') != NULL)
|
||||||
|
return xstrdup(file);
|
||||||
|
|
||||||
|
const char *env_path = getenv("PATH");
|
||||||
|
char *path_list = NULL;
|
||||||
|
|
||||||
|
if (env_path != NULL && env_path[0] != '\0')
|
||||||
|
path_list = xstrdup(env_path);
|
||||||
|
else {
|
||||||
|
size_t sc_path_len = confstr(_CS_PATH, NULL, 0);
|
||||||
|
if (sc_path_len > 0) {
|
||||||
|
path_list = xmalloc(sc_path_len);
|
||||||
|
confstr(_CS_PATH, path_list, sc_path_len);
|
||||||
|
} else
|
||||||
|
return xstrdup(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const char *path = strtok(path_list, ":");
|
||||||
|
path != NULL;
|
||||||
|
path = strtok(NULL, ":"))
|
||||||
|
{
|
||||||
|
char *full = xasprintf("%s/%s", path, file);
|
||||||
|
if (access(full, F_OK) == 0) {
|
||||||
|
free(path_list);
|
||||||
|
return full;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(full);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(path_list);
|
||||||
|
return xstrdup(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
foot_execvpe(const char *file, char *const argv[], char *const envp[])
|
||||||
|
{
|
||||||
|
char *path = find_file_in_path(file);
|
||||||
|
int ret = execve(path, argv, envp);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Getting here is an error
|
||||||
|
*/
|
||||||
|
free(path);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else /* !__FreeBSD__ */
|
||||||
|
|
||||||
|
#define foot_execvpe(file, argv, envp) execvpe(file, argv, envp)
|
||||||
|
|
||||||
|
#endif /* !__FreeBSD__ */
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
is_valid_shell(const char *shell)
|
is_valid_shell(const char *shell)
|
||||||
{
|
{
|
||||||
|
|
@ -145,8 +204,8 @@ emit_notifications(int fd, const user_notifications_t *notifications)
|
||||||
}
|
}
|
||||||
|
|
||||||
static noreturn void
|
static noreturn void
|
||||||
slave_exec(int ptmx, char *argv[], int err_fd, bool login_shell,
|
slave_exec(int ptmx, char *argv[], char *const envp[], int err_fd,
|
||||||
const user_notifications_t *notifications)
|
bool login_shell, const user_notifications_t *notifications)
|
||||||
{
|
{
|
||||||
int pts = -1;
|
int pts = -1;
|
||||||
const char *pts_name = ptsname(ptmx);
|
const char *pts_name = ptsname(ptmx);
|
||||||
|
|
@ -232,7 +291,7 @@ slave_exec(int ptmx, char *argv[], int err_fd, bool login_shell,
|
||||||
} else
|
} else
|
||||||
file = argv[0];
|
file = argv[0];
|
||||||
|
|
||||||
execvp(file, argv);
|
foot_execvpe(file, argv, envp);
|
||||||
|
|
||||||
err:
|
err:
|
||||||
(void)!write(err_fd, &errno, sizeof(errno));
|
(void)!write(err_fd, &errno, sizeof(errno));
|
||||||
|
|
@ -246,8 +305,8 @@ err:
|
||||||
|
|
||||||
pid_t
|
pid_t
|
||||||
slave_spawn(int ptmx, int argc, const char *cwd, char *const *argv,
|
slave_spawn(int ptmx, int argc, const char *cwd, char *const *argv,
|
||||||
const char *term_env, const char *conf_shell, bool login_shell,
|
char *const *envp, const char *term_env, const char *conf_shell,
|
||||||
const user_notifications_t *notifications)
|
bool login_shell, const user_notifications_t *notifications)
|
||||||
{
|
{
|
||||||
int fork_pipe[2];
|
int fork_pipe[2];
|
||||||
if (pipe2(fork_pipe, O_CLOEXEC) < 0) {
|
if (pipe2(fork_pipe, O_CLOEXEC) < 0) {
|
||||||
|
|
@ -319,7 +378,8 @@ slave_spawn(int ptmx, int argc, const char *cwd, char *const *argv,
|
||||||
if (is_valid_shell(shell_argv[0]))
|
if (is_valid_shell(shell_argv[0]))
|
||||||
setenv("SHELL", shell_argv[0], 1);
|
setenv("SHELL", shell_argv[0], 1);
|
||||||
|
|
||||||
slave_exec(ptmx, shell_argv, fork_pipe[1], login_shell, notifications);
|
slave_exec(ptmx, shell_argv, envp != NULL ? envp : environ,
|
||||||
|
fork_pipe[1], login_shell, notifications);
|
||||||
BUG("Unexpected return from slave_exec()");
|
BUG("Unexpected return from slave_exec()");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
|
||||||
4
slave.h
4
slave.h
|
|
@ -6,6 +6,6 @@
|
||||||
#include "user-notification.h"
|
#include "user-notification.h"
|
||||||
|
|
||||||
pid_t slave_spawn(
|
pid_t slave_spawn(
|
||||||
int ptmx, int argc, const char *cwd, char *const *argv, const char *term_env,
|
int ptmx, int argc, const char *cwd, char *const *argv, char *const *envp,
|
||||||
const char *conf_shell, bool login_shell,
|
const char *term_env, const char *conf_shell, bool login_shell,
|
||||||
const user_notifications_t *notifications);
|
const user_notifications_t *notifications);
|
||||||
|
|
|
||||||
|
|
@ -1034,7 +1034,7 @@ static void fdm_client_terminated(
|
||||||
struct terminal *
|
struct terminal *
|
||||||
term_init(const struct config *conf, struct fdm *fdm, struct reaper *reaper,
|
term_init(const struct config *conf, struct fdm *fdm, struct reaper *reaper,
|
||||||
struct wayland *wayl, const char *foot_exe, const char *cwd,
|
struct wayland *wayl, const char *foot_exe, const char *cwd,
|
||||||
const char *token, int argc, char *const *argv,
|
const char *token, int argc, char *const *argv, char *const *envp,
|
||||||
void (*shutdown_cb)(void *data, int exit_code), void *shutdown_data)
|
void (*shutdown_cb)(void *data, int exit_code), void *shutdown_data)
|
||||||
{
|
{
|
||||||
int ptmx = -1;
|
int ptmx = -1;
|
||||||
|
|
@ -1241,7 +1241,7 @@ term_init(const struct config *conf, struct fdm *fdm, struct reaper *reaper,
|
||||||
|
|
||||||
/* Start the slave/client */
|
/* Start the slave/client */
|
||||||
if ((term->slave = slave_spawn(
|
if ((term->slave = slave_spawn(
|
||||||
term->ptmx, argc, term->cwd, argv,
|
term->ptmx, argc, term->cwd, argv, envp,
|
||||||
conf->term, conf->shell, conf->login_shell,
|
conf->term, conf->shell, conf->login_shell,
|
||||||
&conf->notifications)) == -1)
|
&conf->notifications)) == -1)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -670,7 +670,7 @@ struct config;
|
||||||
struct terminal *term_init(
|
struct terminal *term_init(
|
||||||
const struct config *conf, struct fdm *fdm, struct reaper *reaper,
|
const struct config *conf, struct fdm *fdm, struct reaper *reaper,
|
||||||
struct wayland *wayl, const char *foot_exe, const char *cwd,
|
struct wayland *wayl, const char *foot_exe, const char *cwd,
|
||||||
const char *token, int argc, char *const *argv,
|
const char *token, int argc, char *const *argv, char *const *envp,
|
||||||
void (*shutdown_cb)(void *data, int exit_code), void *shutdown_data);
|
void (*shutdown_cb)(void *data, int exit_code), void *shutdown_data);
|
||||||
|
|
||||||
bool term_shutdown(struct terminal *term);
|
bool term_shutdown(struct terminal *term);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue