From freefall.cdrom.com!owner-freebsd-hackers Wed Aug 24 07:58:32 1994
Return-Path: <owner-freebsd-hackers@freefall.cdrom.com>
Received: from freefall.cdrom.com by tfs.com (smail3.1.28.1) with SMTP
	id m0qdJmQ-0003xpa; Wed, 24 Aug 94 07:58 PDT
Received: (from root@localhost) by freefall.cdrom.com (8.6.8/8.6.6) id HAA12879 for freebsd-hackers-outgoing; Wed, 24 Aug 1994 07:54:14 -0700
Received: from id.slip.bcm.tmc.edu (id.slip.bcm.tmc.edu [128.249.248.67]) by freefall.cdrom.com (8.6.8/8.6.6) with ESMTP id HAA12864 for <freebsd-hackers@freefall.cdrom.com>; Wed, 24 Aug 1994 07:51:33 -0700
Received: by id.slip.bcm.tmc.edu (8.6.8/1.34)
	id JAA17760; Wed, 24 Aug 1994 09:48:58 -0501
Date: Wed, 24 Aug 1994 09:48:58 -0501
From: rich@id.slip.bcm.tmc.edu (Rich Murphey)
Message-Id: <199408241449.JAA17760@id.slip.bcm.tmc.edu>
To: davidg@Root.COM
CC: ache@astral.msk.su, batie@agora.rdrop.com, marc@dev.com,
        freebsd-hackers@freefall.cdrom.com
In-reply-to: <199408240955.CAA02488@corbin.Root.COM> (message from David Greenman on Wed, 24 Aug 1994 02:55:06 -0700)
Subject: Re: apply this patch file
Reply-To: rich@freefall.cdrom.com
Sender: freebsd-hackers-owner@freefall.cdrom.com
Precedence: bulk
Status: RO

:From: David Greenman <davidg@root.com>
:
:>This is against POSIX: POSIX says that you can't do anything
:>with carrier lost device until closing it, i.e. clearing
:>TS_ZOMBIE is illegal. Proper POSIX way is close()/open() device
:>again like kermit/uucp does. Ask Bruce for more detailed info.
:
:   I'm aware of the issues involved.
:   The problem has to do with a vnode reference that prevents the tty from
:being completely closed (caused by the tty being a session leader with a
:control tty). Regardless of what POSIX says, this is the only reasonable way
:to solve this problem until the code is changed to allow a session leader to
:get rid of it's control tty. I tried to find a way to do this and was
:unsuccessful. The only solution that the code allows is for the process to
:exit. It should not be necessary for the process to exit. If you can come up
:with fixes for slattach and pppd so that they work without the patch, then
:please do.

Bruce Evans suggested doing the fork before reopening the tty and
redialing.  That fixes slattach and I commited it in the 2.0 tree.
I've also sent a copy of the patch for 1.1.5's slattach to Poul.

diff -rub slattach.orig/slattach.c src/sbin/slattach/slattach.c
--- slattach.orig/slattach.c	Mon May  9 14:04:20 1994
+++ src/sbin/slattach/slattach.c	Tue Aug 23 00:39:05 1994
@@ -85,8 +85,8 @@
  * gjung@gjbsd.franken.de
  *
  * sighup_handler changed to set CLOCAL before running redial_cmd.
- * added flag exiting, so exit_handler is not run twice.
- *
+ * added flag exiting, so exit_handler is not run twice.  Fork
+ * before reopening tty.
  */
 
 #ifndef lint
@@ -126,13 +126,13 @@
 void	sigint_handler();	/* SIGINT handler */
 void	sigterm_handler();	/* SIGTERM handler */
 void	exit_handler(int ret);	/* run exit_cmd iff specified upon exit. */
-void	setup_line();		/* configure slip line */
-void	attach_line();		/* switch to slip line discipline */
+void	setup_line(int cflag);	/* configure terminal settings */
+void	slip_discipline();	/* switch to slip line discipline */
+void	configure_network();	/* configure slip interface */
+void	acquire_line();		/* get tty device as controling terminal */
 
 int	fd = -1;
 char	*dev = (char *)0;
-int	slipdisc = SLIPDISC;
-int	ttydisc = TTYDISC;
 int	flow_control = 0;	/* non-zero to enable hardware flow control. */
 int	modem_control = 0;	/* non-zero iff we watch carrier. */
 int	comstate;		/* TIOCMGET current state of serial driver */
@@ -145,7 +145,6 @@
 FILE	*console;
 
 struct	termios tty;
-struct	termios tty_orig;	/* For saving original tty state */
 
 char	devname[32];
 char	hostname[MAXHOSTNAMELEN];
