I alluded to this in #1005, and finally found the time to look into it.
Reproducer:
- OpenRC is built without PAM
- User has
/bin/bash as a shell
- User sets
XDG_RUNTIME_DIR in their ~/.profile
- The service
user.$USER is linked to the user service
Execution steps for starting the service:
user.$USER is started by OpenRC
$RC_LIBEXECDIR/bin/openrc-user $USER is called by the supervisor, with a clean environment
- The binary gets
$USER's shell, prefixes it with - to start it as a login shell, and executes -/bin/bash -c "$RC_LIBEXECDIR/sh/openrc-user.sh start" as the user
- Bash, at this point, does not run any login or other scripts, and directly calls
openrc-user.sh start
openrc-user.sh fails, because XDG_RUNTIME_DIR isn't set by any of the previous steps
With PAM/systemd-logind, a PAM session would have been opened by openrc-user, and the session's environment (likely containing XDG_RUNTIME_DIR) would have then been merged with the binary's. Without PAM, or if PAM didn't set XDG_RUNTIME_DIR, it's up to the shell to export the variable. But under Bash, ~/.profile nor any system scripts are ever sourced.
The root of the issue is what I assume is an intentional operation of Bash: Prefixing - to argv[0] does internally cause Bash to think it's a login shell, but because it's being run non-interactively, it does not run any login scripts. This is documented in the Bash manual—in Invoking Bash:
A login shell is one whose first character of argument zero is ‘-’, or one invoked with the --login option.
But then in Bash Startup Files:
Invoked non-interactively
[...]
As noted above, if a non-interactive shell is invoked with the --login option, Bash attempts to read and execute commands from the login shell startup files.
So, the only time login scripts are sourced are when the shell is an interactive login shell, or when it is a non-interactive shell explicitly called with the --login/-l option.
As far as I can tell, the only direct fix for this is to add a shim that prepends --login to the options specifically if the shell is detected as Bash. It should also be able to handle links, since Bash executed as sh will also not execute login scripts without the option:
When invoked as an interactive login shell, or as a non-interactive shell with the --login option, it first attempts to read and execute commands from /etc/profile and ~/.profile, in that order. The --noprofile option inhibits this behavior.
This linking use-case is very common in modern Linux, and I'd say most distros link sh to bash, excluding special kids like Alpine with Busybox ash.
As a Zsh user, this is absurd functionality, so I never expected this to be the issue...
I alluded to this in #1005, and finally found the time to look into it.
Reproducer:
/bin/bashas a shellXDG_RUNTIME_DIRin their~/.profileuser.$USERis linked to theuserserviceExecution steps for starting the service:
user.$USERis started by OpenRC$RC_LIBEXECDIR/bin/openrc-user $USERis called by the supervisor, with a clean environment$USER's shell, prefixes it with-to start it as a login shell, and executes-/bin/bash -c "$RC_LIBEXECDIR/sh/openrc-user.sh start"as the useropenrc-user.sh startopenrc-user.shfails, becauseXDG_RUNTIME_DIRisn't set by any of the previous stepsWith PAM/
systemd-logind, a PAM session would have been opened byopenrc-user, and the session's environment (likely containingXDG_RUNTIME_DIR) would have then been merged with the binary's. Without PAM, or if PAM didn't setXDG_RUNTIME_DIR, it's up to the shell to export the variable. But under Bash,~/.profilenor any system scripts are ever sourced.The root of the issue is what I assume is an intentional operation of Bash: Prefixing
-toargv[0]does internally cause Bash to think it's a login shell, but because it's being run non-interactively, it does not run any login scripts. This is documented in the Bash manual—in Invoking Bash:But then in Bash Startup Files:
So, the only time login scripts are sourced are when the shell is an interactive login shell, or when it is a non-interactive shell explicitly called with the
--login/-loption.As far as I can tell, the only direct fix for this is to add a shim that prepends
--loginto the options specifically if the shell is detected as Bash. It should also be able to handle links, since Bash executed asshwill also not execute login scripts without the option:This linking use-case is very common in modern Linux, and I'd say most distros link
shtobash, excluding special kids like Alpine with Busyboxash.As a Zsh user, this is absurd functionality, so I never expected this to be the issue...