这是我的main.go,我使用go run main.go run sh
创建一个在其中运行shell的进程。
package main
import (
"io/ioutil"
"os"
"os/exec"
"path/filepath"
"strconv"
"syscall"
"github.com/sirupsen/logrus"
)
func main() {
if len(os.Args) < 2 {
logrus.Errorf("missing commands")
return
}
switch os.Args[1] {
case "run":
run()
case "child":
child()
default:
logrus.Errorf("wrong command")
return
}
}
func run() {
logrus.Info("Setting up...")
cmd := exec.Command("/proc/self/exe", append([]string{"child"}, os.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 | syscall.CLONE_NEWNS,
}
check(cmd.Run())
}
func child() {
logrus.Infof("Running %v", os.Args[2:])
cmd := exec.Command(os.Args[2], os.Args[3:]...)
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
check(syscall.Sethostname([]byte("newhost")))
check(syscall.Chroot("/root/busybox"))
check(os.Chdir("/"))
check(syscall.Mount("proc", "proc", "proc", 0, ""))
check(syscall.Mount("tempdir", "temp", "tmpfs", 0, ""))
check(cmd.Run())
check(syscall.Unmount("proc", 0))
check(syscall.Unmount("temp", 0))
}
func check(err error) {
if err != nil {
logrus.Errorln(err)
}
}
当我在新shell中运行mount
时,它会返回
proc on /proc type proc (rw,relatime)
tempdir on /temp type tmpfs (rw,relatime)
只是工作正常。
但是当我将子功能改为
时func child() {
...
check(os.Chdir("/"))
check(syscall.Mount("proc", "proc", "proc", 0, ""))
check(syscall.Mount("tempdir", "temp", "tmpfs", 0, ""))
defer check(syscall.Unmount("proc", 0))
defer check(syscall.Unmount("temp", 0))
check(cmd.Run())
}
再次运行mount
,它会返回mount: no /proc/mounts
。
defer
用于将函数推迟到外部函数的末尾。但似乎syscall.Umount()
之前调用了cmd.Run()
。谢谢你的帮助。
答案 0 :(得分:2)
defer check(syscall.Unmount("proc", 0))
defer check(syscall.Unmount("temp", 0))
您正在推迟check
- 调用,但会立即评估其参数,这意味着,syscall.Unmount
不会被推迟。见https://golang.org/ref/spec#Defer_statements
每次&#34;推迟&#34;语句执行,函数值和 调用的参数将照常计算并重新保存但是 不调用实际函数。相反,延迟函数是 在周围函数返回之前立即调用 相反的顺序他们被推迟了。如果是延迟函数值 求值为nil,在调用函数时执行恐慌,而不是 什么时候推迟&#34;声明已经执行。
如果您无法取消支票,请使用匿名功能:
defer func() { check(syscall.Unmount("proc", 0)) }()
defer func() { check(syscall.Unmount("temp", 0)) }()
答案 1 :(得分:1)
The Go Programming Language Specification
每次&#34;推迟&#34;语句执行,函数值和 呼叫的参数照常评估并重新保存,但是 不调用实际函数。代替, 在周围之前立即调用延迟函数 函数返回,按逆序延迟。
有关
check(cmd.Run())
check(syscall.Unmount("proc", 0))
check(syscall.Unmount("temp", 0))
按相反顺序推迟
defer check(syscall.Unmount("temp", 0))
defer check(syscall.Unmount("proc", 0))
check(cmd.Run())
对于您的第二个问题,&#34;文件系统在调用cmd.Run()
之前卸载&#34;,&#34;每次&#34;延迟&#34;语句执行时,函数值和调用参数将照常计算并重新保存,但不会调用实际函数。&#34;