Changing Control Terminal in A/UX (long reply)

John Sovereign john at unisoft.UUCP
Thu Jul 6 14:08:03 AEST 1989


In article <4174 at emory.mathcs.emory.edu> km at mathcs.emory.edu (Ken Mandelberg) writes:
>... [in A/UX] there is no provision for changing the control terminal of
>a process to a tty that is already open. On BSD you can accomplish this
>for example, with a TIOCNOTTY followed by an open of the desired
>terminal (even if the terminal is already open).

BSD's behavior might be considered a security hole in need of plugging.

>In other words A/UX seems to strictly obey the System V semantics that
>dictate that a proc's control terminal is either inherited from its
>parent, or is associated with a terminal not already open (as it
>establishes a new process group and becomes the process group leader).

To be more precise, under A/UX, establishing the controlling tty via open(2)
requires these conditions: (a) the calling process is a "classical" process
group leader, i.e., its process id is equal to its process group id, (b)
the calling process is not currently controlled by any terminal, and (c) the
device being opened does not have a controlling process associated with it.

>Is there a trick that I am missing?

Yes.  You can muck with the device's idea of the controlling process,
using TIOCSPGRP.  The code below demonstrates this.

>What does POSIX say on the issue? I notice that the BSD doc clearly
>allow the control terminal change, the SunOS doc "currently" allows it,
>and the System V doc disallows it.

Unfortunately, your application is not supported by POSIX as currently
defined.  The POSIX functionality is similar to A/UX in this area, i.e.,
a System V base with (optional) job control support.  POSIX requires that
a controlling terminal be associated with only one session; the association
is determined by the session leader (IEEE Std 1003.1-1988 section 7.1.1.3).

Since session membership is defined by inheritance (section 3.1.2.2) and
the creation of a new session releases any associated controlling terminal
(section 4.3.2.2), only children of a session leader may be associated with
its controlling terminal.  Furthermore, the POSIX version of the BSD setpgrp(),
called setpgid(), is paranoid and does not allow processes to "join" process
groups in other sessions (section 4.3.3.4).

One of the really wonderful things (;-<) about POSIX is that it muddles the
the whole issue by making control-terminal allocation "implementation-defined".

>Ken Mandelberg      | km at mathcs.emory.edu          PREFERRED
>Emory University    | {decvax,gatech}!emory!km     UUCP 
>Dept of Math and CS | km at emory.bitnet              NON-DOMAIN BITNET  
>Atlanta, GA 30322   | Phone: (404) 727-7963

John "POSIX: The Final Solution" Sovereign	|	uunet!unisoft!john

			--- cut here ---
/*
 * attach:	attach a process to a tty (A/UX special),
 *		even if it already has a process associated with it
 *
 *		if there is a process already controlled by the tty,
 *		join its process group as well
 */

#include <fcntl.h>
#include <sys/ioctl.h>
#include <compat.h>

#define	CTRLTTY		"/dev/tty"

main(argc, argv)
int argc;
char **argv;
{
	int oldpgrp, newpgrp, fd, i;

	if (!argv[1]) {
		printf("usage: attach tty\n");
		exit(1);
	}

	/*
	 * use the BSD version of setpgrp
	 * and prevent TIOCSPGRP's from putting us in the background
	 */
	if (setcompat(COMPAT_BSDTTY|COMPAT_BSDSIGNALS|COMPAT_CLRPGROUP) == -1)
		perror("setcompat");

	/* record the tty's foreground process group */
	if ((fd = open(argv[1], O_RDWR)) == -1)
		perror(argv[1]);
	if (ioctl(fd, TIOCGPGRP, &oldpgrp) == -1)
		perror("GPGRP");
	(void) close(fd);

	/* unnecessary if there's no process associated with the tty */
	if (oldpgrp != 0) {
		newpgrp = 0;
		if ((fd = open(argv[1], O_RDWR)) == -1)
			perror(argv[1]);
		if (ioctl(fd, TIOCSPGRP, &newpgrp) == -1)
			perror("SPGRP 0");
		if (ioctl(fd, TIOCGPGRP, &newpgrp) == -1)
			perror("GPGRP 0");
		(void) close(fd);
		if (newpgrp != 0)
			printf("tty pgrp is %d, not zero\n", newpgrp);
	}

	/* disconnect from the inherited controlling tty */
	if ((fd = open(CTRLTTY, O_RDWR)) == -1)
		perror("could not open CTRLTTY\n");
	if (ioctl(fd, TIOCNOTTY, 0) == -1)
		perror("TIOCNOTTY");
	(void) close(fd);

	/*
	 * make sure we're a "classical" process group leader
	 * after the TIOCNOTTY since it clears the pgrp
	 */
	if (setpgrp(0, getpid()) == -1)
		perror("setpgrp");
	if (getpid() != getpgrp())
		printf("not process group leader: pid = %d; pgrp = %d\n",
			getpid(), getpgrp());

	/* establish the controlling tty (we hope) */
	if ((fd = open(argv[1], O_RDWR)) == -1)
		perror(argv[1]);

	/* test that the above open() established the controlling tty */
	if (open(CTRLTTY, O_RDWR) == -1)
		perror("could not open /dev/tty");
	else
		printf("opened /dev/tty\n");

	/* unnecessary if there's no process associated with the tty */
	if (oldpgrp != 0) {
		/* join the old foreground process group */
		if (setpgrp(0, oldpgrp) == -1)
			perror("setpgrp(0, oldpgrp)");
		if (getpgrp() != oldpgrp)
			printf("still in own process group %d instead of %d\n",
				getpgrp(), oldpgrp);

		/* re-establish the foreground process group */
		if (ioctl(fd, TIOCSPGRP, &oldpgrp) == -1)
			perror("SPGRP");
		if (ioctl(fd, TIOCGPGRP, &newpgrp) == -1)
			perror("GPGRP");
		if (newpgrp != oldpgrp)
			printf("expected to reset tty pgrp to %d; still %d\n",
				oldpgrp, newpgrp);
	}

	/* verify process group membership by a keyboard interrupt */
	pause();
}



More information about the Comp.unix.aux mailing list