Fall back to 'getent passwd' when SHELL is unset

The Release was set to 3, so that this CentOS Stream 9 build (ie.,
toolbox-0.3-3.el9) is considered newer than the corresponding RHEL 9.8
Z-stream build (ie., toolbox-0.3-2.el9_8):
  $ rpmdev-vercmp 0.3-2.el9 0.3-2.el9_8
  0.3-2.el9 < 0.3-2.el9_8
  $ rpmdev-vercmp 0.3-3.el9 0.3-2.el9_8
  0.3-3.el9 > 0.3-2.el9_8

Resolves: RHEL-152669
This commit is contained in:
Debarshi Ray 2026-03-16 14:56:54 +01:00
parent 0b665bfe36
commit 119592cbc5
3 changed files with 310 additions and 5 deletions

View File

@ -1,4 +1,4 @@
From 4649e50c28321185cbaa81a37efbd317b84ae840 Mon Sep 17 00:00:00 2001
From 85481653d2fdbb8a23ec7552d1a2f589b5ed4694 Mon Sep 17 00:00:00 2001
From: Debarshi Ray <rishi@fedoraproject.org>
Date: Wed, 18 Aug 2021 17:55:21 +0200
Subject: [PATCH 1/2] cmd/run: Make sosreport work by setting the HOST
@ -22,10 +22,10 @@ index ceb277a3640a..72b673f506b3 100644
"--preserve-fds", preserveFDs,
}...)
--
2.51.0
2.53.0
From b2ba8445bee988143d546bc15fa3a8a8c019aa2e Mon Sep 17 00:00:00 2001
From a1df0b1a13f45f086e66631a87fe94d711e41075 Mon Sep 17 00:00:00 2001
From: Debarshi Ray <rishi@fedoraproject.org>
Date: Fri, 10 Dec 2021 13:42:15 +0100
Subject: [PATCH 2/2] test/system: Update to test the migration path for
@ -100,5 +100,5 @@ index 000000000000..cf35d60ac25c
+ skip "Testing of entering toolboxes is not implemented"
+}
--
2.51.0
2.53.0

View File

