From f1d64f811ddb6f45dc24d82eb08bbaf4fc0ab1b3 Mon Sep 17 00:00:00 2001 From: Corey Hinshaw Date: Sat, 9 Feb 2019 23:32:29 -0500 Subject: [PATCH] Add swayrun command to run sway using a login shell When running Sway from a display manager, a user's login shell is not used. Because of this, profile scripts are not run and the environment may not be configured. As suggested in #3109, this can be solved by a wrapper that runs sway via the user's configured shell. This is similar to the approach taken by GNOME to source the standard set of profile scripts. This could be accomplished with a shell script, but a dedicated binary avoids dependencies on specific shells. The sway.desktop wayland session file is also updated to call the swayrun wrapper. --- meson.build | 2 ++ sway.desktop | 2 +- swayrun/main.c | 71 +++++++++++++++++++++++++++++++++++++++++++ swayrun/meson.build | 7 +++++ swayrun/swayrun.1.scd | 34 +++++++++++++++++++++ 5 files changed, 115 insertions(+), 1 deletion(-) create mode 100644 swayrun/main.c create mode 100644 swayrun/meson.build create mode 100644 swayrun/swayrun.1.scd diff --git a/meson.build b/meson.build index c50fab176..3f60ba83a 100644 --- a/meson.build +++ b/meson.build @@ -107,6 +107,7 @@ if scdoc.found() 'swaymsg/swaymsg.1.scd', 'swaynag/swaynag.1.scd', 'swaynag/swaynag.5.scd', + 'swayrun/swayrun.1.scd' ] foreach filename : man_files topic = filename.split('.')[-3].split('/')[-1] @@ -149,6 +150,7 @@ subdir('client') subdir('swaybg') subdir('swaybar') subdir('swaynag') +subdir('swayrun') config = configuration_data() config.set('datadir', join_paths(prefix, datadir)) diff --git a/sway.desktop b/sway.desktop index 98c9af293..2e83cc893 100644 --- a/sway.desktop +++ b/sway.desktop @@ -1,5 +1,5 @@ [Desktop Entry] Name=Sway Comment=SirCmpwn's Wayland window manager -Exec=sway +Exec=swayrun Type=Application diff --git a/swayrun/main.c b/swayrun/main.c new file mode 100644 index 000000000..f8ffd9e86 --- /dev/null +++ b/swayrun/main.c @@ -0,0 +1,71 @@ +#define _POSIX_C_SOURCE 200809L // for getline +#include +#include +#include +#include +#include +#include +#include "stringop.h" + +#define SWAY_COMMAND "sway" + +char allowed_shell(char *shell) { + FILE *fp; + char *line = NULL; + size_t len = 0; + char allowed = false; + + if (strstr(shell, "false") != NULL || strstr(shell, "nologin") != NULL) { + return false; + } + + fp = fopen("/etc/shells", "r"); + if (fp == NULL) { + return true; + } + + while (getline(&line, &len, fp) != -1) { + strip_whitespace(line); + if (strcmp(shell, line) == 0) { + allowed = true; + break; + } + } + + fclose(fp); + if (line) { + free(line); + } + return allowed; +} + +int main(int argc, char **argv) { + char *shell = getenv("SHELL"); + + if (shell && allowed_shell(shell)) { + // 3 exec arguments + argc + argv[argc] NULL pointer + int exec_argc = 4 + argc; + char **exec_argv = malloc(exec_argc * sizeof(char*)); + + // Prefix - to shell path to indicate login shell + char *login_shell = malloc(strlen(shell) + 2); + strcpy(login_shell, "-"); + strcat(login_shell, shell); + + // Build the argumrnts to exec + memcpy(exec_argv + 3, argv, (argc + 1) * sizeof(argv)); + exec_argv[0] = login_shell; + exec_argv[1] = "-c"; + exec_argv[2] = "exec " SWAY_COMMAND " \"$@\""; + exec_argv[3] = shell; + + execvp(shell, exec_argv); + fprintf(stderr, "Could not run %s using login shell: %s\n", SWAY_COMMAND, shell); + } else { + argv[0] = SWAY_COMMAND; + execvp(SWAY_COMMAND, argv); + fprintf(stderr, "Could not run %s\n", SWAY_COMMAND); + } + + return errno; +} diff --git a/swayrun/meson.build b/swayrun/meson.build new file mode 100644 index 000000000..5ad98bc84 --- /dev/null +++ b/swayrun/meson.build @@ -0,0 +1,7 @@ +executable( + 'swayrun', + 'main.c', + include_directories: [sway_inc], + link_with: [lib_sway_common], + install: true +) diff --git a/swayrun/swayrun.1.scd b/swayrun/swayrun.1.scd new file mode 100644 index 000000000..e8f84fd9e --- /dev/null +++ b/swayrun/swayrun.1.scd @@ -0,0 +1,34 @@ +swayrun(1) + +# NAME + +swayrun - Run Sway from a login shell + +# SYNOPSIS + +_swayrun_ [options...] [command] + +# DESCRIPTION + +Attempts to run *sway*(1) via the user's login shell. This allows environment +configuration and other login actions, for example when run via a login manager. + +All arguments to swayrun will be passed through unaltered to sway. + +If a valid login shell cannot be determined, sway will be executed normally. + +# CONFIGURATION + +swayrun will consult */etc/shells* if it exists for a list of valid login +shells. In addition, *false* and *nologin* will be considered invalid shells. + +# ENVIRONMENT + +The following environment variables have an effect on swayrun: + +_SHELL_ + Holds the path to the login shell. + +# SEE + +*sway*(1) *shells*(5)