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.

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