bin/69986: [patch] sysinstall: No job control in fixit shell on serial console

dada at sbox.tugraz.at dada at sbox.tugraz.at
Wed Aug 4 00:40:47 PDT 2004


>Number:         69986
>Category:       bin
>Synopsis:       [patch] sysinstall: No job control in fixit shell on serial console
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Wed Aug 04 07:40:24 GMT 2004
>Closed-Date:
>Last-Modified:
>Originator:     Martin Kammerhofer
>Release:        FreeBSD 4.10-STABLE i386
>Organization:
Graz UNI
>Environment:
System: FreeBSD Martin.liebt.Susi 4.10-STABLE FreeBSD 4.10-STABLE #0: Sat Jul 24 15:53:45 CEST 2004 toor at Martin.liebt.Susi:/usr/src/sys/compile/GEIDORF4 i386
>Description:
Running a fixit shell on a serial console is dangerous. Suppose a
program hangs (e.g. mount_nfs) and the user types Cntrl-C to stop it
==> game over. INTR will be delivered to sysinstall, the blocking
process will persist, sysinstall will not unmount the fixit media and
therefore further attempts to spawn a fixit shell will fail. The user
has to reboot.
>How-To-Repeat:
Boot with serial console into sysinstall. (Option "-h" to boot2 or
"set console=comconsole" in loader.) Invoke one of the fixit options
(DVD, Floppy, Shell). Start a program (e.g. "ls -R /") and stop it
with INTR (i.e. type Cntrl-C).
>Fix:
Explanation of patch:

The code path for the usual case (running on syscons) is almost
unchanged. Two ioctls calls are omitted. TIOCNOTTY was futile since it
_only_ works on /dev/tty (and invoking it on /dev/tty would not help
in any way here). TIOCSCTTY was redundant because login_tty(3) calls
setsid(2) (creating a new session without a controlling terminal) and
sets the controlling terminal afterwards.

The code path for the serial console keeps console descriptors 0 and 1
(rather than closing and reopening them). Stderr is duplicated from
stdout because sysinstall redirected it.
  Calling setsid(2) was wrong: A terminal can be the controlling
terminal for at most one session!  The serial console is already the
controlling terminal for sysinstall's session. There is _no_ way to
make it the controlling terminal for another session too.
  Rather than creating a new session we keep things as they are. Job
control and signals will work as expected for the fixit shell. We only
have to reset the foreground process group after the fixit shell
exited. This ensures that keyboard generated signals will reach
sysinstall again.

