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/user"
"path"
"sync"
"syscall"
)
@ -27,6 +28,7 @@ type Sandbox struct {
stderr io.ReadCloser
addr string
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"),
stderr: pp,
}
sbox.ready.Add(1)
go sbox.logMessages()
if sbox.profile.XServer.Enabled {
go func() {
sbox.ready.Wait()
go sbox.startXpraClient()
}()
}
d.nextSboxId += 1
d.sandboxes = append(d.sandboxes, sbox)
return sbox, nil
@ -115,11 +124,13 @@ func (sbox *Sandbox) remove() {
func (sbox *Sandbox) logMessages() {
scanner := bufio.NewScanner(sbox.stderr)
seenOk := false
for scanner.Scan() {
line := scanner.Text()
if line == "XPRA READY" {
sbox.daemon.log.Info("Xpra server is ready for connection")
go sbox.startXpraClient()
if line == "OK" && !seenOk {
sbox.daemon.log.Info("oz-init (%s) is ready", sbox.profile.Name)
seenOk = true
sbox.ready.Done()
} else if len(line) > 1 {
sbox.logLine(line)
}

@ -15,20 +15,22 @@ import (
"os/user"
"strconv"
"strings"
"sync"
"syscall"
)
const SocketAddress = "/tmp/oz-init-control"
type initState struct {
log *logging.Logger
profile *oz.Profile
config *oz.Config
uid int
gid int
user *user.User
display int
fs *fs.Filesystem
log *logging.Logger
profile *oz.Profile
config *oz.Config
uid int
gid int
user *user.User
display int
fs *fs.Filesystem
xpraReady sync.WaitGroup
}
// 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)
os.Exit(1)
}
oz.ReapChildProcs(st.log, st.handleChildExit)
if st.profile.XServer.Enabled {
if st.display == 0 {
st.log.Error("Cannot start xpra because no display number was passed to oz-init")
os.Exit(1)
}
st.xpraReady.Add(1)
st.startXpraServer()
}
oz.ReapChildProcs(st.log, st.handleChildExit)
st.xpraReady.Wait()
st.launchApplication()
s, err := ipc.NewServer(SocketAddress, messageFactory, st.log,
handlePing,
@ -142,6 +147,7 @@ func (st *initState) runInit() {
if err := os.Chown(SocketAddress, st.uid, st.gid); err != nil {
st.log.Warning("Failed to chown oz-init control socket: %v", err)
}
os.Stderr.WriteString("OK\n")
if err := s.Run(); err != nil {
st.log.Warning("MsgServer.Run() return err: %v", err)
@ -178,11 +184,13 @@ func (st *initState) startXpraServer() {
func (st *initState) readXpraOutput(r io.ReadCloser) {
sc := bufio.NewScanner(r)
seenReady := false
for sc.Scan() {
line := sc.Text()
if len(line) > 0 {
if strings.Contains(line, "xpra is ready.") {
os.Stderr.WriteString("XPRA READY\n")
if strings.Contains(line, "xpra is ready.") && !seenReady {
seenReady = true
st.xpraReady.Done()
if !st.config.LogXpra {
r.Close()
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) {
ps, err := oz.LoadProfiles(dir)
if err != nil {

Loading…
Cancel
Save