install.c revision 8677
1230557Sjimharris/*
2230557Sjimharris * The new sysinstall program.
3230557Sjimharris *
4230557Sjimharris * This is probably the last program in the `sysinstall' line - the next
5230557Sjimharris * generation being essentially a complete rewrite.
6230557Sjimharris *
7230557Sjimharris * $Id: install.c,v 1.45 1995/05/21 01:56:01 phk Exp $
8230557Sjimharris *
9230557Sjimharris * Copyright (c) 1995
10230557Sjimharris *	Jordan Hubbard.  All rights reserved.
11230557Sjimharris *
12230557Sjimharris * Redistribution and use in source and binary forms, with or without
13230557Sjimharris * modification, are permitted provided that the following conditions
14230557Sjimharris * are met:
15230557Sjimharris * 1. Redistributions of source code must retain the above copyright
16230557Sjimharris *    notice, this list of conditions and the following disclaimer,
17230557Sjimharris *    verbatim and that no modifications are made prior to this
18230557Sjimharris *    point in the file.
19230557Sjimharris * 2. Redistributions in binary form must reproduce the above copyright
20230557Sjimharris *    notice, this list of conditions and the following disclaimer in the
21230557Sjimharris *    documentation and/or other materials provided with the distribution.
22230557Sjimharris * 3. All advertising materials mentioning features or use of this software
23230557Sjimharris *    must display the following acknowledgement:
24230557Sjimharris *	This product includes software developed by Jordan Hubbard
25230557Sjimharris *	for the FreeBSD Project.
26230557Sjimharris * 4. The name of Jordan Hubbard or the FreeBSD project may not be used to
27230557Sjimharris *    endorse or promote products derived from this software without specific
28230557Sjimharris *    prior written permission.
29230557Sjimharris *
30230557Sjimharris * THIS SOFTWARE IS PROVIDED BY JORDAN HUBBARD ``AS IS'' AND
31230557Sjimharris * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
32230557Sjimharris * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
33230557Sjimharris * ARE DISCLAIMED.  IN NO EVENT SHALL JORDAN HUBBARD OR HIS PETS BE LIABLE
34230557Sjimharris * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
35230557Sjimharris * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
36230557Sjimharris * OR SERVICES; LOSS OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION)
37230557Sjimharris * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
38230557Sjimharris * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
39230557Sjimharris * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
40230557Sjimharris * SUCH DAMAGE.
41230557Sjimharris *
42230557Sjimharris */
43230557Sjimharris
44230557Sjimharris#include "sysinstall.h"
45230557Sjimharris#include <sys/disklabel.h>
46230557Sjimharris#include <sys/errno.h>
47230557Sjimharris#include <sys/fcntl.h>
48230557Sjimharris#include <sys/wait.h>
49230557Sjimharris#include <unistd.h>
50230557Sjimharris
51230557SjimharrisBoolean SystemWasInstalled;
52230557Sjimharris
53230557Sjimharrisstatic void	make_filesystems(void);
54230557Sjimharrisstatic void	copy_self(void);
55230557Sjimharrisstatic void	cpio_extract(void);
56230557Sjimharrisstatic void	install_configuration_files(void);
57230557Sjimharrisstatic void	do_final_setup(void);
58230557Sjimharris
59230557Sjimharrisstatic void
60230557SjimharrisinstallInitial(void)
61230557Sjimharris{
62230557Sjimharris    extern u_char boot1[], boot2[];
63230557Sjimharris    extern u_char mbr[], bteasy17[];
64230557Sjimharris    u_char *mbrContents;
65230557Sjimharris    Device **devs;
66230557Sjimharris    int i;
67230557Sjimharris    static Boolean alreadyDone = FALSE;
68230557Sjimharris    char *cp;
69240514Sjimharris
70230557Sjimharris    if (alreadyDone)
71230557Sjimharris	return;
72230557Sjimharris
73230557Sjimharris    if (!getenv(DISK_PARTITIONED)) {
74230557Sjimharris	msgConfirm("You need to partition your disk before you can proceed with\nthe installation.");
75230557Sjimharris	return;
76230557Sjimharris    }
77230557Sjimharris    if (!getenv(DISK_LABELLED)) {
78230557Sjimharris	msgConfirm("You need to assign disk labels before you can proceed with\nthe installation.");
79230557Sjimharris	return;
80230557Sjimharris    }
81230557Sjimharris
82230557Sjimharris    /* Figure out what kind of MBR the user wants */
83230557Sjimharris    dmenuOpenSimple(&MenuMBRType);
84230557Sjimharris    mbrContents = NULL;
85230557Sjimharris    cp = getenv("bootManager");
86230557Sjimharris    if (cp) {
87230557Sjimharris	if (!strcmp(cp, "bteasy"))
88230557Sjimharris	    mbrContents = bteasy17;
89230557Sjimharris	else if (!strcmp(cp, "mbr"))
90230557Sjimharris	    mbrContents = mbr;
91230557Sjimharris    }
92240514Sjimharris
93230557Sjimharris    /* If we refuse to proceed, bail. */
94230557Sjimharris    if (msgYesNo("Last Chance!  Are you SURE you want continue the installation?\n\nIf you're running this on an existing system, we STRONGLY\nencourage you to make proper backups before proceeding.\nWe take no responsibility for lost disk contents!"))
95230557Sjimharris	return;
96230557Sjimharris
97230557Sjimharris    devs = deviceFind(NULL, DEVICE_TYPE_DISK);
98230557Sjimharris    for (i = 0; devs[i]; i++) {
99230557Sjimharris	Disk *d = (Disk *)devs[i]->private;
100230557Sjimharris	Chunk *c1;
101230557Sjimharris
102230557Sjimharris	if (!devs[i]->enabled)
103230557Sjimharris	    continue;
104240514Sjimharris
105230557Sjimharris	if (mbrContents) {
106230557Sjimharris	    Set_Boot_Mgr(d, mbrContents);
107230557Sjimharris	    mbrContents = NULL;
108230557Sjimharris	}
109240514Sjimharris	Set_Boot_Blocks(d, boot1, boot2);
110240514Sjimharris	msgNotify("Writing partition information to drive %s", d->name);
111230557Sjimharris	Write_Disk(d);
112230557Sjimharris
113230557Sjimharris	/* Now scan for bad blocks, if necessary */
114230557Sjimharris	for (c1 = d->chunks->part; c1; c1 = c1->next) {
115230557Sjimharris	    if (c1->flags & CHUNK_BAD144) {
116230557Sjimharris		int ret;
117230557Sjimharris
118230557Sjimharris		msgNotify("Running bad block scan on partition %s", c1->name);
119230557Sjimharris		ret = vsystem("bad144 -v /dev/r%s 1234", c1->name);
120230557Sjimharris		if (ret)
121230557Sjimharris		    msgConfirm("Bad144 init on %s returned status of %d!",
122230557Sjimharris			c1->name, ret);
123230557Sjimharris		ret = vsystem("bad144 -v -s /dev/r%s", c1->name);
124230557Sjimharris		if (ret)
125230557Sjimharris		    msgConfirm("Bad144 scan on %s returned status of %d!",
126230557Sjimharris			c1->name, ret);
127230557Sjimharris	    }
128230557Sjimharris	}
129230557Sjimharris    }
130230557Sjimharris    make_filesystems();
131230557Sjimharris    copy_self();
132230557Sjimharris    dialog_clear();
133230557Sjimharris    chroot("/mnt");
134230557Sjimharris    chdir("/");
135230557Sjimharris    cpio_extract();
136230557Sjimharris    alreadyDone = TRUE;
137230557Sjimharris}
138230557Sjimharris
139230557Sjimharrisstatic void
140230557SjimharrisinstallFinal(void)
141230557Sjimharris{
142230557Sjimharris    static Boolean alreadyDone = FALSE;
143230557Sjimharris
144230557Sjimharris    if (alreadyDone)
145230557Sjimharris	return;
146230557Sjimharris    install_configuration_files();
147230557Sjimharris    do_final_setup();
148230557Sjimharris    alreadyDone = TRUE;
149230557Sjimharris}
150230557Sjimharris
151230557Sjimharris/*
152240514Sjimharris * What happens when we select "GO".  This is broken into a 3 stage installation so that
153240514Sjimharris * the user can do a full installation but come back here again to load more distributions,
154240514Sjimharris * perhaps from a different media type.  This would allow, for example, the user to load the
155230557Sjimharris * majority of the system from CDROM and then use ftp to load just the DES dist.
156230557Sjimharris */
157230557Sjimharrisint
158230557SjimharrisinstallCommit(char *str)
159230557Sjimharris{
160230557Sjimharris    if (!Dists) {
161230557Sjimharris	msgConfirm("You haven't told me what distributions to load yet!\nPlease select a distribution from the Distributions menu.");
162230557Sjimharris	return 0;
163230557Sjimharris    }
164230557Sjimharris    if (!mediaVerify())
165230557Sjimharris	return 0;
166230557Sjimharris
167230557Sjimharris    installInitial();
168230557Sjimharris    distExtractAll();
169230557Sjimharris    installFinal();
170230557Sjimharris    return 0;
171230557Sjimharris}
172230557Sjimharris
173230557Sjimharris/* Go newfs and/or mount all the filesystems we've been asked to */
174230557Sjimharrisstatic void
175230557Sjimharrismake_filesystems(void)
176230557Sjimharris{
177230557Sjimharris    int i;
178230557Sjimharris    Disk *disk;
179230557Sjimharris    Chunk *c1, *c2;
180230557Sjimharris    Device **devs;
181230557Sjimharris
182230557Sjimharris    command_clear();
183230557Sjimharris    devs = deviceFind(NULL, DEVICE_TYPE_DISK);
184230557Sjimharris
185230557Sjimharris    /* First look for the root device and mount it */
186230557Sjimharris    for (i = 0; devs[i]; i++) {
187230557Sjimharris	disk = (Disk *)devs[i]->private;
188230557Sjimharris	msgDebug("Scanning disk %s for root filesystem\n", disk->name);
189230557Sjimharris	if (!disk->chunks)
190230557Sjimharris	    msgFatal("No chunk list found for %s!", disk->name);
191230557Sjimharris	for (c1 = disk->chunks->part; c1; c1 = c1->next) {
192230557Sjimharris	    if (c1->type == freebsd) {
193230557Sjimharris		for (c2 = c1->part; c2; c2 = c2->next) {
194230557Sjimharris		    if (c2->type == part && c2->subtype != FS_SWAP &&
195230557Sjimharris			c2->private && c2->flags & CHUNK_IS_ROOT) {
196230557Sjimharris			char dname[40];
197230557Sjimharris			PartInfo *p = (PartInfo *)c2->private;
198230557Sjimharris
199230557Sjimharris			if (strcmp(p->mountpoint, "/")) {
200230557Sjimharris			    msgConfirm("Warning: %s is marked as a root partition but is mounted on %s", c2->name, p->mountpoint);
201230557Sjimharris			    continue;
202230557Sjimharris			}
203230557Sjimharris			if (p->newfs) {
204230557Sjimharris			    int i;
205230557Sjimharris
206230557Sjimharris			    sprintf(dname, "/dev/r%sa", disk->name);
207230557Sjimharris			    msgNotify("Making a new root filesystem on %s", dname);
208230557Sjimharris			    i = vsystem("%s %s", p->newfs_cmd,dname);
209230557Sjimharris			    if (i) {
210230557Sjimharris				msgConfirm("Unable to make new root filesystem!  Command returned status %d", i);
211230557Sjimharris				return;
212230557Sjimharris			    }
213230557Sjimharris			}
214230557Sjimharris			else
215230557Sjimharris			    msgConfirm("Warning:  You have selected a Read-Only root device\nand may be unable to find the appropriate device entries on it\nif it is from an older pre-slice version of FreeBSD.");
216230557Sjimharris			sprintf(dname, "/dev/%sa", disk->name);
217230557Sjimharris			if (Mount("/mnt", dname)) {
218230557Sjimharris			    msgConfirm("Unable to mount the root file system!  Giving up.");
219230557Sjimharris			    return;
220230557Sjimharris			}
221230557Sjimharris			else {
222230557Sjimharris			    extern int makedevs(void);
223230557Sjimharris
224230557Sjimharris			    msgNotify("Making device files");
225230557Sjimharris			    if (Mkdir("/mnt/dev", NULL)
226230557Sjimharris				|| chdir("/mnt/dev")
227230557Sjimharris				|| makedevs())
228230557Sjimharris				msgConfirm("Failed to make some of the devices in /mnt!");
229230557Sjimharris			    if (Mkdir("/mnt/stand", NULL))
230230557Sjimharris				msgConfirm("Unable to make /mnt/stand directory!");
231230557Sjimharris			    chdir("/");
232230557Sjimharris			    break;
233230557Sjimharris			}
234230557Sjimharris		    }
235230557Sjimharris		}
236230557Sjimharris	    }
237230557Sjimharris	}
238230557Sjimharris    }
239230557Sjimharris
240230557Sjimharris    /* Now buzz through the rest of the partitions and mount them too */
241230557Sjimharris    for (i = 0; devs[i]; i++) {
242230557Sjimharris	disk = (Disk *)devs[i]->private;
243230557Sjimharris	if (!disk->chunks)
244230557Sjimharris	    msgFatal("No chunk list found for %s!", disk->name);
245230557Sjimharris
246230557Sjimharris	/* Make the proper device mount points in /mnt/dev */
247230557Sjimharris	MakeDevDisk(disk, "/mnt/dev");
248230557Sjimharris
249230557Sjimharris	for (c1 = disk->chunks->part; c1; c1 = c1->next) {
250230557Sjimharris	    if (c1->type == freebsd) {
251230557Sjimharris		for (c2 = c1->part; c2; c2 = c2->next) {
252230557Sjimharris		    if (c2->type == part && c2->subtype != FS_SWAP && c2->private) {
253230557Sjimharris			PartInfo *tmp = (PartInfo *)c2->private;
254230557Sjimharris
255230557Sjimharris			if (!strcmp(tmp->mountpoint, "/"))
256230557Sjimharris			    continue;
257230557Sjimharris
258230557Sjimharris			if (tmp->newfs)
259			    command_shell_add(tmp->mountpoint,
260					      "%s /mnt/dev/r%s", tmp->newfs_cmd, c2->name);
261			command_func_add(tmp->mountpoint, Mount, c2->name);
262		    }
263		}
264	    }
265	}
266    }
267    command_sort();
268    command_execute();
269}
270
271/* Copy the boot floppy contents into /stand */
272static void
273copy_self(void)
274{
275    int i;
276
277    msgNotify("Copying the boot floppy to /stand on root filesystem");
278    i = vsystem("find -x /stand | cpio -pdmv /mnt");
279    if (i)
280	msgConfirm("Copy returned error status of %d!", i);
281}
282
283static void
284cpio_extract(void)
285{
286    int i, j, zpid, cpid, pfd[2];
287
288 tryagain:
289    while (CpioFD == -1) {
290	msgConfirm("Please Insert CPIO floppy in floppy drive 0");
291	CpioFD = open("/dev/rfd0", O_RDWR);
292	if (CpioFD >= 0)
293	    break;
294	msgDebug("Error on open of cpio floppy: %s (%d)\n", strerror(errno), errno);
295    }
296    j = fork();
297    if (!j) {
298	chdir("/");
299	msgNotify("Extracting contents of CPIO floppy...");
300	pipe(pfd);
301	zpid = fork();
302	if (!zpid) {
303	    dup2(CpioFD, 0); close(CpioFD);
304	    dup2(pfd[1], 1); close(pfd[1]);
305	    close(pfd[0]);
306	    i = execl("/stand/gunzip", "/stand/gunzip", 0);
307	    msgDebug("/stand/gunzip command returns %d status\n", i);
308	    exit(i);
309	}
310	cpid = fork();
311	if (!cpid) {
312	    dup2(pfd[0], 0); close(pfd[0]);
313	    close(CpioFD);
314	    close(pfd[1]);
315	    if (DebugFD != -1) {
316		dup2(DebugFD, 1);
317		dup2(DebugFD, 2);
318	    }
319	    else {
320		close(1); open("/dev/null", O_WRONLY);
321		dup2(1, 2);
322	    }
323	    i = execl("/stand/cpio", "/stand/cpio", "-iduvm", 0);
324	    msgDebug("/stand/cpio command returns %d status\n", i);
325	    exit(i);
326	}
327	close(pfd[0]);
328	close(pfd[1]);
329	close(CpioFD);
330
331	i = waitpid(zpid, &j, 0);
332	if (i < 0 || _WSTATUS(j)) {
333	    dialog_clear();
334	    msgConfirm("gunzip returned error status of %d!", _WSTATUS(j));
335	    exit(1);
336	}
337	i = waitpid(cpid, &j, 0);
338	if (i < 0 || _WSTATUS(j)) {
339	    dialog_clear();
340	    msgConfirm("cpio returned error status of %d!", _WSTATUS(j));
341	    exit(2);
342	}
343	exit(0);
344    }
345    else
346	i = wait(&j);
347    if (i < 0 || _WSTATUS(j) || access("/OK", R_OK) == -1) {
348	dialog_clear();
349	msgConfirm("CPIO floppy did not extract properly!  Please verify\nthat your media is correct and try again.");
350	close(CpioFD);
351	CpioFD = -1;
352	goto tryagain;
353    }
354    unlink("/OK");
355}
356
357static void
358install_configuration_files(void)
359{
360}
361
362static void
363do_final_setup(void)
364{
365}
366