From eebc7da16917c225ea874b5401b5c7cd3f81369e Mon Sep 17 00:00:00 2001 From: yo Date: Sun, 19 Dec 2021 12:42:29 +0100 Subject: [PATCH] gocage stop now functionnal --- cmd/stop.go | 166 ++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 141 insertions(+), 25 deletions(-) diff --git a/cmd/stop.go b/cmd/stop.go index d8c0f9a..68f63cd 100644 --- a/cmd/stop.go +++ b/cmd/stop.go @@ -1,10 +1,13 @@ package cmd import ( + "os" "fmt" // "log" -// "strings" + "errors" "os/exec" +// "reflect" + "strings" ) // TODO : Use SYS_RCTL_GET_RACCT syscall @@ -23,7 +26,7 @@ func removeRctlRules(jail string, rules []string) error { cmd = append(cmd, "-r") cmd = append(cmd, fmt.Sprintf("jail:%s:%s", jail, r)) - // TODO : Log in another channel than stdout (will scramble diusplay) + // TODO : Log in another channel than stdout (will scramble display) //log.Println(fmt.Sprintf("Removing all rules for jail %s: %s", jail, cmd)) //out, err := exec.Command(cmd[0], cmd[1:]...).Output() @@ -35,31 +38,121 @@ func removeRctlRules(jail string, rules []string) error { } -// TODO -func umountJailedZFS(jail *Jail) error { -/* - for _, zd := range jail.Config.Jail_zfs_dataset { - +// TODO: Validate with >1 dataset +func umountAndUnjailZFS(jail *Jail) error { + var ds []string + + // Make sure we have a string array + ds = append(ds, jail.Config.Jail_zfs_dataset) + + for _, zd := range ds { + // 1. Get dataset and childs + cmd := fmt.Sprintf("zfs list -H -r -o name -S name %s/%s", jail.Zpool, zd) + out, err := executeCommand(cmd) + if err != nil { + fmt.Printf(fmt.Sprintf("ERROR listing dataset %s/%s\n", jail.Zpool, zd)) + os.Exit(1) + } + for _, c := range strings.Split(out, "\n") { + if len(c) == 0 { + continue + } + fmt.Printf("Unmounting dataset %s: ", c) + cmd := fmt.Sprintf("zfs umount %s", c) + _, err := executeCommandInJail(jail, cmd) + if err != nil { + return err + } + fmt.Printf("OK\n") + } } -*/ + + // 2. Unjail dataset from the host + cmd := fmt.Sprintf("zfs unjail %s %s/%s", jail.InternalName, jail.Zpool, ds[len(ds)-1]) + _, err := executeCommand(cmd) + if err != nil { + fmt.Printf("ERROR unjailing %s/%s: %s\n", jail.Zpool, ds[len(ds)-1], err.Error()) + return err + } + return nil } +func destroyVNetInterfaces(jail *Jail) error { + for _, i := range strings.Split(jail.Config.Ip4_addr, ",") { + iname := fmt.Sprintf("%s.%d", strings.Split(i, "|")[0], jail.JID) + fmt.Printf("%s: ", iname) + _, err := executeCommand(fmt.Sprintf("ifconfig %s destroy", iname)) + if err != nil { + return err + } else { + fmt.Printf("OK\n") + } + } + + return nil +} + + +func deleteDevfsRuleset(jail *Jail) error { + cmd := "devfs rule showsets" + out, err := executeCommand(cmd) + if err != nil { + return errors.New(fmt.Sprintf("ERROR listing rulesets: %s", err.Error())) + } + + for _, r := range strings.Split(out, "\n") { + if r == jail.Config.Devfs_ruleset { + cmd := fmt.Sprintf("devfs rule -s %s delset", jail.Config.Devfs_ruleset) + _, err := executeCommand(cmd) + return err + } + } + + return nil +} + + +// Internal usage only +func stopJail(jail *Jail) error { + cmd := "jail -q" + + // Test if conf file exist (iocage created) + cf := fmt.Sprintf("/var/run/jail.%s.conf", jail.InternalName) + file, err := os.Open(cf) + if err != nil { + file.Close() + cmd = fmt.Sprintf("%s -f %s", cmd, cf) + } + cmd = fmt.Sprintf("%s -r %s", cmd, jail.InternalName) + + _, err = executeCommand(cmd) + if err != nil { + return err + } + + return nil +} + /* Stop jail: Remove rctl rules Execute prestop if set (jailhost perimeter) Execute stop if set (inside jail) - Umount ZFS dataset - Unmount mountpoint + Umount ZFS dataset from inside jail + Unjail ZFS dataset from jailhost + If VNet + Delete VNet interface on host Delete devfs ruleset + Effectively stop jail process + Umount all mountpoints from $jail/fstab Use setfib for each command Shouldnt rctl rules be removed last, when jail is stopped? */ -func stopJail(args []string) { +func StopJail(args []string) { // Current jail were stopping var cj *Jail @@ -83,47 +176,70 @@ func stopJail(args []string) { out, err := executeCommand(fmt.Sprintf("rctl jail:%s", cj.InternalName)) if err == nil && len(out) > 0 { - fmt.Printf(" > Remove RCTL rules: ") + fmt.Printf(" > Remove RCTL rules:\n") err := removeRctlRules(cj.InternalName, []string{""}) if err != nil { fmt.Printf("ERROR: %s\n", err.Error()) } else { - fmt.Printf("OK\n") + fmt.Printf(" > Remove RCTL rules: OK\n") } } if len (cj.Config.Exec_prestop) > 0 { - fmt.Printf(" > Execute prestop: ") - out, err := executeCommand(cj.Config.Exec_prestop) + fmt.Printf(" > Execute prestop:\n") + _, err := executeCommand(cj.Config.Exec_prestop) if err != nil { fmt.Printf("ERROR: %s\n", err.Error()) } else { - fmt.Printf("OK\n") - fmt.Printf("%s\n", out) + fmt.Printf(" > Execute prestop: OK\n") } } if len (cj.Config.Exec_stop) > 0 { - fmt.Printf(" > Execute stop: ") - out, err := executeCommandInJail(cj, cj.Config.Exec_stop) + fmt.Printf(" > Execute stop:\n") + _, err := executeCommandInJail(cj, cj.Config.Exec_stop) if err != nil { fmt.Printf("ERROR: %s\n", err.Error()) } else { - fmt.Printf("OK\n") - fmt.Printf("%s\n", out) + fmt.Printf(" > Execute stop: OK\n") } } - + if cj.Config.Jail_zfs > 0 { - fmt.Printf(" > Umount jailed ZFS: ") - err := umountJailedZFS(cj) + fmt.Printf(" > Umount jailed ZFS:\n") + err := umountAndUnjailZFS(cj) if err != nil { fmt.Printf("ERROR: %s\n", err.Error()) } else { - fmt.Printf("OK\n") + fmt.Printf(" > Umount jailed ZFS: OK\n") + } + } + + if cj.Config.Vnet > 0 && len(cj.Config.Ip4_addr) > 0 { + fmt.Printf(" > Destroy VNet interfaces:\n") + err := destroyVNetInterfaces(cj) + if err != nil { + fmt.Printf("ERROR: %s\n", err.Error()) + } else { + fmt.Printf(" > Destroy VNet interfaces: OK\n") } } + fmt.Printf(" > Remove devfsruleset %s:\n", cj.Config.Devfs_ruleset) + err = deleteDevfsRuleset(cj) + if err != nil { + fmt.Printf("ERROR: %s\n", err.Error()) + } else { + fmt.Printf(" > Remove devfsruleset %s: OK\n", cj.Config.Devfs_ruleset) + } + + fmt.Printf(" > Stop jail %s:\n", cj.Name) + err = stopJail(cj) + if err != nil { + fmt.Printf("ERROR: %s\n", err.Error()) + } else { + fmt.Printf(" > Stop jail %s: OK\n", cj.Name) + } } }