diff --git a/include/sway/commands.h b/include/sway/commands.h index 5210d3ba75..d76a428ec4 100644 --- a/include/sway/commands.h +++ b/include/sway/commands.h @@ -127,6 +127,7 @@ sway_cmd cmd_default_floating_border; sway_cmd cmd_default_orientation; sway_cmd cmd_exec; sway_cmd cmd_exec_always; +sway_cmd cmd_exec_output; sway_cmd cmd_exit; sway_cmd cmd_floating; sway_cmd cmd_floating_maximum_size; diff --git a/include/sway/config.h b/include/sway/config.h index bb770c6f7f..50ac4c1f5d 100644 --- a/include/sway/config.h +++ b/include/sway/config.h @@ -521,6 +521,7 @@ struct sway_config { enum sway_fowa focus_on_window_activation; enum sway_popup_during_fullscreen popup_during_fullscreen; enum xwayland_mode xwayland; + int exec_out; // swaybg char *swaybg_command; diff --git a/sway/commands.c b/sway/commands.c index c2c12ee655..9b4680d969 100644 --- a/sway/commands.c +++ b/sway/commands.c @@ -59,6 +59,7 @@ static const struct cmd_handler handlers[] = { { "default_floating_border", cmd_default_floating_border }, { "exec", cmd_exec }, { "exec_always", cmd_exec_always }, + { "exec_output", cmd_exec_output }, { "floating_maximum_size", cmd_floating_maximum_size }, { "floating_minimum_size", cmd_floating_minimum_size }, { "floating_modifier", cmd_floating_modifier }, diff --git a/sway/commands/exec_always.c b/sway/commands/exec_always.c index 8bc1048cd6..abb3eac8ff 100644 --- a/sway/commands/exec_always.c +++ b/sway/commands/exec_always.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include "sway/commands.h" #include "sway/config.h" @@ -81,7 +82,23 @@ struct cmd_results *cmd_exec_process(int argc, char **argv) { if (ctx && !no_startup_id) { export_startup_id(ctx); } + int errfd = -1; + if (config->exec_out >= 0) { + errfd = fcntl(STDERR_FILENO, F_DUPFD_CLOEXEC); // save for logging + if (dup2(config->exec_out, STDOUT_FILENO) < 0) { + sway_log_errno(SWAY_ERROR, "dup2(exec_out, stdout) failed"); + close(STDOUT_FILENO); + } + if (dup2(config->exec_out, STDERR_FILENO) < 0) { + sway_log_errno(SWAY_ERROR, "dup2(exec_out, stderr) failed"); + close(STDERR_FILENO); + } + close(config->exec_out); + } execlp("sh", "sh", "-c", cmd, (void *)NULL); + if (errfd >= 0) { + dup2(errfd, STDERR_FILENO); + } sway_log_errno(SWAY_ERROR, "execlp failed"); _exit(1); } diff --git a/sway/commands/exec_output.c b/sway/commands/exec_output.c new file mode 100644 index 0000000000..64bbdd7724 --- /dev/null +++ b/sway/commands/exec_output.c @@ -0,0 +1,33 @@ +#include +#include +#include "sway/commands.h" + +struct cmd_results *cmd_exec_output(int argc, char **argv) { + struct cmd_results *error = + checkarg(argc, "exec_output", EXPECTED_AT_MOST, 1); + if (error) { + return error; + } + + if (config->exec_out >= 0) { + if (close(config->exec_out) < 0) { + return cmd_results_new( + CMD_FAILURE, + "Failed to close existing fd %d", + config->exec_out + ); + }; + config->exec_out = -1; + } + + if (argc == 0) { + return cmd_results_new(CMD_SUCCESS, NULL); + } + + int out = open(argv[0], O_RDWR | O_APPEND | O_CREAT, 0600); // u=rw + if (out < 0) { + return cmd_results_new(CMD_FAILURE, "Could not open file %s", argv[0]); + } + config->exec_out = out; + return cmd_results_new(CMD_SUCCESS, NULL); +} diff --git a/sway/config.c b/sway/config.c index 1090edc5cb..7455850640 100644 --- a/sway/config.c +++ b/sway/config.c @@ -257,6 +257,7 @@ static void config_defaults(struct sway_config *config) { config->focus_on_window_activation = FOWA_URGENT; config->popup_during_fullscreen = POPUP_SMART; config->xwayland = XWAYLAND_MODE_LAZY; + config->exec_out = -1; config->titlebar_border_thickness = 1; config->titlebar_h_padding = 5; diff --git a/sway/meson.build b/sway/meson.build index 8042c89bed..5da9cb219d 100644 --- a/sway/meson.build +++ b/sway/meson.build @@ -55,6 +55,7 @@ sway_sources = files( 'commands/exit.c', 'commands/exec.c', 'commands/exec_always.c', + 'commands/exec_output.c', 'commands/floating.c', 'commands/floating_minmax_size.c', 'commands/floating_modifier.c',