@@ -171,7 +170,6 @@
 int main(int argc, char **argv)
 {
 	int option;
-	char name[32];
 	extern char *optarg;
 	extern int optind;
 
@@ -244,22 +242,13 @@
 
 	if (!foreground)
 		daemon(0,0);	/* fork, setsid, chdir /, and close std*. */
+	/* daemon() closed stderr, so log errors from here on. */
+	openlog("slattach",LOG_CONS|LOG_PID,LOG_DAEMON);
 
-	/* Note: daemon() closes stderr, so log errors from here on. */
-	(void)sprintf(name,"slattach[%d]", getpid());
-	openlog(name,LOG_CONS,LOG_DAEMON);
+	acquire_line();		/* get tty device as controling terminal */
+	setup_line(0);		/* configure for slip line discipline */
+	slip_discipline();	/* switch to slip line discipline */
 
-	if ((fd = open(dev, O_RDWR | O_NONBLOCK)) < 0) {
-                syslog(LOG_ERR, "open(%s): %m", dev);
-		exit_handler(1);
-	}
-	/* acquire the serial line as a controling terminal. */
-	if (ioctl(fd, TIOCSCTTY, 0) < 0)
-		syslog(LOG_NOTICE,"ioctl(TIOCSCTTY) failed: %s: %m");
-	/* Make us the foreground process group associated with the
-	   slip line which is our controlling terminal. */
-	if (tcsetpgrp(fd, getpid()) < 0)
-		syslog(LOG_NOTICE,"tcsetpgrp failed: %s: %m");
 	/* upon INT log a timestamp and exit.  */
 	if ((int)signal(SIGINT,sigint_handler) < 0)
 		syslog(LOG_NOTICE,"cannot install SIGINT handler: %s: %m");
@@ -269,36 +258,76 @@
 	/* upon HUP redial and reconnect.  */
 	if ((int)signal(SIGHUP,sighup_handler) < 0)
 		syslog(LOG_NOTICE,"cannot install SIGHUP handler: %s: %m");
-	/* Keep track of our original terminal values for redialing */
-	if (tcgetattr(fd, &tty_orig) < 0) {           
-		syslog(LOG_ERR, "tcgetattr: %m");
-		exit_handler(1);
-         }
-
-
-	setup_line();
 
 	if (redial_on_startup)
 		sighup_handler();
-	else
-		attach_line();
-	if (!(modem_control & CLOCAL)) {
+	else if (!(modem_control & CLOCAL)) {
 		ioctl(fd, TIOCMGET, &comstate);
 		if (!(comstate & TIOCM_CD)) { /* check for carrier */
 			/* force a redial if no carrier */
 			kill (getpid(), SIGHUP);
 		}
 	}
+	else
+		configure_network(); /* configure the network if needed. */
+
 	for (;;) {
-		sigset_t mask = 0;
+		sigset_t mask;
+		sigemptyset(&mask);
 		sigsuspend(&mask);
 	}
 }
 
-void setup_line()
+/* Close all FDs, fork, reopen tty port as 0-2, and make it the
+   controlling terminal for our process group. */
+void acquire_line()
+{
+	int ttydisc = TTYDISC;
+	int pgrp;
+
+	ioctl(fd, TIOCSETD, &ttydisc); /* reset to tty discipline */
+
+	(void)close(STDIN_FILENO); /* close FDs before forking. */
+	(void)close(STDOUT_FILENO);
+	(void)close(STDERR_FILENO);
+	if (fd > 2)
+		(void)close(fd);
+
+	signal(SIGHUP, SIG_IGN); /* ignore HUP signal when parent dies. */
+	daemon(0,0);		/* fork, setsid, chdir /, and close std*. */
+
+	while (getppid () != 1)
+		sleep (1);	/* Wait for parent to die. */
+
+	if ((int)signal(SIGHUP,sighup_handler) < 0) /* Re-enable HUP signal */
+		syslog(LOG_NOTICE,"cannot install SIGHUP handler: %s: %m");
+
+	if ((fd = open(dev, O_RDWR | O_NONBLOCK, 0)) < 0) {
+		syslog(LOG_ERR, "open(%s) fd=%d: %m", dev, fd);
+		exit_handler(1);
+	}
+	(void)dup2(fd, STDIN_FILENO);
+	(void)dup2(fd, STDOUT_FILENO);
+	(void)dup2(fd, STDERR_FILENO);
+	if (fd > 2)
+		(void)close (fd);
+	fd = STDIN_FILENO;
+
+	/* acquire the serial line as a controling terminal. */
+	if (ioctl(fd, TIOCSCTTY, 0) < 0)
+		syslog(LOG_NOTICE,"ioctl(TIOCSCTTY) failed: %s: %m");
+	/* Make us the foreground process group associated with the
+	   slip line which is our controlling terminal. */
+	if (tcsetpgrp(fd, getpid()) < 0)
+		syslog(LOG_NOTICE,"tcsetpgrp failed: %s: %m");
+}
+
+/* Set the tty flags and set DTR. */
+/* Call as setup_line(CLOCAL) to force clocal assertion. */
+void setup_line(int cflag)
 {
 	tty.c_lflag = tty.c_iflag = tty.c_oflag = 0;
-	tty.c_cflag = CREAD | CS8 | flow_control | modem_control;
+	tty.c_cflag = CREAD | CS8 | flow_control | modem_control | cflag;
 	tty.c_ispeed = tty.c_ospeed = speed;
 	/* set the line speed and flow control */
 	if (tcsetattr(fd, TCSAFLUSH, &tty) < 0) {
@@ -310,6 +339,13 @@
                 syslog(LOG_ERR, "ioctl(TIOCSDTR): %m");
                 exit_handler(1);
         }
+}
+
+/* Put the line in slip discipline. */
+void slip_discipline()
+{
+	int slipdisc = SLIPDISC;
+
 	/* Switch to slip line discipline. */
 	if (ioctl(fd, TIOCSETD, &slipdisc) < 0) {
                 syslog(LOG_ERR, "ioctl(TIOCSETD): %m");
@@ -322,8 +358,8 @@
 	}
 }
 
-/* switch to slip line discipline and configure the network. */
-void attach_line()
+/* configure the interface, eg. by passing the unit number to a script. */
+void configure_network()
 {
 	int new_unit;
 
@@ -354,27 +390,17 @@
 	}
 }
 
