Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Start a process in Go and detach from it

Tags:

linux

process

go

I need to start a new process in Go with the following requirements:

  • The starting process should run even after the Go process is terminated
  • I need to be able to set the Unix user/group that's running it
  • I need to be able to set the environment variables inherited
  • I need control over std in/out/err

Here is an attempt:

var attr = os.ProcAttr {
Dir: "/bin",
Env: os.Environ(),
Files: []*os.File{
    os.Stdin,
    "stdout.log",
    "stderr.log",
  },
}
process, err := os.StartProcess("sleep", []string{"1"}, &attr)

This works fine but has the following shortcomings from the requirements:

  • No way to set Unix user/group
  • The started process ends when the Go process (parent) stops

This needs to run on Linux only if that simplifies things.

like image 832
Khash Avatar asked Apr 12 '14 14:04

Khash


People also ask

How to start process detached?

We can use the & operator, and the nohup, disown, setsid, and screen commands to start a process detached from the terminal. However, to detach a process that has already started, we need to use the bg command after pausing the process using Ctrl+Z.

How to detach program from terminal?

Use Ctrl + Z to suspend a program then bg to run the process in background and disown to detach it from your current terminal session.

How do I run a shell script detached?

Here is how you can detach a process from bash shell. If a given process is running in the foreground, press Ctrl+z to interrupt it. Then run it in the background. Finally, type disown along with job sequence number of the backgrounded job.


1 Answers

  1. You can use process.Release to detach the child process from the parent one and make it survive after parent death
  2. Look at the definition of *os.ProcAttr.Sys.Credentials attribute : it looks like using the attribute you can set process user and group ID.

Here is a working version of your example (I did not check if process ID's where actually the one set )

package main

import "fmt"
import "os"
import "syscall"

const (
    UID = 501
    GUID = 100
    )


func main() {
    // The Credential fields are used to set UID, GID and attitional GIDS of the process
    // You need to run the program as  root to do this
        var cred =  &syscall.Credential{ UID, GUID, []uint32{} }
    // the Noctty flag is used to detach the process from parent tty
    var sysproc = &syscall.SysProcAttr{  Credential:cred, Noctty:true }
    var attr = os.ProcAttr{
        Dir: ".",
        Env: os.Environ(),
        Files: []*os.File{
            os.Stdin,
            nil,
            nil,
        },
            Sys:sysproc,

    }
    process, err := os.StartProcess("/bin/sleep", []string{"/bin/sleep", "100"}, &attr)
    if err == nil {

        // It is not clear from docs, but Realease actually detaches the process
        err = process.Release();
        if err != nil {
            fmt.Println(err.Error())
        }

    } else {
        fmt.Println(err.Error())
    }
}
like image 102
bieffe62 Avatar answered Sep 22 '22 07:09

bieffe62