...
1
2
3
4
5
6
7
8
9
10
11
12
13
14 package activatecmd
15
16 import (
17 "fmt"
18 "net"
19 "os"
20 "os/exec"
21 "strings"
22 "syscall"
23 )
24
25 var prefixes = []string{"NOTIFY_", "LISTEN_", "EINHORN_"}
26
27
28
29 func ClearEnv(env []string) (ret []string) {
30 for _, e := range env {
31 ok := true
32 for _, prefix := range prefixes {
33 if strings.HasPrefix(e, prefix) {
34 ok = false
35 break
36 }
37 }
38 if ok {
39 ret = append(ret, e)
40 }
41 }
42 return
43 }
44
45 type ListenerSet struct {
46 files []*os.File
47 }
48
49
50
51
52
53 func NewListenerSet(listeners []net.Listener) (*ListenerSet, error) {
54 s := new(ListenerSet)
55 for i, lis := range listeners {
56 lf, ok := lis.(filer)
57 if !ok {
58 return nil, fmt.Errorf("unable to get file from listener %d (type %T)", i, lis)
59 }
60 f, err := lf.File()
61 if err != nil {
62 return nil, fmt.Errorf("unable to get file from listener %d: %s", i, err)
63 }
64
65
66
67 if err := syscall.SetNonblock(int(f.Fd()), true); err != nil {
68 return nil, fmt.Errorf("unable to get file from listener %d: %s", i, err)
69 }
70 s.files = append(s.files, f)
71 }
72 return s, nil
73 }
74
75
76 func (s *ListenerSet) Close() error {
77 for _, f := range s.files {
78 f.Close()
79 }
80 return nil
81 }
82
83
84 func (s *ListenerSet) Attach(cmd *exec.Cmd) error {
85 if cmd.Env == nil {
86 cmd.Env = ClearEnv(os.Environ())
87 }
88 for i, f := range s.files {
89 cmd.Env = append(cmd.Env, fmt.Sprintf("EINHORN_FD_%d=%d", i, 3+len(cmd.ExtraFiles)))
90 cmd.ExtraFiles = append(cmd.ExtraFiles, f)
91 }
92 cmd.Env = append(cmd.Env, fmt.Sprintf("EINHORN_FD_COUNT=%d", len(s.files)))
93 cmd.Env = append(cmd.Env, fmt.Sprintf("EINHORN_MASTER_PID=%d", os.Getpid()))
94 return nil
95 }
96
97 type filer interface {
98 File() (*os.File, error)
99 }
100
View as plain text