install.c revision 8651
1/*
2 * The new sysinstall program.
3 *
4 * This is probably the last program in the `sysinstall' line - the next
5 * generation being essentially a complete rewrite.
6 *
7 * $Id: install.c,v 1.37 1995/05/20 14:05:28 jkh Exp $
8 *
9 * Copyright (c) 1995
10 *	Jordan Hubbard.  All rights reserved.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 *    notice, this list of conditions and the following disclaimer,
17 *    verbatim and that no modifications are made prior to this
18 *    point in the file.
19 * 2. Redistributions in binary form must reproduce the above copyright
20 *    notice, this list of conditions and the following disclaimer in the
21 *    documentation and/or other materials provided with the distribution.
22 * 3. All advertising materials mentioning features or use of this software
23 *    must display the following acknowledgement:
24 *	This product includes software developed by Jordan Hubbard
25 *	for the FreeBSD Project.
26 * 4. The name of Jordan Hubbard or the FreeBSD project may not be used to
27 *    endorse or promote products derived from this software without specific
28 *    prior written permission.
29 *
30 * THIS SOFTWARE IS PROVIDED BY JORDAN HUBBARD ``AS IS'' AND
31 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
32 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
33 * ARE DISCLAIMED.  IN NO EVENT SHALL JORDAN HUBBARD OR HIS PETS BE LIABLE
34 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
35 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
36 * OR SERVICES; LOSS OF USE, DATA, LIFE OR PROFITS; OR BUSINESS INTERRUPTION)
37 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
38 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
39 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
40 * SUCH DAMAGE.
41 *
42 */
43
44#include "sysinstall.h"
45#include <sys/disklabel.h>
46#include <sys/errno.h>
47#include <sys/fcntl.h>
48#include <sys/wait.h>
49#include <unistd.h>
50
51Boolean SystemWasInstalled;
52
53static void	make_filesystems(void);
54static void	copy_self(void);
55static void	cpio_extract(void);
56static void	install_configuration_files(void);
57static void	do_final_setup(void);
58
59static Boolean
60preInstallCheck(void)
61{
62    if (!getenv(DISK_PARTITIONED)) {
63	msgConfirm("You need to partition your disk before you can proceed with\nthe installation.");
64
65	return FALSE;
66    }
67    if (!getenv(DISK_LABELLED)) {
68	msgConfirm("You need to assign disk labels before you can proceed with\nthe installation.");
69	return FALSE;
70    }
71    if (!Dists) {
72	msgConfirm("You haven't told me what distributions to load yet!\nPlease select a distribution from the Distributions menu.");
73	return FALSE;
74    }
75    return TRUE;
76}
77
78static void
79installInitial(void)
80{
81    extern u_char boot1[], boot2[];
82    extern u_char mbr[], bteasy17[];
83    u_char *mbrContents;
84    Device **devs;
85    int i;
86    static Boolean alreadyDone = FALSE;
87
88    if (alreadyDone)
89	return;
90
91    /* If things aren't kosher, or we refuse to proceed, bail. */
92    if (!preInstallCheck()
93	|| 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!"))
94	return;
95
96    mbrContents = NULL;
97    if (!msgYesNo("Would you like to install a boot manager?\n\nThis will allow you to easily select between other operating systems\non the first disk, or boot from a disk other than the first."))
98	mbrContents = bteasy17;
99    else if (!msgYesNo("Would you like to remove an existing boot manager?"))
100	mbrContents = mbr;
101    devs = deviceFind(NULL, DEVICE_TYPE_DISK);
102    for (i = 0; devs[i]; i++) {
103	Disk *d = (Disk *)devs[i]->private;
104	Chunk *c1;
105
106	if (!devs[i]->enabled)
107	    continue;
108
109	if (mbrContents) {
110	    Set_Boot_Mgr(d, mbrContents);
111	    mbrContents = NULL;
112	}
113	Set_Boot_Blocks(d, boot1, boot2);
114	msgNotify("Writing partition information to drive %s", d->name);
115	Write_Disk(d);
116
117	/* Now scan for bad blocks, if necessary */
118	for (c1 = d->chunks->part; c1; c1 = c1->next) {
119	    if (c1->flags & CHUNK_BAD144) {
120		int ret;
121
122		msgNotify("Running bad block scan on partition %s", c1->name);
123		ret = vsystem("bad144 -v /dev/r%s 1234", c1->name);
124		if (ret)
125		    msgConfirm("Bad144 init on %s returned status of %d!", c1->name, ret);
126		ret = vsystem("bad144 -v -s /dev/r%s", c1->name);
127		if (ret)
128		    msgConfirm("Bad144 scan on %s returned status of %d!", c1->name, ret);
129	    }
130	}
131    }
132    make_filesystems();
133    copy_self();
134    dialog_clear();
135    cpio_extract();
136    alreadyDone = TRUE;
137}
138
139static void
140installFinal(void)
141{
142    static Boolean alreadyDone = FALSE;
143
144    if (alreadyDone)
145	return;
146    install_configuration_files();
147    do_final_setup();
148    alreadyDone = TRUE;
149}
150
151int
152installCommit(char *str)
153{
154    installInitial();
155    if (!mediaVerify())
156	return 0;
157    distExtractAll();
158    installFinal();
159    return 0;
160}
161
162/* Go newfs and/or mount all the filesystems we've been asked to */
163static void
164make_filesystems(void)
165{
166    int i;
167    Disk *disk;
168    Chunk *c1, *c2;
169    Device **devs;
170
171    command_clear();
172    devs = deviceFind(NULL, DEVICE_TYPE_DISK);
173
174    /* First look for the root device and mount it */
175    for (i = 0; devs[i]; i++) {
176	disk = (Disk *)devs[i]->private;
177	msgDebug("Scanning disk %s for root filesystem\n", disk->name);
178	if (!disk->chunks)
179	    msgFatal("No chunk list found for %s!", disk->name);
180	for (c1 = disk->chunks->part; c1; c1 = c1->next) {
181	    if (c1->type == freebsd) {
182		for (c2 = c1->part; c2; c2 = c2->next) {
183		    if (c2->type == part && c2->subtype != FS_SWAP &&
184			c2->private && c2->flags & CHUNK_IS_ROOT) {
185			char dname[40];
186			PartInfo *p = (PartInfo *)c2->private;
187
188			if (strcmp(p->mountpoint, "/")) {
189			    msgConfirm("Warning: %s is marked as a root partition but is mounted on %s", c2->name, p->mountpoint);
190			    continue;
191			}
192			if (p->newfs) {
193			    int i;
194
195			    sprintf(dname, "/dev/r%sa", disk->name);
196			    msgNotify("Making a new root filesystem on %s", dname);
197			    i = vsystem("newfs %s", dname);
198			    if (i) {
199				msgConfirm("Unable to make new root filesystem!  Command returned status %d", i);
200				return;
201			    }
202			}
203			else
204			    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.");
205			sprintf(dname, "/dev/%sa", disk->name);
206			if (Mount("/mnt", dname)) {
207			    msgConfirm("Unable to mount the root file system!  Giving up.");
208			    return;
209			}
210			else {
211			    extern int makedevs(void);
212
213			    msgNotify("Making device files");
214			    if (Mkdir("/mnt/dev", NULL)
215				|| chdir("/mnt/dev")
216				|| makedevs())
217				msgConfirm("Failed to make some of the devices in /mnt!");
218			    if (Mkdir("/mnt/stand", NULL))
219				msgConfirm("Unable to make /mnt/stand directory!");
220			    chdir("/");
221			    break;
222			}
223		    }
224		}
225	    }
226	}
227    }
228
229    /* Now buzz through the rest of the partitions and mount them too */
230    for (i = 0; devs[i]; i++) {
231	disk = (Disk *)devs[i]->private;
232	if (!disk->chunks)
233	    msgFatal("No chunk list found for %s!", disk->name);
234
235	/* Make the proper device mount points in /mnt/dev */
236	MakeDevDisk(disk, "/mnt/dev");
237
238	for (c1 = disk->chunks->part; c1; c1 = c1->next) {
239	    if (c1->type == freebsd) {
240		for (c2 = c1->part; c2; c2 = c2->next) {
241		    if (c2->type == part && c2->subtype != FS_SWAP && c2->private) {
242			PartInfo *tmp = (PartInfo *)c2->private;
243
244			if (!strcmp(tmp->mountpoint, "/"))
245			    continue;
246
247			if (tmp->newfs)
248			    command_shell_add(tmp->mountpoint,
249					      "%s /mnt/dev/r%s", tmp->newfs_cmd, c2->name);
250			command_func_add(tmp->mountpoint, Mount, c2->name);
251		    }
252		}
253	    }
254	}
255    }
256    command_sort();
257    command_execute();
258}
259
260/* Copy the boot floppy contents into /stand */
261static void
262copy_self(void)
263{
264    int i;
265
266    msgNotify("Copying the boot floppy to /stand on root filesystem");
267    i = vsystem("find -x / | cpio -pdmv /mnt");
268    if (i)
269	msgConfirm("Copy returned error status of %d!", i);
270}
271
272static void
273cpio_extract(void)
274{
275    int i, j, zpid, cpid, pfd[2];
276
277 tryagain:
278    while (CpioFD == -1) {
279	msgConfirm("Please Insert CPIO floppy in floppy drive 0");
280	CpioFD = open("/dev/rfd0", O_RDONLY);
281	if (CpioFD >= 0)
282	    break;
283	msgDebug("Error on open of cpio floppy: %s (%d)\n", strerror(errno), errno);
284    }
285    j = fork();
286    if (!j) {
287	chroot("/mnt");	chdir("/");
288	msgNotify("Extracting contents of CPIO floppy...");
289	pipe(pfd);
290	zpid = fork();
291	if (!zpid) {
292	    dup2(CpioFD, 0); close(CpioFD);
293	    dup2(pfd[1], 1); close(pfd[1]);
294	    close(pfd[0]);
295	    i = execl("/stand/gunzip", "/stand/gunzip", 0);
296	    msgDebug("/stand/gunzip command returns %d status\n", i);
297	    exit(i);
298	}
299	cpid = fork();
300	if (!cpid) {
301	    dup2(pfd[0], 0); close(pfd[0]);
302	    close(CpioFD);
303	    close(pfd[1]);
304	    if (DebugFD != -1) {
305		dup2(DebugFD, 1);
306		dup2(DebugFD, 2);
307	    }
308	    else {
309		close(1); open("/dev/null", O_WRONLY);
310		dup2(1, 2);
311	    }
312	    i = execl("/stand/cpio", "/stand/cpio", "-iduvm", 0);
313	    msgDebug("/stand/cpio command returns %d status\n", i);
314	    exit(i);
315	}
316	close(pfd[0]);
317	close(pfd[1]);
318	close(CpioFD);
319
320	i = waitpid(zpid, &j, 0);
321	if (i < 0 || j) {
322	    msgConfirm("gunzip returned status of %d, error was: %s (%d)!  Help!", j, strerror(errno), errno);
323	    exit(1);
324	}
325	i = waitpid(cpid, &j, 0);
326	if (i < 0 || j) {
327	    msgConfirm("cpio returned status of %d, error was: %s (%d)!  Help!", j, strerror(errno), errno);
328	    exit(2);
329	}
330	exit(0);
331    }
332    else
333	i = wait(&j);
334    if (i < 0 || j || access("/mnt/OK", R_OK) == -1) {
335	msgConfirm("CPIO floppy did not extract properly!  Please verify\n\that your media is correct and try again");
336	close(CpioFD);
337	CpioFD = -1;
338	goto tryagain;
339    }
340    unlink("/mnt/OK");
341}
342
343static void
344install_configuration_files(void)
345{
346}
347
348static void
349do_final_setup(void)
350{
351}
352