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. 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. --=_4vgnvhj5bjc----rvBrfwv0bxPCAGwG134BKeT1Q1Hym6HC4JrqokY1ReTpVM50 Content-Type: text/plain; name="file.diff" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="file.diff" 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); } } } 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).
Responsible Changed From-To: freebsd-bugs->freebsd-qa Over to maintainer(s).
Responsible Changed From-To: freebsd-bugs->freebsd-sysinstall Over to maintainer(s)
sysinstall has been replaced by bsdinstall in FreeBSD 9.x. Closing.