Пример #1
1
func start(c *exec.Cmd) (io.ReadCloser, io.WriteCloser, error) {
	c.SysProcAttr = &syscall.SysProcAttr{}
	//c.SysProcAttr.CreationFlags = 16 // CREATE_NEW_CONSOLE

	stdin, err := c.StdinPipe()

	if err != nil {
		return nil, nil, err
	}

	stdout, err := c.StdoutPipe()

	if err != nil {
		return nil, nil, err
	}

	stderr, err := c.StderrPipe()

	if err != nil {
		return nil, nil, err
	}

	t := &term{}
	t.cmd = c
	t.stderr = stderr
	t.stdout = stdout
	t.stdin = stdin

	err = t.start()
	if err != nil {
		return nil, nil, err
	}

	return t, t, nil
}
Пример #2
0
func Example() {
	var cmd *exec.Cmd
	memd := func(t *tcptest.TCPTest) {
		cmd = exec.Command("memcached", "-p", fmt.Sprintf("%d", t.Port()))
		cmd.SysProcAttr = &syscall.SysProcAttr{
			Setpgid: true,
		}

		go cmd.Run()
		for loop := true; loop; {
			select {
			case <-t.Done():
				cmd.Process.Kill()
				loop = false
			}
		}
	}

	server, err := tcptest.Start2(memd, 30*time.Second)
	if err != nil {
		log.Fatalf("Failed to start memcached: %s", err)
	}

	log.Printf("memcached started on port %d", server.Port())
	defer func() {
		if cmd != nil && cmd.Process != nil {
			cmd.Process.Signal(syscall.SIGTERM)
		}
	}()

	server.Stop()

	server.Wait()
}
func (r *RealCommandRunner) Start(cmd *exec.Cmd) error {
	if cmd.SysProcAttr == nil {
		cmd.SysProcAttr = &syscall.SysProcAttr{
			Setpgid: true,
		}
	} else {
		cmd.SysProcAttr.Setpgid = true
	}

	if r.debug {
		log.Printf("\x1b[40;36mspawning: %s\x1b[0m\n", prettyCommand(cmd))
		r.tee(cmd)
	}

	err := r.resolve(cmd).Start()

	if r.debug {
		if err != nil {
			log.Printf("\x1b[40;31mspawning failed: %s\x1b[0m\n", err)
		} else {
			log.Printf("\x1b[40;32mspawning succeeded\x1b[0m\n")
		}
	}

	return err
}
Пример #4
0
// Configures the given Command to produce a hidden window, if possible. Must
// be called before the Command is executed.
func Hide(c *exec.Cmd) {
	if c.SysProcAttr == nil {
		c.SysProcAttr = &syscall.SysProcAttr{HideWindow: true}
	} else {
		c.SysProcAttr.HideWindow = true
	}
}
Пример #5
0
func start(c *exec.Cmd) (pty *os.File, err error) {
	pty, tty, err := open()
	if err != nil {
		return nil, err
	}
	defer tty.Close()

	err = setEcho(pty, false)
	if err != nil {
		return nil, err
	}

	err = setEcho(tty, false)
	if err != nil {
		return nil, err
	}

	c.Stdout = tty
	c.Stdin = tty
	c.Stderr = tty
	if c.SysProcAttr == nil {
		c.SysProcAttr = &syscall.SysProcAttr{}
	}
	c.SysProcAttr.Setctty = true
	c.SysProcAttr.Setsid = true
	err = c.Start()
	if err != nil {
		pty.Close()
		return nil, err
	}

	return pty, err
}
Пример #6
0
// timedCommand executes the given command, terminating it forcefully
// if it is still running after the given timeout elapses.
func (e *executor) timedCommand(timeout time.Duration, opts opts, command *exec.Cmd) error {
	// Make the process of this command a new process group leader
	// to facilitate clean up of processes that time out.
	command.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}
	// Kill this process group explicitly when receiving SIGTERM
	// or SIGINT signals.
	sigchan := make(chan os.Signal, 1)
	signal.Notify(sigchan, syscall.SIGTERM, syscall.SIGQUIT, syscall.SIGINT)
	go func() {
		<-sigchan
		e.terminateProcessGroup(opts, command)
	}()
	if err := command.Start(); err != nil {
		e.printf(e.verboseStdout(opts), "FAILED: %v", err)
		return err
	}
	done := make(chan error, 1)
	go func() {
		done <- command.Wait()
	}()
	select {
	case <-time.After(timeout):
		// The command has timed out.
		e.terminateProcessGroup(opts, command)
		// Allow goroutine to exit.
		<-done
		e.printf(e.verboseStdout(opts), "TIMED OUT")
		return commandTimedOutErr
	case err := <-done:
		e.printf(e.verboseStdout(opts), okOrFailed(err))
		return err
	}
}
Пример #7
0
func (pipe *Pipe) runPtyCmd(cmd *exec.Cmd) error {
	py, tty, err := pty.Open()
	if err != nil {
		return err
	}
	defer tty.Close()
	env := os.Environ()
	env = append(env, "TERM=xterm")
	cmd.Env = env
	cmd.Stdout = tty
	cmd.Stdin = tty
	cmd.Stderr = tty
	cmd.SysProcAttr = &syscall.SysProcAttr{Setctty: true, Setsid: true}
	ws := &Winsize{
		Width:  uint16(pipe.opts.Width),
		Height: uint16(pipe.opts.Height),
	}
	_, _, syserr := syscall.Syscall(syscall.SYS_IOCTL, py.Fd(), uintptr(syscall.TIOCSWINSZ), uintptr(unsafe.Pointer(ws)))
	if syserr != 0 {
		return syserr
	}
	pCmd := pipedCmd{
		pipe:   pipe,
		cmd:    cmd,
		stdin:  py,
		stdout: py,
		stderr: nil,
	}
	return pCmd.run()
}
func (r *RealCommandRunner) Run(cmd *exec.Cmd) error {
	if cmd.SysProcAttr == nil {
		cmd.SysProcAttr = &syscall.SysProcAttr{
			Setpgid: true,
		}
	} else {
		cmd.SysProcAttr.Setpgid = true
	}

	if r.debug {
		log.Printf("\x1b[40;36mexecuting: %s\x1b[0m\n", prettyCommand(cmd))
		r.tee(cmd)
	}

	err := r.resolve(cmd).Run()

	if r.debug {
		if err != nil {
			log.Printf("\x1b[40;31mcommand failed (%s): %s\x1b[0m\n", prettyCommand(cmd), err)
		} else {
			log.Printf("\x1b[40;32mcommand succeeded (%s)\x1b[0m\n", prettyCommand(cmd))
		}
	}

	return err
}
Пример #9
0
// Launch creates and begins debugging a new process. First entry in
// `cmd` is the program to run, and then rest are the arguments
// to be supplied to that process.
func Launch(cmd []string) (*Process, error) {
	var (
		proc *exec.Cmd
		err  error
	)
	// check that the argument to Launch is an executable file
	if fi, staterr := os.Stat(cmd[0]); staterr == nil && (fi.Mode()&0111) == 0 {
		return nil, NotExecutableErr
	}
	dbp := New(0)
	dbp.execPtraceFunc(func() {
		proc = exec.Command(cmd[0])
		proc.Args = cmd
		proc.Stdout = os.Stdout
		proc.Stderr = os.Stderr
		proc.SysProcAttr = &syscall.SysProcAttr{Ptrace: true, Setpgid: true}
		err = proc.Start()
	})
	if err != nil {
		return nil, err
	}
	dbp.Pid = proc.Process.Pid
	_, _, err = dbp.wait(proc.Process.Pid, 0)
	if err != nil {
		return nil, fmt.Errorf("waiting for target execve failed: %s", err)
	}
	return initializeDebugProcess(dbp, proc.Path, false)
}
func TestMemd(t *testing.T) {
	var cmd *exec.Cmd
	memd := func(t *tcptest.TCPTest) {
		cmd = exec.Command("memcached", "-p", fmt.Sprintf("%d", t.Port()))
		cmd.SysProcAttr = &syscall.SysProcAttr{
			Setpgid: true,
		}
		cmd.Run()
	}

	server, err := tcptest.Start2(memd, 30*time.Second)
	if err != nil {
		log.Fatalf("Failed to start memcached: %s", err)
	}
	t.Logf("memcached started on port %d", server.Port())
	defer func() {
		if cmd != nil && cmd.Process != nil {
			cmd.Process.Signal(syscall.SIGTERM)
		}
	}()

	argv := []string{"-p", fmt.Sprintf("%d", server.Port()), "-k", "test"}
	ckr := run(argv)
	if ckr.Status.String() != "OK" {
		t.Errorf("faild to check memcache:%s", ckr)
	}
	cmd.Process.Signal(syscall.SIGTERM)
	server.Wait()
}
Пример #11
0
func (w *Spawn) spawnWithTty(cmd *exec.Cmd) ([]*os.File, error) {
	pty, tty, err := w.PTY.Open()
	if err != nil {
		return nil, fmt.Errorf("container_daemon: open pipe: %s", err)
	}

	cmd.Stdin = tty
	cmd.Stdout = tty
	cmd.Stderr = tty

	if cmd.SysProcAttr == nil {
		cmd.SysProcAttr = &syscall.SysProcAttr{}
	}

	cmd.SysProcAttr.Setctty = true
	cmd.SysProcAttr.Setsid = true

	exitFd, err := wireExit(cmd, w.Runner)
	if err != nil {
		pty.Close()
		tty.Close()
		return nil, err
	}

	return []*os.File{pty, exitFd}, err
}
Пример #12
0
func PutInBackgroundIfLinux(cmd *exec.Cmd) {
	// To put this in the background, we have to change the process group
	//	per: https://groups.google.com/forum/#!topic/golang-nuts/shST-SDqIp4.
	//	But it doesn't work on Windows
	cmd.SysProcAttr = &syscall.SysProcAttr{
		Setpgid: true,
	}
}
Пример #13
0
//PtyRun assigns a psuedo terminal tty to the corresponding std.io set and returns an error indicating state
func PtyRun(c *exec.Cmd, tty *os.File) (err error) {
	defer tty.Close()
	c.Stdout = tty
	c.Stdin = tty
	c.Stderr = tty
	c.SysProcAttr = &syscall.SysProcAttr{Setctty: true, Setsid: true}
	return c.Start()
}
Пример #14
0
func (e *ExecScriptCheck) setChroot(cmd *exec.Cmd) {
	if e.FSIsolation {
		if cmd.SysProcAttr == nil {
			cmd.SysProcAttr = &syscall.SysProcAttr{}
		}
		cmd.SysProcAttr.Chroot = e.taskDir
	}
	cmd.Dir = "/"
}
Пример #15
0
func (p *Pty) SetCmd(c *exec.Cmd) {
	c.Stdin = p.tty
	c.Stdout = p.tty
	c.Stderr = p.tty
	if c.SysProcAttr == nil {
		c.SysProcAttr = &syscall.SysProcAttr{}
	}
	c.SysProcAttr.Setctty = true
	c.SysProcAttr.Setsid = true
}
Пример #16
0
func (r *RealCommandRunner) Background(cmd *exec.Cmd) error {
	if cmd.SysProcAttr == nil {
		cmd.SysProcAttr = &syscall.SysProcAttr{
			Setpgid: true,
		}
	} else {
		cmd.SysProcAttr.Setpgid = true
	}

	return cmd.Start()
}
Пример #17
0
// Set OS-specific SysProcAttrs if they exist
func cleanupSubcmd(c *exec.Cmd) {
	// Send the subprocess a SIGTERM when we exit
	attr := new(syscall.SysProcAttr)

	r := reflect.ValueOf(attr)
	f := reflect.Indirect(r).FieldByName(`Pdeathsig`)

	if f.IsValid() {
		f.Set(reflect.ValueOf(syscall.SIGTERM))
		c.SysProcAttr = attr
	}
}
Пример #18
0
func serviceHandleUsersFor(service *Service, cmd *exec.Cmd) {
	config := (*service).config
	userName := config.User
	if !userName.IsTrimmedEmpty() {
		cmd.SysProcAttr = &syscall.SysProcAttr{}
		uid, gid, err := lookupUser(userName.String())
		if err != nil {
			panics.New("Could not run as user '%v'.", userName).CausedBy(err).Throw()
		}
		cmd.SysProcAttr.Credential = &syscall.Credential{Uid: uint32(uid), Gid: uint32(gid)}
	}
}
Пример #19
0
// --- functions
func CmdDaemonWrapper(c *cli.Context) {
	args := os.Args
	args[1] = "_daemon"
	started := []time.Time{}

	sigTerm := make(chan os.Signal, 1)
	signal.Notify(sigTerm, os.Interrupt)
	signal.Notify(sigTerm, syscall.SIGTERM)
	var cmd *exec.Cmd

	go func() {
		<-sigTerm
		cmd.Process.Kill()
		os.Exit(1)
	}()

	sigHup := make(chan os.Signal, 1)
	signal.Notify(sigHup, syscall.SIGHUP)
	go func() {
		for {
			<-sigHup
			cmd.Process.Signal(syscall.SIGHUP)
		}
	}()

	for {
		cmd = exec.Command(args[0], args[1:]...)
		cmd.Stdout = os.Stdout
		cmd.Stderr = os.Stderr
		envHappoUserId := os.Getenv("HAPPO_USER_ID")
		if envHappoUserId != "" {
			uid, err := strconv.Atoi(envHappoUserId)
			if err != nil {
				log.Print("HAPPO_USER_ID ", envHappoUserId)
				log.Fatal(err)
			}
			cmd.SysProcAttr = &syscall.SysProcAttr{}
			cmd.SysProcAttr.Credential = &syscall.Credential{Uid: uint32(uid)}
		}
		started = append(started, time.Now())

		cmd.Start()
		cmd.Wait()

		if len(started) > 10 && time.Now().Add(-30*time.Second).Before(started[len(started)-5]) {
			log.Fatal("Restarted too fast. Abort!")
			os.Exit(1)
		}
	}
}
Пример #20
0
func SetNamespace(cmd *exec.Cmd) {
	// XXX: keep move with Go 1.4 and later's

	cmd.SysProcAttr = &syscall.SysProcAttr{}
	//cmd.SysProcAttr.Cloneflags = syscall.CLONE_NEWUSER | syscall.CLONE_NEWNS | syscall.CLONE_NEWUTS | syscall.CLONE_NEWPID | syscall.CLONE_NEWIPC | syscall.CLONE_NEWNET
	cmd.SysProcAttr.Cloneflags = syscall.CLONE_NEWUSER /*| syscall.CLONE_NEWNS*/ | syscall.CLONE_NEWUTS | syscall.CLONE_NEWPID | syscall.CLONE_NEWIPC /*| syscall.CLONE_NEWNET*/
	cmd.SysProcAttr.Credential = &syscall.Credential{
		Uid: 0,
		Gid: 0,
	}

	cmd.SysProcAttr.UidMappings = []syscall.SysProcIDMap{{ContainerID: 0, HostID: 1001, Size: 1}}
	cmd.SysProcAttr.GidMappings = []syscall.SysProcIDMap{{ContainerID: 0, HostID: 1001, Size: 1}}
}
Пример #21
0
func (t *Terminal) Start(c *exec.Cmd) (err error) {
	if t == nil {
		return errors.New("terminal not assigned.")
	}
	//defer t.Tty.Close()
	c.Stdout = t.Tty
	c.Stdin = t.Tty
	c.Stderr = t.Tty
	c.SysProcAttr = &syscall.SysProcAttr{Setctty: true, Setsid: true}
	if err = c.Start(); err != nil {
		fmt.Println("error is ", err)
		t.Pty.Close()
		return
	}
	return
}
Пример #22
0
// NewTty creates a pseudo-TTY for a command and modifies it appropriately so
// the command thinks it's a real terminal
func NewTty(cmd *exec.Cmd) *Tty {
	tty := &Tty{}
	tty.cmd = cmd
	// Assign pty/tty so git thinks it's a real terminal
	tty.outpty, tty.outtty, _ = pty.Open()
	cmd.Stdin = tty.outtty
	cmd.Stdout = tty.outtty
	tty.errpty, tty.errtty, _ = pty.Open()
	cmd.Stderr = tty.errtty
	if cmd.SysProcAttr == nil {
		cmd.SysProcAttr = &syscall.SysProcAttr{}
	}
	cmd.SysProcAttr.Setctty = true
	cmd.SysProcAttr.Setsid = true

	return tty
}
Пример #23
0
func (exer *Executor) Prepare(cmd *exec.Cmd) (err error) {
	exer.path = cmd.Path
	if cmd.SysProcAttr == nil {
		cmd.SysProcAttr = &syscall.SysProcAttr{}
	}
	if exer.chroot != "" {
		if cmd.Dir == "" {
			cmd.Dir = "/"
		}
		cmd.SysProcAttr.Chroot = exer.chroot
		if err = exer.MkJail(); err != nil {
			return
		}
	}
	cmd.SysProcAttr.Credential = &syscall.Credential{Uid: uint32(exer.id), Gid: uint32(exer.id)}
	return
}
Пример #24
0
func (s *server) Print(stream pb.ServerPrintService_PrintServer) error {
	var cmd *exec.Cmd = nil
	var out bytes.Buffer
	dataReader := newDataReader()
	for {
		content, err := stream.Recv()
		if err == io.EOF {
			close(dataReader.ch)
			stream.SendAndClose(&pb.PrintResponse{0})
			fmt.Printf("%q\n", out.String())
		}
		if err != nil {
			return err
		}

		if x, ok := content.GetPrintContentType().(*pb.PrintContent_PrintInfo); ok {
			dir, err := filepath.Abs(filepath.Dir(os.Args[0]))
			if err != nil {
				log.Fatal(err)
			}
			cmd = exec.Command(path.Join(dir, "gswin32c.exe"),
				"-dNOPAUSE", "-dBATCH", "-sDEVICE=mswinpr2",
				fmt.Sprintf("-dNumCopies=%d", x.PrintInfo.Copies),
				fmt.Sprintf("-dDEVICEWIDTHPOINTS=%d", x.PrintInfo.PageSizeWidth),
				fmt.Sprintf("-dDEVICEHEIGHTPOINTS=%d", x.PrintInfo.PageSizeHeight),
				"-sOutputFile=%printer%"+x.PrintInfo.PrinterName,
				"-")
			fmt.Printf("cmd.Args %v\n", cmd.Args)
			cmd.Stdin = dataReader
			cmd.Stdout = &out
			cmd.SysProcAttr = &syscall.SysProcAttr{HideWindow: true}
			go func(cmd *exec.Cmd) {
				err := cmd.Run()
				if err != nil {
					log.Fatal(err)
				}
			}(cmd)
		}
		if x, ok := content.GetPrintContentType().(*pb.PrintContent_Content); ok {
			if cmd != nil && cmd.Stdin != nil {
				dataReader.ch <- x.Content
			}
		}
	}
	return nil
}
Пример #25
0
// Start assigns a pseudo-terminal tty os.File to c.Stdin, c.Stdout,
// and c.Stderr, calls c.Start, and returns the File of the tty's
// corresponding pty.
func Start(c *exec.Cmd) (pty *os.File, err error) {
	pty, tty, err := Open()
	if err != nil {
		return nil, err
	}
	defer tty.Close()
	c.Stdout = tty
	c.Stdin = tty
	c.Stderr = tty
	c.SysProcAttr = &syscall.SysProcAttr{Setctty: true, Setsid: true}
	err = c.Start()
	if err != nil {
		pty.Close()
		return nil, err
	}
	return pty, err
}
Пример #26
0
func (self *TestEnv) startMemcached() {
	var cmd *exec.Cmd
	var server *tcptest.TCPTest
	var err error
	for i := 0; i < 5; i++ {
		server, err = tcptest.Start(func(port int) {
			out, err := os.OpenFile("memcached.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)

			cmd = exec.Command("memcached", "-vv", "-p", fmt.Sprintf("%d", port))
			cmd.SysProcAttr = &syscall.SysProcAttr{
				Setpgid: true,
			}
			stderrpipe, err := cmd.StderrPipe()
			if err != nil {
				self.FailNow("Failed to open pipe to stderr")
			}
			stdoutpipe, err := cmd.StdoutPipe()
			if err != nil {
				self.FailNow("Failed to open pipe to stdout")
			}

			go io.Copy(out, stderrpipe)
			go io.Copy(out, stdoutpipe)
			cmd.Run()
		}, time.Minute)
		if err == nil {
			break
		}
		self.Logf("Failed to start memcached: %s", err)
	}

	if server == nil {
		self.FailNow("Failed to start memcached")
	}

	self.MemdPort = server.Port()

	self.AddGuard(func() {
		if cmd != nil && cmd.Process != nil {
			self.Logf("Killing memcached")
			cmd.Process.Signal(syscall.SIGTERM)
		}
		server.Wait()
	})
}
Пример #27
0
func processLife(cmd *exec.Cmd, errc chan error) {
	// FIXME(nightlyone) This works neither in Windows nor Plan9.
	// Fix it, once we have users of this platform.
	// NOTE: Cannot setsid and and setpgid in one child. Would need double fork or exec,
	// which makes things very hard.
	cmd.SysProcAttr = &syscall.SysProcAttr{
		Setpgid: true,
	}

	if err := cmd.Start(); err != nil {
		errc <- &NotAvailableError{
			args: cmd.Args,
			err:  err,
		}
	} else {
		errc <- cmd.Wait()
	}
}
Пример #28
0
func (self *TestEnv) startQueue() {
	var cmd *exec.Cmd
	tt, err := tcptest.Start(func(port int) {
		path, err := exec.LookPath("redis-server")
		if err != nil {
			self.Test.Errorf("Failed to find redis-server: %s", err)
			self.Test.FailNow()
		}

		out, err := os.OpenFile("redis.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0644)
		cmd = exec.Command(path, "--port", fmt.Sprintf("%d", port), "--loglevel", "verbose")
		cmd.SysProcAttr = &syscall.SysProcAttr{
			Setpgid: true,
		}
		stderrpipe, err := cmd.StderrPipe()
		if err != nil {
			self.FailNow("Failed to open pipe to stderr")
		}
		stdoutpipe, err := cmd.StdoutPipe()
		if err != nil {
			self.FailNow("Failed to open pipe to stdout")
		}

		go io.Copy(out, stderrpipe)
		go io.Copy(out, stdoutpipe)
		err = cmd.Run()
		if err != nil {
			self.Test.Logf("Command %v exited: %s", cmd.Args, err)
		}
	}, 5*time.Second)

	if err != nil {
		self.Test.Fatalf("Failed to start redis-server: %s", err)
	}

	addr := fmt.Sprintf("127.0.0.1:%d", tt.Port())
	self.QueueConfig = &config.QueueConfig{
		Addr: addr,
	}

	self.AddGuard(func() {
		cmd.Process.Signal(syscall.SIGTERM)
	})
}
Пример #29
0
func finishRunning(cmd *exec.Cmd) error {
	stepName := strings.Join(cmd.Args, " ")
	if *verbose {
		cmd.Stdout = os.Stdout
		cmd.Stderr = os.Stderr
	}
	log.Printf("Running: %v", stepName)
	defer func(start time.Time) {
		log.Printf("Step '%s' finished in %s", stepName, time.Since(start))
	}(time.Now())

	cmd.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}
	if err := cmd.Start(); err != nil {
		return fmt.Errorf("error starting %v: %v", stepName, err)
	}

	finished := make(chan error)

	go func() {
		finished <- cmd.Wait()
	}()

	for {
		select {
		case <-terminate.C:
			terminate.Reset(time.Duration(0)) // Kill subsequent processes immediately.
			syscall.Kill(-cmd.Process.Pid, syscall.SIGKILL)
			cmd.Process.Kill()
			return fmt.Errorf("Terminate testing after 15m after %s timeout during %s", *timeout, stepName)
		case <-interrupt.C:
			log.Printf("Interrupt testing after %s timeout. Will terminate in another 15m", *timeout)
			terminate.Reset(15 * time.Minute)
			if err := syscall.Kill(-cmd.Process.Pid, syscall.SIGINT); err != nil {
				log.Printf("Failed to interrupt %v. Will terminate immediately: %v", stepName, err)
				syscall.Kill(-cmd.Process.Pid, syscall.SIGTERM)
				cmd.Process.Kill()
			}
		case err := <-finished:
			return err
		}
	}
}
Пример #30
0
Файл: pty.go Проект: yubo/gotty
// Start assigns a pseudo-terminal tty os.File to c.Stdin, c.Stdout,
// and c.Stderr, calls c.Start, and returns the File of the tty's
// corresponding pty.
func ptyStart(c *exec.Cmd) (p *os.File, err error) {
	p, tty, err := pty.Open()
	if err != nil {
		return nil, err
	}
	defer tty.Close()
	c.Stdout = tty
	c.Stdin = tty
	c.Stderr = tty
	c.SysProcAttr = &syscall.SysProcAttr{Setctty: true, Setsid: true}

	if daemon.user != nil {
		uid, e1 := strconv.Atoi(daemon.user.Uid)
		gid, e2 := strconv.Atoi(daemon.user.Gid)
		if e1 == nil && e2 == nil {
			c.SysProcAttr.Credential = &syscall.Credential{
				Uid:    uint32(uid),
				Gid:    uint32(gid),
				Groups: daemon.ugroups,
			}
			c.Dir = daemon.user.HomeDir

			c.Env = make([]string, len(GlobalOpt.Env)+1)
			i := 0
			for k, v := range GlobalOpt.Env {
				c.Env[i] = fmt.Sprintf("%s=%s", k, v)
				i += 1
			}
			c.Env[i] = fmt.Sprintf("HOME=%s", c.Dir)

			glog.V(3).Infof("uid:%d gid:%d groups:%v env:\n%s\n",
				uid, gid, daemon.ugroups, strings.Join(c.Env, "\n"))
		}
	}

	err = c.Start()
	if err != nil {
		p.Close()
		return nil, err
	}
	return p, err
}