func testNewLinuxHostTaoServer(t *testing.T) (Tao, error) {
	lh, err := testNewRootLinuxHost()
	if err != nil {
		return nil, fmt.Errorf("Can't make root linux host: %s", err)
	}

	hostRead, childWrite, err := os.Pipe()
	if err != nil {
		return nil, fmt.Errorf("Can't make pipe: %s", err)
	}

	childRead, hostWrite, err := os.Pipe()
	if err != nil {
		childWrite.Close()
		hostRead.Close()
		return nil, fmt.Errorf("Can't make pipe: %s", err)
	}

	hostChannel := util.NewPairReadWriteCloser(hostRead, hostWrite)
	childChannel := util.NewPairReadWriteCloser(childRead, childWrite)

	child := &LinuxHostChild{
		channel:      hostChannel,
		ChildSubprin: []auth.PrinExt{auth.PrinExt{Name: "TestChild"}},
		Cmd:          nil, // The Cmd field is not used in this test.
	}

	go NewLinuxHostTaoServer(lh, child).Serve(hostChannel)
	return &RPC{protorpc.NewClient(childChannel), "Tao"}, nil
}
// Start starts the the hosted process and returns a tao channel to it.
func (p *HostedProcess) Start() (channel io.ReadWriteCloser, err error) {
	var extraFiles []*os.File
	var evar string
	switch p.Factory.channelType {
	case "pipe":
		// Get a pipe pair for communication with the child.
		var serverRead, clientRead, serverWrite, clientWrite *os.File
		serverRead, clientWrite, err = os.Pipe()
		if err != nil {
			return
		}
		defer clientWrite.Close()

		clientRead, serverWrite, err = os.Pipe()
		if err != nil {
			serverRead.Close()
			return
		}
		defer clientRead.Close()

		channel = util.NewPairReadWriteCloser(serverRead, serverWrite)
		extraFiles = []*os.File{clientRead, clientWrite} // fd 3, fd 4

		// Note: ExtraFiles below ensures readfd=3, writefd=4 in child
		evar = HostSpecEnvVar + "=tao::RPC+tao::FDMessageChannel(3, 4)"
	case "unix":
		// Get a random name for the socket.
		nameBytes := make([]byte, sockNameLen)
		if _, err = rand.Read(nameBytes); err != nil {
			return
		}
		sockName := base64.URLEncoding.EncodeToString(nameBytes)
		sockPath := path.Join(p.Factory.socketPath, sockName)
		channel = util.NewUnixSingleReadWriteCloser(sockPath)
		if channel == nil {
			err = fmt.Errorf("Couldn't create a new Unix channel\n")
			return
		}
		evar = HostSpecEnvVar + "=" + sockPath
	default:
		err = fmt.Errorf("invalid channel type '%s'\n", p.Factory.channelType)
		return
	}
	defer func() {
		if err != nil {
			channel.Close()
			channel = nil
		}
	}()

	env := p.spec.Env
	if env == nil {
		env = os.Environ()
	}
	// Make sure that the child knows to use the right kind of channel.
	etvar := HostChannelTypeEnvVar + "=" + p.Factory.channelType
	replaced := false
	replacedType := false
	for i, pair := range env {
		if strings.HasPrefix(pair, HostSpecEnvVar+"=") {
			env[i] = evar
			replaced = true
		}

		if strings.HasPrefix(pair, HostChannelTypeEnvVar+"=") {
			env[i] = etvar
			replacedType = true
		}
	}
	if !replaced {
		env = append(env, evar)
	}

	if !replacedType {
		env = append(env, etvar)
	}

	if (p.spec.Uid == 0 || p.spec.Gid == 0) && !p.spec.Superuser {
		err = fmt.Errorf("Uid and Gid must be nonzero unless Superuser is set\n")
		return
	}

	wd := p.spec.Dir
	if wd == "" {
		wd = p.Tempdir
	}

	// Every hosted process is given its own process group (Setpgid=true). This
	// ensures that hosted processes will not be in orphaned process groups,
	// allowing them to receive job control signals (SIGTTIN, SIGTTOU, and
	// SIGTSTP).
	//
	// If this host is running in "daemon" mode, i.e. without a controlling tty
	// and in our own session and process group, then this host will be (a) the
	// parent of a process in the child's group, (b) in the same session, and
	// (c) not in the same group as the child, so it will serve as the anchor
	// that keeps the child process groups from being considered orphaned.
	//
	// If this host is running in "foreground" mode, i.e. with a controlling tty
	// and as part of our parent process's session but in our own process group,
	// then the same three conditions are satisified, so this host can still
	// serve as the anchor that keeps the child process groups from being
	// considered orphaned. (Note: We could also use Setpid=false in this case,
	// since the host would be part of the child process group and our parent
	// would then meet the requirements.)

	spa := &syscall.SysProcAttr{
		Credential: &syscall.Credential{
			Uid: uint32(p.spec.Uid),
			Gid: uint32(p.spec.Uid),
		},
		// Setsid: true, // Create session.
		Setpgid: true, // Set process group ID to new pid (SYSV setpgrp)
		// Setctty: true, // Set controlling terminal to fd Ctty (only meaningful if Setsid is set)
		// Noctty: true, // Detach fd 0 from controlling terminal
		// Ctty: 0, // Controlling TTY fd (Linux only)
	}
	argv := []string{p.Argv0}
	argv = append(argv, p.spec.Args...)
	p.Cmd = exec.Cmd{
		Path:        p.Temppath,
		Dir:         wd,
		Args:        argv,
		Stdin:       p.spec.Stdin,
		Stdout:      p.spec.Stdout,
		Stderr:      p.spec.Stderr,
		Env:         env,
		ExtraFiles:  extraFiles,
		SysProcAttr: spa,
	}

	if err = p.Cmd.Start(); err != nil {
		return
	}

	// Reap the child when the process dies.
	sc := make(chan os.Signal, 1)
	signal.Notify(sc, syscall.SIGCHLD)
	go func() {
		<-sc
		p.Cmd.Wait()
		signal.Stop(sc)
		os.RemoveAll(p.Tempdir)
		p.Done <- true
		close(p.Done) // prevent any more blocking
	}()

	// TODO(kwalsh) put channel into p, remove the struct in linux_host.go

	return
}