diff --git a/create-container/README.md b/create-container/README.md new file mode 100644 index 0000000..1311ed7 --- /dev/null +++ b/create-container/README.md @@ -0,0 +1,9 @@ +# Create a container from scratch + + +## Get started +```bash +sudo su +go build . +./jb-container run /bin/bash +``` \ No newline at end of file diff --git a/create-container/go.mod b/create-container/go.mod index addc03a..4ee52a0 100644 --- a/create-container/go.mod +++ b/create-container/go.mod @@ -1,3 +1,3 @@ -module c-container +module jb-container go 1.21.0 diff --git a/create-container/jb-container b/create-container/jb-container new file mode 100755 index 0000000..f5835ec Binary files /dev/null and b/create-container/jb-container differ diff --git a/create-container/main.go b/create-container/main.go index 5db2fa1..b5b2f10 100644 --- a/create-container/main.go +++ b/create-container/main.go @@ -3,25 +3,84 @@ package main import ( "fmt" "os" + "os/exec" + "syscall" ) -func runContainer() { - fmt.Println("Sup") +func runContainer(args []string) { + fmt.Printf("Running %v as PID %d\n", args[2:], os.Getppid()) + cmd := exec.Command("/proc/self/exe", append([]string{"child"}, args[2:]...)...) + + cmd.Stdin = os.Stdin + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + cmd.SysProcAttr = &syscall.SysProcAttr{ + Cloneflags: syscall.CLONE_NEWUTS | syscall.CLONE_NEWPID, + } + + isFuncPanic(cmd.Run()) } -func main() { - var cmds [1]string +func runContainerChild(args []string) { + + cmd := exec.Command(args[2], args[3:]...) + cmd.Stdin = os.Stdin + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr - cmds[0] = "run" + isFuncPanic(syscall.Chroot(os.Getenv("HOME"))) + isFuncPanic(os.Chdir("/")) + isFuncPanic(syscall.Mount("proc", "proc", "proc", 0, "")) + isFuncPanic(cmd.Run()) - if len(os.Args) < 2 { - panic("Provide at leas 1 argument") + isFuncPanic(cmd.Run()) +} + +func messageHelper(cmds []string, opts []string) { + cmdsDescriptions := []string{ + "you can start a container", + "run as a child", + } + optsDescriptions := []string{ + "provides message helper", + } + + fmt.Println("Usage: jb-docker [COMMAND] [OPTIONS]") + fmt.Println("\nAvailable commands:") + for idxCmd := range cmds { + fmt.Println(fmt.Sprintf("[%s] - %s", cmds[idxCmd], cmdsDescriptions[idxCmd])) + } + fmt.Println("\nAvailable options:") + for idxOpt := range opts { + fmt.Println(fmt.Sprintf("[%s] - %s", opts[idxOpt], optsDescriptions[idxOpt])) } - fmt.Println(len(os.Args)) - switch os.Args[1] { +} + +func startContainer(args []string) { + cmds := []string{"run", "child"} + opts := []string{"--help"} + + if len(args) < 2 { + panic("Provide at least 1 argument") + } + switch args[1] { case cmds[0]: - runContainer() + runContainer(args) + case cmds[1]: + runContainerChild(args) + case opts[0]: + messageHelper(cmds, opts) default: - panic("Provide at leas 1 argument") + fmt.Println(fmt.Sprintf("jb-docker: '%s' is not a jb-docker command.\nSee 'jb-docker --help'", args[1])) + } +} + +func isFuncPanic(err error) { + if err != nil { + panic(err) } } + +func main() { + startContainer(os.Args) +}