diff --git a/internal/app/wwctl/container/exec/child/main.go b/internal/app/wwctl/container/exec/child/main.go new file mode 100644 index 00000000..f35944ea --- /dev/null +++ b/internal/app/wwctl/container/exec/child/main.go @@ -0,0 +1,90 @@ +//go:build linux +// +build linux + +package child + +import ( + "fmt" + "os" + "path" + "syscall" + + "github.com/hpcng/warewulf/internal/pkg/container" + "github.com/hpcng/warewulf/internal/pkg/util" + "github.com/hpcng/warewulf/internal/pkg/wwlog" + "github.com/pkg/errors" + "github.com/spf13/cobra" +) + +func CobraRunE(cmd *cobra.Command, args []string) error { + if os.Getpid() != 1 { + wwlog.Printf(wwlog.ERROR, "PID is not 1: %d\n", os.Getpid()) + os.Exit(1) + } + + containerName := args[0] + + if !container.ValidSource(containerName) { + wwlog.Printf(wwlog.ERROR, "Unknown Warewulf container: %s\n", containerName) + os.Exit(1) + } + + containerPath := container.RootFsDir(containerName) + + err := syscall.Mount("", "/", "", syscall.MS_PRIVATE|syscall.MS_REC, "") + if err != nil { + return errors.Wrap(err, "failed to mount") + } + + err = syscall.Mount("/dev", path.Join(containerPath, "/dev"), "", syscall.MS_BIND, "") + if err != nil { + return errors.Wrap(err, "failed to mount /dev") + } + + for _, b := range binds { + var source string + var dest string + + bind := util.SplitValidPaths(b, ":") + source = bind[0] + + if len(bind) == 1 { + dest = source + } else { + dest = bind[1] + } + + err := syscall.Mount(source, path.Join(containerPath, dest), "", syscall.MS_BIND, "") + if err != nil { + fmt.Printf("BIND ERROR: %s\n", err) + os.Exit(1) + } + } + + err = syscall.Chroot(containerPath) + if err != nil { + return errors.Wrap(err, "failed to chroot") + } + + err = os.Chdir("/") + if err != nil { + return errors.Wrap(err, "failed to chdir") + } + + err = syscall.Mount("/proc", "/proc", "proc", 0, "") + if err != nil { + return errors.Wrap(err, "failed to mount proc") + } + + os.Setenv("PS1", fmt.Sprintf("[%s] Warewulf> ", containerName)) + os.Setenv("PATH", "/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin") + os.Setenv("HISTFILE", "/dev/null") + + err = syscall.Exec(args[1], args[1:], os.Environ()) + if err != nil { + wwlog.Printf(wwlog.ERROR, "%s\n", err) + os.Exit(1) + } + + return nil +} diff --git a/internal/app/wwctl/container/exec/child/non-Linux.go b/internal/app/wwctl/container/exec/child/non-Linux.go new file mode 100644 index 00000000..96a4a9c7 --- /dev/null +++ b/internal/app/wwctl/container/exec/child/non-Linux.go @@ -0,0 +1,15 @@ +//go:build !linux +// +build !linux + +package child + +import ( + "github.com/hpcng/warewulf/internal/pkg/wwlog" + "github.com/spf13/cobra" +) + +func CobraRunE(cmd *cobra.Command, args []string) error { + wwlog.Printf(wwlog.ERROR, "This command does not work on non-Linux hosts\n") + + return nil +} diff --git a/internal/app/wwctl/container/exec/child/root.go b/internal/app/wwctl/container/exec/child/root.go new file mode 100644 index 00000000..0b7dde7c --- /dev/null +++ b/internal/app/wwctl/container/exec/child/root.go @@ -0,0 +1,24 @@ +package child + +import "github.com/spf13/cobra" + +var ( + baseCmd = &cobra.Command{ + DisableFlagsInUseLine: true, + Use: "__child", + Hidden: true, + RunE: CobraRunE, + Args: cobra.MinimumNArgs(1), + FParseErrWhitelist: cobra.FParseErrWhitelist{UnknownFlags: true}, + } + binds []string +) + +func init() { + baseCmd.PersistentFlags().StringArrayVarP(&binds, "bind", "b", []string{}, "bind points") +} + +// GetRootCommand returns the root cobra.Command for the application. +func GetCommand() *cobra.Command { + return baseCmd +} diff --git a/internal/app/wwctl/container/exec/root.go b/internal/app/wwctl/container/exec/root.go index ec8e33a5..913d4f79 100644 --- a/internal/app/wwctl/container/exec/root.go +++ b/internal/app/wwctl/container/exec/root.go @@ -1,6 +1,7 @@ package exec import ( + "github.com/hpcng/warewulf/internal/app/wwctl/container/exec/child" "github.com/hpcng/warewulf/internal/pkg/container" "github.com/spf13/cobra" ) @@ -28,6 +29,7 @@ var ( ) func init() { + baseCmd.AddCommand(child.GetCommand()) baseCmd.PersistentFlags().StringArrayVarP(&binds, "bind", "b", []string{}, "Bind a local path into the container (must exist)") }