1) actually launch application

2) improved signaling from oz-init to oz-daemon when ready
networking
brl 10 years ago
parent de065fb4de
commit 5c9f8b40ad

@ -11,6 +11,7 @@ import (
"os/exec" "os/exec"
"os/user" "os/user"
"path" "path"
"sync"
"syscall" "syscall"
) )
@ -27,6 +28,7 @@ type Sandbox struct {
stderr io.ReadCloser stderr io.ReadCloser
addr string addr string
xpra *xpra.Xpra xpra *xpra.Xpra
ready sync.WaitGroup
} }
/* /*
@ -95,7 +97,14 @@ func (d *daemonState) launch(p *oz.Profile, uid, gid uint32) (*Sandbox, error) {
addr: path.Join(fs.Root(), "tmp", "oz-init-control"), addr: path.Join(fs.Root(), "tmp", "oz-init-control"),
stderr: pp, stderr: pp,
} }
sbox.ready.Add(1)
go sbox.logMessages() go sbox.logMessages()
if sbox.profile.XServer.Enabled {
go func() {
sbox.ready.Wait()
go sbox.startXpraClient()
}()
}
d.nextSboxId += 1 d.nextSboxId += 1
d.sandboxes = append(d.sandboxes, sbox) d.sandboxes = append(d.sandboxes, sbox)
return sbox, nil return sbox, nil
@ -115,11 +124,13 @@ func (sbox *Sandbox) remove() {
func (sbox *Sandbox) logMessages() { func (sbox *Sandbox) logMessages() {
scanner := bufio.NewScanner(sbox.stderr) scanner := bufio.NewScanner(sbox.stderr)
seenOk := false
for scanner.Scan() { for scanner.Scan() {
line := scanner.Text() line := scanner.Text()
if line == "XPRA READY" { if line == "OK" && !seenOk {
sbox.daemon.log.Info("Xpra server is ready for connection") sbox.daemon.log.Info("oz-init (%s) is ready", sbox.profile.Name)
go sbox.startXpraClient() seenOk = true
sbox.ready.Done()
} else if len(line) > 1 { } else if len(line) > 1 {
sbox.logLine(line) sbox.logLine(line)
} }

@ -15,20 +15,22 @@ import (
"os/user" "os/user"
"strconv" "strconv"
"strings" "strings"
"sync"
"syscall" "syscall"
) )
const SocketAddress = "/tmp/oz-init-control" const SocketAddress = "/tmp/oz-init-control"
type initState struct { type initState struct {
log *logging.Logger log *logging.Logger
profile *oz.Profile profile *oz.Profile
config *oz.Config config *oz.Config
uid int uid int
gid int gid int
user *user.User user *user.User
display int display int
fs *fs.Filesystem fs *fs.Filesystem
xpraReady sync.WaitGroup
} }
// By convention oz-init writes log messages to stderr with a single character // By convention oz-init writes log messages to stderr with a single character
@ -121,15 +123,18 @@ func (st *initState) runInit() {
st.log.Error("Error: setting up filesystem failed: %v\n", err) st.log.Error("Error: setting up filesystem failed: %v\n", err)
os.Exit(1) os.Exit(1)
} }
oz.ReapChildProcs(st.log, st.handleChildExit)
if st.profile.XServer.Enabled { if st.profile.XServer.Enabled {
if st.display == 0 { if st.display == 0 {
st.log.Error("Cannot start xpra because no display number was passed to oz-init") st.log.Error("Cannot start xpra because no display number was passed to oz-init")
os.Exit(1) os.Exit(1)
} }
st.xpraReady.Add(1)
st.startXpraServer() st.startXpraServer()
} }
st.xpraReady.Wait()
oz.ReapChildProcs(st.log, st.handleChildExit) st.launchApplication()
s, err := ipc.NewServer(SocketAddress, messageFactory, st.log, s, err := ipc.NewServer(SocketAddress, messageFactory, st.log,
handlePing, handlePing,
@ -142,6 +147,7 @@ func (st *initState) runInit() {
if err := os.Chown(SocketAddress, st.uid, st.gid); err != nil { if err := os.Chown(SocketAddress, st.uid, st.gid); err != nil {
st.log.Warning("Failed to chown oz-init control socket: %v", err) st.log.Warning("Failed to chown oz-init control socket: %v", err)
} }
os.Stderr.WriteString("OK\n")
if err := s.Run(); err != nil { if err := s.Run(); err != nil {
st.log.Warning("MsgServer.Run() return err: %v", err) st.log.Warning("MsgServer.Run() return err: %v", err)
@ -178,11 +184,13 @@ func (st *initState) startXpraServer() {
func (st *initState) readXpraOutput(r io.ReadCloser) { func (st *initState) readXpraOutput(r io.ReadCloser) {
sc := bufio.NewScanner(r) sc := bufio.NewScanner(r)
seenReady := false
for sc.Scan() { for sc.Scan() {
line := sc.Text() line := sc.Text()
if len(line) > 0 { if len(line) > 0 {
if strings.Contains(line, "xpra is ready.") { if strings.Contains(line, "xpra is ready.") && !seenReady {
os.Stderr.WriteString("XPRA READY\n") seenReady = true
st.xpraReady.Done()
if !st.config.LogXpra { if !st.config.LogXpra {
r.Close() r.Close()
return return
@ -195,6 +203,42 @@ func (st *initState) readXpraOutput(r io.ReadCloser) {
} }
} }
func (st *initState) launchApplication() {
cmd := exec.Command(st.profile.Path)
stdout, err := cmd.StdoutPipe()
if err != nil {
st.log.Warning("Failed to create stdout pipe: %v", err)
return
}
stderr, err := cmd.StderrPipe()
if err != nil {
st.log.Warning("Failed to create stderr pipe: %v", err)
return
}
cmd.SysProcAttr = &syscall.SysProcAttr{}
cmd.SysProcAttr.Credential = &syscall.Credential{
Uid: uint32(st.uid),
Gid: uint32(st.gid),
}
cmd.Env = []string{
fmt.Sprintf("DISPLAY=:%d", st.display),
}
if err := cmd.Start(); err != nil {
st.log.Warning("Failed to start application (%s): %v", st.profile.Path, err)
return
}
go st.readApplicationOutput(stdout, "stdout")
go st.readApplicationOutput(stderr, "stderr")
}
func (st *initState) readApplicationOutput(r io.ReadCloser, label string) {
sc := bufio.NewScanner(r)
for sc.Scan() {
line := sc.Text()
st.log.Debug("(%s) %s", label, line)
}
}
func loadProfile(dir, name string) (*oz.Profile, error) { func loadProfile(dir, name string) (*oz.Profile, error) {
ps, err := oz.LoadProfiles(dir) ps, err := oz.LoadProfiles(dir)
if err != nil { if err != nil {

Loading…
Cancel
Save