Program with self-detach

897 views
Skip to first unread message

Paul Borman

unread,
Oct 19, 2011, 7:43:15 PM10/19/11
to golang-nuts
With the caveat that I don't need to worry about Windows, is there a better way than this to have a program detach itself?

Thanks,

    -Paul

import (
    "syscall"
    "os"
)

// Detach detaches the current program by forking and exiting the parent.
// It returns an error only if it was unable to fork.
func Detach() os.Error {
    r1, r2, err1 := syscall.RawSyscall(syscall.SYS_FORK, 0, 0, 0)
    if err1 != 0 {
        return os.NewSyscallError("fork", int(err1))
    }

    // On Darwin:
    //  r1 = child pid in both parent and child.
    //  r2 = 0 in parent, 1 in child.
    // Normal Unix:
    //  r1 = 0 in child.
    if (syscall.OS == "darwin" && r2 == 1) || r1 == 0 {
        return nil
    }
    syscall.RawSyscall(syscall.SYS_EXIT, 0, 0, 0)
    // This really should not be possible...
    panic("Exit failed")
}

Ian Lance Taylor

unread,
Oct 19, 2011, 7:59:33 PM10/19/11
to Paul Borman, golang-nuts
Paul Borman <bor...@google.com> writes:

> With the caveat that I don't need to worry about Windows, is there a better
> way than this to have a program detach itself?

You usually want to have the child call setsid. Otherwise you can still
get signals from the controlling terminal of the parent.

Ian

Paul Borman

unread,
Oct 19, 2011, 8:18:26 PM10/19/11
to Chris Wedgwood, golang-nuts
One bug: r1 != 0 (not r1 == 0)  I had tested it on Darwin and not Linux.

You are absolutely correct that if you worry about signals setsid should be called.  (I even pushed for setsid to get added to the library :-)

No reason to keep forking, a single setsid is all you need before you return.  I didn't add it in because you can do that after Detach returns (and in my case I actually don't have to worry about the signals).

The worst case with goroutines is if you call this while you have routines in the background that are reading/writing IO.  Actually, vfork would probably be better to call than fork.

    -Paul

On Wed, Oct 19, 2011 at 5:00 PM, Chris Wedgwood <c...@f00f.org> wrote:
On Wed, Oct 19, 2011 at 04:43:15PM -0700, Paul Borman wrote:

> With the caveat that I don't need to worry about Windows, is there a
> better way than this to have a program detach itself?

You need to fork, setpgid nad fork again... and only all that if there
is only one goroutine, with appropriate locking.

I have a rough idea on how this *might* work for Mac OS/Linux but it's
not properly implemented yet.

Maybe this weekend.

Chris Wedgwood

unread,
Oct 19, 2011, 8:00:35 PM10/19/11
to Paul Borman, golang-nuts
On Wed, Oct 19, 2011 at 04:43:15PM -0700, Paul Borman wrote:

> With the caveat that I don't need to worry about Windows, is there a
> better way than this to have a program detach itself?

You need to fork, setpgid nad fork again... and only all that if there

Chris Wedgwood

unread,
Oct 19, 2011, 8:37:24 PM10/19/11
to Paul Borman, golang-nuts
On Wed, Oct 19, 2011 at 05:18:26PM -0700, Paul Borman wrote:

