Skip to content

Commit

Permalink
cmd/enter: honor user’s configured shell inside toolbox
Browse files Browse the repository at this point in the history
Signed-off-by: Yann Soubeyrand <yann.soubeyrand@gmx.fr>
  • Loading branch information
yann-soubeyrand committed Jun 23, 2022
1 parent e80cba4 commit 8d78eef
Show file tree
Hide file tree
Showing 8 changed files with 122 additions and 36 deletions.
1 change: 1 addition & 0 deletions doc/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ manuals = {
'toolbox-rm',
'toolbox-rmi',
'toolbox-run',
'toolbox-sh',
],
'5': [
'toolbox.conf',
Expand Down
3 changes: 2 additions & 1 deletion doc/toolbox-create.1.md
Original file line number Diff line number Diff line change
Expand Up @@ -137,4 +137,5 @@ $ toolbox create --authfile ~/auth.json --image registry.example.com/bar

## SEE ALSO

`toolbox(1)`, `toolbox-init-container(1)`, `podman(1)`, `podman-create(1)`, `podman-login(1)`, `podman-pull(1)`
`toolbox(1)`, `toolbox-init-container(1)`, `toolbox-sh(1)`,
`podman(1)`, `podman-create(1)`, `podman-login(1)`, `podman-pull(1)`
6 changes: 0 additions & 6 deletions doc/toolbox-init-container.1.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ toolbox\-init\-container - Initialize a running container
*--media-link*
*--mnt-link*
*--monitor-host*
*--shell SHELL*
*--uid UID*
*--user USER*

Expand Down Expand Up @@ -102,11 +101,6 @@ The bind mounted paths are:
- `/var/log/journal`
- `/var/mnt`

**--shell** SHELL

Create a user inside the toolbox container whose login shell is SHELL. This
option is required.

**--uid** UID

Create a user inside the toolbox container whose numerical user ID is UID. This
Expand Down
21 changes: 21 additions & 0 deletions doc/toolbox-sh.1.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
% toolbox-sh(1)

## NAME
toolbox\-sh - Launch user configured shell inside container

## SYNOPSIS
**toolbox sh**

## DESCRIPTION

Launches the user’s configured shell when entering the toolbox. It is meant to
be the command executed when entering a toolbox and must be run inside the
toolbox container.

A user willing to configure its shell inside the toolbox can do so using
regular tools like `chsh` or `usermod`.

## SEE ALSO

`toolbox(1)`, `toolbox-enter(1)`,
`podman(1)`, `podman-create(1)`, `podman-start(1)`
6 changes: 0 additions & 6 deletions src/cmd/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -389,17 +389,11 @@ func createContainer(container, image, release string, showCommandToEnter bool)

logLevelString := podman.LogLevel.String()

userShell := os.Getenv("SHELL")
if userShell == "" {
return errors.New("failed to get the current user's default shell")
}

entryPoint := []string{
"toolbox", "--log-level", "debug",
"init-container",
"--gid", currentUser.Gid,
"--home", currentUser.HomeDir,
"--shell", userShell,
"--uid", currentUser.Uid,
"--user", currentUser.Username,
"--monitor-host",
Expand Down
9 changes: 1 addition & 8 deletions src/cmd/enter.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,13 +141,6 @@ 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 default shell")
}

command := []string{userShell, "-l"}

hostID, err := utils.GetHostID()
if err != nil {
return fmt.Errorf("failed to get the host ID: %w", err)
Expand All @@ -168,7 +161,7 @@ func enter(cmd *cobra.Command, args []string) error {
defaultContainer,
image,
release,
command,
[]string{"toolbox", "sh"},
emitEscapeSequence,
true,
false); err != nil {
Expand Down
16 changes: 1 addition & 15 deletions src/cmd/initContainer.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@ var (
mediaLink bool
mntLink bool
monitorHost bool
shell string
uid int
user string
}
Expand Down Expand Up @@ -107,15 +106,6 @@ func init() {
false,
"Ensure that certain configuration files inside the toolbox container are in sync with the host")

flags.StringVar(&initContainerFlags.shell,
"shell",
"",
"Create a user inside the toolbox container whose login shell is SHELL")
err = initContainerCmd.MarkFlagRequired("shell")
if err != nil {
panic("Could not mark flag --shell as required")
}

flags.IntVar(&initContainerFlags.uid,
"uid",
0,
Expand Down Expand Up @@ -240,7 +230,6 @@ func initContainer(cmd *cobra.Command, args []string) error {
if err := configureUsers(initContainerFlags.uid,
initContainerFlags.user,
initContainerFlags.home,
initContainerFlags.shell,
initContainerFlags.homeLink,
false); err != nil {
return err
Expand All @@ -249,7 +238,6 @@ func initContainer(cmd *cobra.Command, args []string) error {
if err := configureUsers(initContainerFlags.uid,
initContainerFlags.user,
initContainerFlags.home,
initContainerFlags.shell,
initContainerFlags.homeLink,
true); err != nil {
return err
Expand Down Expand Up @@ -385,7 +373,7 @@ func initContainerHelp(cmd *cobra.Command, args []string) {
}

func configureUsers(targetUserUid int,
targetUser, targetUserHome, targetUserShell string,
targetUser, targetUserHome string,
homeLink, targetUserExists bool) error {
if homeLink {
if err := redirectPath("/home", "/var/home", true); err != nil {
Expand All @@ -405,7 +393,6 @@ func configureUsers(targetUserUid int,
"--append",
"--groups", sudoGroup,
"--home", targetUserHome,
"--shell", targetUserShell,
"--uid", fmt.Sprint(targetUserUid),
targetUser,
}
Expand All @@ -425,7 +412,6 @@ func configureUsers(targetUserUid int,
"--groups", sudoGroup,
"--home-dir", targetUserHome,
"--no-create-home",
"--shell", targetUserShell,
"--uid", fmt.Sprint(targetUserUid),
targetUser,
}
Expand Down
96 changes: 96 additions & 0 deletions src/cmd/sh.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
/*
* Copyright © 2019 – 2021 Red Hat Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package cmd

import (
"errors"
"fmt"
"os"
"os/exec"
"os/user"
"strings"
"syscall"

"github.com/containers/toolbox/pkg/utils"
"github.com/spf13/cobra"
)

var shCmd = &cobra.Command{
Use: "sh",
Short: "Launch user configured shell inside container",
Hidden: true,
RunE: sh,
}

func init() {
shCmd.SetHelpFunc(shHelp)
rootCmd.AddCommand(shCmd)
}

func sh(cmd *cobra.Command, args []string) error {
if !utils.IsInsideContainer() {
var builder strings.Builder
fmt.Fprintf(&builder, "the 'sh' command can only be used inside containers\n")
fmt.Fprintf(&builder, "Run '%s --help' for usage.", executableBase)

errMsg := builder.String()
return errors.New(errMsg)
}

u, err := user.Current()
if err != nil {
return fmt.Errorf("failed to get current user: %w", err)
}

out, err := exec.Command("getent", "passwd", u.Username).Output()
if err != nil {
if err, ok := err.(*exec.ExitError); ok {
return fmt.Errorf("failed to get user shell: %w", err)
}
return err
}

s := strings.Split(strings.TrimSuffix(string(out), "\n"), ":")[6]

err = syscall.Exec(s, []string{"-l"}, os.Environ())
if err != nil {
return fmt.Errorf("failed to execute user shell: %w", err)
}

return nil
}

func shHelp(cmd *cobra.Command, args []string) {
if utils.IsInsideContainer() {
if !utils.IsInsideToolboxContainer() {
fmt.Fprintf(os.Stderr, "Error: this is not a toolbox container\n")
return
}

if _, err := utils.ForwardToHost(); err != nil {
fmt.Fprintf(os.Stderr, "Error: %s\n", err)
return
}

return
}

if err := showManual("toolbox-sh"); err != nil {
fmt.Fprintf(os.Stderr, "Error: %s\n", err)
return
}
}

0 comments on commit 8d78eef

Please sign in to comment.