@ -2,6 +2,7 @@ package ozinit
import (
import (
"bufio"
"bufio"
"bytes"
"encoding/json"
"encoding/json"
"fmt"
"fmt"
"io"
"io"
@ -11,6 +12,7 @@ import (
"os/signal"
"os/signal"
"os/user"
"os/user"
"path"
"path"
"regexp"
"strconv"
"strconv"
"strings"
"strings"
"sync"
"sync"
@ -44,6 +46,7 @@ type initState struct {
xpra * xpra . Xpra
xpra * xpra . Xpra
xpraReady sync . WaitGroup
xpraReady sync . WaitGroup
network * network . SandboxNetwork
network * network . SandboxNetwork
dbusUuid string
}
}
type InitData struct {
type InitData struct {
@ -59,6 +62,12 @@ type InitData struct {
Display int
Display int
}
}
const (
DBUS_VAR_REGEXP = "[A-Za-z_]+=[a-zA-Z_:-@]+=/tmp/.+"
)
var dbusValidVar = regexp . MustCompile ( DBUS_VAR_REGEXP )
// 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
// prefix indicating the logging level. These messages are read one line at a time
// prefix indicating the logging level. These messages are read one line at a time
// over a pipe by oz-daemon and translated into appropriate log events.
// over a pipe by oz-daemon and translated into appropriate log events.
@ -164,12 +173,20 @@ func (st *initState) runInit() {
if syscall . Sethostname ( [ ] byte ( st . profile . Name ) ) != nil {
if syscall . Sethostname ( [ ] byte ( st . profile . Name ) ) != nil {
st . log . Error ( "Failed to set hostname to (%s)" , st . profile . Name )
st . log . Error ( "Failed to set hostname to (%s)" , st . profile . Name )
os . Exit ( 1 )
}
}
if syscall . Setdomainname ( [ ] byte ( "local" ) ) != nil {
if syscall . Setdomainname ( [ ] byte ( "local" ) ) != nil {
st . log . Error ( "Failed to set domainname" )
st . log . Error ( "Failed to set domainname" )
}
}
st . log . Info ( "Hostname set to (%s.local)" , st . profile . Name )
st . log . Info ( "Hostname set to (%s.local)" , st . profile . Name )
if st . needsDbus ( ) {
if err := st . setupDbus ( ) ; err != nil {
st . log . Error ( "Unable to setup dbus: %v" , err )
os . Exit ( 1 )
}
}
oz . ReapChildProcs ( st . log , st . handleChildExit )
oz . ReapChildProcs ( st . log , st . handleChildExit )
if st . profile . XServer . Enabled {
if st . profile . XServer . Enabled {
@ -179,6 +196,13 @@ func (st *initState) runInit() {
st . xpraReady . Wait ( )
st . xpraReady . Wait ( )
st . log . Info ( "XPRA started" )
st . log . Info ( "XPRA started" )
if st . needsDbus ( ) {
if err := st . getDbusSession ( ) ; err != nil {
st . log . Error ( "Unable to get dbus session information: %v" , err )
os . Exit ( 1 )
}
}
fsbx := path . Join ( "/tmp" , "oz-sandbox" )
fsbx := path . Join ( "/tmp" , "oz-sandbox" )
err = ioutil . WriteFile ( fsbx , [ ] byte ( st . profile . Name ) , 0644 )
err = ioutil . WriteFile ( fsbx , [ ] byte ( st . profile . Name ) , 0644 )
@ -195,6 +219,63 @@ func (st *initState) runInit() {
st . log . Info ( "oz-init exiting..." )
st . log . Info ( "oz-init exiting..." )
}
}
func ( st * initState ) needsDbus ( ) bool {
return ( st . profile . XServer . AudioMode == oz . PROFILE_AUDIO_FULL ||
st . profile . XServer . AudioMode == oz . PROFILE_AUDIO_SPEAKER ||
st . profile . XServer . EnableNotifications == true )
}
func ( st * initState ) setupDbus ( ) error {
exec . Command ( "/usr/bin/dbus-uuidgen" , "--ensure" ) . Run ( )
buuid , err := exec . Command ( "/usr/bin/dbus-uuidgen" , "--get" ) . CombinedOutput ( )
if err != nil || string ( buuid ) == "" {
return fmt . Errorf ( "dbus-uuidgen failed: %v %v" , err , string ( buuid ) )
}
st . dbusUuid = strings . TrimSpace ( string ( bytes . Trim ( buuid , "\x00" ) ) )
st . log . Debug ( "dbus-uuid: %s" , st . dbusUuid )
return nil
}
func ( st * initState ) getDbusSession ( ) error {
args := [ ] string {
"--autolaunch" ,
st . dbusUuid ,
"--sh-syntax" ,
"--close-stderr" ,
}
dcmd := exec . Command ( "/usr/bin/dbus-launch" , args ... )
dcmd . Env = append ( [ ] string { } , st . launchEnv ... )
st . log . Debug ( "%s /usr/bin/dbus-launch %s" , strings . Join ( dcmd . Env , " " ) , strings . Join ( args , " " ) )
dcmd . SysProcAttr = & syscall . SysProcAttr { }
dcmd . SysProcAttr . Credential = & syscall . Credential {
Uid : st . uid ,
Gid : st . gid ,
}
benvs , err := dcmd . Output ( )
if err != nil && len ( benvs ) <= 1 {
return fmt . Errorf ( "dbus-launch failed: %v %v" , err , string ( benvs ) )
}
benvs = bytes . Trim ( benvs , "\x00" )
senvs := strings . TrimSpace ( string ( benvs ) )
senvs = strings . Replace ( senvs , "export " , "" , - 1 )
senvs = strings . Replace ( senvs , ";" , "" , - 1 )
senvs = strings . Replace ( senvs , "'" , "" , - 1 )
dbusenv := ""
for _ , line := range strings . Split ( senvs , "\n" ) {
if dbusValidVar . MatchString ( line ) {
dbusenv = line
break ;
}
}
if dbusenv != "" {
st . launchEnv = append ( st . launchEnv , dbusenv )
vv := strings . Split ( dbusenv , "=" )
os . Setenv ( vv [ 0 ] , strings . Join ( vv [ 1 : ] , "=" ) )
}
return nil
}
func ( st * initState ) startXpraServer ( ) {
func ( st * initState ) startXpraServer ( ) {
if st . user == nil {
if st . user == nil {
st . log . Warning ( "Cannot start xpra server because no user is set" )
st . log . Warning ( "Cannot start xpra server because no user is set" )