> No reason to keep forking, a single setsid is all you need before you
> return. I didn't add it in because you can do that after Detach returns
> (and in my case I actually don't have to worry about the signals).

you want to reparent to init not the controlling process

Paul Borman

unread,
Oct 19, 2011, 8:51:21 PM10/19/11
to Chris Wedgwood, golang-nuts
It will reparent to init.  When a program exits all of its children reparent to init, not to the grandparent.  Back 25 years ago I used to have to do the double fork, but that was because of how process groups worked, controlling terminals, and such.  Setsid is your friend.  You do probably want to  close fildes 0 before detaching.

So, this should teach me to program at 30,000 feet.  I was right it is r1 == 0.  I have MacOS in my lap but Linux is down on the ground.  Anyhow, with Linux exit isn't exit, you need to use exit_group instead.  Putting the setsid in there is probably a decent idea.

Mikio Hara

unread,
Oct 19, 2011, 9:02:32 PM10/19/11
to Paul Borman, Chris Wedgwood, golang-nuts
On Thu, Oct 20, 2011 at 9:51 AM, Paul Borman <bor...@google.com> wrote:

> So, this should teach me to program at 30,000 feet.

go-wiki?

Russ Cox

unread,
Oct 20, 2011, 9:28:01 PM10/20/11
to Paul Borman, golang-nuts
There is no way to detach safely.

If any threads have started - and that's always a possibility -
your program will get very confused and basically stop working
if you make the parent exit and have the child continue.

Russ

Paul Borman

unread,
Oct 21, 2011, 2:36:28 PM10/21/11
to r...@golang.org, golang-nuts
Sigh, yes, fork() lies, it does not duplicate the entire process.  You only have 1 thread in the child.

The question is if you can know if Go has started any extra threads.  Thus far Go should not start any new threads during init (though it may queue up for some to start once init has returned?)  If runtime·sched.mcount is 1 then it should be safe to detach, right?  Are there plans to spawn additional threads during init processing?  If the number of goroutines is 1 then it should be safe to do a detach as long as you reduce down to one thread first.

Russ Cox

unread,
Oct 24, 2011, 1:26:52 PM10/24/11
to Paul Borman, golang-nuts
On Fri, Oct 21, 2011 at 14:36, Paul Borman <bor...@google.com> wrote:
> The question is if you can know if Go has started any extra threads.  Thus
> far Go should not start any new threads during init (though it may queue up
> for some to start once init has returned?)  If runtime·sched.mcount is 1
> then it should be safe to detach, right?  Are there plans to spawn
> additional threads during init processing?

Yes. In fact that's now enabled at tip.
We'll no doubt do something for daemonize at some point,
but it is not trivial.

Russ

Message has been deleted

Uriel

unread,
Jun 2, 2012, 3:20:50 AM6/2/12
to Peter Thrun, golan...@googlegroups.com
On Fri, Jun 1, 2012 at 11:12 PM, Peter Thrun <peter...@ymail.com> wrote:
>> We'll no doubt do something for daemonize at some point, but it is not
>> trivial.
>
> Has something been done to support daemonize?

To keep track of progress with this is best to check this issue:
http://code.google.com/p/go/issues/detail?id=227

The consensus seems to be that the best is to use some like
daemontools's supervise or other similar tools.

Saul Hazledine

unread,
Jun 2, 2012, 4:16:35 AM6/2/12
to golan...@googlegroups.com
Hello,

On Thursday, 20 October 2011 01:43:15 UTC+2, Paul Borman wrote:
<cool forking code omitted >

Could something like this be used to do simple privilege separation? At the moment I run Nginx on port 80 just to proxy to a go webserver running as somebody less trusted. It would be cool to fork and drop root after opening the port.

I'm also open to other better suggestions as I suspect other people have effortlessly got round this.

Saul Hazledine

Vasiliy Tolstov

unread,
Jun 2, 2012, 5:45:16 AM6/2/12
to Saul Hazledine, golan...@googlegroups.com
2012/6/2 Saul Hazledine <sha...@gmail.com>:
Now i'm use go web server on port 8080 binded to 127.0.0.1 and
iptables rule to redirect al traffic to it.


--
Vasiliy Tolstov,
Clodo.ru
e-mail: v.to...@selfip.ru
jabber: va...@selfip.ru

Christian Himpel

unread,
Jun 2, 2012, 6:57:42 AM6/2/12
to Vasiliy Tolstov, Saul Hazledine, golan...@googlegroups.com
>> Could something like this be used to do simple privilege separation? At the
>> moment I run Nginx on port 80 just to proxy to a go webserver running as
>> somebody less trusted. It would be cool to fork and drop root after opening
>> the port.
>
> Now i'm use go web server on port 8080 binded to 127.0.0.1 and
> iptables rule to redirect al traffic to it.

on linux you can also use file capabilities to allow bind on privileged ports:
# setcap CAP_NET_BIND_SERVICE=ep /path/to/binary
Reply all
Reply to author
Forward
0 new messages