install.c revision 8702
1192836Sed/*
2192836Sed * The new sysinstall program.
3192836Sed *
4192836Sed * This is probably the last program in the `sysinstall' line - the next
5192836Sed * generation being essentially a complete rewrite.
6192836Sed *
7192836Sed * $Id: install.c,v 1.46 1995/05/21 15:40:48 jkh Exp $
8192836Sed *
9192836Sed * Copyright (c) 1995
10192836Sed *	Jordan Hubbard.  All rights reserved.
11192834Sed *
12192834Sed * Redistribution and use in source and binary forms, with or without
13192834Sed * modification, are permitted provided that the following conditions
14192834Sed * are met:
15192834Sed * 1. Redistributions of source code must retain the above copyright
16192834Sed *    notice, this list of conditions and the following disclaimer,
17192834Sed *    verbatim and that no modifications are made prior to this
18192834Sed *    point in the file.
19192834Sed * 2. Redistributions in binary form must reproduce the above copyright
20192834Sed *    notice, this list of conditions and the following disclaimer in the
21192834Sed *    documentation and/or other materials provided with the distribution.
22192834Sed * 3. All advertising materials mentioning features or use of this software
23192834Sed *    must display the following acknowledgement:
24192834Sed *	This product includes software developed by Jordan Hubbard
25192834Sed *	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 Disk *rootdisk;
60static Chunk *rootdev;
61
62static Boolean
63checkLabels(void)
64{
65    Device **devs;
66    Disk *disk;
67    Chunk *c1, *c2, *swapdev = NULL;
68    int i;
69
70    devs = deviceFind(NULL, DEVICE_TYPE_DISK);
71    /* First verify that we have a root device */
72    for (i = 0; devs[i]; i++) {
73	if (!devs[i]->enabled)
74	    continue;
75	disk = (Disk *)devs[i]->private;
76	msgDebug("Scanning disk %s for root filesystem\n", disk->name);
77	if (!disk->chunks)
78	    msgFatal("No chunk list found for %s!", disk->name);
79	for (c1 = disk->chunks->part; c1; c1 = c1->next) {
80	    if (c1->type == freebsd) {
81		for (c2 = c1->part; c2; c2 = c2->next) {
82		    if (c2->type == part && c2->subtype != FS_SWAP &&
83			c2->private && c2->flags & CHUNK_IS_ROOT) {
84			rootdisk = disk;
85			rootdev = c2;
86			break;
87		    }
88		}
89	    }
90	}
91    }
92
93    /* Now register the swap devices */
94    for (i = 0; devs[i]; i++) {
95	disk = (Disk *)devs[i]->private;
96	msgDebug("Scanning disk %s for swap partitions\n", disk->name);
97	if (!disk->chunks)
98	    msgFatal("No chunk list found for %s!", disk->name);
99	for (c1 = disk->chunks->part; c1; c1 = c1->next) {
100	    if (c1->type == freebsd) {
101		for (c2 = c1->part; c2; c2 = c2->next) {
102		    if (c2->type == part && c2->subtype == FS_SWAP) {
103			swapdev = c2;
104			break;
105		    }
106		}
107	    }
108	}
109    }
110
111    if (!rootdev) {
112	msgConfirm("No root device found - you must label a partition as /\n in the label editor.");
113	return FALSE;
114    }
115    if (!swapdev) {
116	msgConfirm("No swap devices found - you must create at least one\nswap partition.");
117	return FALSE;
118    }
119    return TRUE;
120}
121
122static void
123installInitial(void)
124{
125    extern u_char boot1[], boot2[];
126    extern u_char mbr[], bteasy17[];
127    u_char *mbrContents;
128    Device **devs;
129    int i;
130    static Boolean alreadyDone = FALSE;
131    char *cp;
132
133    if (alreadyDone)
134	return;
135
136    if (!getenv(DISK_PARTITIONED)) {
137	msgConfirm("You need to partition your disk before you can proceed with\nthe installation.");
138	return;
139    }
140    if (!getenv(DISK_LABELLED)) {
141	msgConfirm("You need to assign disk labels before you can proceed with\nthe installation.");
142	return;
143    }
144    if (!checkLabels())
145	return;
146
147    /* Figure out what kind of MBR the user wants */
148    dmenuOpenSimple(&MenuMBRType);
149    mbrContents = NULL;
150    cp = getenv("bootManager");
151    if (cp) {
152	if (!strcmp(cp, "bteasy"))
153	    mbrContents = bteasy17;
154	else if (!strcmp(cp, "mbr"))
155	    mbrContents = mbr;
156    }
157
158    /* If we refuse to proceed, bail. */
159    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!"))
160	return;
161
162    devs = deviceFind(NULL, DEVICE_TYPE_DISK);
163    for (i = 0; devs[i]; i++) {
164	Chunk *c1;
165	Disk *d = (Disk *)devs[i]->private;
166
167	if (!devs[i]->enabled)
168	    continue;
169
170	if (mbrContents) {
171	    Set_Boot_Mgr(d, mbrContents);
172	    mbrContents = NULL;
173	}
174	Set_Boot_Blocks(d, boot1, boot2);
175	msgNotify("Writing partition information to drive %s", d->name);
176	Write_Disk(d);
177
178	/* Now scan for bad blocks, if necessary */
179	for (c1 = d->chunks->part; c1; c1 = c1->next) {
180	    if (c1->flags & CHUNK_BAD144) {
181		int ret;
182
183		msgNotify("Running bad block scan on partition %s", c1->name);
184		ret = vsystem("bad144 -v /dev/r%s 1234", c1->name);
185		if (ret)
186		    msgConfirm("Bad144 init on %s returned status of %d!",
187			c1->name, ret);
188		ret = vsystem("bad144 -v -s /dev/r%s", c1->name);
189		if (ret)
190		    msgConfirm("Bad144 scan on %s returned status of %d!",
191			c1->name, ret);
192	    }
193	}
194    }
195    make_filesystems();
196    copy_self();
197    dialog_clear();
198    chroot("/mnt");
199    chdir("/");
200    cpio_extract();
201    alreadyDone = TRUE;
202}
203
204static void
205installFinal(void)
206{
207    static Boolean alreadyDone = FALSE;
208
209    if (alreadyDone)
210	return;
211    install_configuration_files();
212    do_final_setup();
213    alreadyDone = TRUE;
214}
215
216/*
217 * What happens when we select "GO".  This is broken into a 3 stage installation so that
218 * the user can do a full installation but come back here again to load more distributions,
219 * perhaps from a different media type.  This would allow, for example, the user to load the
220 * majority of the system from CDROM and then use ftp to load just the DES dist.
221 */
222int
223installCommit(char *str)
224{
225    if (!Dists) {
226	msgConfirm("You haven't told me what distributions to load yet!\nPlease select a distribution from the Distributions menu.");
227	return 0;
228    }
229    if (!mediaVerify())
230	return 0;
231
232    installInitial();
233    distExtractAll();
234    installFinal();
235    return 0;
236}
237
238/* Go newfs and/or mount all the filesystems we've been asked to */
239static void
240make_filesystems(void)
241{
242    int i;
243    Disk *disk;
244    Chunk *c1, *c2;
245    Device **devs;
246    char dname[40];
247    PartInfo *p = (PartInfo *)rootdev->private;
248
249    command_clear();
250    devs = deviceFind(NULL, DEVICE_TYPE_DISK);
251
252    /* First, create and mount the root device */
253    if (strcmp(p->mountpoint, "/"))
254	msgConfirm("Warning: %s is marked as a root partition but is mounted on %s", rootdev->name, p->mountpoint);
255
256    if (p->newfs) {
257	int i;
258
259	sprintf(dname, "/dev/r%sa", rootdisk->name);
260	msgNotify("Making a new root filesystem on %s", dname);
261	i = vsystem("%s %s", p->newfs_cmd, dname);
262	if (i) {
263	    msgConfirm("Unable to make new root filesystem!  Command returned status %d", i);
264	    return;
265	}
266    }
267    else
268	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.");
269    sprintf(dname, "/dev/%sa", rootdisk->name);
270    if (Mount("/mnt", dname)) {
271	msgConfirm("Unable to mount the root file system!  Giving up.");
272	return;
273    }
274    else {
275	extern int makedevs(void);
276
277	msgNotify("Making device files");
278	if (Mkdir("/mnt/dev", NULL) || chdir("/mnt/dev") || makedevs())
279	    msgConfirm("Failed to make some of the devices in /mnt!");
280	if (Mkdir("/mnt/stand", NULL)) {
281	    msgConfirm("Unable to make /mnt/stand directory!");
282	    return;
283	}
284	chdir("/");
285    }
286
287    /* Now buzz through the rest of the partitions and mount them too */
288    for (i = 0; devs[i]; i++) {
289	disk = (Disk *)devs[i]->private;
290	if (!disk->chunks)
291	    msgFatal("No chunk list found for %s!", disk->name);
292
293	/* Make the proper device mount points in /mnt/dev */
294	MakeDevDisk(disk, "/mnt/dev");
295
296	for (c1 = disk->chunks->part; c1; c1 = c1->next) {
297	    if (c1->type == freebsd) {
298		for (c2 = c1->part; c2; c2 = c2->next) {
299		    if (c2->type == part && c2->subtype != FS_SWAP && c2->private) {
300			PartInfo *tmp = (PartInfo *)c2->private;
301
302			if (!strcmp(tmp->mountpoint, "/"))
303			    continue;
304
305			if (tmp->newfs)
306			    command_shell_add(tmp->mountpoint, "%s /mnt/dev/r%s", tmp->newfs_cmd, c2->name);
307			command_func_add(tmp->mountpoint, Mount, c2->name);
308		    }
309		    else if (c2->type == part && c2->subtype == FS_SWAP) {
310			char fname[80];
311			int i;
312
313			sprintf(fname, "/mnt/dev/%s", c2->name);
314			i = swapon(fname);
315			if (!i)
316			    msgNotify("Added %s as a swap device", fname);
317			else
318			    msgConfirm("Unable to add %s as a swap device: %s", fname, strerror(errno));
319		    }
320		}
321	    }
322	}
323    }
324    command_sort();
325    command_execute();
326}
327
328/* Copy the boot floppy contents into /stand */
329static void
330copy_self(void)
331{
332    int i;
333
334    msgNotify("Copying the boot floppy to /stand on root filesystem");
335    i = vsystem("find -x /stand | cpio -pdmv /mnt");
336    if (i)
337	msgConfirm("Copy returned error status of %d!", i);
338}
339
340static void
341cpio_extract(void)
342{
343    int i, j, zpid, cpid, pfd[2];
344
345#if 0
346    if (mediaDevice && mediaDevice->type == DEVICE_TYPE_CDROM) {
347	if (mediaDevice->init) {
348	    if ((*mediaDevice->init)(mediaDevice)) {
349		CpioFD = open("/cdrom/floppies/cpio.flp", O_RDONLY);
350		if (CpioFD != -1)
351		    msgNotify("Loading CPIO floppy from CDROM");
352	    }
353	}
354    }
355#endif
356 tryagain:
357    while (CpioFD == -1) {
358	msgConfirm("Please Insert CPIO floppy in floppy drive 0");
359	CpioFD = open("/dev/rfd0", O_RDONLY);
360	if (CpioFD >= 0)
361	    break;
362	msgDebug("Error on open of cpio floppy: %s (%d)\n", strerror(errno), errno);
363    }
364    j = fork();
365    if (!j) {
366	chdir("/");
367	msgNotify("Extracting contents of CPIO floppy...");
368	pipe(pfd);
369	zpid = fork();
370	if (!zpid) {
371	    dup2(CpioFD, 0); close(CpioFD);
372	    dup2(pfd[1], 1); close(pfd[1]);
373	    if (DebugFD != -1)
374		dup2(DebugFD, 2);
375	    close(pfd[0]);
376	    i = execl("/stand/gunzip", "/stand/gunzip", 0);
377	    msgDebug("/stand/gunzip command returns %d status\n", i);
378	    exit(i);
379	}
380	cpid = fork();
381	if (!cpid) {
382	    dup2(pfd[0], 0); close(pfd[0]);
383	    close(CpioFD);
384	    close(pfd[1]);
385	    if (DebugFD != -1) {
386		dup2(DebugFD, 1);
387		dup2(DebugFD, 2);
388	    }
389	    else {
390		close(1); open("/dev/null", O_WRONLY);
391		dup2(1, 2);
392	    }
393	    i = execl("/stand/cpio", "/stand/cpio", "-iduvm", 0);
394	    msgDebug("/stand/cpio command returns %d status\n", i);
395	    exit(i);
396	}
397	close(pfd[0]);
398	close(pfd[1]);
399	close(CpioFD);
400
401	i = waitpid(zpid, &j, 0);
402	if (i < 0 || _WSTATUS(j)) {
403	    dialog_clear();
404	    msgConfirm("gunzip returned error status of %d!", _WSTATUS(j));
405	    exit(1);
406	}
407	i = waitpid(cpid, &j, 0);
408	if (i < 0 || _WSTATUS(j)) {
409	    dialog_clear();
410	    msgConfirm("cpio returned error status of %d!", _WSTATUS(j));
411	    exit(2);
412	}
413	exit(0);
414    }
415    else
416	i = wait(&j);
417    if (i < 0 || _WSTATUS(j) || access("/OK", R_OK) == -1) {
418	dialog_clear();
419	msgConfirm("CPIO floppy did not extract properly!  Please verify\nthat your media is correct and try again.");
420	close(CpioFD);
421	CpioFD = -1;
422	goto tryagain;
423    }
424    unlink("/OK");
425}
426
427static void
428install_configuration_files(void)
429{
430}
431
432static void
433do_final_setup(void)
434{
435}
436