You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

97 lines
2.1 KiB

10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
  1. package process
  2. import (
  3. "bytes"
  4. "fmt"
  5. "io"
  6. "io/ioutil"
  7. "os"
  8. "os/exec"
  9. "time"
  10. )
  11. type Process struct {
  12. Label string
  13. ExecPath string
  14. Pid int
  15. StartTime time.Time
  16. EndTime time.Time
  17. OutputPath string
  18. Cmd *exec.Cmd `json:"-"`
  19. ExitState *os.ProcessState `json:"-"`
  20. OutputFile *os.File `json:"-"`
  21. WaitCh chan struct{} `json:"-"`
  22. }
  23. const (
  24. ProcessModeStd = iota
  25. ProcessModeDaemon
  26. )
  27. // execPath: command name
  28. // args: args to command. (should not include name)
  29. func Create(mode int, label string, execPath string, args []string, input string, outPath string) (*Process, error) {
  30. outFile, err := os.OpenFile(outPath, os.O_RDWR|os.O_CREATE|os.O_APPEND, 0600)
  31. if err != nil {
  32. return nil, err
  33. }
  34. cmd := exec.Command(execPath, args...)
  35. switch mode {
  36. case ProcessModeStd:
  37. cmd.Stdout = io.MultiWriter(os.Stdout, outFile)
  38. cmd.Stderr = io.MultiWriter(os.Stderr, outFile)
  39. cmd.Stdin = nil
  40. case ProcessModeDaemon:
  41. cmd.Stdout = outFile
  42. cmd.Stderr = outFile
  43. cmd.Stdin = nil
  44. }
  45. if input != "" {
  46. cmd.Stdin = bytes.NewReader([]byte(input))
  47. }
  48. if err := cmd.Start(); err != nil {
  49. return nil, err
  50. }
  51. proc := &Process{
  52. Label: label,
  53. ExecPath: execPath,
  54. Pid: cmd.Process.Pid,
  55. StartTime: time.Now(),
  56. OutputPath: outPath,
  57. Cmd: cmd,
  58. ExitState: nil,
  59. OutputFile: outFile,
  60. WaitCh: make(chan struct{}),
  61. }
  62. go func() {
  63. err := proc.Cmd.Wait()
  64. if err != nil {
  65. fmt.Printf("Process exit: %v\n", err)
  66. if exitError, ok := err.(*exec.ExitError); ok {
  67. proc.ExitState = exitError.ProcessState
  68. }
  69. }
  70. proc.EndTime = time.Now() // TODO make this goroutine-safe
  71. close(proc.WaitCh)
  72. }()
  73. return proc, nil
  74. }
  75. func ReadOutput(proc *Process) string {
  76. output, err := ioutil.ReadFile(proc.OutputPath)
  77. if err != nil {
  78. return fmt.Sprintf("ERROR READING OUTPUT: %v", err)
  79. }
  80. return string(output)
  81. }
  82. func Stop(proc *Process, kill bool) error {
  83. defer proc.OutputFile.Close()
  84. if kill {
  85. fmt.Printf("Killing process %v\n", proc.Cmd.Process)
  86. return proc.Cmd.Process.Kill()
  87. } else {
  88. fmt.Printf("Stopping process %v\n", proc.Cmd.Process)
  89. return proc.Cmd.Process.Signal(os.Interrupt)
  90. }
  91. }