|  |  | @ -1,34 +1,34 @@ | 
			
		
	
		
		
			
				
					
					|  |  |  | package ozinit |  |  |  | package ozinit | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | import ( |  |  |  | import ( | 
			
		
	
		
		
			
				
					
					|  |  |  | 	"os" |  |  |  | 	"bufio" | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 	"fmt" | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 	"github.com/kr/pty" | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 	"github.com/op/go-logging" | 
			
		
	
		
		
			
				
					
					|  |  |  | 	"github.com/subgraph/oz" |  |  |  | 	"github.com/subgraph/oz" | 
			
		
	
		
		
			
				
					
					|  |  |  | 	"github.com/subgraph/oz/fs" |  |  |  | 	"github.com/subgraph/oz/fs" | 
			
		
	
		
		
			
				
					
					|  |  |  | 	"github.com/subgraph/oz/ipc" |  |  |  | 	"github.com/subgraph/oz/ipc" | 
			
		
	
		
		
			
				
					
					|  |  |  | 	"os/exec" |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 	"syscall" |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 	"github.com/op/go-logging" |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 	"github.com/kr/pty" |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 	"fmt" |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 	"github.com/subgraph/oz/xpra" |  |  |  | 	"github.com/subgraph/oz/xpra" | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 	"io" | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 	"os" | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 	"os/exec" | 
			
		
	
		
		
			
				
					
					|  |  |  | 	"os/user" |  |  |  | 	"os/user" | 
			
		
	
		
		
			
				
					
					|  |  |  | 	"strconv" |  |  |  | 	"strconv" | 
			
		
	
		
		
			
				
					
					|  |  |  | 	"io" |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 	"bufio" |  |  |  |  | 
			
		
	
		
		
			
				
					
					|  |  |  | 	"strings" |  |  |  | 	"strings" | 
			
		
	
		
		
			
				
					
					|  |  |  |  |  |  |  | 	"syscall" | 
			
		
	
		
		
			
				
					
					|  |  |  | ) |  |  |  | ) | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | const profileDirectory = "/var/lib/oz/cells.d" |  |  |  | const profileDirectory = "/var/lib/oz/cells.d" | 
			
		
	
		
		
			
				
					
					|  |  |  | 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 | 
			
		
	
		
		
			
				
					
					|  |  |  | 	uid int |  |  |  | 	uid     int | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | 	gid int |  |  |  | 	gid     int | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | 	user *user.User |  |  |  | 	user    *user.User | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 	display int |  |  |  | 	display int | 
			
		
	
		
		
			
				
					
					|  |  |  | 	fs *fs.Filesystem |  |  |  | 	fs      *fs.Filesystem | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | } |  |  |  | } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | // 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
 | 
			
		
	
	
		
		
			
				
					|  |  | @ -38,7 +38,7 @@ func createLogger() *logging.Logger { | 
			
		
	
		
		
			
				
					
					|  |  |  | 	l := logging.MustGetLogger("oz-init") |  |  |  | 	l := logging.MustGetLogger("oz-init") | 
			
		
	
		
		
			
				
					
					|  |  |  | 	be := logging.NewLogBackend(os.Stderr, "", 0) |  |  |  | 	be := logging.NewLogBackend(os.Stderr, "", 0) | 
			
		
	
		
		
			
				
					
					|  |  |  | 	f := logging.MustStringFormatter("%{level:.1s} %{message}") |  |  |  | 	f := logging.MustStringFormatter("%{level:.1s} %{message}") | 
			
		
	
		
		
			
				
					
					|  |  |  | 	fbe := logging.NewBackendFormatter(be,f) |  |  |  | 	fbe := logging.NewBackendFormatter(be, f) | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 	logging.SetBackend(fbe) |  |  |  | 	logging.SetBackend(fbe) | 
			
		
	
		
		
			
				
					
					|  |  |  | 	return l |  |  |  | 	return l | 
			
		
	
		
		
			
				
					
					|  |  |  | } |  |  |  | } | 
			
		
	
	
		
		
			
				
					|  |  | @ -65,29 +65,29 @@ func parseArgs() *initState { | 
			
		
	
		
		
			
				
					
					|  |  |  | 	uidval := getvar("INIT_UID") |  |  |  | 	uidval := getvar("INIT_UID") | 
			
		
	
		
		
			
				
					
					|  |  |  | 	dispval := os.Getenv("INIT_DISPLAY") |  |  |  | 	dispval := os.Getenv("INIT_DISPLAY") | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | 	p,err := loadProfile(pname) |  |  |  | 	p, err := loadProfile(pname) | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 	if err != nil { |  |  |  | 	if err != nil { | 
			
		
	
		
		
			
				
					
					|  |  |  | 		log.Error("Could not load profile %s: %v", pname, err) |  |  |  | 		log.Error("Could not load profile %s: %v", pname, err) | 
			
		
	
		
		
			
				
					
					|  |  |  | 		os.Exit(1) |  |  |  | 		os.Exit(1) | 
			
		
	
		
		
			
				
					
					|  |  |  | 	} |  |  |  | 	} | 
			
		
	
		
		
			
				
					
					|  |  |  | 	uid,err := strconv.Atoi(uidval) |  |  |  | 	uid, err := strconv.Atoi(uidval) | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 	if err != nil { |  |  |  | 	if err != nil { | 
			
		
	
		
		
			
				
					
					|  |  |  | 		log.Error("Could not parse INIT_UID argument (%s) into an integer: %v", uidval, err) |  |  |  | 		log.Error("Could not parse INIT_UID argument (%s) into an integer: %v", uidval, err) | 
			
		
	
		
		
			
				
					
					|  |  |  | 		os.Exit(1) |  |  |  | 		os.Exit(1) | 
			
		
	
		
		
			
				
					
					|  |  |  | 	} |  |  |  | 	} | 
			
		
	
		
		
			
				
					
					|  |  |  | 	u,err := user.LookupId(uidval) |  |  |  | 	u, err := user.LookupId(uidval) | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 	if err != nil { |  |  |  | 	if err != nil { | 
			
		
	
		
		
			
				
					
					|  |  |  | 		log.Error("Failed to look up user with uid=%s: %v", uidval, err) |  |  |  | 		log.Error("Failed to look up user with uid=%s: %v", uidval, err) | 
			
		
	
		
		
			
				
					
					|  |  |  | 		os.Exit(1) |  |  |  | 		os.Exit(1) | 
			
		
	
		
		
			
				
					
					|  |  |  | 	} |  |  |  | 	} | 
			
		
	
		
		
			
				
					
					|  |  |  | 	gid,err := strconv.Atoi(u.Gid) |  |  |  | 	gid, err := strconv.Atoi(u.Gid) | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 	if err != nil { |  |  |  | 	if err != nil { | 
			
		
	
		
		
			
				
					
					|  |  |  | 		log.Error("Failed to parse gid value (%s) from user struct: %v", u.Gid, err) |  |  |  | 		log.Error("Failed to parse gid value (%s) from user struct: %v", u.Gid, err) | 
			
		
	
		
		
			
				
					
					|  |  |  | 		os.Exit(1) |  |  |  | 		os.Exit(1) | 
			
		
	
		
		
			
				
					
					|  |  |  | 	} |  |  |  | 	} | 
			
		
	
		
		
			
				
					
					|  |  |  | 	display := 0 |  |  |  | 	display := 0 | 
			
		
	
		
		
			
				
					
					|  |  |  | 	if dispval != "" { |  |  |  | 	if dispval != "" { | 
			
		
	
		
		
			
				
					
					|  |  |  | 		d,err := strconv.Atoi(dispval) |  |  |  | 		d, err := strconv.Atoi(dispval) | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 		if err != nil { |  |  |  | 		if err != nil { | 
			
		
	
		
		
			
				
					
					|  |  |  | 			log.Error("Unable to parse display (%s) into an integer: %v", dispval, err) |  |  |  | 			log.Error("Unable to parse display (%s) into an integer: %v", dispval, err) | 
			
		
	
		
		
			
				
					
					|  |  |  | 			os.Exit(1) |  |  |  | 			os.Exit(1) | 
			
		
	
	
		
		
			
				
					|  |  | @ -96,13 +96,13 @@ func parseArgs() *initState { | 
			
		
	
		
		
			
				
					
					|  |  |  | 	} |  |  |  | 	} | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | 	return &initState{ |  |  |  | 	return &initState{ | 
			
		
	
		
		
			
				
					
					|  |  |  | 		log: log, |  |  |  | 		log:     log, | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 		profile: p, |  |  |  | 		profile: p, | 
			
		
	
		
		
			
				
					
					|  |  |  | 		uid: uid, |  |  |  | 		uid:     uid, | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | 		gid: gid, |  |  |  | 		gid:     gid, | 
			
				
				
			
		
	
		
		
			
				
					
					|  |  |  | 		user: u, |  |  |  | 		user:    u, | 
			
				
				
			
		
	
		
		
	
		
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 		display: display, |  |  |  | 		display: display, | 
			
		
	
		
		
			
				
					
					|  |  |  | 		fs: fs.NewFromProfile(p, u, log), |  |  |  | 		fs:      fs.NewFromProfile(p, u, log), | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 	} |  |  |  | 	} | 
			
		
	
		
		
			
				
					
					|  |  |  | } |  |  |  | } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
	
		
		
			
				
					|  |  | @ -127,7 +127,7 @@ func (st *initState) runInit() { | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | 	oz.ReapChildProcs(st.log, st.handleChildExit) |  |  |  | 	oz.ReapChildProcs(st.log, st.handleChildExit) | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | 	s,err := ipc.NewServer(socketAddress, messageFactory, st.log, |  |  |  | 	s, err := ipc.NewServer(socketAddress, messageFactory, st.log, | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 		handlePing, |  |  |  | 		handlePing, | 
			
		
	
		
		
			
				
					
					|  |  |  | 		st.handleRunShell, |  |  |  | 		st.handleRunShell, | 
			
		
	
		
		
			
				
					
					|  |  |  | 	) |  |  |  | 	) | 
			
		
	
	
		
		
			
				
					|  |  | @ -152,14 +152,14 @@ func (st *initState) startXpraServer() { | 
			
		
	
		
		
			
				
					
					|  |  |  | 		return |  |  |  | 		return | 
			
		
	
		
		
			
				
					
					|  |  |  | 	} |  |  |  | 	} | 
			
		
	
		
		
			
				
					
					|  |  |  | 	xpra := xpra.NewServer(&st.profile.XServer, uint64(st.display), workdir) |  |  |  | 	xpra := xpra.NewServer(&st.profile.XServer, uint64(st.display), workdir) | 
			
		
	
		
		
			
				
					
					|  |  |  | 	p,err := xpra.Process.StderrPipe() |  |  |  | 	p, err := xpra.Process.StderrPipe() | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 	if err != nil { |  |  |  | 	if err != nil { | 
			
		
	
		
		
			
				
					
					|  |  |  | 		st.log.Warning("Error creating stderr pipe for xpra output: %v", err) |  |  |  | 		st.log.Warning("Error creating stderr pipe for xpra output: %v", err) | 
			
		
	
		
		
			
				
					
					|  |  |  | 		os.Exit(1) |  |  |  | 		os.Exit(1) | 
			
		
	
		
		
			
				
					
					|  |  |  | 	} |  |  |  | 	} | 
			
		
	
		
		
			
				
					
					|  |  |  | 	go st.readXpraOutput(p) |  |  |  | 	go st.readXpraOutput(p) | 
			
		
	
		
		
			
				
					
					|  |  |  | 	xpra.Process.Env = []string{ |  |  |  | 	xpra.Process.Env = []string{ | 
			
		
	
		
		
			
				
					
					|  |  |  | 		"HOME="+ st.user.HomeDir, |  |  |  | 		"HOME=" + st.user.HomeDir, | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 	} |  |  |  | 	} | 
			
		
	
		
		
			
				
					
					|  |  |  | 	xpra.Process.SysProcAttr = &syscall.SysProcAttr{} |  |  |  | 	xpra.Process.SysProcAttr = &syscall.SysProcAttr{} | 
			
		
	
		
		
			
				
					
					|  |  |  | 	xpra.Process.SysProcAttr.Credential = &syscall.Credential{ |  |  |  | 	xpra.Process.SysProcAttr.Credential = &syscall.Credential{ | 
			
		
	
	
		
		
			
				
					|  |  | @ -192,11 +192,11 @@ func (st *initState) readXpraOutput(r io.ReadCloser) { | 
			
		
	
		
		
			
				
					
					|  |  |  | } |  |  |  | } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | func loadProfile(name string) (*oz.Profile, error) { |  |  |  | func loadProfile(name string) (*oz.Profile, error) { | 
			
		
	
		
		
			
				
					
					|  |  |  | 	ps,err := oz.LoadProfiles(profileDirectory) |  |  |  | 	ps, err := oz.LoadProfiles(profileDirectory) | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 	if err != nil { |  |  |  | 	if err != nil { | 
			
		
	
		
		
			
				
					
					|  |  |  | 		return nil, err |  |  |  | 		return nil, err | 
			
		
	
		
		
			
				
					
					|  |  |  | 	} |  |  |  | 	} | 
			
		
	
		
		
			
				
					
					|  |  |  | 	for _,p := range ps { |  |  |  | 	for _, p := range ps { | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 		if name == p.Name { |  |  |  | 		if name == p.Name { | 
			
		
	
		
		
			
				
					
					|  |  |  | 			return p, nil |  |  |  | 			return p, nil | 
			
		
	
		
		
			
				
					
					|  |  |  | 		} |  |  |  | 		} | 
			
		
	
	
		
		
			
				
					|  |  | @ -228,7 +228,7 @@ func (st *initState) handleRunShell(rs *RunShellMsg, msg *ipc.Message) error { | 
			
		
	
		
		
			
				
					
					|  |  |  | 	cmd.Env = append(cmd.Env, "PATH=/usr/bin:/bin") |  |  |  | 	cmd.Env = append(cmd.Env, "PATH=/usr/bin:/bin") | 
			
		
	
		
		
			
				
					
					|  |  |  | 	cmd.Env = append(cmd.Env, fmt.Sprintf("PS1=[%s] $ ", st.profile.Name)) |  |  |  | 	cmd.Env = append(cmd.Env, fmt.Sprintf("PS1=[%s] $ ", st.profile.Name)) | 
			
		
	
		
		
			
				
					
					|  |  |  | 	st.log.Info("Executing shell...") |  |  |  | 	st.log.Info("Executing shell...") | 
			
		
	
		
		
			
				
					
					|  |  |  | 	f,err := ptyStart(cmd) |  |  |  | 	f, err := ptyStart(cmd) | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 	defer f.Close() |  |  |  | 	defer f.Close() | 
			
		
	
		
		
			
				
					
					|  |  |  | 	if err != nil { |  |  |  | 	if err != nil { | 
			
		
	
		
		
			
				
					
					|  |  |  | 		return msg.Respond(&ErrorMsg{err.Error()}) |  |  |  | 		return msg.Respond(&ErrorMsg{err.Error()}) | 
			
		
	
	
		
		
			
				
					|  |  | @ -238,7 +238,7 @@ func (st *initState) handleRunShell(rs *RunShellMsg, msg *ipc.Message) error { | 
			
		
	
		
		
			
				
					
					|  |  |  | } |  |  |  | } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  | 
 | 
			
		
	
		
		
			
				
					
					|  |  |  | func ptyStart(c *exec.Cmd) (ptty *os.File, err error) { |  |  |  | func ptyStart(c *exec.Cmd) (ptty *os.File, err error) { | 
			
		
	
		
		
			
				
					
					|  |  |  | 	ptty,tty, err := pty.Open() |  |  |  | 	ptty, tty, err := pty.Open() | 
			
				
				
			
		
	
		
		
	
		
		
			
				
					
					|  |  |  | 	if err != nil { |  |  |  | 	if err != nil { | 
			
		
	
		
		
			
				
					
					|  |  |  | 		return nil, err |  |  |  | 		return nil, err | 
			
		
	
		
		
			
				
					
					|  |  |  | 	} |  |  |  | 	} | 
			
		
	
	
		
		
			
				
					|  |  | @ -261,4 +261,3 @@ func ptyStart(c *exec.Cmd) (ptty *os.File, err error) { | 
			
		
	
		
		
			
				
					
					|  |  |  | func (is *initState) handleChildExit(pid int, wstatus syscall.WaitStatus) { |  |  |  | func (is *initState) handleChildExit(pid int, wstatus syscall.WaitStatus) { | 
			
		
	
		
		
			
				
					
					|  |  |  | 	is.log.Debug("Child process pid=%d exited with status %d", pid, wstatus.ExitStatus()) |  |  |  | 	is.log.Debug("Child process pid=%d exited with status %d", pid, wstatus.ExitStatus()) | 
			
		
	
		
		
			
				
					
					|  |  |  | } |  |  |  | } | 
			
		
	
		
		
			
				
					
					|  |  |  | 
 |  |  |  |  | 
			
		
	
	
		
		
			
				
					|  |  | 
 |