Index: head/usr.sbin/sysinstall/main.c =================================================================== --- head/usr.sbin/sysinstall/main.c (revision 186130) +++ head/usr.sbin/sysinstall/main.c (revision 186131) @@ -1,215 +1,214 @@ /* * The new sysinstall program. * * This is probably the last attempt in the `sysinstall' line, the next * generation being slated for what's essentially a complete rewrite. * * $FreeBSD$ * * Copyright (c) 1995 * Jordan Hubbard. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer, * verbatim and that no modifications are made prior to this * point in the file. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY JORDAN HUBBARD ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL JORDAN HUBBARD OR HIS PETS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * */ #include "sysinstall.h" #include #include #include #include const char *StartName; /* Initial contents of argv[0] */ const char *ProgName = "sysinstall"; static void screech(int sig) { msgDebug("\007Signal %d caught! That's bad!\n", sig); longjmp(BailOut, sig); } int main(int argc, char **argv) { int choice, scroll, curr, max, status; char titlestr[80], *arch, *osrel, *ostype; struct rlimit rlim; /* Record name to be able to restart */ StartName = argv[0]; /* Catch fatal signals and complain about them if running as init */ if (getpid() == 1) { signal(SIGBUS, screech); signal(SIGSEGV, screech); } signal(SIGPIPE, SIG_IGN); /* We don't work too well when running as non-root anymore */ if (geteuid() != 0) { fprintf(stderr, "Error: This utility should only be run as root.\n"); return 1; } /* * Given what it does sysinstall (and stuff sysinstall runs like * pkg_add) shouldn't be subject to process limits. Better to just * let them have what they think they need than have them blow * their brains out during an install (in sometimes strange and * mysterious ways). */ rlim.rlim_cur = rlim.rlim_max = RLIM_INFINITY; if (setrlimit(RLIMIT_DATA, &rlim) != 0) fprintf(stderr, "Warning: setrlimit() of datasize failed.\n"); if (setrlimit(RLIMIT_STACK, &rlim) != 0) fprintf(stderr, "Warning: setrlimit() of stacksize failed.\n"); #ifdef PC98 { /* XXX */ char *p = getenv("TERM"); if (p && strcmp(p, "cons25") == 0) setenv("TERM", "cons25w", 1); } #endif /* Set up whatever things need setting up */ systemInitialize(argc, argv); /* Set default flag and variable values */ installVarDefaults(NULL); /* only when multi-user is it reasonable to do this here */ if (!RunningAsInit) installEnvironment(); if (argc > 1 && !strcmp(argv[1], "-fake")) { variable_set2(VAR_DEBUG, "YES", 0); Fake = TRUE; msgConfirm("I'll be just faking it from here on out, OK?"); } if (argc > 1 && !strcmp(argv[1], "-restart")) Restarting = TRUE; /* Try to preserve our scroll-back buffer */ if (OnVTY) { for (curr = 0; curr < 25; curr++) putchar('\n'); } /* Move stderr aside */ if (DebugFD) dup2(DebugFD, 2); /* Initialize driver modules, if we haven't already done so (ie, the user hit Ctrl-C -> Restart. */ if (!pvariable_get("modulesInitialize")) { moduleInitialize(); pvariable_set("modulesInitialize=1"); } /* Initialize PC Card, if we haven't already done so. */ #ifdef PCCARD_ARCH if (!variable_cmp(VAR_SKIP_PCCARD, "YES") && variable_get(VAR_SKIP_PCCARD)!=1 && !pvariable_get("pccardInitialize")) { pccardInitialize(); pvariable_set("pccardInitialize=1"); } #endif /* Probe for all relevant devices on the system */ deviceGetAll(); /* Prompt for the driver floppy if appropriate. */ if (!pvariable_get("driverFloppyCheck")) { driverFloppyCheck(); pvariable_set("driverFloppyCheck=1"); } /* First, see if we have any arguments to process (and argv[0] counts if it's not "sysinstall") */ if (!RunningAsInit) { int i, start_arg; if (!strstr(argv[0], "sysinstall")) start_arg = 0; else if (Fake || Restarting) start_arg = 2; else start_arg = 1; for (i = start_arg; i < argc; i++) { if (DITEM_STATUS(dispatchCommand(argv[i])) != DITEM_SUCCESS) systemShutdown(1); } if (argc > start_arg) systemShutdown(0); } else dispatch_load_file_int(TRUE); status = setjmp(BailOut); if (status) { msgConfirm("A signal %d was caught - I'm saving what I can and shutting\n" "down. If you can reproduce the problem, please turn Debug on\n" "in the Options menu for the extra information it provides\n" "in debugging problems like this.", status); systemShutdown(status); } /* Get user's country and keymap */ if (RunningAsInit) configCountry(NULL); /* Add FreeBSD version info to the menu title */ arch = getsysctlbyname("hw.machine_arch"); osrel = getsysctlbyname("kern.osrelease"); ostype = getsysctlbyname("kern.ostype"); snprintf(titlestr, sizeof(titlestr), "%s/%s %s - %s", ostype, arch, osrel, MenuInitial.title); free(arch); free(osrel); free(ostype); MenuInitial.title = titlestr; /* Begin user dialog at outer menu */ dialog_clear(); while (1) { choice = scroll = curr = max = 0; dmenuOpen(&MenuInitial, &choice, &scroll, &curr, &max, TRUE); if (getpid() != 1 #if defined(__sparc64__) || !msgNoYes("Are you sure you wish to exit? The system will halt.") #else - || !msgNoYes("Are you sure you wish to exit? The system will reboot\n" - "(be sure to remove any floppies/CDs/DVDs from the drives).") + || !msgNoYes("Are you sure you wish to exit? The system will reboot.") #endif ) break; } /* Say goodnight, Gracie */ systemShutdown(0); return 0; /* We should never get here */ } Index: head/usr.sbin/sysinstall/system.c =================================================================== --- head/usr.sbin/sysinstall/system.c (revision 186130) +++ head/usr.sbin/sysinstall/system.c (revision 186131) @@ -1,544 +1,549 @@ /* * The new sysinstall program. * * This is probably the last program in the `sysinstall' line - the next * generation being essentially a complete rewrite. * * $FreeBSD$ * * Jordan Hubbard * * My contributions are in the public domain. * * Parts of this file are also blatantly stolen from Poul-Henning Kamp's * previous version of sysinstall, and as such fall under his "BEERWARE license" * so buy him a beer if you like it! Buy him a beer for me, too! * Heck, get him completely drunk and send me pictures! :-) */ #include "sysinstall.h" #include #include #include #include #include #include #include #include #include #include #include /* Where we stick our temporary expanded doc file */ #define DOC_TMP_DIR "/tmp/.doc" #define DOC_TMP_FILE "/tmp/.doc/doc.tmp" static pid_t ehs_pid; /* * Handle interrupt signals - this probably won't work in all cases * due to our having bogotified the internal state of dialog or curses, * but we'll give it a try. */ static int intr_continue(dialogMenuItem *self) { return DITEM_LEAVE_MENU; } static int intr_reboot(dialogMenuItem *self) { systemShutdown(-1); /* NOTREACHED */ return 0; } static int intr_restart(dialogMenuItem *self) { int ret, fd, fdmax; mediaClose(); free_variables(); fdmax = getdtablesize(); for (fd = 3; fd < fdmax; fd++) close(fd); ret = execl(StartName, StartName, "-restart", (char *)NULL); msgDebug("execl failed (%s)\n", strerror(errno)); /* NOTREACHED */ return -1; } static dialogMenuItem intrmenu[] = { { "Abort", "Abort the installation", NULL, intr_reboot }, { "Restart", "Restart the installation program", NULL, intr_restart }, { "Continue", "Continue the installation", NULL, intr_continue }, }; static void handle_intr(int sig) { WINDOW *save = savescr(); use_helpline(NULL); use_helpfile(NULL); if (OnVTY) { ioctl(0, VT_ACTIVATE, 1); /* Switch back */ msgInfo(NULL); } (void)dialog_menu("Installation interrupt", "Do you want to abort the installation?", -1, -1, 3, -3, intrmenu, NULL, NULL, NULL); restorescr(save); } #if 0 /* * Harvest children if we are init. */ static void reap_children(int sig) { int errbak = errno; while (waitpid(-1, NULL, WNOHANG) > 0) ; errno = errbak; } #endif /* Expand a file into a convenient location, nuking it each time */ static char * expand(char *fname) { char *unzipper = RunningAsInit ? "/stand/" UNZIPPER : "/usr/bin/" UNZIPPER; if (!directory_exists(DOC_TMP_DIR)) { Mkdir(DOC_TMP_DIR); if (chown(DOC_TMP_DIR, 0, 0) < 0) return NULL; if (chmod(DOC_TMP_DIR, S_IRWXU) < 0) return NULL; } else unlink(DOC_TMP_FILE); if (!file_readable(fname) || vsystem("%s < %s > %s", unzipper, fname, DOC_TMP_FILE)) return NULL; return DOC_TMP_FILE; } /* Initialize system defaults */ void systemInitialize(int argc, char **argv) { size_t i; int boothowto; sigset_t signalset; signal(SIGINT, SIG_IGN); globalsInit(); i = sizeof(boothowto); if (!sysctlbyname("debug.boothowto", &boothowto, &i, NULL, 0) && (i == sizeof(boothowto)) && (boothowto & RB_VERBOSE)) variable_set2(VAR_DEBUG, "YES", 0); /* Are we running as init? */ if (getpid() == 1) { struct ufs_args ufs_args; int fd; RunningAsInit = 1; setsid(); close(0); fd = open("/dev/ttyv0", O_RDWR); if (fd == -1) { fd = open("/dev/console", O_RDWR); /* fallback */ variable_set2(VAR_FIXIT_TTY, "serial", 0); /* give fixit a hint */ } else OnVTY = TRUE; /* * To make _sure_ we're on a VTY and don't have /dev/console switched * away to a serial port or something, attempt to set the cursor appearance. */ if (OnVTY) { int fd2, type; type = 0; /* normal */ if ((fd2 = open("/dev/console", O_RDWR)) != -1) { if (ioctl(fd2, CONS_CURSORTYPE, &type) == -1) { OnVTY = FALSE; variable_set2(VAR_FIXIT_TTY, "serial", 0); /* Tell Fixit the console type */ close(fd); close(fd2); open("/dev/console", O_RDWR); } else close(fd2); } } close(1); dup(0); close(2); dup(0); printf("%s running as init on %s\n", argv[0], OnVTY ? "vty0" : "serial console"); ioctl(0, TIOCSCTTY, (char *)NULL); setlogin("root"); setenv("PATH", "/stand:/bin:/sbin:/usr/sbin:/usr/bin:/mnt/bin:/mnt/sbin:/mnt/usr/sbin:/mnt/usr/bin:/usr/X11R6/bin", 1); setbuf(stdin, 0); setbuf(stderr, 0); #if 0 signal(SIGCHLD, reap_children); #endif memset(&ufs_args, 0, sizeof(ufs_args)); mount("ufs", "/", MNT_UPDATE, &ufs_args); } else { char hname[256]; /* Initalize various things for a multi-user environment */ if (!gethostname(hname, sizeof hname)) variable_set2(VAR_HOSTNAME, hname, 0); } if (set_termcap() == -1) { printf("Can't find terminal entry\n"); exit(-1); } /* XXX - libdialog has particularly bad return value checking */ init_dialog(); /* If we haven't crashed I guess dialog is running ! */ DialogActive = TRUE; /* Make sure HOME is set for those utilities that need it */ if (!getenv("HOME")) setenv("HOME", "/", 1); signal(SIGINT, handle_intr); /* * Make sure we can be interrupted even if we were re-executed * from an interrupt. */ sigemptyset(&signalset); sigaddset(&signalset, SIGINT); sigprocmask(SIG_UNBLOCK, &signalset, NULL); (void)vsystem("rm -rf %s", DOC_TMP_DIR); } /* Close down and prepare to exit */ void systemShutdown(int status) { /* If some media is open, close it down */ - if (status >=0) - mediaClose(); + if (status >=0) { + if (mediaDevice != NULL && mediaDevice->type == DEVICE_TYPE_CDROM) { + mediaClose(); + msgConfirm("Be sure to remove the media from the drive."); + } else + mediaClose(); + } /* write out any changes to rc.conf .. */ configRC_conf(); /* Shut down the dialog library */ if (DialogActive) { end_dialog(); DialogActive = FALSE; } /* Shut down curses */ endwin(); /* If we have a temporary doc dir lying around, nuke it */ (void)vsystem("rm -rf %s", DOC_TMP_DIR); /* REALLY exit! */ if (RunningAsInit) { /* Put the console back */ ioctl(0, VT_ACTIVATE, 2); #if defined(__sparc64__) reboot(RB_HALT); #else reboot(RB_AUTOBOOT); #endif } else exit(status); } /* Run some general command */ int systemExecute(char *command) { int status; struct termios foo; WINDOW *w = savescr(); dialog_clear(); dialog_update(); end_dialog(); DialogActive = FALSE; if (tcgetattr(0, &foo) != -1) { foo.c_cc[VERASE] = '\010'; tcsetattr(0, TCSANOW, &foo); } if (!Fake) status = system(command); else { status = 0; msgDebug("systemExecute: Faked execution of `%s'\n", command); } DialogActive = TRUE; restorescr(w); return status; } /* suspend/resume libdialog/curses screen */ static WINDOW *oldW; void systemSuspendDialog(void) { oldW = savescr(); dialog_clear(); dialog_update(); end_dialog(); DialogActive = FALSE; } void systemResumeDialog(void) { DialogActive = TRUE; restorescr(oldW); } /* Display a help file in a filebox */ int systemDisplayHelp(char *file) { char *fname = NULL; char buf[FILENAME_MAX]; int ret = 0; WINDOW *w = savescr(); fname = systemHelpFile(file, buf); if (!fname) { snprintf(buf, FILENAME_MAX, "The %s file is not provided on this particular floppy image.", file); use_helpfile(NULL); use_helpline(NULL); dialog_mesgbox("Sorry!", buf, -1, -1); ret = 1; } else { use_helpfile(NULL); use_helpline(NULL); dialog_textbox(file, fname, LINES, COLS); } restorescr(w); return ret; } char * systemHelpFile(char *file, char *buf) { if (!file) return NULL; if (file[0] == '/') return file; snprintf(buf, FILENAME_MAX, "/stand/help/%s.hlp.gz", file); if (file_readable(buf)) return expand(buf); snprintf(buf, FILENAME_MAX, "/stand/help/%s.hlp", file); if (file_readable(buf)) return expand(buf); snprintf(buf, FILENAME_MAX, "/stand/help/%s.TXT.gz", file); if (file_readable(buf)) return expand(buf); snprintf(buf, FILENAME_MAX, "/stand/help/%s.TXT", file); if (file_readable(buf)) return expand(buf); snprintf(buf, FILENAME_MAX, "/usr/src/usr.sbin/%s/help/%s.hlp", ProgName, file); if (file_readable(buf)) return buf; snprintf(buf, FILENAME_MAX, "/usr/src/usr.sbin/%s/help/%s.TXT", ProgName, file); if (file_readable(buf)) return buf; return NULL; } void systemChangeTerminal(char *color, const u_char c_term[], char *mono, const u_char m_term[]) { if (OnVTY) { int setupterm(char *color, int, int *); if (ColorDisplay) { setenv("TERM", color, 1); setenv("TERMCAP", c_term, 1); reset_shell_mode(); setterm(color); cbreak(); noecho(); } else { setenv("TERM", mono, 1); setenv("TERMCAP", m_term, 1); reset_shell_mode(); setterm(mono); cbreak(); noecho(); } } clear(); refresh(); dialog_clear(); } int vsystem(char *fmt, ...) { va_list args; int pstat; pid_t pid; int omask; sig_t intsave, quitsave; char *cmd; int i; struct stat sb; cmd = (char *)alloca(FILENAME_MAX); cmd[0] = '\0'; va_start(args, fmt); vsnprintf(cmd, FILENAME_MAX, fmt, args); va_end(args); omask = sigblock(sigmask(SIGCHLD)); if (Fake) { msgDebug("vsystem: Faked execution of `%s'\n", cmd); return 0; } if (isDebug()) msgDebug("Executing command `%s'\n", cmd); pid = fork(); if (pid == -1) { (void)sigsetmask(omask); i = 127; } else if (!pid) { /* Junior */ (void)sigsetmask(omask); if (DebugFD != -1) { dup2(DebugFD, 0); dup2(DebugFD, 1); dup2(DebugFD, 2); } else { close(1); open("/dev/null", O_WRONLY); dup2(1, 2); } if (stat("/stand/sh", &sb) == 0) execl("/stand/sh", "/stand/sh", "-c", cmd, (char *)NULL); else execl("/bin/sh", "/bin/sh", "-c", cmd, (char *)NULL); exit(1); } else { intsave = signal(SIGINT, SIG_IGN); quitsave = signal(SIGQUIT, SIG_IGN); pid = waitpid(pid, &pstat, 0); (void)sigsetmask(omask); (void)signal(SIGINT, intsave); (void)signal(SIGQUIT, quitsave); i = (pid == -1) ? -1 : WEXITSTATUS(pstat); if (isDebug()) msgDebug("Command `%s' returns status of %d\n", cmd, i); } return i; } void systemCreateHoloshell(void) { int waitstatus; if ((FixItMode || OnVTY) && RunningAsInit) { if (ehs_pid != 0) { int pstat; if (kill(ehs_pid, 0) == 0) { if (msgNoYes("There seems to be an emergency holographic shell\n" "already running on VTY 4.\n\n" "Kill it and start a new one?")) return; /* try cleaning up as much as possible */ (void) kill(ehs_pid, SIGHUP); sleep(1); (void) kill(ehs_pid, SIGKILL); } /* avoid too many zombies */ (void) waitpid(ehs_pid, &pstat, WNOHANG); } 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) 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"); fflush(stdout); } execlp("sh", "-sh", 0); msgDebug("Was unable to execute sh for Holographic shell!\n"); exit(1); } else { if (strcmp(variable_get(VAR_FIXIT_TTY), "standard") == 0) { WINDOW *w = savescr(); msgNotify("Starting an emergency holographic shell on VTY4"); sleep(2); restorescr(w); } else { (void)waitpid(ehs_pid, &waitstatus, 0); /* we only wait for shell to finish in serial mode since there is no virtual console */ systemResumeDialog(); } } } }