@ -0,0 +1,297 @@
From 2aef63319f5cb66df492efe8409b8748be22a625 Mon Sep 17 00:00:00 2001
From: Debarshi Ray <rishi@fedoraproject.org>
Date: Fri, 6 Mar 2026 21:07:54 +0100
Subject: [PATCH 1/2] doc, cmd: Tweak the wording and error messages for
consistency
The useradd(8) and usermod(8) manuals use the term 'login shell', except
one instance in useradd(8) where it says 'default login shell' [1,2].
The toolbox-init-container(1) manual and the 'init-container' command
already use 'login shell', and it's shorter than 'default shell'. So,
it wins.
Fallout from the following:
* 6c86cabbe5da6e542b50c5c043b4d213c6279bbc
* 59055cf9eb03d69a53b7f59a91b8def171da2fef
* 662bd899314d74977f8b973989d2548c1bf80fea
* 8f30d718066facb0c3db946db07e9c17f38741b7
[1] https://man7.org/linux/man-pages/man8/useradd.8.html
[2] https://man7.org/linux/man-pages/man8/usermod.8.html
https://github.com/containers/toolbox/pull/1767
---
doc/toolbox-enter.1.md | 4 ++--
src/cmd/create.go | 2 +-
src/cmd/enter.go | 2 +-
src/cmd/rootMigrationPath.go | 2 +-
4 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/doc/toolbox-enter.1.md b/doc/toolbox-enter.1.md
index 4061ef8233ab..2769a6b968f9 100644
--- a/doc/toolbox-enter.1.md
+++ b/doc/toolbox-enter.1.md
@@ -11,8 +11,8 @@ toolbox\-enter - Enter a Toolbx container for interactive use
## DESCRIPTION
Spawns an interactive shell inside a Toolbx container that was created using
-the `toolbox create` command. It tries to spawn the user's default shell, but
-if it's not available inside the container then it falls back to `/bin/bash`.
+the `toolbox create` command. It tries to spawn the user's login shell, but if
+it's not available inside the container then it falls back to `/bin/bash`.
When invoked without any options, `toolbox enter` will try to enter the default
Toolbx container for the host, or if there's only one container available then
diff --git a/src/cmd/create.go b/src/cmd/create.go
index 531721b60f2d..c0ac138aa8d7 100644
--- a/src/cmd/create.go
+++ b/src/cmd/create.go
@@ -406,7 +406,7 @@ func createContainer(container, image, release, authFile string, showCommandToEn
userShell := os.Getenv("SHELL")
if userShell == "" {
- return errors.New("failed to get the current user's default shell")
+ return errors.New("failed to get the current user's login shell")
}
entryPoint := []string{
diff --git a/src/cmd/enter.go b/src/cmd/enter.go
index 8602b744ba35..1fc32e8a65d3 100644
--- a/src/cmd/enter.go
+++ b/src/cmd/enter.go
@@ -116,7 +116,7 @@ func enter(cmd *cobra.Command, args []string) error {
userShell := os.Getenv("SHELL")
if userShell == "" {
- return errors.New("failed to get the current user's default shell")
+ return errors.New("failed to get the current user's login shell")
}
command := []string{userShell, "-l"}
diff --git a/src/cmd/rootMigrationPath.go b/src/cmd/rootMigrationPath.go
index 38b5d4956515..1c689c829088 100644
--- a/src/cmd/rootMigrationPath.go
+++ b/src/cmd/rootMigrationPath.go
@@ -63,7 +63,7 @@ func rootRunImpl(cmd *cobra.Command, args []string) error {
userShell := os.Getenv("SHELL")
if userShell == "" {
- return errors.New("failed to get the current user's default shell")
+ return errors.New("failed to get the current user's login shell")
}
command := []string{userShell, "-l"}
--
2.53.0
From 92eaafa5cc3e32d90f44d79144c30820f5557799 Mon Sep 17 00:00:00 2001
From: Rolv-Apneseth <rolv.apneseth@gmail.com>
Date: Thu, 19 Feb 2026 16:32:04 +0000
Subject: [PATCH 2/2] cmd, test/system: Fall back to 'getent passwd' when SHELL
is unset
The SHELL environment variable is supposed to be set during login, as
the case may be, by the GNOME Display Manager (or GDM) [1], OpenSSH [2],
login(1) [3], su(1) [4], systemd [5], etc.
During the GNOME login sequence, GDM and the Pluggable Authentication
Modules for Linux (or PAM) creates a session with gnome-session(1) as
the session leader, and sets the SHELL environment variable on it. Then
the session leader sets it in the 'systemd --user' unit activation
environment. Meanwhile, the system-wide user@.service has already set
SHELL on 'systemd --user', and this gets propagated into the per-user
service manager's unit activation environment. This gets overwritten by
the same value by gnome-session(1).
However, sometimes it's unexpectedly missing. eg., the runtime
environment of the GitHub Actions workflow [6]; and it has been reported
missing on some occasions in Fedora CoreOS, and in RHEL CoreOS spawned
by 'oc debug ...' in Red Hat OpenShift clusters. The reasons for these
are unclear.
Therefore, it's worth falling back to 'getent passwd' in those cases to
avoid completely breaking the 'create' and 'enter' commands.
[1] GDM commit 48dfb0c6fc683eb0
https://gitlab.gnome.org/GNOME/gdm/-/commit/48dfb0c6fc683eb0
[2] OpenSSH commit d4a8b7e34dd619a4
https://github.com/openssh/openssh-portable/commit/d4a8b7e34dd619a4
[3] https://man7.org/linux/man-pages/man1/login.1.html
[4] https://man7.org/linux/man-pages/man1/su.1.html
[5] https://www.freedesktop.org/software/systemd/man/run0.html
https://www.freedesktop.org/software/systemd/man/systemd.exec.html
[6] Commit c22b09d095c7a8ac
https://github.com/containers/toolbox/commit/c22b09d095c7a8ac
https://github.com/containers/toolbox/pull/1507
https://github.com/orgs/community/discussions/59413
https://github.com/containers/toolbox/issues/1615
https://issues.redhat.com/browse/OCPBUGS-76557
Signed-off-by: Rolv-Apneseth <rolv.apneseth@gmail.com>
---
src/cmd/create.go | 6 +++---
src/cmd/enter.go | 6 +++---
src/cmd/rootMigrationPath.go | 6 +++---
src/cmd/utils.go | 39 ++++++++++++++++++++++++++++++++++++
test/system/101-create.bats | 29 +++++++++++++++++++++++++++
5 files changed, 77 insertions(+), 9 deletions(-)
diff --git a/src/cmd/create.go b/src/cmd/create.go
index c0ac138aa8d7..908e8f240fba 100644
--- a/src/cmd/create.go
+++ b/src/cmd/create.go
@@ -404,9 +404,9 @@ func createContainer(container, image, release, authFile string, showCommandToEn
logLevelString := podman.LogLevel.String()
- userShell := os.Getenv("SHELL")
- if userShell == "" {
- return errors.New("failed to get the current user's login shell")
+ userShell, err := getCurrentUserShell()
+ if err != nil {
+ return err
}
entryPoint := []string{
diff --git a/src/cmd/enter.go b/src/cmd/enter.go
index 1fc32e8a65d3..51be3c4b8daa 100644
--- a/src/cmd/enter.go
+++ b/src/cmd/enter.go
@@ -114,9 +114,9 @@ func enter(cmd *cobra.Command, args []string) error {
return err
}
- userShell := os.Getenv("SHELL")
- if userShell == "" {
- return errors.New("failed to get the current user's login shell")
+ userShell, err := getCurrentUserShell()
+ if err != nil {
+ return err
}
command := []string{userShell, "-l"}
diff --git a/src/cmd/rootMigrationPath.go b/src/cmd/rootMigrationPath.go
index 1c689c829088..9861320b39a4 100644
--- a/src/cmd/rootMigrationPath.go
+++ b/src/cmd/rootMigrationPath.go
@@ -61,9 +61,9 @@ func rootRunImpl(cmd *cobra.Command, args []string) error {
return err
}
- userShell := os.Getenv("SHELL")
- if userShell == "" {
- return errors.New("failed to get the current user's login shell")
+ userShell, err := getCurrentUserShell()
+ if err != nil {
+ return err
}
command := []string{userShell, "-l"}
diff --git a/src/cmd/utils.go b/src/cmd/utils.go
index 250184f0c4c9..12a5e87a50b6 100644
--- a/src/cmd/utils.go
+++ b/src/cmd/utils.go
@@ -31,6 +31,7 @@ import (
"strings"
"syscall"
+ "github.com/containers/toolbox/pkg/shell"
"github.com/containers/toolbox/pkg/utils"
"github.com/sirupsen/logrus"
"golang.org/x/sys/unix"
@@ -383,6 +384,44 @@ func getCurrentUserHomeDir() string {
return currentUser.HomeDir
}
+func getCurrentUserShell() (string, error) {
+ if currentUser == nil {
+ panic("current user unknown")
+ }
+
+ if userShell := os.Getenv("SHELL"); userShell != "" {
+ return userShell, nil
+ }
+
+ logrus.Debug("Getting the current user's login shell: failed to read SHELL")
+ logrus.Debug("Using 'getent passwd' instead")
+
+ var stderr strings.Builder
+ var stdout strings.Builder
+
+ if err := shell.Run("getent", nil, &stdout, &stderr, "passwd", currentUser.Uid); err != nil {
+ errString := stderr.String()
+ logrus.Debugf("Getting the current user's login shell failed: %s", errString)
+ return "", fmt.Errorf("failed to get the current user's login shell: %w", err)
+ }
+
+ output := stdout.String()
+ passwdLine := strings.TrimSpace(output)
+ if len(passwdLine) == 0 {
+ return "", errors.New("failed to get the current user's login shell: no getent(1) output")
+ }
+
+ passwdLineParts := strings.Split(passwdLine, ":")
+ passwdLinePartsCount := len(passwdLineParts)
+ if passwdLinePartsCount != 7 {
+ logrus.Debugf("Getting the current user's login shell: failed to parse getent(1) output: %s",
+ passwdLine)
+ return "", errors.New("failed to get the current user's login shell: invalid getent(1) output")
+ }
+
+ return passwdLineParts[passwdLinePartsCount-1], nil
+}
+
func getUsageForCommonCommands() string {
var builder strings.Builder
builder.WriteString("create Create a new Toolbx container\n")
diff --git a/test/system/101-create.bats b/test/system/101-create.bats
index 58068e4222a7..a31cb12dfa1f 100644
--- a/test/system/101-create.bats
+++ b/test/system/101-create.bats
@@ -60,6 +60,35 @@ teardown() {
assert_output "true"
}
+@test "create: Smoke test with SHELL unset" {
+ local default_container
+ default_container="$(get_system_id)-toolbox-$(get_system_version)"
+
+ pull_default_image
+ unset SHELL
+
+ run --keep-empty-lines --separate-stderr "$TOOLBX" create
+
+ assert_success
+ assert_line --index 0 "Created container: $default_container"
+ assert_line --index 1 "Enter with: toolbox enter"
+ assert [ ${#lines[@]} -eq 2 ]
+ assert [ ${#stderr_lines[@]} -eq 0 ]
+
+ run podman ps --all
+
+ assert_success
+ assert_output --regexp "Created[[:blank:]]+$default_container"
+
+ run podman inspect \
+ --format '{{index .Config.Labels "com.github.containers.toolbox"}}' \
+ --type container \
+ "$default_container"
+
+ assert_success
+ assert_output "true"
+}
+
@test "create: With a custom name (using option --container)" {
pull_default_image
--
2.53.0

View File

@ -42,7 +42,7 @@ Version: 0.3
%endif
%endif
Release: 1%{?dist}
Release: 3%{?dist}
Summary: Tool for interactive command line environments on Linux
License: ASL 2.0
@ -52,6 +52,9 @@ Source0: https://github.com/containers/%{name}/releases/download/%{version
# RHEL specific
Source1: %{name}.conf
# Upstream
Patch0: toolbox-Fall-back-to-getent-passwd-when-SHELL-is-unset.patch
# Fedora specific
Patch100: toolbox-Make-the-build-flags-match-Fedora.patch
@ -124,6 +127,7 @@ The %{name}-tests package contains system tests for %{name}.
%prep
%setup -q
%patch -P0 -p1
%if 0%{?fedora}
%patch -P100 -p1
@ -197,6 +201,10 @@ install -m0644 %{SOURCE1} %{buildroot}%{_sysconfdir}/containers/%{name}.conf
%changelog
* Mon Mar 16 2026 Debarshi Ray <rishi@fedoraproject.org> - 0.3-3
- Fall back to 'getent passwd' when SHELL is unset
Resolves: RHEL-152669
* Tue Oct 07 2025 Debarshi Ray <rishi@fedoraproject.org> - 0.3-1
- Update to 0.3
Resolves: RHEL-117475