install.c revision 8757
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.56 1995/05/26 08:41:40 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/ioctl.h>
48#include <sys/fcntl.h>
49#include <sys/wait.h>
50#include <unistd.h>
51
52Boolean SystemWasInstalled;
53
54static void	make_filesystems(void);
55static void	copy_self(void);
56static void	root_extract(void);
57
58static Disk *rootdisk;
59static Chunk *rootdev;
60
61static Boolean
62checkLabels(void)
63{
64    Device **devs;
65    Disk *disk;
66    Chunk *c1, *c2, *swapdev = NULL;
67    int i;
68
69    devs = deviceFind(NULL, DEVICE_TYPE_DISK);
70    /* First verify that we have a root device */
71    for (i = 0; devs[i]; i++) {
72	if (!devs[i]->enabled)
73	    continue;
74	disk = (Disk *)devs[i]->private;
75	msgDebug("Scanning disk %s for root filesystem\n", disk->name);
76	if (!disk->chunks)
77	    msgFatal("No chunk list found for %s!", disk->name);
78	for (c1 = disk->chunks->part; c1; c1 = c1->next) {
79	    if (c1->type == freebsd) {
80		for (c2 = c1->part; c2; c2 = c2->next) {
81		    if (c2->type == part && c2->subtype != FS_SWAP &&
82			c2->private && c2->flags & CHUNK_IS_ROOT) {
83			rootdisk = disk;
84			rootdev = c2;
85			break;
86		    }
87		}
88	    }
89	}
90    }
91
92    /* Now check for swap devices */
93    for (i = 0; devs[i]; i++) {
94	disk = (Disk *)devs[i]->private;
95	msgDebug("Scanning disk %s for swap partitions\n", disk->name);
96	if (!disk->chunks)
97	    msgFatal("No chunk list found for %s!", disk->name);
98	for (c1 = disk->chunks->part; c1; c1 = c1->next) {
99	    if (c1->type == freebsd) {
100		for (c2 = c1->part; c2; c2 = c2->next) {
101		    if (c2->type == part && c2->subtype == FS_SWAP) {
102			swapdev = c2;
103			break;
104		    }
105		}
106	    }
107	}
108    }
109
110    if (!rootdev) {
111	msgConfirm("No root device found - you must label a partition as /\n in the label editor.");
112	return FALSE;
113    }
114    if (!swapdev) {
115	msgConfirm("No swap devices found - you must create at least one\nswap partition.");
116	return FALSE;
117    }
118    return TRUE;
119}
120
121static Boolean
122installInitial(void)
123{
124    extern u_char boot1[], boot2[];
125    extern u_char mbr[], bteasy17[];
126    u_char *mbrContents;
127    Device **devs;
128    int i;
129    static Boolean alreadyDone = FALSE;
130    char *cp;
131
132    if (alreadyDone)
133	return TRUE;
134
135    if (!getenv(DISK_PARTITIONED)) {
136	msgConfirm("You need to partition your disk before you can proceed with\nthe installation.");
137	return FALSE;
138    }
139    if (!getenv(DISK_LABELLED)) {
140	msgConfirm("You need to assign disk labels before you can proceed with\nthe installation.");
141	return FALSE;
142    }
143    if (!checkLabels())
144	return FALSE;
145
146    /* Figure out what kind of MBR the user wants */
147    dmenuOpenSimple(&MenuMBRType);
148    mbrContents = NULL;
149    cp = getenv("bootManager");
150    if (cp) {
151	if (!strcmp(cp, "bteasy"))
152	    mbrContents = bteasy17;
153	else if (!strcmp(cp, "mbr"))
154	    mbrContents = mbr;
155    }
156
157    /* If we refuse to proceed, bail. */
158    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!"))
159	return FALSE;
160
161    devs = deviceFind(NULL, DEVICE_TYPE_DISK);
162    for (i = 0; devs[i]; i++) {
163	Chunk *c1;
164	Disk *d = (Disk *)devs[i]->private;
165
166	if (!devs[i]->enabled)
167	    continue;
168
169	if (mbrContents) {
170	    Set_Boot_Mgr(d, mbrContents);
171	    mbrContents = NULL;
172	}
173	Set_Boot_Blocks(d, boot1, boot2);
174	msgNotify("Writing partition information to drive %s", d->name);
175	Write_Disk(d);
176
177	/* Now scan for bad blocks, if necessary */
178	for (c1 = d->chunks->part; c1; c1 = c1->next) {
179	    if (c1->flags & CHUNK_BAD144) {
180		int ret;
181
182		msgNotify("Running bad block scan on partition %s", c1->name);
183		ret = vsystem("bad144 -v /dev/r%s 1234", c1->name);
184		if (ret)
185		    msgConfirm("Bad144 init on %s returned status of %d!",
186			c1->name, ret);
187		ret = vsystem("bad144 -v -s /dev/r%s", c1->name);
188		if (ret)
189		    msgConfirm("Bad144 scan on %s returned status of %d!",
190			c1->name, ret);
191	    }
192	}
193    }
194    make_filesystems();
195    copy_self();
196    dialog_clear();
197    chroot("/mnt");
198    chdir("/");
199    variable_set2(RUNNING_ON_ROOT, "yes");
200    /* If we're running as init, stick a shell over on the 4th VTY */
201    if (RunningAsInit && !fork()) {
202	int i, fd;
203
204	for (i = 0; i < 64; i++)
205	    close(i);
206	fd = open("/dev/ttyv3", O_RDWR);
207	ioctl(0, TIOCSCTTY, &fd);
208	dup2(0, 1);
209	dup2(0, 2);
210	execlp("sh", "-sh", 0);
211	exit(1);
212    }
213    root_extract();
214    vsystem("(cd /stand; find etc) | cpio -pdmv /");
215    alreadyDone = TRUE;
216    return TRUE;
217}
218
219static void
220installFinal(void)
221{
222    static Boolean alreadyDone = FALSE;
223
224    if (alreadyDone)
225	return;
226    configFstab();
227    configSysconfig();
228    configResolv();
229    alreadyDone = TRUE;
230    SystemWasInstalled = TRUE;
231}
232
233/*
234 * What happens when we select "GO".  This is broken into a 3 stage installation so that
235 * the user can do a full installation but come back here again to load more distributions,
236 * perhaps from a different media type.  This would allow, for example, the user to load the
237 * majority of the system from CDROM and then use ftp to load just the DES dist.
238 */
239int
240installCommit(char *str)
241{
242    if (!Dists) {
243	msgConfirm("You haven't told me what distributions to load yet!\nPlease select a distribution from the Distributions menu.");
244	return 0;
245    }
246    if (!mediaVerify())
247	return 0;
248
249    if (!installInitial())
250	return 0;
251    distExtractAll();
252    installFinal();
253    return 0;
254}
255
256/* Go newfs and/or mount all the filesystems we've been asked to */
257static void
258make_filesystems(void)
259{
260    int i;
261    Disk *disk;
262    Chunk *c1, *c2;
263    Device **devs;
264    char dname[40];
265    PartInfo *p = (PartInfo *)rootdev->private;
266
267    command_clear();
268    devs = deviceFind(NULL, DEVICE_TYPE_DISK);
269
270    /* First, create and mount the root device */
271    if (strcmp(p->mountpoint, "/"))
272	msgConfirm("Warning: %s is marked as a root partition but is mounted on %s", rootdev->name, p->mountpoint);
273
274    if (p->newfs) {
275	int i;
276
277	sprintf(dname, "/dev/r%sa", rootdisk->name);
278	msgNotify("Making a new root filesystem on %s", dname);
279	i = vsystem("%s %s", p->newfs_cmd, dname);
280	if (i) {
281	    msgConfirm("Unable to make new root filesystem!  Command returned status %d", i);
282	    return;
283	}
284    }
285    else {
286	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.");
287	sprintf(dname, "/dev/r%sa", rootdisk->name);
288	msgNotify("Checking integrity of existing %s filesystem", dname);
289	i = vsystem("fsck -y %s", dname);
290	if (i)
291	    msgConfirm("Warning: fsck returned status off %d - this partition may be\nunsafe to use.", i);
292    }
293    sprintf(dname, "/dev/%sa", rootdisk->name);
294    if (Mount("/mnt", dname)) {
295	msgConfirm("Unable to mount the root file system!  Giving up.");
296	return;
297    }
298    else {
299	extern int makedevs(void);
300
301	msgNotify("Making device files");
302	if (Mkdir("/mnt/dev", NULL) || chdir("/mnt/dev") || makedevs())
303	    msgConfirm("Failed to make some of the devices in /mnt!");
304	if (Mkdir("/mnt/stand", NULL)) {
305	    msgConfirm("Unable to make /mnt/stand directory!");
306	    return;
307	}
308	chdir("/");
309    }
310
311    /* Now buzz through the rest of the partitions and mount them too */
312    for (i = 0; devs[i]; i++) {
313	disk = (Disk *)devs[i]->private;
314	if (!disk->chunks)
315	    msgFatal("No chunk list found for %s!", disk->name);
316
317	/* Make the proper device mount points in /mnt/dev */
318	MakeDevDisk(disk, "/mnt/dev");
319
320	for (c1 = disk->chunks->part; c1; c1 = c1->next) {
321	    if (c1->type == freebsd) {
322		for (c2 = c1->part; c2; c2 = c2->next) {
323		    if (c2->type == part && c2->subtype != FS_SWAP && c2->private) {
324			PartInfo *tmp = (PartInfo *)c2->private;
325
326			if (!strcmp(tmp->mountpoint, "/"))
327			    continue;
328
329			if (tmp->newfs)
330			    command_shell_add(tmp->mountpoint, "%s /mnt/dev/r%s", tmp->newfs_cmd, c2->name);
331			else
332			    command_shell_add(tmp->mountpoint, "fsck -y /mnt/dev/r%s", c2->name);
333			command_func_add(tmp->mountpoint, Mount, c2->name);
334		    }
335		    else if (c2->type == part && c2->subtype == FS_SWAP) {
336			char fname[80];
337			int i;
338
339			sprintf(fname, "/mnt/dev/%s", c2->name);
340			i = swapon(fname);
341			if (!i)
342			    msgNotify("Added %s as a swap device", fname);
343			else
344			    msgConfirm("Unable to add %s as a swap device: %s", fname, strerror(errno));
345		    }
346		}
347	    }
348	    else if (c1->type == fat) {
349		PartInfo *tmp = (PartInfo *)c1->private;
350
351		if (!tmp)
352		    continue;
353		command_func_add(tmp->mountpoint, Mount_DOS, c1->name);
354	    }
355	}
356    }
357    command_sort();
358    command_execute();
359}
360
361/* Copy the boot floppy contents into /stand */
362static void
363copy_self(void)
364{
365    int i;
366
367    msgWeHaveOutput("Copying the boot floppy to /stand on root filesystem");
368    i = vsystem("find -x /stand | cpio -pdmv /mnt");
369    if (i)
370	msgConfirm("Copy returned error status of %d!", i);
371    /* copy up the etc files */
372    (void)vsystem("(cd /mnt/stand; find etc) | cpio -pdmv /mnt");
373}
374
375static void loop_on_root_floppy();
376
377static void
378root_extract(void)
379{
380    int fd, status;
381
382    if (OnCDROM) {
383	fd = open("/floppies/root.flp", O_RDONLY);
384	mediaExtractDist("root.flp", "/", fd);
385	return;
386    }
387    if (mediaDevice) {
388	switch(mediaDevice->type) {
389
390	case DEVICE_TYPE_DOS:
391	case DEVICE_TYPE_FTP:
392	case DEVICE_TYPE_DISK:
393	case DEVICE_TYPE_NETWORK:
394	case DEVICE_TYPE_CDROM:
395	    if (mediaDevice->init)
396		if (!(*mediaDevice->init)(mediaDevice))
397		    break;
398	    fd = (*mediaDevice->get)("root.flp", "floppies/");
399	    if (fd != -1) {
400		msgNotify("Loading root floppy over %s", mediaDevice->name);
401		status = mediaExtractDist("root.flp", "/", fd);
402		if (mediaDevice->close)
403		    (*mediaDevice->close)(mediaDevice, fd);
404		else
405		    close(fd);
406	    }
407	    break;
408
409	case DEVICE_TYPE_FLOPPY:
410	default:
411	    loop_on_root_floppy();
412	    break;
413	}
414    }
415    else
416	loop_on_root_floppy();
417}
418
419static void
420loop_on_root_floppy(void)
421{
422    int fd;
423
424    fd = genericGetDist("root.flp", NULL, TRUE);
425    if (fd == -1)
426	return;
427    mediaExtractDist("root.flp", "/", fd);
428}
429