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.
This commit is contained in:
Corey Hinshaw 2019-02-09 23:32:29 -05:00
parent ec5da0ca5b
commit f1d64f811d
5 changed files with 115 additions and 1 deletions

View file

@ -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))

View file

@ -1,5 +1,5 @@
[Desktop Entry]
Name=Sway
Comment=SirCmpwn's Wayland window manager
Exec=sway
Exec=swayrun
Type=Application

71
swayrun/main.c Normal file
View file

@ -0,0 +1,71 @@
#define _POSIX_C_SOURCE 200809L // for getline
#include <errno.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#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;
}

7
swayrun/meson.build Normal file
View file

@ -0,0 +1,7 @@
executable(
'swayrun',
'main.c',
include_directories: [sway_inc],
link_with: [lib_sway_common],
install: true
)

34
swayrun/swayrun.1.scd Normal file
View file

@ -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)