func (tg *ThreadGroup) SetControllingTTY(tty *TTY, arg int32) error {
	tty.mu.Lock()
	defer tty.mu.Unlock()

	// We might be asked to set the controlling terminal of multiple
	// processes, so we lock both the TaskSet and SignalHandlers.
	tg.pidns.owner.mu.Lock()
	defer tg.pidns.owner.mu.Unlock()
	tg.signalHandlers.mu.Lock()
	defer tg.signalHandlers.mu.Unlock()

	// "The calling process must be a session leader and not have a
	// controlling terminal already." - tty_ioctl(4)
	if tg.processGroup.session.leader != tg || tg.tty != nil {
		return syserror.EINVAL
	}

	// "If this terminal is already the controlling terminal of a different
	// session group, then the ioctl fails with EPERM, unless the caller
	// has the CAP_SYS_ADMIN capability and arg equals 1, in which case the
	// terminal is stolen, and all processes that had it as controlling
	// terminal lose it." - tty_ioctl(4)
	if tty.tg != nil && tg.processGroup.session != tty.tg.processGroup.session {
		if !auth.CredentialsFromContext(tg.leader).HasCapability(linux.CAP_SYS_ADMIN) || arg != 1 {
			return syserror.EPERM
		}
		// Steal the TTY away. Unlike TIOCNOTTY, don't send signals.
		for othertg := range tg.pidns.owner.Root.tgids {
			// This won't deadlock by locking tg.signalHandlers
			// because at this point:
			// - We only lock signalHandlers if it's in the same
			//   session as the tty's controlling thread group.
			// - We know that the calling thread group is not in
			//   the same session as the tty's controlling thread
			//   group.
			if othertg.processGroup.session == tty.tg.processGroup.session {
				othertg.signalHandlers.mu.Lock()
				othertg.tty = nil
				othertg.signalHandlers.mu.Unlock()
			}
		}
	}

	// Set the controlling terminal and foreground process group.
	tg.tty = tty
	tg.processGroup.session.foreground = tg.processGroup
	// Set this as the controlling process of the terminal.
	tty.tg = tg

	return nil
}
// SetControllingTTY sets tty as the controlling terminal of tg.
SetControllingTTY sets tty as the controlling terminal of tg.
// SetControllingTTY sets tty as the controlling terminal of tg .
func (tg *ThreadGroup) SetControllingTTY(tty *TTY, arg int32) error {
	tty.mu.Lock()
	defer tty.mu.Unlock()
	tg.pidns.owner.mu.Lock()
	defer tg.pidns.owner.mu.Unlock()
	tg.signalHandlers.mu.Lock()
	defer tg.signalHandlers.mu.Unlock()
	if tg.processGroup.session.leader != tg || tg.tty != nil {
		return syserror.EINVAL
	}
	if tty.tg != nil && tg.processGroup.session != tty.tg.processGroup.session {
		if !auth.CredentialsFromContext(tg.leader).HasCapability(linux.CAP_SYS_ADMIN) || arg != 1 {
			return syserror.EPERM
		}
		for othertg := range tg.pidns.owner.Root.tgids {
			if othertg.processGroup.session == tty.tg.processGroup.session {
				othertg.signalHandlers.mu.Lock()
				othertg.tty = nil
				othertg.signalHandlers.mu.Unlock()
			}
		}
	}
	tg.tty = tty
	tg.processGroup.session.foreground = tg.processGroup
	tty.tg = tg
	return nil
}
func ( tg * ThreadGroup ) SetControllingTTY ( tty * TTY , arg int32 ) error { tty . mu . Lock ( ) defer tty . mu . Unlock ( ) tg . pidns . owner . mu . Lock ( ) defer tg . pidns . owner . mu . Unlock ( ) tg . signalHandlers . mu . Lock ( ) defer tg . signalHandlers . mu . Unlock ( ) if tg . processGroup . session . leader != tg || tg . tty != nil { return syserror . EINVAL } if tty . tg != nil && tg . processGroup . session != tty . tg . processGroup . session { if ! auth . CredentialsFromContext ( tg . leader ) . HasCapability ( linux . CAP_SYS_ADMIN ) || arg != 1 { return syserror . EPERM } for othertg := range tg . pidns . owner . Root . tgids { if othertg . processGroup . session == tty . tg . processGroup . session { othertg . signalHandlers . mu . Lock ( ) othertg . tty = nil othertg . signalHandlers . mu . Unlock ( ) } } } tg . tty = tty tg . processGroup . session . foreground = tg . processGroup tty . tg = tg return nil }
SetControllingTTY sets tty as the controlling terminal of tg.
SetControllingTTY sets tty as the controlling terminal of tg .
// We might be asked to set the controlling terminal of multiple // processes, so we lock both the TaskSet and SignalHandlers. // "The calling process must be a session leader and not have a // controlling terminal already." - tty_ioctl(4) // "If this terminal is already the controlling terminal of a different // session group, then the ioctl fails with EPERM, unless the caller // has the CAP_SYS_ADMIN capability and arg equals 1, in which case the // terminal is stolen, and all processes that had it as controlling // terminal lose it." - tty_ioctl(4) // Steal the TTY away. Unlike TIOCNOTTY, don't send signals. // This won't deadlock by locking tg.signalHandlers // because at this point: // - We only lock signalHandlers if it's in the same //   session as the tty's controlling thread group. // - We know that the calling thread group is not in //   the same session as the tty's controlling thread //   group. // Set the controlling terminal and foreground process group. // Set this as the controlling process of the terminal.