From 6f9bb504bebaa5e3f393c14311833980888eb9e0 Mon Sep 17 00:00:00 2001 From: yo Date: Sat, 10 Jun 2023 14:12:53 +0200 Subject: [PATCH] Fix forever waiting on services not properly closing pipes at start --- cmd/start.go | 4 +-- cmd/utils.go | 70 ++++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 70 insertions(+), 4 deletions(-) diff --git a/cmd/start.go b/cmd/start.go index 78b15f5..f9ceed5 100644 --- a/cmd/start.go +++ b/cmd/start.go @@ -1423,9 +1423,9 @@ func StartJail(args []string) { if len(cj.Config.Exec_start) > 0 { fmt.Printf(" > Start services:\n") cmd := fmt.Sprintf("/usr/sbin/setfib %s /usr/sbin/jexec %d %s", cj.Config.Exec_fib, cj.JID, cj.Config.Exec_start) - out, err := executeCommand(cmd) + err := executeCommandNonBlocking(cmd) if err != nil && len(out) > 0 { - fmt.Printf("Error: %v: %s\n", err, out) + fmt.Printf("Error: %v\n", err) } else { fmt.Printf(" > Start services: OK\n") } diff --git a/cmd/utils.go b/cmd/utils.go index 318aeba..cdb3a1a 100644 --- a/cmd/utils.go +++ b/cmd/utils.go @@ -215,7 +215,7 @@ func executeCommand(cmdline string) (string, error) { // else word = word + string(c) } - + if len(cmd) > 1 { out, err = exec.Command(cmd[0], cmd[1:]...).CombinedOutput() } else { @@ -225,6 +225,72 @@ func executeCommand(cmdline string) (string, error) { return string(out), err } +/* From iocage: +* # Courtesy of @william-gr +* # service(8) and some rc.d scripts have the bad h*abit of +* # exec'ing and never closing stdout/stderr. This makes +* # sure we read only enough until the command exits and do +* # not wait on the pipe to close on the other end. +* So this function executes process without waiting after completion +*/ +func executeCommandNonBlocking(cmdline string) (error) { + var cmd []string + var oCmd *exec.Cmd + var err error + + if gUseSudo { + cmd = append(cmd, "sudo") + } + + var word string + var in_escaped bool + // Split by words, or " enclosed words + for i, c := range (cmdline) { + if string(c) == "\"" { + if in_escaped { + // This is the closing " + cmd = append(cmd, word) + in_escaped = false + } else { + in_escaped = true + } + continue + } + if string(c) == " " { + if in_escaped { + word = word + string(c) + continue + } else { + cmd = append(cmd, word) + word = "" + continue + } + } + if i == (len(cmdline) - 1) { + word = word + string(c) + cmd = append(cmd, word) + break + } + + // else + word = word + string(c) + } + + if len(cmd) > 1 { + oCmd = exec.Command(cmd[0], cmd[1:]...) + } else { + oCmd = exec.Command(cmd[0]) + } + + if err = oCmd.Start(); err != nil { + return err + } + + err = oCmd.Wait() + + return err +} + // Executed command outputs to stdout in realtime func executeCommandWithOutputToStdout(cmdline string) (error) { var cmd []string @@ -616,7 +682,7 @@ func copyDevfsRuleset(ruleset int, srcrs int) error { /******************************************************************************** * Returns value of parameter as read in /var/run/jail.$InternalName.conf - * Directoves without value will return "true" if found + * Directives without value will return "true" if found * Returns an error if parameter not found in file *******************************************************************************/ func getValueFromRunningConfig(jname string, param string) (string, error) {