-/* Signal handler for SIGHUP when carrier is dropped. */
+/* signup_handler() is invoked when carrier drops, eg. before redial. */
 void sighup_handler()
 {
 	if(exiting) return;
 again:
-	/* reset discipline */
-	if (ioctl(fd, TIOCSETD, &ttydisc) < 0) {
-		syslog(LOG_ERR, "ioctl(TIOCSETD): %m");
-		exit_handler(1);
-	}
 	/* invoke a shell for redial_cmd or punt. */
 	if (redial_cmd) {
+		acquire_line();
+		setup_line(CLOCAL);
 		syslog(LOG_NOTICE,"SIGHUP on %s (sl%d); running %s",
 		       dev,unit,redial_cmd);
-		if (!(modem_control & CLOCAL)) {
-			tty_orig.c_cflag |= CLOCAL;
-			if (tcsetattr(fd, TCSAFLUSH, &tty_orig) < 0) {
-				syslog(LOG_ERR, "tcsetattr(TCSAFLUSH): %m");
-				exit_handler(1);
-			}
-		}
 		system(redial_cmd);
 		/* Now check again for carrier (dial command is done): */
 		if (!(modem_control & CLOCAL)) {
@@ -390,50 +416,33 @@
 			}
 		}
 	} else {
-		/*
-		 * No redial command.
-		 *
-		 * If modem control, just wait for carrier before
-		 * falling through to setup_line() and attach_line().
-		 * If no modem control, just fall through immediately.
-		 */
+		/* If modem control, just wait for carrier before attaching.
+		   If no modem control, just fall through immediately. */
 		if (!(modem_control & CLOCAL)) {
 		    int carrier = 0;
-
 		    syslog(LOG_NOTICE, "Waiting for carrier on %s (sl%d)",
 		      dev, unit);
-
-		    /* Now wait for carrier before attaching line: */
+			/* Now wait for carrier before attaching line. */
+			/* We must poll since CLOCAL prevents signal. */
 		    while (! carrier) {
-			/*
-			 * Don't burn the CPU checking for carrier;
-			 * carrier must be polled since there is no
-			 * way to have a signal sent when carrier
-			 * goes high (SIGHUP can only be sent when
-			 * carrier is dropped); so add space between
-			 * checks for carrier:
-			 */
 			sleep(2);
-
-			/* Check for carrier present on tty port: */
 			ioctl(fd, TIOCMGET, &comstate);
-			if (comstate & TIOCM_CD) {
+				if (comstate & TIOCM_CD)
 			    carrier = 1;
 			}
-		    }
-
 		    syslog(LOG_NOTICE, "Carrier now present on %s (sl%d)",
 		      dev, unit);
 		}
 	}
-	setup_line();
-	attach_line();
+	setup_line(0);
+	slip_discipline();
+	configure_network();
 }
 /* Signal handler for SIGINT.  We just log and exit. */
 void sigint_handler()
 {
 	if(exiting) return;
-	syslog(LOG_NOTICE,"sl%d on %s caught SIGINT, exiting.",unit,dev);
+	syslog(LOG_NOTICE,"SIGINT on %s (sl%d); exiting",dev,unit);
 	exit_handler(0);
 }
 /* Signal handler for SIGTERM.  We just log and exit. */


