1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
|
// +build !windows
package bind
import (
"fmt"
"log"
"net"
"os"
"strconv"
"syscall"
)
const tooBigErr = "bind: einhorn@%d not found (einhorn only passed %d fds)"
const bindErr = "bind: could not bind einhorn@%d: not running under einhorn"
const einhornErr = "bind: einhorn environment initialization error"
const ackErr = "bind: error ACKing to einhorn: %v"
var einhornNumFds int
func envInt(val string) (int, error) {
return strconv.Atoi(os.Getenv(val))
}
// Unfortunately this can't be a normal init function, because their execution
// order is undefined, and we need to run before the init() in bind.go.
func einhornInit() {
mpid, err := envInt("EINHORN_MASTER_PID")
if err != nil || mpid != os.Getppid() {
return
}
einhornNumFds, err = envInt("EINHORN_FD_COUNT")
if err != nil {
einhornNumFds = 0
return
}
// Prevent einhorn's fds from leaking to our children
for i := 0; i < einhornNumFds; i++ {
syscall.CloseOnExec(einhornFdMap(i))
}
}
func usingEinhorn() bool {
return einhornNumFds > 0
}
func einhornFdMap(n int) int {
name := fmt.Sprintf("EINHORN_FD_%d", n)
fno, err := envInt(name)
if err != nil {
log.Fatal(einhornErr)
}
return fno
}
func einhornBind(n int) (net.Listener, error) {
if !usingEinhorn() {
return nil, fmt.Errorf(bindErr, n)
}
if n >= einhornNumFds || n < 0 {
return nil, fmt.Errorf(tooBigErr, n, einhornNumFds)
}
fno := einhornFdMap(n)
f := os.NewFile(uintptr(fno), fmt.Sprintf("einhorn@%d", n))
defer f.Close()
return net.FileListener(f)
}
// Fun story: this is actually YAML, not JSON.
const ackMsg = `{"command": "worker:ack", "pid": %d}` + "\n"
func einhornAck() {
if !usingEinhorn() {
return
}
log.Print("bind: ACKing to einhorn")
ctl, err := net.Dial("unix", os.Getenv("EINHORN_SOCK_PATH"))
if err != nil {
log.Fatalf(ackErr, err)
}
defer ctl.Close()
_, err = fmt.Fprintf(ctl, ackMsg, os.Getpid())
if err != nil {
log.Fatalf(ackErr, err)
}
}
|