Index: install.c
===================================================================
RCS file: /home/ncvs/src/usr.sbin/sysinstall/install.c,v
retrieving revision 1.354
diff -u -t -r1.354 install.c
--- install.c	15 May 2004 05:06:19 -0000	1.354
+++ install.c	2 Aug 2004 18:14:12 -0000
@@ -449,6 +449,7 @@
 {
     pid_t child;
     int waitstatus;
+    sig_t sigttou;
 
     if (!directory_exists("/var/tmp/vi.recover")) {
         if (DITEM_STATUS(Mkdir("/var/tmp/vi.recover")) != DITEM_SUCCESS) {
@@ -470,6 +471,7 @@
         msgConfirm("Couldn't symlink the /etc/ files!  I'm not sure I like this..");
     if (!file_readable(TERMCAP_FILE))
         create_termcap();
+    sigttou = signal(SIGTTOU, SIG_IGN);
     if (strcmp(variable_get(VAR_FIXIT_TTY), "serial") == 0) 
         systemSuspendDialog();  /* must be before the fork() */
     if (!(child = fork())) {
@@ -477,37 +479,34 @@
         struct termios foo;
         extern int login_tty(int);
 
-        ioctl(0, TIOCNOTTY, NULL);
-        for (i = getdtablesize(); i >= 0; --i)
+        for (i = getdtablesize(); i >= 2; --i)
             close(i);
-
-        if (strcmp(variable_get(VAR_FIXIT_TTY), "serial") == 0) 
-            fd = open("/dev/console", O_RDWR);
-        else
-            fd = open("/dev/ttyv3", O_RDWR);
-        ioctl(0, TIOCSCTTY, &fd);
-        dup2(0, 1);
-        dup2(0, 2);
         DebugFD = 2;
-        if (login_tty(fd) == -1)
-            msgDebug("fixit: I can't set the controlling terminal.\n");
-
-        signal(SIGTTOU, SIG_IGN);
-        if (tcgetattr(0, &foo) != -1) {
-            foo.c_cc[VERASE] = '\010';
-            if (tcsetattr(0, TCSANOW, &foo) == -1)
-                msgDebug("fixit shell: Unable to set erase character.\n");
-        }
-        else
-            msgDebug("fixit shell: Unable to get terminal attributes!\n");
-        setenv("PATH", "/bin:/sbin:/usr/bin:/usr/sbin:/stand:"
-               "/mnt2/stand:/mnt2/bin:/mnt2/sbin:/mnt2/usr/bin:/mnt2/usr/sbin", 1);
         if (strcmp(variable_get(VAR_FIXIT_TTY), "serial") == 0) {
             printf("Waiting for fixit shell to exit.\n"
                 "When you are done, type ``exit'' to exit\n"
                 "the fixit shell and be returned here.\n\n");
             fflush(stdout);
+            dup2(1, 2); /* connect stderr to comconsole */
         }
+        else {
+            close(0);
+            fd = open("/dev/ttyv3", O_RDWR);
+            dup2(0, 1);
+            dup2(0, 2);
+            if (login_tty(fd) == -1)
+                msgDebug("fixit: I can't set the controlling terminal.\n");
+
+            if (tcgetattr(0, &foo) != -1) {
+                foo.c_cc[VERASE] = '\010';
+                if (tcsetattr(0, TCSANOW, &foo) == -1)
+                    msgDebug("fixit shell: Unable to set erase character.\n");
+            }
+            else
+                msgDebug("fixit shell: Unable to get terminal attributes!\n");
+        }
+        setenv("PATH", "/bin:/sbin:/usr/bin:/usr/sbin:/stand:"
+               "/mnt2/stand:/mnt2/bin:/mnt2/sbin:/mnt2/usr/bin:/mnt2/usr/sbin", 1);
 
         /* use the .profile from the fixit medium */
         setenv("HOME", "/mnt2", 1);
@@ -524,6 +523,8 @@
                 "the fixit shell and be returned here\n.");
         }
         (void)waitpid(child, &waitstatus, 0);
+        tcsetpgrp(0, getpgrp()); /* go back to foreground group */
+        (void)signal(SIGTTOU, sigttou);
         if (strcmp(variable_get(VAR_FIXIT_TTY), "serial") == 0)
             systemResumeDialog();
     }
Index: system.c
===================================================================
RCS file: /home/ncvs/src/usr.sbin/sysinstall/system.c,v
retrieving revision 1.123
diff -u -t -r1.123 system.c
--- system.c	11 Mar 2004 11:58:16 -0000	1.123
+++ system.c	2 Aug 2004 18:30:45 -0000
@@ -462,6 +462,7 @@
 systemCreateHoloshell(void)
 {
     int waitstatus;
+    sig_t sigttou;
 
     if ((FixItMode || OnVTY) && RunningAsInit) {
 
@@ -485,41 +486,40 @@
             (void) waitpid(ehs_pid, &pstat, WNOHANG);
         }
 
+        sigttou = signal(SIGTTOU, SIG_IGN);
         if (strcmp(variable_get(VAR_FIXIT_TTY), "serial") == 0) 
             systemSuspendDialog();      /* must be before the fork() */
         if ((ehs_pid = fork()) == 0) {
             int i, fd;
             struct termios foo;
             extern int login_tty(int);
-            
-            ioctl(0, TIOCNOTTY, NULL);
-            for (i = getdtablesize(); i >= 0; --i)
+
+            for (i = getdtablesize(); i >= 2; --i)
                 close(i);
-            if (strcmp(variable_get(VAR_FIXIT_TTY), "serial") == 0) 
-                fd = open("/dev/console", O_RDWR);
-            else
-                fd = open("/dev/ttyv3", O_RDWR);
-            ioctl(0, TIOCSCTTY, &fd);
-            dup2(0, 1);
-            dup2(0, 2);
             DebugFD = 2;
-            if (login_tty(fd) == -1)
-                msgDebug("Doctor: I can't set the controlling terminal.\n");
-            signal(SIGTTOU, SIG_IGN);
-            if (tcgetattr(fd, &foo) != -1) {
-                foo.c_cc[VERASE] = '\010';
-                if (tcsetattr(fd, TCSANOW, &foo) == -1)
-                    msgDebug("Doctor: I'm unable to set the erase character.\n");
-            }
-            else
-                msgDebug("Doctor: I'm unable to get the terminal attributes!\n");
             if (strcmp(variable_get(VAR_FIXIT_TTY), "serial") == 0) {
-                printf("Type ``exit'' in this fixit shell to resume sysinstall.\n\n");
+                printf("Type ``exit'' in this fixit shell to resume sysinstall.\n\n");
                 fflush(stdout);
+                dup2(1, 2);     /* connect stderr to comconsole */
+            }
+            else {
+                close(0);
+                fd = open("/dev/ttyv3", O_RDWR);
+                dup2(0, 1);
+                dup2(0, 2);
+                if (login_tty(fd) == -1)
+                    msgDebug("Doctor: I can't set the controlling terminal.\n");
+                if (tcgetattr(fd, &foo) != -1) {
+                    foo.c_cc[VERASE] = '\010';
+                    if (tcsetattr(fd, TCSANOW, &foo) == -1)
+                        msgDebug("Doctor: I'm unable to set the erase character.\n");
+                }
+                else
+                    msgDebug("Doctor: I'm unable to get the terminal attributes!\n");
             }
             execlp("sh", "-sh", 0);
             msgDebug("Was unable to execute sh for Holographic shell!\n");
-            exit(1);
+            _exit(1);
         }
         else {
             if (strcmp(variable_get(VAR_FIXIT_TTY), "standard") == 0) {
@@ -535,8 +535,10 @@
                                                            it serial mode
                                                            since there is no
                                                            virtual console */
+                tcsetpgrp(0, getpgrp()); /* go back to foreground group */
                 systemResumeDialog();
             }
+            (void)signal(SIGTTOU, sigttou);
         }
     }
 }

--=_4vgnvhj5bjc--

>Release-Note:
>Audit-Trail:
>Unformatted:
 This message is in MIME format.
 
 --=_4vgnvhj5bjc
 Content-Type: text/plain; charset="ISO-8859-1"
 Content-Disposition: inline
 Content-Transfer-Encoding: 7bit
 
 
 --=_4vgnvhj5bjc
 Content-Type: text/plain; charset="ISO-8859-1"; name="sysinstall.pr"
 Content-Disposition: inline; filename="sysinstall.pr"
 Content-Transfer-Encoding: 7bit
 
 


More information about the freebsd-bugs mailing list