gocage/cmd/stop.go

246 lines
5.5 KiB
Go
Raw Normal View History

package cmd
import (
2021-12-19 12:42:29 +01:00
"os"
"fmt"
// "log"
2021-12-19 12:42:29 +01:00
"errors"
"os/exec"
2021-12-19 12:42:29 +01:00
// "reflect"
"strings"
)
// TODO : Use SYS_RCTL_GET_RACCT syscall
func removeRctlRules(jail string, rules []string) error {
var cmd []string
if len(rules) == 0 {
rules[0] = ""
}
for _, r := range rules {
if gUseSudo {
cmd = append(cmd, "sudo")
}
cmd = append(cmd, "/usr/bin/rctl")
cmd = append(cmd, "-r")
cmd = append(cmd, fmt.Sprintf("jail:%s:%s", jail, r))
2021-12-19 12:42:29 +01:00
// 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()
_, err := exec.Command(cmd[0], cmd[1:]...).Output()
return err
}
return nil
}
2021-12-19 12:42:29 +01:00
// 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")
}
}
2021-12-19 12:42:29 +01:00
// 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
}
2021-12-19 12:42:29 +01:00
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)
2021-12-19 12:42:29 +01:00
Umount ZFS dataset from inside jail
Unjail ZFS dataset from jailhost
If VNet
Delete VNet interface on host
Delete devfs ruleset
2021-12-19 12:42:29 +01:00
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?
*/
2021-12-19 12:42:29 +01:00
func StopJail(args []string) {
// Current jail were stopping
var cj *Jail
for _, j := range args {
fmt.Printf("> Stopping jail %s\n", j)
for _, rj := range gJails {
if rj.Name == j {
cj = &rj
break
}
}
if cj == nil {
fmt.Printf("Jail not found: %s\n", j)
continue
}
if cj.Running == false {
fmt.Printf("Jail %s is not running!\n", cj.Name)
continue
}
out, err := executeCommand(fmt.Sprintf("rctl jail:%s", cj.InternalName))
if err == nil && len(out) > 0 {
2021-12-19 12:42:29 +01:00
fmt.Printf(" > Remove RCTL rules:\n")
err := removeRctlRules(cj.InternalName, []string{""})
if err != nil {
fmt.Printf("ERROR: %s\n", err.Error())
} else {
2021-12-19 12:42:29 +01:00
fmt.Printf(" > Remove RCTL rules: OK\n")
}
}
if len (cj.Config.Exec_prestop) > 0 {
2021-12-19 12:42:29 +01:00
fmt.Printf(" > Execute prestop:\n")
_, err := executeCommand(cj.Config.Exec_prestop)
if err != nil {
fmt.Printf("ERROR: %s\n", err.Error())
} else {
2021-12-19 12:42:29 +01:00
fmt.Printf(" > Execute prestop: OK\n")
}
}
if len (cj.Config.Exec_stop) > 0 {
2021-12-19 12:42:29 +01:00
fmt.Printf(" > Execute stop:\n")
_, err := executeCommandInJail(cj, cj.Config.Exec_stop)
if err != nil {
fmt.Printf("ERROR: %s\n", err.Error())
} else {
2021-12-19 12:42:29 +01:00
fmt.Printf(" > Execute stop: OK\n")
}
}
2021-12-19 12:42:29 +01:00
if cj.Config.Jail_zfs > 0 {
2021-12-19 12:42:29 +01:00
fmt.Printf(" > Umount jailed ZFS:\n")
err := umountAndUnjailZFS(cj)
if err != nil {
fmt.Printf("ERROR: %s\n", err.Error())
} else {
2021-12-19 12:42:29 +01:00
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")
}
}
2021-12-19 12:42:29 +01:00
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)
}
}
}