1 // exec_helpers.go -- helper functions used with fork, exec, wait.
3 // Copyright 2010 The Go Authors. All rights reserved.
4 // Use of this source code is governed by a BSD-style
5 // license that can be found in the LICENSE file.
11 // Lock synchronizing creation of new file descriptors with fork.
13 // We want the child in a fork/exec sequence to inherit only the
14 // file descriptors we intend. To do that, we mark all file
15 // descriptors close-on-exec and then, in the child, explicitly
16 // unmark the ones we want the exec'ed program to keep.
17 // Unix doesn't make this easy: there is, in general, no way to
18 // allocate a new file descriptor close-on-exec. Instead you
19 // have to allocate the descriptor and then mark it close-on-exec.
20 // If a fork happens between those two events, the child's exec
21 // will inherit an unwanted file descriptor.
23 // This lock solves that race: the create new fd/mark close-on-exec
24 // operation is done holding ForkLock for reading, and the fork itself
25 // is done holding ForkLock for writing. At least, that's the idea.
26 // There are some complications.
28 // Some system calls that create new file descriptors can block
29 // for arbitrarily long times: open on a hung NFS server or named
30 // pipe, accept on a socket, and so on. We can't reasonably grab
31 // the lock across those operations.
33 // It is worse to inherit some file descriptors than others.
34 // If a non-malicious child accidentally inherits an open ordinary file,
35 // that's not a big deal. On the other hand, if a long-lived child
36 // accidentally inherits the write end of a pipe, then the reader
37 // of that pipe will not see EOF until that child exits, potentially
38 // causing the parent program to hang. This is a common problem
39 // in threaded C programs that use popen.
41 // Luckily, the file descriptors that are most important not to
42 // inherit are not the ones that can take an arbitrarily long time
43 // to create: pipe returns instantly, and the net package uses
44 // non-blocking I/O to accept on a listening socket.
45 // The rules for which file descriptor-creating operations use the
46 // ForkLock are as follows:
48 // 1) Pipe. Does not block. Use the ForkLock.
49 // 2) Socket. Does not block. Use the ForkLock.
50 // 3) Accept. If using non-blocking mode, use the ForkLock.
51 // Otherwise, live with the race.
52 // 4) Open. Can block. Use O_CLOEXEC if available (Linux).
53 // Otherwise, live with the race.
54 // 5) Dup. Does not block. Use the ForkLock.
55 // On Linux, could use fcntl F_DUPFD_CLOEXEC
56 // instead of the ForkLock, but only for dup(fd, -1).
60 var ForkLock sync
.RWMutex
62 // Convert array of string to array
63 // of NUL-terminated byte pointer.
64 func StringArrayPtr(ss
[]string) []*byte {
65 bb
:= make([]*byte, len(ss
)+1);
66 for i
:= 0; i
< len(ss
); i
++ {
67 bb
[i
] = StringBytePtr(ss
[i
]);
73 func CloseOnExec(fd
int) {
74 fcntl(fd
, F_SETFD
, FD_CLOEXEC
);
77 func SetNonblock(fd
int, nonblocking
bool) (errno
int) {
78 flag
, err
:= fcntl(fd
, F_GETFL
, 0);
87 flag
, err
= fcntl(fd
, F_SETFL
, flag
);
91 // Wait status is 7 bits at bottom, either 0 (exited),
92 // 0x7F (stopped), or a signal number that caused an exit.
93 // The 0x80 bit is whether there was a core dump.
94 // An extra number (exit code, signal causing a stop)
95 // is in the high bits. At least that's the idea.
96 // There are various irregularities. For example, the
97 // "continued" status is 0xFFFF, distinguishing itself
98 // from stopped via the core dump bit.
108 func (w WaitStatus
) Exited() bool {
109 return w
&mask
== exited
;
112 func (w WaitStatus
) Signaled() bool {
113 return w
&mask
!= stopped
&& w
&mask
!= exited
;
116 func (w WaitStatus
) Stopped() bool {
117 return w
&0xFF == stopped
;
120 func (w WaitStatus
) Continued() bool {
124 func (w WaitStatus
) CoreDump() bool {
125 return w
.Signaled() && w
&core
!= 0;
128 func (w WaitStatus
) ExitStatus() int {
132 return int(w
>> shift
) & 0xFF;
135 func (w WaitStatus
) Signal() int {
139 return int(w
& mask
);
142 func (w WaitStatus
) StopSignal() int {
146 return int(w
>> shift
) & 0xFF;
149 func (w WaitStatus
) TrapCause() int {
150 if w
.StopSignal() != SIGTRAP
{
153 return int(w
>> shift
) >> 8;