111568Sjkh/*
211568Sjkh * The new sysinstall program.
311568Sjkh *
411568Sjkh * This is probably the last program in the `sysinstall' line - the next
511568Sjkh * generation being essentially a complete rewrite.
611568Sjkh *
750479Speter * $FreeBSD$
811568Sjkh *
911568Sjkh * Copyright (c) 1995
1011568Sjkh *	Jordan Hubbard.  All rights reserved.
1111568Sjkh *
1211568Sjkh * Redistribution and use in source and binary forms, with or without
1311568Sjkh * modification, are permitted provided that the following conditions
1411568Sjkh * are met:
1511568Sjkh * 1. Redistributions of source code must retain the above copyright
1611568Sjkh *    notice, this list of conditions and the following disclaimer,
1711568Sjkh *    verbatim and that no modifications are made prior to this
1811568Sjkh *    point in the file.
1911568Sjkh * 2. Redistributions in binary form must reproduce the above copyright
2011568Sjkh *    notice, this list of conditions and the following disclaimer in the
2111568Sjkh *    documentation and/or other materials provided with the distribution.
2211568Sjkh *
2311568Sjkh * THIS SOFTWARE IS PROVIDED BY JORDAN HUBBARD ``AS IS'' AND
2411568Sjkh * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2511568Sjkh * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2611568Sjkh * ARE DISCLAIMED.  IN NO EVENT SHALL JORDAN HUBBARD OR HIS PETS BE LIABLE
2711568Sjkh * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2811568Sjkh * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2911568Sjkh * OR SERVICES; LOSS OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION)
3011568Sjkh * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3111568Sjkh * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3211568Sjkh * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3311568Sjkh * SUCH DAMAGE.
3411568Sjkh *
3511568Sjkh */
3611568Sjkh
3711568Sjkh#include "sysinstall.h"
3811568Sjkh#include <sys/disklabel.h>
3911568Sjkh#include <sys/errno.h>
4011568Sjkh#include <sys/ioctl.h>
4111568Sjkh#include <sys/fcntl.h>
4211568Sjkh#include <sys/wait.h>
4311568Sjkh#include <sys/param.h>
4411568Sjkh#include <sys/stat.h>
4511568Sjkh#include <unistd.h>
4611568Sjkh#include <sys/mount.h>
4711568Sjkh
4829222Sjkhstatic int installUpgradeNonInteractive(dialogMenuItem *self);
4929222Sjkh
5011568Sjkhtypedef struct _hitList {
5111568Sjkh    enum { JUST_COPY, CALL_HANDLER } action ;
5211568Sjkh    char *name;
5311568Sjkh    Boolean optional;
5411568Sjkh    void (*handler)(struct _hitList *self);
5511568Sjkh} HitList;
5611568Sjkh
5711568Sjkh/* These are the only meaningful files I know about */
5811568Sjkhstatic HitList etc_files [] = {
5911568Sjkh   { JUST_COPY,		"Xaccel.ini",		TRUE, NULL },
6098079Sobrien   { JUST_COPY,		"X11",			TRUE, NULL },
6111568Sjkh   { JUST_COPY,		"adduser.conf",		TRUE, NULL },
6211568Sjkh   { JUST_COPY,		"aliases",		TRUE, NULL },
6311568Sjkh   { JUST_COPY,		"aliases.db",		TRUE, NULL },
6411568Sjkh   { JUST_COPY,		"amd.map",		TRUE, NULL },
6543949Sjkh   { JUST_COPY,		"auth.conf",		TRUE, NULL },
6611568Sjkh   { JUST_COPY,		"crontab",		TRUE, NULL },
6711568Sjkh   { JUST_COPY,		"csh.cshrc",		TRUE, NULL },
6811568Sjkh   { JUST_COPY,		"csh.login",		TRUE, NULL },
6911568Sjkh   { JUST_COPY,		"csh.logout",		TRUE, NULL },
7043949Sjkh   { JUST_COPY,		"cvsupfile",		TRUE, NULL },
71159113Sceri   { JUST_COPY,		"devfs.conf",		TRUE, NULL },
7282680Sjkh   { JUST_COPY,		"dhclient.conf",	TRUE, NULL },
7311568Sjkh   { JUST_COPY,		"disktab",		TRUE, NULL },
7443949Sjkh   { JUST_COPY,		"dumpdates",		TRUE, NULL },
7511568Sjkh   { JUST_COPY,		"exports",		TRUE, NULL },
7611568Sjkh   { JUST_COPY,		"fbtab",		TRUE, NULL },
7721726Sjkh   { JUST_COPY,		"fstab",		FALSE, NULL },
7811568Sjkh   { JUST_COPY,		"ftpusers",		TRUE, NULL },
7924548Sjkh   { JUST_COPY,		"gettytab",		TRUE, NULL },
8011568Sjkh   { JUST_COPY,		"gnats",		TRUE, NULL },
8111568Sjkh   { JUST_COPY,		"group",		FALSE, NULL },
8211568Sjkh   { JUST_COPY,		"hosts",		TRUE, NULL },
8382680Sjkh   { JUST_COPY,		"hosts.allow",		TRUE, NULL },
8411568Sjkh   { JUST_COPY,		"hosts.equiv",		TRUE, NULL },
8511568Sjkh   { JUST_COPY,		"hosts.lpd",		TRUE, NULL },
8621726Sjkh   { JUST_COPY,		"inetd.conf",		TRUE, NULL },
8711568Sjkh   { JUST_COPY,		"localtime",		TRUE, NULL },
8811568Sjkh   { JUST_COPY,		"login.access",		TRUE, NULL },
8943949Sjkh   { JUST_COPY,		"login.conf",		TRUE, NULL },
9072787Sjkh   { JUST_COPY,		"mail",			TRUE, NULL },
9111568Sjkh   { JUST_COPY,		"mail.rc",		TRUE, NULL },
92159113Sceri   { JUST_COPY,		"mac.conf",		TRUE, NULL },
9311568Sjkh   { JUST_COPY,		"make.conf",		TRUE, NULL },
9411568Sjkh   { JUST_COPY,		"manpath.config",	TRUE, NULL },
9543949Sjkh   { JUST_COPY,		"master.passwd",	FALSE, NULL },
96159113Sceri   { JUST_COPY,		"mergemaster.rc",	TRUE, NULL },
9711568Sjkh   { JUST_COPY,		"motd",			TRUE, NULL },
9811568Sjkh   { JUST_COPY,		"namedb",		TRUE, NULL },
9911568Sjkh   { JUST_COPY,		"networks",		TRUE, NULL },
10036320Ssteve   { JUST_COPY,		"newsyslog.conf",	TRUE, NULL },
10188515Ssheldonh   { JUST_COPY,		"nsmb.conf",		TRUE, NULL },
10265532Snectar   { JUST_COPY,		"nsswitch.conf",	TRUE, NULL },
103159113Sceri   { JUST_COPY,		"ntp.conf",		TRUE, NULL },
10443949Sjkh   { JUST_COPY,		"pam.conf",		TRUE, NULL },
10543949Sjkh   { JUST_COPY,		"passwd",		TRUE, NULL },
10643949Sjkh   { JUST_COPY,		"periodic",		TRUE, NULL },
107159113Sceri   { JUST_COPY,		"pf.conf",		TRUE, NULL },
108159113Sceri   { JUST_COPY,		"portsnap.conf",	TRUE, NULL },
10911568Sjkh   { JUST_COPY,		"ppp",			TRUE, NULL },
11011568Sjkh   { JUST_COPY,		"printcap",		TRUE, NULL },
11111568Sjkh   { JUST_COPY,		"profile",		TRUE, NULL },
112159113Sceri   { JUST_COPY,		"protocols",		TRUE, NULL },
11311568Sjkh   { JUST_COPY,		"pwd.db",		TRUE, NULL },
11411568Sjkh   { JUST_COPY,		"rc.local",		TRUE, NULL },
11544890Sjkh   { JUST_COPY,		"rc.firewall",		TRUE, NULL },
11643949Sjkh   { JUST_COPY,		"rc.conf.local",	TRUE, NULL },
11711568Sjkh   { JUST_COPY,		"remote",		TRUE, NULL },
11811568Sjkh   { JUST_COPY,		"resolv.conf",		TRUE, NULL },
11911568Sjkh   { JUST_COPY,		"rmt",			TRUE, NULL },
12011568Sjkh   { JUST_COPY,		"sendmail.cf",		TRUE, NULL },
12143949Sjkh   { JUST_COPY,		"sendmail.cw",		TRUE, NULL },
12221726Sjkh   { JUST_COPY,		"services",		TRUE, NULL },
12311568Sjkh   { JUST_COPY,		"shells",		TRUE, NULL },
12411568Sjkh   { JUST_COPY,		"skeykeys",		TRUE, NULL },
125159113Sceri   { JUST_COPY,		"snmpd.config",		TRUE, NULL },
12611568Sjkh   { JUST_COPY,		"spwd.db",		TRUE, NULL },
127159113Sceri   { JUST_COPY,		"src.conf",		TRUE, NULL },
12874730Sjkh   { JUST_COPY,		"ssh",			TRUE, NULL },
129152993Sphilip   { JUST_COPY,		"sysctl.conf",		TRUE, NULL },
13011568Sjkh   { JUST_COPY,		"syslog.conf",		TRUE, NULL },
13111568Sjkh   { JUST_COPY,		"ttys",			TRUE, NULL },
132156123Sjhb   { 0,			NULL,			FALSE, NULL },
13311568Sjkh};
13411568Sjkh
135156123Sjhbstatic void
13611568SjkhtraverseHitlist(HitList *h)
13711568Sjkh{
13821728Sjkh    system("rm -rf /etc/upgrade");
13921728Sjkh    Mkdir("/etc/upgrade");
14011568Sjkh    while (h->name) {
14111568Sjkh	if (!file_readable(h->name)) {
14215355Sjkh	    if (!h->optional)
14311568Sjkh		msgConfirm("Unable to find an old /etc/%s file!  That is decidedly non-standard and\n"
14421720Sjkh			   "your upgraded system may function a little strangely as a result.", h->name);
14511568Sjkh	}
14611568Sjkh	else {
14711568Sjkh	    if (h->action == JUST_COPY) {
14821726Sjkh		/* Move the just-loaded copy aside */
14921728Sjkh		vsystem("mv /etc/%s /etc/upgrade/%s", h->name, h->name);
15011568Sjkh
15111568Sjkh		/* Copy the old one into its place */
15211568Sjkh		msgNotify("Resurrecting %s..", h->name);
15311568Sjkh		/* Do this with tar so that symlinks and such are preserved */
15415355Sjkh		if (vsystem("tar cf - %s | tar xpf - -C /etc", h->name))
15511568Sjkh		    msgConfirm("Unable to resurrect your old /etc/%s!  Hmmmm.", h->name);
15611568Sjkh	    }
15711568Sjkh	    else /* call handler */
15811568Sjkh		h->handler(h);
15911568Sjkh	}
16011568Sjkh	++h;
16111568Sjkh    }
16211568Sjkh}
16316975Sjkh
16411568Sjkhint
16515091SjkhinstallUpgrade(dialogMenuItem *self)
16611568Sjkh{
16730345Sjkh    char saved_etc[FILENAME_MAX];
16811568Sjkh    Boolean extractingBin = TRUE;
16911568Sjkh
17029222Sjkh    if (variable_get(VAR_NONINTERACTIVE))
17129222Sjkh	return installUpgradeNonInteractive(self);
17229222Sjkh
17343685Sjkh    variable_set2(SYSTEM_STATE, "upgrade", 0);
17457509Sjkh    dialog_clear();
17511752Sjkh
17683020Sbmah    if (msgYesNo("Before beginning a binary upgrade, please review the upgrade instructions,\n"
17783020Sbmah		 "which are located in the \"Install\" document under the main documentation\n"
17883020Sbmah		 "menu.  Given that you have read these instructions and understand the risks\n"
17983020Sbmah		 "and precautions involved, are you sure that you want to proceed with\n"
18083020Sbmah		 "this upgrade?") != 0)
18154587Sjkh	return DITEM_FAILURE;
18211752Sjkh
18311568Sjkh    if (!Dists) {
18430345Sjkh	msgConfirm("First, you must select some distribution components.  The upgrade procedure\n"
18530345Sjkh		   "will only upgrade the distributions you select in the next set of menus.");
18621710Sjkh	if (!dmenuOpenSimple(&MenuDistributions, FALSE) || !Dists)
18754587Sjkh	    return DITEM_FAILURE;
18811568Sjkh    }
18995327Sobrien    else if (!(Dists & DIST_BASE)) {	    /* No base selected?  Not much of an upgrade.. */
19095327Sobrien	if (msgYesNo("You didn't select the base distribution as one of the distributons to load.\n"
19120518Sjkh		     "This one is pretty vital to a successful upgrade.  Are you SURE you don't\n"
19295327Sobrien		     "want to select the base distribution?  Chose No to bring up the Distributions\n"
19330345Sjkh		     "menu again.") != 0) {
19417164Sjkh	    if (!dmenuOpenSimple(&MenuDistributions, FALSE))
19554587Sjkh		return DITEM_FAILURE;
19611568Sjkh	}
19711568Sjkh    }
19811568Sjkh
19911568Sjkh    /* Still?!  OK!  They must know what they're doing.. */
20095327Sobrien    if (!(Dists & DIST_BASE))
20111568Sjkh	extractingBin = FALSE;
20211568Sjkh
20317164Sjkh    if (RunningAsInit) {
20417164Sjkh	Device **devs;
20517164Sjkh	int i, cnt;
20617164Sjkh	char *cp;
20711568Sjkh
20817164Sjkh	cp = variable_get(VAR_DISK);
20917164Sjkh	devs = deviceFind(cp, DEVICE_TYPE_DISK);
21017164Sjkh	cnt = deviceCount(devs);
21117164Sjkh	if (!cnt) {
21217164Sjkh	    msgConfirm("No disks found!  Please verify that your disk controller is being\n"
21317164Sjkh		       "properly probed at boot time.  See the Hardware Guide on the\n"
21417164Sjkh		       "Documentation menu for clues on diagnosing this type of problem.");
21557509Sjkh	    return DITEM_FAILURE | DITEM_RESTORE;
21617164Sjkh	}
21717164Sjkh	else {
21834733Sjkh	    /* Enable all the drives before we start */
21917164Sjkh	    for (i = 0; i < cnt; i++)
22017164Sjkh		devs[i]->enabled = TRUE;
22117164Sjkh	}
22211568Sjkh
22317164Sjkh	msgConfirm("OK.  First, we're going to go to the disk label editor.  In this editor\n"
22421726Sjkh		   "you will be expected to Mount any partitions you're interested in\n"
22517164Sjkh		   "upgrading.  DO NOT set the Newfs flag to Y on anything in the label editor\n"
22617164Sjkh		   "unless you're absolutely sure you know what you're doing!  In this\n"
22717164Sjkh		   "instance, you'll be using the label editor as little more than a fancy\n"
22821726Sjkh		   "screen-oriented partition mounting tool.\n\n"
22917164Sjkh		   "Once you're done in the label editor, press Q to return here for the next\n"
23017164Sjkh		   "step.");
23117164Sjkh
23217164Sjkh	if (DITEM_STATUS(diskLabelEditor(self)) == DITEM_FAILURE) {
23320518Sjkh	    msgConfirm("The disk label editor returned an error status.  Upgrade operation\n"
23417164Sjkh		       "aborted.");
23557509Sjkh	    return DITEM_FAILURE | DITEM_RESTORE;
23617164Sjkh	}
23717164Sjkh
23817164Sjkh	/* Don't write out MBR info */
23943685Sjkh	variable_set2(DISK_PARTITIONED, "written", 0);
24017164Sjkh	if (DITEM_STATUS(diskLabelCommit(self)) == DITEM_FAILURE) {
24117164Sjkh	    msgConfirm("Not all file systems were properly mounted.  Upgrade operation\n"
24217164Sjkh		       "aborted.");
24317164Sjkh	    variable_unset(DISK_PARTITIONED);
24457509Sjkh	    return DITEM_FAILURE | DITEM_RESTORE;
24517164Sjkh	}
24611568Sjkh
24722072Sjkh	msgNotify("Updating /stand on root filesystem");
24822072Sjkh	(void)vsystem("find -x /stand | cpio %s -pdum /mnt", cpioVerbosity());
24922072Sjkh
25021713Sjkh	if (DITEM_STATUS(chroot("/mnt")) == DITEM_FAILURE) {
25121713Sjkh	    msgConfirm("Unable to chroot to /mnt - something is wrong with the\n"
25221713Sjkh		       "root partition or the way it's mounted if this doesn't work.");
25321713Sjkh	    variable_unset(DISK_PARTITIONED);
25457509Sjkh	    return DITEM_FAILURE | DITEM_RESTORE;
25521713Sjkh	}
25621713Sjkh	chdir("/");
25734811Sjkh	installEnvironment();
25821713Sjkh	systemCreateHoloshell();
25911568Sjkh    }
26012127Sjkh
26130345Sjkh    saved_etc[0] = '\0';
26245402Sjkh
263165706Sceri    /* Don't allow sources to be upgraded if we have src already */
26445402Sjkh    if (directory_exists("/usr/src/") && (Dists & DIST_SRC)) {
26545402Sjkh	Dists &= ~DIST_SRC;
26668730Sjkh	SrcDists = 0;
26745402Sjkh	msgConfirm("Warning: /usr/src exists and sources were selected as upgrade\n"
26845402Sjkh		   "targets.  Unfortunately, this is not the way to upgrade your\n"
26945402Sjkh		   "sources - please use CTM or CVSup or some other method which\n"
27045402Sjkh		   "handles ``deletion events'', unlike this particular feature.\n\n"
27145402Sjkh		   "Your existing /usr/src will not be affected by this upgrade.\n");
27245402Sjkh    }
27345402Sjkh
27411568Sjkh    if (extractingBin) {
27530345Sjkh	while (!*saved_etc) {
27693595Sobrien	    char *cp = msgGetInput("/var/tmp/etc", "Under which directory do you wish to save your current /etc?");
27730345Sjkh
27830345Sjkh	    if (!cp || !*cp || Mkdir(cp)) {
27911568Sjkh		if (msgYesNo("Directory was not specified, was invalid or user selected Cancel.\n\n"
28011568Sjkh			     "Doing an upgrade without first backing up your /etc directory is a very\n"
28118830Sjkh			     "bad idea!  Do you want to go back and specify the save directory again?") != 0)
28211568Sjkh		    break;
28311568Sjkh	    }
28430345Sjkh	    else {
28530345Sjkh		SAFE_STRCPY(saved_etc, cp);
28630345Sjkh	    }
28711568Sjkh	}
28811568Sjkh
28930345Sjkh	if (saved_etc[0]) {
29011568Sjkh	    msgNotify("Preserving /etc directory..");
29130018Sjkh	    if (vsystem("tar -cBpf - -C /etc . | tar --unlink -xBpf - -C %s", saved_etc))
29216975Sjkh		if (msgYesNo("Unable to backup your /etc into %s.\n"
29320208Sjkh			     "Do you want to continue anyway?", saved_etc) != 0)
29454587Sjkh		    return DITEM_FAILURE;
29546994Sjkh	    msgNotify("Preserving /root directory..");
29646994Sjkh	    vsystem("tar -cBpf - -C / root | tar --unlink -xBpf - -C %s", saved_etc);
29711568Sjkh	}
29830832Sjkh
29930832Sjkh	msgNotify("chflags'ing old binaries - please wait.");
300164170Sceri	(void)vsystem("chflags -R noschg /bin /sbin /lib /libexec /usr/bin /usr/sbin /usr/lib /usr/libexec /var/empty /boot/kernel*");
30130832Sjkh
302159112Sceri	if (directory_exists("/boot/kernel")) {
303165720Sceri	    if (directory_exists("/boot/kernel.prev")) {
304165720Sceri		msgNotify("Removing /boot/kernel.prev");
305165720Sceri		if (system("rm -fr /boot/kernel.prev")) {
306165720Sceri		    msgConfirm("NOTICE: I'm trying to back up /boot/kernel to\n"
307165720Sceri			       "/boot/kernel.prev, but /boot/kernel.prev exists and I\n"
308165720Sceri			       "can't remove it.  This means that the backup will, in\n"
309165720Sceri			       "all probability, fail.");
310165720Sceri		}
311165720Sceri	    }
312159112Sceri	    msgNotify("Moving old kernel to /boot/kernel.prev");
313159112Sceri	    if (system("mv /boot/kernel /boot/kernel.prev")) {
31411568Sjkh		if (!msgYesNo("Hmmm!  I couldn't move the old kernel over!  Do you want to\n"
31511752Sjkh			      "treat this as a big problem and abort the upgrade?  Due to the\n"
31611752Sjkh			      "way that this upgrade process works, you will have to reboot\n"
31715788Sjkh			      "and start over from the beginning.  Select Yes to reboot now"))
31815788Sjkh		    systemShutdown(1);
31911673Sjkh	    }
32034733Sjkh	    else
321159112Sceri		msgConfirm("NOTICE: Your old kernel is in /boot/kernel.prev should this\n"
322159112Sceri			   "upgrade fail for any reason and you need to boot your old\n"
323159112Sceri			   "kernel.");
32411568Sjkh	}
32511568Sjkh    }
32611752Sjkh
32730018Sjkhmedia:
32830345Sjkh    /* We do this very late, but we unfortunately need to back up /etc first */
32930018Sjkh    if (!mediaVerify())
33054587Sjkh	return DITEM_FAILURE;
33130018Sjkh
33279065Sdd    if (!DEVICE_INIT(mediaDevice)) {
33330018Sjkh	if (!msgYesNo("Couldn't initialize the media.  Would you like\n"
33430018Sjkh		   "to adjust your media selection and try again?")) {
33530018Sjkh	    mediaDevice = NULL;
33630018Sjkh	    goto media;
33730018Sjkh	}
33830018Sjkh	else
33957509Sjkh	    return DITEM_FAILURE | DITEM_REDRAW | DITEM_RESTORE;
34030018Sjkh    }
34130018Sjkh
342164172Sceri    msgNotify("Beginning extraction of distributions.");
34315419Sjkh    if (DITEM_STATUS(distExtractAll(self)) == DITEM_FAILURE) {
34495327Sobrien	msgConfirm("Hmmmm.  We couldn't even extract the base distribution.  This upgrade\n"
34521710Sjkh		   "should be considered a failure and started from the beginning, sorry!\n"
34621710Sjkh		   "The system will reboot now.");
34721710Sjkh	dialog_clear();
34821710Sjkh	systemShutdown(1);
34921710Sjkh    }
35021726Sjkh    else if (Dists) {
35195327Sobrien	if (!extractingBin || !(Dists & DIST_BASE)) {
35221726Sjkh	    msgNotify("The extraction process seems to have had some problems, but we got most\n"
35321710Sjkh		       "of the essentials.  We'll treat this as a warning since it may have been\n"
35421710Sjkh		       "only non-essential distributions which failed to load.");
35521710Sjkh	}
35621710Sjkh	else {
35795327Sobrien	    msgConfirm("Hmmmm.  We couldn't even extract the base distribution.  This upgrade\n"
35811752Sjkh		       "should be considered a failure and started from the beginning, sorry!\n"
35911752Sjkh		       "The system will reboot now.");
36015355Sjkh	    dialog_clear();
36115788Sjkh	    systemShutdown(1);
36211568Sjkh	}
36311568Sjkh    }
36411568Sjkh
36544036Sjkh    if (extractingBin)
366170320Sdelphij	vsystem("disklabel -B `awk '$2~/\\/$/ {print substr($1, 6, 5)}' /etc/fstab`");
36721728Sjkh    msgNotify("First stage of upgrade completed successfully!\n\n"
36812025Sjkh	       "Next comes stage 2, where we attempt to resurrect your /etc\n"
36912025Sjkh	       "directory!");
37012025Sjkh
371209069Srandi    if (chdir(saved_etc)) {
37211568Sjkh	msgConfirm("Unable to go to your saved /etc directory in %s?!  Argh!\n"
37311568Sjkh		   "Something went seriously wrong!  It's quite possible that\n"
37411568Sjkh		   "your former /etc is toast.  I hope you didn't have any\n"
37521720Sjkh		   "important customizations you wanted to keep in there.. :(", saved_etc);
37611568Sjkh    }
37711752Sjkh    else {
37811752Sjkh	/* Now try to resurrect the /etc files */
37911752Sjkh	traverseHitlist(etc_files);
38046994Sjkh	/* Resurrect the root dotfiles */
38146994Sjkh	vsystem("tar -cBpf - root | tar -xBpf - -C / && rm -rf root");
38211752Sjkh    }
38311568Sjkh
38434867Sjkh    msgConfirm("Upgrade completed!  All of your old /etc files have been restored.\n"
38534867Sjkh	       "For your reference, the new /etc files are in /etc/upgrade/ in case\n"
38634867Sjkh	       "you wish to upgrade these files by hand (though that should not be\n"
38734867Sjkh	       "strictly necessary).  If your root partition is specified in /etc/fstab\n"
38834867Sjkh	       "using the old \"compatibility\" slice, you may also wish to update it to\n"
38934867Sjkh	       "use a fully qualified slice name in order to avoid warnings on startup.\n\n"
39034867Sjkh	       "When you're ready to reboot into the new system, simply exit the installation.");
39157509Sjkh    return DITEM_SUCCESS | DITEM_REDRAW | DITEM_RESTORE;
39211568Sjkh}
39329222Sjkh
39429222Sjkhstatic int
39529222SjkhinstallUpgradeNonInteractive(dialogMenuItem *self)
39629222Sjkh{
39729222Sjkh    char *saved_etc;
39829222Sjkh    Boolean extractingBin = TRUE;
39929222Sjkh
40043685Sjkh    variable_set2(SYSTEM_STATE, "upgrade", 0);
40129222Sjkh
40229222Sjkh    /* Make sure at least BIN is selected */
40395327Sobrien    Dists |= DIST_BASE;
40429222Sjkh
40529222Sjkh    if (RunningAsInit) {
40629222Sjkh	Device **devs;
40729222Sjkh	int i, cnt;
40829222Sjkh	char *cp;
40929222Sjkh
41029222Sjkh	cp = variable_get(VAR_DISK);
41129222Sjkh	devs = deviceFind(cp, DEVICE_TYPE_DISK);
41229222Sjkh	cnt = deviceCount(devs);
41329222Sjkh	if (!cnt) {
41429222Sjkh	    msgConfirm("No disks found!  Please verify that your disk controller is being\n"
41529222Sjkh		       "properly probed at boot time.  See the Hardware Guide on the\n"
41629222Sjkh		       "Documentation menu for clues on diagnosing this type of problem.");
41729222Sjkh	    return DITEM_FAILURE;
41829222Sjkh	}
41929222Sjkh	else {
420164084Sceri	    /* Enable all the drives before we start */
42129222Sjkh	    for (i = 0; i < cnt; i++)
42229222Sjkh		devs[i]->enabled = TRUE;
42329222Sjkh	}
42429222Sjkh
42529222Sjkh	msgConfirm("OK.  First, we're going to go to the disk label editor.  In this editor\n"
42629222Sjkh		   "you will be expected to Mount any partitions you're interested in\n"
42729222Sjkh		   "upgrading.  DO NOT set the Newfs flag to Y on anything in the label editor\n"
42829222Sjkh		   "unless you're absolutely sure you know what you're doing!  In this\n"
42929222Sjkh		   "instance, you'll be using the label editor as little more than a fancy\n"
43029222Sjkh		   "screen-oriented partition mounting tool.\n\n"
43129222Sjkh		   "Once you're done in the label editor, press Q to return here for the next\n"
43229222Sjkh		   "step.");
43329222Sjkh
43429222Sjkh	if (DITEM_STATUS(diskLabelEditor(self)) == DITEM_FAILURE) {
43529222Sjkh	    msgConfirm("The disk label editor returned an error status.  Upgrade operation\n"
43629222Sjkh		       "aborted.");
43754587Sjkh	    return DITEM_FAILURE;
43829222Sjkh	}
43929222Sjkh
44029222Sjkh	/* Don't write out MBR info */
44143685Sjkh	variable_set2(DISK_PARTITIONED, "written", 0);
44229222Sjkh	if (DITEM_STATUS(diskLabelCommit(self)) == DITEM_FAILURE) {
44329222Sjkh	    msgConfirm("Not all file systems were properly mounted.  Upgrade operation\n"
44429222Sjkh		       "aborted.");
44529222Sjkh	    variable_unset(DISK_PARTITIONED);
44654587Sjkh	    return DITEM_FAILURE;
44729222Sjkh	}
44829222Sjkh
44929222Sjkh	if (extractingBin) {
45029222Sjkh	    msgNotify("chflags'ing old binaries - please wait.");
45129222Sjkh	    (void)vsystem("chflags -R noschg /mnt/");
45229222Sjkh	}
45329222Sjkh	msgNotify("Updating /stand on root filesystem");
45429222Sjkh	(void)vsystem("find -x /stand | cpio %s -pdum /mnt", cpioVerbosity());
45529222Sjkh
45629222Sjkh	if (DITEM_STATUS(chroot("/mnt")) == DITEM_FAILURE) {
45729222Sjkh	    msgConfirm("Unable to chroot to /mnt - something is wrong with the\n"
45829222Sjkh		       "root partition or the way it's mounted if this doesn't work.");
45929222Sjkh	    variable_unset(DISK_PARTITIONED);
46054587Sjkh	    return DITEM_FAILURE;
46129222Sjkh	}
46229222Sjkh	chdir("/");
46329222Sjkh	systemCreateHoloshell();
46429222Sjkh    }
46529222Sjkh
46679065Sdd    if (!mediaVerify() || !DEVICE_INIT(mediaDevice)) {
46729222Sjkh	msgNotify("Upgrade: Couldn't initialize media.");
46854587Sjkh	return DITEM_FAILURE;
46929222Sjkh    }
47029222Sjkh
47193595Sobrien    saved_etc = "/var/tmp/etc";
47229222Sjkh    Mkdir(saved_etc);
47329222Sjkh    msgNotify("Preserving /etc directory..");
47429222Sjkh    if (vsystem("tar -cpBf - -C /etc . | tar -xpBf - -C %s", saved_etc)) {
47529222Sjkh	msgNotify("Unable to backup your /etc into %s.", saved_etc);
47654587Sjkh	return DITEM_FAILURE;
47729222Sjkh    }
47829222Sjkh
479164171Sceri    /*
480164171Sceri     * Back up the old kernel, leaving it in place in case we
481164171Sceri     *  crash and reboot.
482164171Sceri     */
483164171Sceri    if (directory_exists("/boot/kernel")) {
484165720Sceri	if (directory_exists("/boot/kernel.prev")) {
485165720Sceri	    msgNotify("Removing /boot/kernel.prev");
486165720Sceri	    if (system("rm -fr /boot/kernel.prev")) {
487165720Sceri		msgConfirm("NOTICE: I'm trying to back up /boot/kernel to\n"
488165720Sceri		    "/boot/kernel.prev, but /boot/kernel.prev exists and I\n"
489165720Sceri		    "can't remove it.  This means that the backup will, in\n"
490165720Sceri		    "all probability, fail.");
491165720Sceri	    }
492165720Sceri	}
493164171Sceri	msgNotify("Copying old kernel to /boot/kernel.prev");
494164171Sceri	vsystem("cp -Rp /boot/kernel /boot/kernel.prev");
495164171Sceri    }
49629222Sjkh
497164172Sceri    msgNotify("Beginning extraction of distributions.");
49829222Sjkh    if (DITEM_STATUS(distExtractAll(self)) == DITEM_FAILURE) {
49995327Sobrien	msgConfirm("Hmmmm.  We couldn't even extract the base distribution.  This upgrade\n"
50029222Sjkh		   "should be considered a failure and started from the beginning, sorry!\n"
50129222Sjkh		   "The system will reboot now.");
50229222Sjkh	dialog_clear();
50329222Sjkh	systemShutdown(1);
50429222Sjkh    }
50529222Sjkh    else if (Dists) {
50695327Sobrien	if (!(Dists & DIST_BASE)) {
50729222Sjkh	    msgNotify("The extraction process seems to have had some problems, but we got most\n"
50829222Sjkh		       "of the essentials.  We'll treat this as a warning since it may have been\n"
50929222Sjkh		       "only non-essential distributions which failed to upgrade.");
51029222Sjkh	}
51129222Sjkh	else {
51295327Sobrien	    msgConfirm("Hmmmm.  We couldn't even extract the base distribution.  This upgrade\n"
51329222Sjkh		       "should be considered a failure and started from the beginning, sorry!\n"
51429222Sjkh		       "The system will reboot now.");
51529222Sjkh	    dialog_clear();
51629222Sjkh	    systemShutdown(1);
51729222Sjkh	}
51829222Sjkh    }
51929222Sjkh
52029222Sjkh    msgNotify("First stage of upgrade completed successfully.");
52129222Sjkh    if (vsystem("tar -cpBf - -C %s . | tar --unlink -xpBf - -C /etc", saved_etc)) {
52229222Sjkh	msgNotify("Unable to resurrect your old /etc!");
52354587Sjkh	return DITEM_FAILURE;
52429222Sjkh    }
52529222Sjkh    return DITEM_SUCCESS | DITEM_REDRAW;
52629222Sjkh}
527