Exemplo n.º 1
0
func (t *Task) Execute(arg0 string, argv []string, attr *os.ProcAttr) (*Status, error) {

	t.Lock()

	if jobControlEnabled() {
		attr.Sys = SysProcAttr(t.Group)
	}

	proc, err := os.StartProcess(arg0, argv, attr)
	if err != nil {
		t.Unlock()
		return nil, err
	}

	if jobControlEnabled() {
		if t.Group == 0 {
			t.Group = proc.Pid
		}
	}

	t.pid = proc.Pid

	t.Unlock()

	status := JoinProcess(proc)

	if jobControlEnabled() {
		if t.Group == t.pid {
			t.Group = 0
		}
	}
	t.pid = 0

	return NewStatus(int64(status)), err
}
Exemplo n.º 2
0
func Restart() {
	var attr os.ProcAttr
	attr.Files = []*os.File{os.Stdin, os.Stdout, os.Stderr}
	attr.Sys = &syscall.SysProcAttr{}
	_, err := os.StartProcess(os.Args[0], os.Args, &attr)
	if err != nil {
		_err(err)
	}
	Stop()
}
Exemplo n.º 3
0
func main() {
	//var php_process os.Process

	path := GetCurrPath()
	php_exe := path + "php-cgi.exe"
	php_ini := path + "php.ini"

	avg := []string{php_exe, "-b", "127.0.0.1:9090", "-c", php_ini}
	if _, err := os.Stat(php_exe); err != nil {
		return
	}

	for {
		/*
			cmd := exec.Command(php_exe, avg...)
			cmd.Stdin = os.Stdin //给新进程设置文件描述符,可以重定向到文件中
			cmd.Stdout = os.Stdout
			cmd.Stderr = os.Stderr

			//隐藏
			cmd.SysProcAttr = &syscall.SysProcAttr{HideWindow: true}

			err := cmd.Start()
		*/

		procAttr := new(os.ProcAttr)
		procAttr.Files = []*os.File{os.Stdin, os.Stdout, os.Stderr}
		procAttr.Sys = &syscall.SysProcAttr{HideWindow: true}

		php_process, err := os.StartProcess(php_exe, avg, procAttr)

		if err != nil {
			fmt.Println(err)
			time.Sleep(time.Second * 10)
			continue
		}
		php_process.Wait()
		//		err = cmd.Wait()
		//fmt.Println("out")
		time.Sleep(time.Second * 1)
	}
}
Exemplo n.º 4
0
/*
MakeDaemon turns the process into a daemon. But given the lack of Go's
support for fork(), MakeDaemon() is forced to run the process all over again,
from the start. Hence, this should probably be your first call after main
begins, unless you understand the effects of calling from somewhere else.
Keep in mind that the PID changes after this function is called, given
that it only returns in the child; the parent will exit without returning.

Options are provided as a DaemonAttr structure. In particular, setting the
CaptureOutput member to true will make the function return two io.Reader
streams to read the process' standard output and standard error, respectively.
That's useful if you want to capture things you'd normally lose given the
lack of console output for a daemon. Some libraries can write error conditions
to standard error or make use of Go's log package, that defaults to standard
error too. Having these streams allows you to capture them as required. (Note
that this function takes no action whatsoever on any of the streams.)

NOTE: If you use them, make sure NOT to take one of these readers and write
the data back again to standard output/error, or you'll end up with a loop.
Also, note that data will be flushed on a line-by-line basis; i.e., partial
lines will be buffered until an end-of-line is seen.

By using the Files member of DaemonAttr you can inherit open files that will
still be open once the program is running as a daemon. This may be convenient in
general, but it's primarily intended to avoid race conditions while forking, in
case a lock (flock) was held on that file. Repeatedly releasing and re-locking
while forking is subject to race conditions, cause a different process could
lock the file in between. But locks held on files declared at DaemonAttr.Files
are guaranteed NOT to be released during the whole process, and still be held by
the daemon. To use this feature you should open the file(s), lock if required
and then call MakeDaemon using pointers to that *os.File objects; i.e., you'd be
passing **os.File objects to MakeDaemon(). However, opening the files (and
locking if required) should only be attempted at the parent. (Recall that
MakeDaemon() will run the code coming "before" it three times; see the
explanation above.) You can filter that by calling Stage() and looking for a
godaemon.StageParent result. The last call to MakeDaemon() at the daemon itself
will actually *load* the *os.File objects for you; that's why you need to
provide a pointer to them. So here's how you'd use it:

	var (
		f   *os.File
		err error
	)

	if godaemon.Stage() == godaemon.StageParent {
		f, err = os.OpenFile(name, opts, perm)
		if err != nil {
			os.Exit(1)
		}
		err = syscall.Flock(int(f.Fd()), syscall.LOCK_EX)
		if err != nil {
			os.Exit(1)
		}
	}

	_, _, err = godaemon.MakeDaemon(&godaemon.DaemonAttr{
		Files: []**os.File{&f},
	})

	// Only the daemon will reach this point, where f will be a valid descriptor
	// pointing to your file "name", still holding the lock (which will have
	// never been released during successive forks). You can operate on f as you
	// normally would, like:
	f.Close()

NOTE: Do not abuse this feature. Even though you could, it's obviously not a
good idea to use this mechanism to keep a terminal device open, for instance.
Otherwise, what you get is not strictly a daemon.


Daemonizing is a 3-stage process. In stage 0, the program increments the
magical environment variable and starts a copy of itself that's a session
leader, with its STDIN, STDOUT, and STDERR disconnected from any tty. It
then exits.

In stage 1, the (new copy of) the program starts another copy that's not
a session leader, and then exits.

In stage 2, the (new copy of) the program chdir's to /, then sets the umask
and reestablishes the original value for the environment variable.
*/
func MakeDaemon(attrs *DaemonAttr) (io.Reader, io.Reader, error) {
	stage, advanceStage, resetEnv := getStage()

	// This is a handy wrapper to do the proper thing in case of fatal
	// conditions. For the first stage you may want to recover, so it will
	// return the error. Otherwise it will exit the process, cause you'll be
	// half-way with some descriptors already changed. There's no chance to
	// write to stdout or stderr in the later case; they'll be already closed.
	fatal := func(err error) (io.Reader, io.Reader, error) {
		if stage > 0 {
			os.Exit(1)
		}
		resetEnv()
		return nil, nil, err
	}

	fileCount := 3 + len(attrs.Files)
	files := make([]*os.File, fileCount, fileCount+2)

	if stage == 0 {
		// Descriptors 0, 1 and 2 are fixed in the "os" package. If we close
		// them, the process may choose to open something else there, with bad
		// consequences if some write to os.Stdout or os.Stderr follows (even
		// from Go's library itself, through the default log package). We thus
		// reserve these descriptors to avoid that.
		nullDev, err := os.OpenFile("/dev/null", 0, 0)
		if err != nil {
			return fatal(err)
		}
		files[0], files[1], files[2] = nullDev, nullDev, nullDev

		fd := 3
		for _, fPtr := range attrs.Files {
			files[fd] = *fPtr
			saveFileName(fd, (*fPtr).Name())
			fd++
		}
	} else {
		files[0], files[1], files[2] = os.Stdin, os.Stdout, os.Stderr

		fd := 3
		for _, fPtr := range attrs.Files {
			*fPtr = os.NewFile(uintptr(fd), getFileName(fd))
			syscall.CloseOnExec(fd)
			files[fd] = *fPtr
			fd++
		}
	}

	if stage < 2 {
		// getExecutablePath() is OS-specific.
		procName, err := GetExecutablePath()
		if err != nil {
			return fatal(fmt.Errorf("can't determine full path to executable: %s", err))
		}

		// If getExecutablePath() returns "" but no error, determinating the
		// executable path is not implemented on the host OS, so daemonization
		// is not supported.
		if len(procName) == 0 {
			return fatal(fmt.Errorf("can't determine full path to executable"))
		}

		if stage == 1 && attrs.CaptureOutput {
			files = files[:fileCount+2]

			// stdout: write at fd:1, read at fd:fileCount
			if files[fileCount], files[1], err = os.Pipe(); err != nil {
				return fatal(err)
			}
			// stderr: write at fd:2, read at fd:fileCount+1
			if files[fileCount+1], files[2], err = os.Pipe(); err != nil {
				return fatal(err)
			}
		}

		if err := advanceStage(); err != nil {
			return fatal(err)
		}
		dir, _ := os.Getwd()
		osAttrs := os.ProcAttr{Dir: dir, Env: os.Environ(), Files: files}

		if stage == 0 {
			sysattrs := syscall.SysProcAttr{Setsid: true}
			osAttrs.Sys = &sysattrs
		}

		progName := attrs.ProgramName
		if len(progName) == 0 {
			progName = os.Args[0]
		}
		args := append([]string{progName}, os.Args[1:]...)
		proc, err := os.StartProcess(procName, args, &osAttrs)
		if err != nil {
			return fatal(fmt.Errorf("can't create process %s: %s", procName, err))
		}
		proc.Release()
		os.Exit(0)
	}

	os.Chdir("/")
	syscall.Umask(0)
	resetEnv()

	for fd := 3; fd < fileCount; fd++ {
		resetFileName(fd)
	}
	currStage = DaemonStage(stage)

	var stdout, stderr *os.File
	if attrs.CaptureOutput {
		stdout = os.NewFile(uintptr(fileCount), "stdout")
		stderr = os.NewFile(uintptr(fileCount+1), "stderr")
	}
	return stdout, stderr, nil
}