github.com/jmitchell/nomad@v0.1.3-0.20151007230021-7ab84c2862d8/command/spawn_daemon_linux.go (about) 1 package command 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "os" 7 "os/exec" 8 "strconv" 9 "strings" 10 "syscall" 11 ) 12 13 // Configuration for the command to start as a daemon. 14 type DaemonConfig struct { 15 exec.Cmd 16 17 // The paths, if not /dev/null, must be either in the tasks root directory 18 // or in the shared alloc directory. 19 StdoutFile string 20 StdinFile string 21 StderrFile string 22 23 Chroot string 24 } 25 26 // Whether to start the user command or abort. 27 type TaskStart bool 28 29 func (c *SpawnDaemonCommand) Run(args []string) int { 30 flags := c.Meta.FlagSet("spawn-daemon", FlagSetClient) 31 flags.Usage = func() { c.Ui.Output(c.Help()) } 32 33 if err := flags.Parse(args); err != nil { 34 return 1 35 } 36 37 // Check that we got json input. 38 args = flags.Args() 39 if len(args) != 1 { 40 c.Ui.Error(c.Help()) 41 return 1 42 } 43 jsonInput, err := strconv.Unquote(args[0]) 44 if err != nil { 45 return c.outputStartStatus(fmt.Errorf("Failed to unquote json input: %v", err), 1) 46 } 47 48 // De-serialize the passed command. 49 var cmd DaemonConfig 50 dec := json.NewDecoder(strings.NewReader(jsonInput)) 51 if err := dec.Decode(&cmd); err != nil { 52 return c.outputStartStatus(err, 1) 53 } 54 55 // Isolate the user process. 56 if _, err := syscall.Setsid(); err != nil { 57 return c.outputStartStatus(fmt.Errorf("Failed setting sid: %v", err), 1) 58 } 59 60 syscall.Umask(0) 61 62 // Redirect logs. 63 stdo, err := os.OpenFile(cmd.StdoutFile, os.O_CREATE|os.O_RDWR|os.O_APPEND, 0666) 64 if err != nil { 65 return c.outputStartStatus(fmt.Errorf("Error opening file to redirect Stdout: %v", err), 1) 66 } 67 68 stde, err := os.OpenFile(cmd.StderrFile, os.O_CREATE|os.O_RDWR|os.O_APPEND, 0666) 69 if err != nil { 70 return c.outputStartStatus(fmt.Errorf("Error opening file to redirect Stderr: %v", err), 1) 71 } 72 73 stdi, err := os.OpenFile(cmd.StdinFile, os.O_CREATE|os.O_RDONLY, 0666) 74 if err != nil { 75 return c.outputStartStatus(fmt.Errorf("Error opening file to redirect Stdin: %v", err), 1) 76 } 77 78 cmd.Cmd.Stdout = stdo 79 cmd.Cmd.Stderr = stde 80 cmd.Cmd.Stdin = stdi 81 82 // Chroot jail the process and set its working directory. 83 if cmd.Cmd.SysProcAttr == nil { 84 cmd.Cmd.SysProcAttr = &syscall.SysProcAttr{} 85 } 86 87 cmd.Cmd.SysProcAttr.Chroot = cmd.Chroot 88 cmd.Cmd.Dir = "/" 89 90 // Wait to get the start command. 91 var start TaskStart 92 dec = json.NewDecoder(os.Stdin) 93 if err := dec.Decode(&start); err != nil { 94 return c.outputStartStatus(err, 1) 95 } 96 97 if !start { 98 return 0 99 } 100 101 // Spawn the user process. 102 if err := cmd.Cmd.Start(); err != nil { 103 return c.outputStartStatus(fmt.Errorf("Error starting user command: %v", err), 1) 104 } 105 106 // Indicate that the command was started successfully. 107 c.outputStartStatus(nil, 0) 108 109 // Wait and then output the exit status. 110 if err := cmd.Wait(); err != nil { 111 return 1 112 } 113 114 return 0 115 }