/* Write exit information to 'exitFile' */ func (be *BdsExec) updateExitFile(exitStr string) { if (be.exitFile != "") && (be.exitFile != "-") { if DEBUG { log.Printf("Debug: Writing exit status '%s' to exit file '%s'\n", exitStr, be.exitFile) } fileutil.WriteFile(be.exitFile, exitStr) } }
/* Execute a command enforcing a timeout and writing exit status to 'exitFile' */ func (be *BdsExec) executeCommandTimeout(osSignal chan os.Signal) int { if DEBUG { log.Printf("Debug, executeCommandTimeout\n") } // Wait for execution to finish or timeout exitStr := "" if be.timeSecs <= 0 { be.timeSecs = 31536000 // Default: One year } // Create a timeout process // References: http://blog.golang.org/2010/09/go-concurrency-patterns-timing-out-and.html exitCode := make(chan string, 1) go execute(be.cmd, exitCode) // Wait until executions ends, timeout or OS signal kill := false run := true for run { select { case exitStr = <-exitCode: kill = false run = false if DEBUG { log.Printf("Debug, executeCommandTimeout: Execution finished (%s)\n", exitStr) } case <-time.After(time.Duration(be.timeSecs) * time.Second): run = false kill = true exitStr = "Time out" if DEBUG { log.Printf("Debug, executeCommandTimeout: Timeout!\n") } case sig := <-osSignal: // Ignore some signals (e.g. "window changed") sigStr := sig.String() if sigStr != "window changed" && sigStr != "child exited" && sigStr != "window size changes" { if VERBOSE || DEBUG { log.Printf("bds: Received OS signal '%s'\n", sigStr) } kill = true exitStr = "Signal received" run = false } } } // Write exitCode to file if (be.exitFile != "") && (be.exitFile != "-") { if DEBUG { log.Printf("Info: Writing exit status '%s' to exit file '%s'\n", exitStr, be.exitFile) } fileutil.WriteFile(be.exitFile, exitStr) } // Should we kill child process? if kill { if DEBUG { log.Printf("Info: Killing process\n") } be.cmd.Process.Kill() be.cmd.Process.Wait() // Reap their souls } if kill { // Should we kill all process groups from taskLoggerFile? if be.taskLoggerFile != "" { be.taskLoggerCleanUpAll() } // Send a SIGKILL to the process group (just in case any child process is still executing) if DEBUG { log.Printf("Info: Killing process group: kill(0, SIGHUP)\n") } syscall.Kill(0, syscall.SIGHUP) } // OK? exit value should be zero if exitStr == "0" { return EXITCODE_OK } // Timeout? if exitStr == "Time out" { return EXITCODE_TIMEOUT } return EXITCODE_ERROR }