From 609dc286ef6c4020833c47845479c06cff52a4b8 Mon Sep 17 00:00:00 2001 From: Jonathon Anderson Date: Mon, 10 Feb 2025 16:45:50 -0700 Subject: [PATCH 1/2] Update PS1 during `wwctl image shell` to include working directory Optionally, use `WW_PS1` to construct the prompt. - Closes: #1245 Signed-off-by: Jonathon Anderson --- CHANGELOG.md | 2 ++ internal/app/wwctl/image/exec/child/main.go | 18 ++++++++++++------ userdocs/contents/images.rst | 15 +++++++++++++++ 3 files changed, 29 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ac3688eb..3f56600c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - syncuser overlay skips duplicate users and groups in passwd and group databases. #829 - `wwctl image syncuser --write` is true by default. #1736 - Update syncuser documentation. #1736 +- Update PS1 during `wwctl image shell` to include working directory by default, + and to include `PS1` from the environment if present. #1245 ### Fixed diff --git a/internal/app/wwctl/image/exec/child/main.go b/internal/app/wwctl/image/exec/child/main.go index f3b5a2e7..e45b2797 100644 --- a/internal/app/wwctl/image/exec/child/main.go +++ b/internal/app/wwctl/image/exec/child/main.go @@ -20,8 +20,6 @@ import ( "github.com/warewulf/warewulf/internal/pkg/wwlog" ) -const exitEval = `$(VALU="$?" ; if [ $VALU == 0 ]; then echo write; else echo discard; fi)` - func CobraRunE(cmd *cobra.Command, args []string) (err error) { if os.Getpid() != 1 { return fmt.Errorf("PID is not 1: %d", os.Getpid()) @@ -78,7 +76,7 @@ func CobraRunE(cmd *cobra.Command, args []string) (err error) { if err != nil { return fmt.Errorf("failed to mount: %w", err) } - ps1Str := fmt.Sprintf("[%s|%s] Warewulf> ", imageName, exitEval) + ps1Prefix := fmt.Sprintf(`[warewulf:%s]`, imageName) if len(lowerObjects) != 0 && nodename == "" { options := fmt.Sprintf("lowerdir=%s,upperdir=%s,workdir=%s", path.Join(runDir, "lower"), imagePath, path.Join(runDir, "work")) @@ -114,11 +112,11 @@ func CobraRunE(cmd *cobra.Command, args []string) (err error) { if err != nil { return fmt.Errorf("couldn't create overlay for node render overlay: %s", err) } - ps1Str = fmt.Sprintf("[%s|ro|%s] Warewulf> ", imageName, nodename) + ps1Prefix = fmt.Sprintf(`warewulf:%s(ro)] `, imageName) } if !image.IsWriteAble(imageName) && nodename == "" { wwlog.Verbose("mounting %s ro", imagePath) - ps1Str = fmt.Sprintf("[%s|ro] Warewulf> ", imageName) + ps1Prefix = fmt.Sprintf(`warewulf:%s(ro)] `, imageName) err = syscall.Mount(imagePath, imagePath, "", syscall.MS_BIND, "") if err != nil { return fmt.Errorf("failed to prepare bind mount: %w", err) @@ -172,7 +170,15 @@ func CobraRunE(cmd *cobra.Command, args []string) (err error) { return fmt.Errorf("failed to mount /run: %w", err) } - os.Setenv("PS1", ps1Str) + var ps1Base string + if v, ok := os.LookupEnv("WW_PS1"); ok { + ps1Base = v + } else { + ps1Base = `\w\$ ` + os.Setenv("WW_PS1", ps1Base) + } + + os.Setenv("PS1", fmt.Sprintf("%s %s", ps1Prefix, ps1Base)) os.Setenv("PATH", "/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin") os.Setenv("HISTFILE", "/dev/null") diff --git a/userdocs/contents/images.rst b/userdocs/contents/images.rst index 253b2b58..888af6ca 100644 --- a/userdocs/contents/images.rst +++ b/userdocs/contents/images.rst @@ -291,6 +291,21 @@ If the files ``/etc/passwd`` or ``/etc/group`` were updated, there will be an additional check to confirm if the users are in sync as described in `Syncuser`_ section. +Specifying a prompt +------------------- + +Warewulf sets a custom prompt during a ``wwctl image shell`` session. This +prompt may be customized using the ``WW_PS1`` variable, which is used to +construct the final ``PS1`` variable for the shell. + +.. code-block:: + + # wwctl image shell rockylinux-9 + [warewulf:rockylinux-9] /# + + # env WW_PS1="\u@\h:\w\$ " wwctl image shell rockylinux-9 + [warewulf:rockylinux-9] root@rocky:/$ + Excluding Files from an Image ----------------------------- From 7f317dff823b5ee583d10253d6355363c629fe4c Mon Sep 17 00:00:00 2001 From: Jonathon Anderson Date: Tue, 11 Feb 2025 14:51:53 -0700 Subject: [PATCH 2/2] Add `WW_HISTFILE` to control shell history location during `wwctl image shell` Co-authored-by: Christian Goll Signed-off-by: Jonathon Anderson --- CHANGELOG.md | 1 + internal/app/wwctl/image/exec/child/main.go | 14 +++++++++++--- userdocs/contents/images.rst | 10 ++++++++++ 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3f56600c..b57c4bae 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Added `UniqueField` template function. #829 - Added `wwctl image build --syncuser`. #1321 - Added support for a DNSSEARCH netdev tag in network configuration overlays. #1256 +- Added `WW_HISTFILE` to control shell history location during `wwctl image shell`. #1732 ### Changed diff --git a/internal/app/wwctl/image/exec/child/main.go b/internal/app/wwctl/image/exec/child/main.go index e45b2797..c3fe9d8f 100644 --- a/internal/app/wwctl/image/exec/child/main.go +++ b/internal/app/wwctl/image/exec/child/main.go @@ -170,6 +170,8 @@ func CobraRunE(cmd *cobra.Command, args []string) (err error) { return fmt.Errorf("failed to mount /run: %w", err) } + os.Setenv("PATH", "/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin") + var ps1Base string if v, ok := os.LookupEnv("WW_PS1"); ok { ps1Base = v @@ -177,10 +179,16 @@ func CobraRunE(cmd *cobra.Command, args []string) (err error) { ps1Base = `\w\$ ` os.Setenv("WW_PS1", ps1Base) } - os.Setenv("PS1", fmt.Sprintf("%s %s", ps1Prefix, ps1Base)) - os.Setenv("PATH", "/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin") - os.Setenv("HISTFILE", "/dev/null") + + var histfile string + if v, ok := os.LookupEnv("WW_HISTFILE"); ok { + histfile = v + } else { + histfile = "/dev/null" + os.Setenv("WW_HISTFILE", histfile) + } + os.Setenv("HISTFILE", histfile) wwlog.Debug("Exec: %s %s", args[1], args[1:]) return syscall.Exec(args[1], args[1:], os.Environ()) diff --git a/userdocs/contents/images.rst b/userdocs/contents/images.rst index 888af6ca..9af651a9 100644 --- a/userdocs/contents/images.rst +++ b/userdocs/contents/images.rst @@ -306,6 +306,16 @@ construct the final ``PS1`` variable for the shell. # env WW_PS1="\u@\h:\w\$ " wwctl image shell rockylinux-9 [warewulf:rockylinux-9] root@rocky:/$ +Shell history +------------- + +By default, Warewulf image shell sessions don't retain history; but you can +specify a history file by specifing ``WW_HISTFILE``. Note that this file is +stored within the image; you may want to exclude it when the image is built. +(See :ref:`exclude`.) + +.. _exclude: + Excluding Files from an Image -----------------------------