18097Sjkh/*
28097Sjkh * The new sysinstall program.
38097Sjkh *
48097Sjkh * This is probably the last program in the `sysinstall' line - the next
58097Sjkh * generation being essentially a complete rewrite.
68097Sjkh *
750479Speter * $FreeBSD$
88097Sjkh *
98097Sjkh * Jordan Hubbard
108097Sjkh *
118097Sjkh * My contributions are in the public domain.
128097Sjkh *
13155347Sceri * Parts of this file are also blatantly stolen from Poul-Henning Kamp's
148629Sjkh * previous version of sysinstall, and as such fall under his "BEERWARE license"
158629Sjkh * so buy him a beer if you like it!  Buy him a beer for me, too!
168629Sjkh * Heck, get him completely drunk and send me pictures! :-)
178097Sjkh */
188097Sjkh
198097Sjkh#include "sysinstall.h"
208097Sjkh#include <signal.h>
2150917Sjkh#include <termios.h>
22123686Sjhb#include <sys/param.h>
238097Sjkh#include <sys/reboot.h>
2466834Sphk#include <sys/consio.h>
258097Sjkh#include <sys/fcntl.h>
268097Sjkh#include <sys/ioctl.h>
27123686Sjhb#include <sys/mount.h>
2842392Sjkh#include <sys/stat.h>
2958547Sjhb#include <sys/sysctl.h>
30123686Sjhb#include <ufs/ufs/ufsmount.h>
318097Sjkh
3216975Sjkh
3316975Sjkh/* Where we stick our temporary expanded doc file */
3442392Sjkh#define	DOC_TMP_DIR	"/tmp/.doc"
3542392Sjkh#define	DOC_TMP_FILE	"/tmp/.doc/doc.tmp"
3616975Sjkh
3721010Sjkhstatic pid_t ehs_pid;
3821010Sjkh
398302Sjkh/*
408302Sjkh * Handle interrupt signals - this probably won't work in all cases
418302Sjkh * due to our having bogotified the internal state of dialog or curses,
428302Sjkh * but we'll give it a try.
438302Sjkh */
4467862Seivindstatic int
4567862Seivindintr_continue(dialogMenuItem *self)
4667862Seivind{
4783440Smurray    return DITEM_LEAVE_MENU;
4867862Seivind}
4967862Seivind
5067862Seivindstatic int
5167862Seivindintr_reboot(dialogMenuItem *self)
5267862Seivind{
5383440Smurray    systemShutdown(-1);
5483440Smurray    /* NOTREACHED */
5583440Smurray    return 0;
5667862Seivind}
5767862Seivind
5867862Seivindstatic int
5967862Seivindintr_restart(dialogMenuItem *self)
6067862Seivind{
6184152Smurray    int ret, fd, fdmax;
62211417Sbrucec    char *arg;
6384152Smurray
6484152Smurray    mediaClose();
6583820Smurray    free_variables();
6684152Smurray    fdmax = getdtablesize();
6784152Smurray    for (fd = 3; fd < fdmax; fd++)
6884152Smurray	close(fd);
69211417Sbrucec
70211417Sbrucec    if (RunningAsInit)
71211417Sbrucec	    arg = "-restart -fakeInit";
72211417Sbrucec    else
73211417Sbrucec	    arg = "-restart";
74211417Sbrucec
75211417Sbrucec    ret = execl(StartName, StartName, arg, NULL);
7683820Smurray    msgDebug("execl failed (%s)\n", strerror(errno));
7783440Smurray    /* NOTREACHED */
7883440Smurray    return -1;
7967862Seivind}
8067862Seivind
8167862Seivindstatic dialogMenuItem intrmenu[] = {
8283440Smurray    { "Abort",   "Abort the installation", NULL, intr_reboot },
8383440Smurray    { "Restart", "Restart the installation program", NULL, intr_restart },
8483440Smurray    { "Continue", "Continue the installation", NULL, intr_continue },
8567862Seivind};
8667862Seivind
8767862Seivind
888097Sjkhstatic void
898097Sjkhhandle_intr(int sig)
908097Sjkh{
9118619Sjkh    WINDOW *save = savescr();
9218619Sjkh
9367862Seivind    use_helpline(NULL);
9467862Seivind    use_helpfile(NULL);
9567862Seivind    if (OnVTY) {
9667862Seivind        ioctl(0, VT_ACTIVATE, 1);       /* Switch back */
9767862Seivind        msgInfo(NULL);
9867862Seivind    }
9967862Seivind    (void)dialog_menu("Installation interrupt",
10067862Seivind		     "Do you want to abort the installation?",
10167862Seivind		     -1, -1, 3, -3, intrmenu, NULL, NULL, NULL);
10267862Seivind    restorescr(save);
1038097Sjkh}
1048097Sjkh
105156119Sjhb#if 0
10683142Smurray/*
10783142Smurray * Harvest children if we are init.
10883142Smurray */
10983142Smurraystatic void
11083142Smurrayreap_children(int sig)
11183142Smurray{
11283142Smurray    int errbak = errno;
11383440Smurray
11483440Smurray    while (waitpid(-1, NULL, WNOHANG) > 0)
11583142Smurray	;
11683142Smurray    errno = errbak;
11783142Smurray}
118156119Sjhb#endif
11983142Smurray
12016975Sjkh/* Expand a file into a convenient location, nuking it each time */
12116975Sjkhstatic char *
12216975Sjkhexpand(char *fname)
12316975Sjkh{
124174473Sobrien    char *unzipper = RunningAsInit ? "/stand/" UNZIPPER : "/usr/bin/" UNZIPPER;
12539814Sjkh
12642392Sjkh    if (!directory_exists(DOC_TMP_DIR)) {
12742392Sjkh	Mkdir(DOC_TMP_DIR);
12842392Sjkh	if (chown(DOC_TMP_DIR, 0, 0) < 0)
12942392Sjkh	    return NULL;
13042392Sjkh	if (chmod(DOC_TMP_DIR, S_IRWXU) < 0)
13142392Sjkh	    return NULL;
13242392Sjkh    }
13342392Sjkh    else
13442392Sjkh	unlink(DOC_TMP_FILE);
135174473Sobrien    if (!file_readable(fname) || vsystem("%s < %s > %s", unzipper, fname,
136174473Sobrien	DOC_TMP_FILE))
13716975Sjkh	return NULL;
13816975Sjkh    return DOC_TMP_FILE;
13916975Sjkh}
14016975Sjkh
1418097Sjkh/* Initialize system defaults */
1428097Sjkhvoid
1438097SjkhsystemInitialize(int argc, char **argv)
1448097Sjkh{
14583843Smurray    size_t i;
14683843Smurray    int boothowto;
14767862Seivind    sigset_t signalset;
14848929Sjkh
1498097Sjkh    signal(SIGINT, SIG_IGN);
1508097Sjkh    globalsInit();
1518097Sjkh
15257490Sjkh    i = sizeof(boothowto);
153126844Sbde    if (!sysctlbyname("debug.boothowto", &boothowto, &i, NULL, 0) &&
15457490Sjkh        (i == sizeof(boothowto)) && (boothowto & RB_VERBOSE))
15557490Sjkh	variable_set2(VAR_DEBUG, "YES", 0);
15657490Sjkh
1578097Sjkh    /* Are we running as init? */
158211417Sbrucec    if (RunningAsInit) {
159123686Sjhb	struct ufs_args ufs_args;
16085366Sjhb	int fd;
16127798Sjkh
1628097Sjkh	setsid();
16318502Spst	close(0);
16427798Sjkh	fd = open("/dev/ttyv0", O_RDWR);
16568012Sjkh	if (fd == -1) {
16627798Sjkh	    fd = open("/dev/console", O_RDWR);	/* fallback */
16768012Sjkh	    variable_set2(VAR_FIXIT_TTY, "serial", 0); /* give fixit a hint */
16868012Sjkh	} else
16918502Spst	    OnVTY = TRUE;
17027798Sjkh	/*
17127798Sjkh	 * To make _sure_ we're on a VTY and don't have /dev/console switched
17227798Sjkh	 * away to a serial port or something, attempt to set the cursor appearance.
17327798Sjkh	 */
17427798Sjkh	if (OnVTY) {
17585366Sjhb	    int fd2, type;
17627798Sjkh
17785366Sjhb	    type = 0;	/* normal */
17827798Sjkh	    if ((fd2 = open("/dev/console", O_RDWR)) != -1) {
17927798Sjkh		if (ioctl(fd2, CONS_CURSORTYPE, &type) == -1) {
18027798Sjkh		    OnVTY = FALSE;
18168012Sjkh		    variable_set2(VAR_FIXIT_TTY, "serial", 0); /* Tell Fixit
18268012Sjkh								  the console
18368012Sjkh								  type */
18427798Sjkh		    close(fd); close(fd2);
18527798Sjkh		    open("/dev/console", O_RDWR);
18627798Sjkh		}
18727798Sjkh		else
18827798Sjkh		    close(fd2);
18927798Sjkh	    }
19027798Sjkh	}
1919202Srgrimes	close(1); dup(0);
1929202Srgrimes	close(2); dup(0);
19327798Sjkh	printf("%s running as init on %s\n", argv[0], OnVTY ? "vty0" : "serial console");
19450780Sjkh	ioctl(0, TIOCSCTTY, (char *)NULL);
1958097Sjkh	setlogin("root");
196186152Skensmith	setenv("PATH", "/stand:/bin:/sbin:/usr/sbin:/usr/bin:/mnt/bin:/mnt/sbin:/mnt/usr/sbin:/mnt/usr/bin", 1);
1978097Sjkh	setbuf(stdin, 0);
1988097Sjkh	setbuf(stderr, 0);
19985847Sjkh#if 0
20083142Smurray	signal(SIGCHLD, reap_children);
20185847Sjkh#endif
202123686Sjhb	memset(&ufs_args, 0, sizeof(ufs_args));
203123686Sjhb	mount("ufs", "/", MNT_UPDATE, &ufs_args);
2048097Sjkh    }
20520335Sjkh    else {
20620335Sjkh	char hname[256];
2078097Sjkh
20820335Sjkh	/* Initalize various things for a multi-user environment */
20920335Sjkh	if (!gethostname(hname, sizeof hname))
21044017Sjkh	    variable_set2(VAR_HOSTNAME, hname, 0);
21120335Sjkh    }
21220335Sjkh
2138418Sjkh    if (set_termcap() == -1) {
2148418Sjkh	printf("Can't find terminal entry\n");
2158418Sjkh	exit(-1);
2168418Sjkh    }
2178097Sjkh
2188097Sjkh    /* XXX - libdialog has particularly bad return value checking */
2198097Sjkh    init_dialog();
22015383Sjkh
2218097Sjkh    /* If we haven't crashed I guess dialog is running ! */
2228097Sjkh    DialogActive = TRUE;
2238097Sjkh
22412661Speter    /* Make sure HOME is set for those utilities that need it */
22512661Speter    if (!getenv("HOME"))
22612661Speter	setenv("HOME", "/", 1);
2278097Sjkh    signal(SIGINT, handle_intr);
22867862Seivind    /*
22967862Seivind     * Make sure we can be interrupted even if we were re-executed
23067862Seivind     * from an interrupt.
23167862Seivind     */
23267862Seivind    sigemptyset(&signalset);
23367862Seivind    sigaddset(&signalset, SIGINT);
23467862Seivind    sigprocmask(SIG_UNBLOCK, &signalset, NULL);
23567862Seivind
23642392Sjkh    (void)vsystem("rm -rf %s", DOC_TMP_DIR);
2378097Sjkh}
2388097Sjkh
2398097Sjkh/* Close down and prepare to exit */
2408097Sjkhvoid
24115788SjkhsystemShutdown(int status)
2428097Sjkh{
24315788Sjkh    /* If some media is open, close it down */
244186131Skensmith    if (status >=0) {
245186131Skensmith	if (mediaDevice != NULL && mediaDevice->type == DEVICE_TYPE_CDROM) {
246186131Skensmith	    mediaClose();
247186131Skensmith	    msgConfirm("Be sure to remove the media from the drive.");
248186131Skensmith	} else
249186131Skensmith	    mediaClose();
250186131Skensmith    }
25115788Sjkh
25225251Sjkh    /* write out any changes to rc.conf .. */
25343811Sjkh    configRC_conf();
25422549Sjkh
25515788Sjkh    /* Shut down the dialog library */
2568097Sjkh    if (DialogActive) {
2578097Sjkh	end_dialog();
2588097Sjkh	DialogActive = FALSE;
2598097Sjkh    }
26015788Sjkh
26115788Sjkh    /* Shut down curses */
26215788Sjkh    endwin();
26315788Sjkh
26442392Sjkh    /* If we have a temporary doc dir lying around, nuke it */
26542392Sjkh    (void)vsystem("rm -rf %s", DOC_TMP_DIR);
26616975Sjkh
2678097Sjkh    /* REALLY exit! */
2688774Sjkh    if (RunningAsInit) {
2698774Sjkh	/* Put the console back */
2709202Srgrimes	ioctl(0, VT_ACTIVATE, 2);
271186075Skensmith#if defined(__sparc64__)
27242386Sjkh	reboot(RB_HALT);
27342386Sjkh#else
274166927Sceri	reboot(RB_AUTOBOOT);
27542386Sjkh#endif
2768774Sjkh    }
2778174Sjkh    else
27815788Sjkh	exit(status);
2798097Sjkh}
2808097Sjkh
2818174Sjkh/* Run some general command */
2828097Sjkhint
2838097SjkhsystemExecute(char *command)
2848097Sjkh{
2858097Sjkh    int status;
28612661Speter    struct termios foo;
28754587Sjkh    WINDOW *w = savescr();
2888097Sjkh
28954587Sjkh    dialog_clear();
2908097Sjkh    dialog_update();
2918097Sjkh    end_dialog();
2928097Sjkh    DialogActive = FALSE;
29312661Speter    if (tcgetattr(0, &foo) != -1) {
29412661Speter	foo.c_cc[VERASE] = '\010';
29512661Speter	tcsetattr(0, TCSANOW, &foo);
29612661Speter    }
29715439Sjkh    if (!Fake)
29815439Sjkh	status = system(command);
29915439Sjkh    else {
30015439Sjkh	status = 0;
30115439Sjkh	msgDebug("systemExecute:  Faked execution of `%s'\n", command);
30215439Sjkh    }
3038097Sjkh    DialogActive = TRUE;
30454587Sjkh    restorescr(w);
3058097Sjkh    return status;
3068097Sjkh}
3078097Sjkh
30863404Sobrien/* suspend/resume libdialog/curses screen */
30963404Sobrienstatic    WINDOW *oldW;
31063404Sobrien
31163404Sobrienvoid
31263404SobriensystemSuspendDialog(void)
31363404Sobrien{
31463404Sobrien
31563404Sobrien    oldW  = savescr();
31663404Sobrien    dialog_clear();
31763404Sobrien    dialog_update();
31863404Sobrien    end_dialog();
31963404Sobrien    DialogActive = FALSE;
32063404Sobrien}
32163404Sobrien
32263404Sobrienvoid
32363404SobriensystemResumeDialog(void)
32463404Sobrien{
32563404Sobrien
32663404Sobrien    DialogActive = TRUE;
32763404Sobrien    restorescr(oldW);
32863404Sobrien}
32963404Sobrien
33012661Speter/* Display a help file in a filebox */
3318174Sjkhint
33212661SpetersystemDisplayHelp(char *file)
3338174Sjkh{
3348208Sjkh    char *fname = NULL;
3358208Sjkh    char buf[FILENAME_MAX];
33615393Sjkh    int ret = 0;
33754587Sjkh    WINDOW *w = savescr();
33854587Sjkh
3398208Sjkh    fname = systemHelpFile(file, buf);
3408174Sjkh    if (!fname) {
3418174Sjkh	snprintf(buf, FILENAME_MAX, "The %s file is not provided on this particular floppy image.", file);
3428208Sjkh	use_helpfile(NULL);
3438208Sjkh	use_helpline(NULL);
3448208Sjkh	dialog_mesgbox("Sorry!", buf, -1, -1);
34515393Sjkh	ret = 1;
3468174Sjkh    }
3478174Sjkh    else {
3488208Sjkh	use_helpfile(NULL);
3498208Sjkh	use_helpline(NULL);
3508174Sjkh	dialog_textbox(file, fname, LINES, COLS);
3518174Sjkh    }
35254587Sjkh    restorescr(w);
35315393Sjkh    return ret;
3548174Sjkh}
3558208Sjkh
3568208Sjkhchar *
3578208SjkhsystemHelpFile(char *file, char *buf)
3588208Sjkh{
3598208Sjkh    if (!file)
3608208Sjkh	return NULL;
36157490Sjkh    if (file[0] == '/')
36257490Sjkh	return file;
36316975Sjkh    snprintf(buf, FILENAME_MAX, "/stand/help/%s.hlp.gz", file);
36410882Speter    if (file_readable(buf))
36516975Sjkh	return expand(buf);
366101562Sjhay    snprintf(buf, FILENAME_MAX, "/stand/help/%s.hlp", file);
367101562Sjhay    if (file_readable(buf))
368101562Sjhay	return expand(buf);
36940841Sjkh    snprintf(buf, FILENAME_MAX, "/stand/help/%s.TXT.gz", file);
37040841Sjkh    if (file_readable(buf))
37140841Sjkh	return expand(buf);
372101562Sjhay    snprintf(buf, FILENAME_MAX, "/stand/help/%s.TXT", file);
373101562Sjhay    if (file_readable(buf))
374101562Sjhay	return expand(buf);
375178946Sobrien    snprintf(buf, FILENAME_MAX, "/usr/src/usr.sbin/%s/help/%s.hlp", ProgName,
376178941Sobrien	file);
37715788Sjkh    if (file_readable(buf))
37815788Sjkh	return buf;
379178946Sobrien    snprintf(buf, FILENAME_MAX, "/usr/src/usr.sbin/%s/help/%s.TXT", ProgName,
380178941Sobrien	file);
38140841Sjkh    if (file_readable(buf))
38240841Sjkh	return buf;
3838829Sphk    return NULL;
3848208Sjkh}
3858278Sjkh
3868278Sjkhvoid
3878302SjkhsystemChangeTerminal(char *color, const u_char c_term[],
3888302Sjkh		     char *mono, const u_char m_term[])
3898278Sjkh{
3908601Sjkh    if (OnVTY) {
39154473Sjkh	int setupterm(char *color, int, int *);
39254473Sjkh
3938302Sjkh	if (ColorDisplay) {
3948302Sjkh	    setenv("TERM", color, 1);
3958302Sjkh	    setenv("TERMCAP", c_term, 1);
3968601Sjkh	    reset_shell_mode();
3978601Sjkh	    setterm(color);
3988601Sjkh	    cbreak(); noecho();
3998302Sjkh	}
4008302Sjkh	else {
4018302Sjkh	    setenv("TERM", mono, 1);
4028302Sjkh	    setenv("TERMCAP", m_term, 1);
4038601Sjkh	    reset_shell_mode();
4048601Sjkh	    setterm(mono);
4058601Sjkh	    cbreak(); noecho();
4068302Sjkh	}
4078302Sjkh    }
4089202Srgrimes    clear();
4099202Srgrimes    refresh();
4109202Srgrimes    dialog_clear();
4118278Sjkh}
4128278Sjkh
4138658Sphkint
4148658Sphkvsystem(char *fmt, ...)
4158658Sphk{
4168658Sphk    va_list args;
4178768Sjkh    int pstat;
4188658Sphk    pid_t pid;
4198658Sphk    int omask;
4208658Sphk    sig_t intsave, quitsave;
42112661Speter    char *cmd;
42212661Speter    int i;
423148734Skensmith    struct stat sb;
4248629Sjkh
42515417Sjkh    cmd = (char *)alloca(FILENAME_MAX);
4268658Sphk    cmd[0] = '\0';
4278658Sphk    va_start(args, fmt);
4288658Sphk    vsnprintf(cmd, FILENAME_MAX, fmt, args);
4298658Sphk    va_end(args);
4308837Sjkh
4318658Sphk    omask = sigblock(sigmask(SIGCHLD));
43215439Sjkh    if (Fake) {
43315439Sjkh	msgDebug("vsystem:  Faked execution of `%s'\n", cmd);
43415439Sjkh	return 0;
43515439Sjkh    }
4368837Sjkh    if (isDebug())
43712661Speter	msgDebug("Executing command `%s'\n", cmd);
43812661Speter    pid = fork();
43912661Speter    if (pid == -1) {
4408658Sphk	(void)sigsetmask(omask);
4418658Sphk	i = 127;
44212661Speter    }
44312661Speter    else if (!pid) {	/* Junior */
4448658Sphk	(void)sigsetmask(omask);
4458658Sphk	if (DebugFD != -1) {
4468658Sphk	    dup2(DebugFD, 0);
4478658Sphk	    dup2(DebugFD, 1);
4488658Sphk	    dup2(DebugFD, 2);
4498658Sphk	}
45015419Sjkh	else {
45115419Sjkh	    close(1); open("/dev/null", O_WRONLY);
45215419Sjkh	    dup2(1, 2);
45315419Sjkh	}
454148734Skensmith	if (stat("/stand/sh", &sb) == 0)
455137883Sobrien	    execl("/stand/sh", "/stand/sh", "-c", cmd, (char *)NULL);
456137883Sobrien	else
45715419Sjkh	    execl("/bin/sh", "/bin/sh", "-c", cmd, (char *)NULL);
45812661Speter	exit(1);
45912661Speter    }
46012661Speter    else {
46112661Speter	intsave = signal(SIGINT, SIG_IGN);
46212661Speter	quitsave = signal(SIGQUIT, SIG_IGN);
46312661Speter	pid = waitpid(pid, &pstat, 0);
46412661Speter	(void)sigsetmask(omask);
46512661Speter	(void)signal(SIGINT, intsave);
46612661Speter	(void)signal(SIGQUIT, quitsave);
46712661Speter	i = (pid == -1) ? -1 : WEXITSTATUS(pstat);
46812661Speter	if (isDebug())
46912661Speter	    msgDebug("Command `%s' returns status of %d\n", cmd, i);
47012661Speter    }
47112661Speter    return i;
47212661Speter}
47312661Speter
47412661Spetervoid
47512661SpetersystemCreateHoloshell(void)
47612661Speter{
47763404Sobrien    int waitstatus;
47821010Sjkh
47963404Sobrien    if ((FixItMode || OnVTY) && RunningAsInit) {
48063404Sobrien
48121010Sjkh	if (ehs_pid != 0) {
48221010Sjkh	    int pstat;
48321010Sjkh
48421010Sjkh	    if (kill(ehs_pid, 0) == 0) {
48521010Sjkh
48670005Sjkh		if (msgNoYes("There seems to be an emergency holographic shell\n"
48750780Sjkh			     "already running on VTY 4.\n\n"
48821010Sjkh			     "Kill it and start a new one?"))
48921010Sjkh		    return;
49021010Sjkh
49121010Sjkh		/* try cleaning up as much as possible */
49221010Sjkh		(void) kill(ehs_pid, SIGHUP);
49321010Sjkh		sleep(1);
49421010Sjkh		(void) kill(ehs_pid, SIGKILL);
49521010Sjkh	    }
49621010Sjkh
49721010Sjkh	    /* avoid too many zombies */
49821010Sjkh	    (void) waitpid(ehs_pid, &pstat, WNOHANG);
49921010Sjkh	}
50021010Sjkh
50168012Sjkh	if (strcmp(variable_get(VAR_FIXIT_TTY), "serial") == 0)
50263404Sobrien	    systemSuspendDialog();	/* must be before the fork() */
50321010Sjkh	if ((ehs_pid = fork()) == 0) {
50412661Speter	    int i, fd;
50512661Speter	    struct termios foo;
50612661Speter	    extern int login_tty(int);
50712661Speter
50820335Sjkh	    ioctl(0, TIOCNOTTY, NULL);
50920354Sjkh	    for (i = getdtablesize(); i >= 0; --i)
51012661Speter		close(i);
51168012Sjkh	    if (strcmp(variable_get(VAR_FIXIT_TTY), "serial") == 0)
51268012Sjkh	        fd = open("/dev/console", O_RDWR);
51368012Sjkh	    else
51463404Sobrien	        fd = open("/dev/ttyv3", O_RDWR);
51512661Speter	    ioctl(0, TIOCSCTTY, &fd);
51612661Speter	    dup2(0, 1);
51712661Speter	    dup2(0, 2);
51820335Sjkh	    DebugFD = 2;
51912661Speter	    if (login_tty(fd) == -1)
52012661Speter		msgDebug("Doctor: I can't set the controlling terminal.\n");
52112661Speter	    signal(SIGTTOU, SIG_IGN);
52212661Speter	    if (tcgetattr(fd, &foo) != -1) {
52312661Speter		foo.c_cc[VERASE] = '\010';
52412661Speter		if (tcsetattr(fd, TCSANOW, &foo) == -1)
52512661Speter		    msgDebug("Doctor: I'm unable to set the erase character.\n");
5268837Sjkh	    }
5278837Sjkh	    else
52812661Speter		msgDebug("Doctor: I'm unable to get the terminal attributes!\n");
52968012Sjkh	    if (strcmp(variable_get(VAR_FIXIT_TTY), "serial") == 0) {
53063404Sobrien	        printf("Type ``exit'' in this fixit shell to resume sysinstall.\n\n");
53163404Sobrien		fflush(stdout);
53263404Sobrien	    }
533209069Srandi	    execlp("sh", "-sh", NULL);
53412661Speter	    msgDebug("Was unable to execute sh for Holographic shell!\n");
53512661Speter	    exit(1);
5368589Sjkh	}
53715458Sjkh	else {
53868012Sjkh	    if (strcmp(variable_get(VAR_FIXIT_TTY), "standard") == 0) {
53963404Sobrien	        WINDOW *w = savescr();
54054722Sjkh
54163404Sobrien	        msgNotify("Starting an emergency holographic shell on VTY4");
54263404Sobrien	        sleep(2);
54363404Sobrien	        restorescr(w);
54463404Sobrien	    }
54568012Sjkh	    else {
54668012Sjkh	        (void)waitpid(ehs_pid, &waitstatus, 0); /* we only wait for
54768012Sjkh							   shell to finish
548171027Sphilip							   in serial mode
54968012Sjkh							   since there is no
55068012Sjkh							   virtual console */
55163404Sobrien	        systemResumeDialog();
55263404Sobrien	    }
55315458Sjkh	}
5548584Sjkh    }
5558307Sjkh}
556