install.c revision 8756
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.55 1995/05/25 18:48:25 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    alreadyDone = TRUE;
215    return TRUE;
216}
217
218static void
219installFinal(void)
220{
221    static Boolean alreadyDone = FALSE;
222
223    if (alreadyDone)
224	return;
225    configFstab();
226    configSysconfig();
227    configResolv();
228    alreadyDone = TRUE;
229    SystemWasInstalled = TRUE;
230}
231
232/*
233 * What happens when we select "GO".  This is broken into a 3 stage installation so that
234 * the user can do a full installation but come back here again to load more distributions,
235 * perhaps from a different media type.  This would allow, for example, the user to load the
236 * majority of the system from CDROM and then use ftp to load just the DES dist.
237 */
238int
239installCommit(char *str)
240{
241    if (!Dists) {
242	msgConfirm("You haven't told me what distributions to load yet!\nPlease select a distribution from the Distributions menu.");
243	return 0;
244    }
245    if (!mediaVerify())
246	return 0;
247
248    if (!installInitial())
249	return 0;
250    distExtractAll();
251    installFinal();
252    return 0;
253}
254
255/* Go newfs and/or mount all the filesystems we've been asked to */
256static void
257make_filesystems(void)
258{
259    int i;
260    Disk *disk;
261    Chunk *c1, *c2;
262    Device **devs;
263    char dname[40];
264    PartInfo *p = (PartInfo *)rootdev->private;
265
266    command_clear();
267    devs = deviceFind(NULL, DEVICE_TYPE_DISK);
268
269    /* First, create and mount the root device */
270    if (strcmp(p->mountpoint, "/"))
271	msgConfirm("Warning: %s is marked as a root partition but is mounted on %s", rootdev->name, p->mountpoint);
272
273    if (p->newfs) {
274	int i;
275
276	sprintf(dname, "/dev/r%sa", rootdisk->name);
277	msgNotify("Making a new root filesystem on %s", dname);
278	i = vsystem("%s %s", p->newfs_cmd, dname);
279	if (i) {
280	    msgConfirm("Unable to make new root filesystem!  Command returned status %d", i);
281	    return;
282	}
283    }
284    else {
285	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.");
286	sprintf(dname, "/dev/r%sa", rootdisk->name);
287	msgNotify("Checking integrity of existing %s filesystem", dname);
288	i = vsystem("fsck -y %s", dname);
289	if (i)
290	    msgConfirm("Warning: fsck returned status off %d - this partition may be\nunsafe to use.", i);
291    }
292    sprintf(dname, "/dev/%sa", rootdisk->name);
293    if (Mount("/mnt", dname)) {
294	msgConfirm("Unable to mount the root file system!  Giving up.");
295	return;
296    }
297    else {
298	extern int makedevs(void);
299
300	msgNotify("Making device files");
301	if (Mkdir("/mnt/dev", NULL) || chdir("/mnt/dev") || makedevs())
302	    msgConfirm("Failed to make some of the devices in /mnt!");
303	if (Mkdir("/mnt/stand", NULL)) {
304	    msgConfirm("Unable to make /mnt/stand directory!");
305	    return;
306	}
307	chdir("/");
308    }
309
310    /* Now buzz through the rest of the partitions and mount them too */
311    for (i = 0; devs[i]; i++) {
312	disk = (Disk *)devs[i]->private;
313	if (!disk->chunks)
314	    msgFatal("No chunk list found for %s!", disk->name);
315
316	/* Make the proper device mount points in /mnt/dev */
317	MakeDevDisk(disk, "/mnt/dev");
318
319	for (c1 = disk->chunks->part; c1; c1 = c1->next) {
320	    if (c1->type == freebsd) {
321		for (c2 = c1->part; c2; c2 = c2->next) {
322		    if (c2->type == part && c2->subtype != FS_SWAP && c2->private) {
323			PartInfo *tmp = (PartInfo *)c2->private;
324
325			if (!strcmp(tmp->mountpoint, "/"))
326			    continue;
327
328			if (tmp->newfs)
329			    command_shell_add(tmp->mountpoint, "%s /mnt/dev/r%s", tmp->newfs_cmd, c2->name);
330			else
331			    command_shell_add(tmp->mountpoint, "fsck -y /mnt/dev/r%s", c2->name);
332			command_func_add(tmp->mountpoint, Mount, c2->name);
333		    }
334		    else if (c2->type == part && c2->subtype == FS_SWAP) {
335			char fname[80];
336			int i;
337
338			sprintf(fname, "/mnt/dev/%s", c2->name);
339			i = swapon(fname);
340			if (!i)
341			    msgNotify("Added %s as a swap device", fname);
342			else
343			    msgConfirm("Unable to add %s as a swap device: %s", fname, strerror(errno));
344		    }
345		}
346	    }
347	    else if (c1->type == fat) {
348		PartInfo *tmp = (PartInfo *)c1->private;
349
350		if (!tmp)
351		    continue;
352		command_func_add(tmp->mountpoint, Mount_DOS, c1->name);
353	    }
354	}
355    }
356    command_sort();
357    command_execute();
358}
359
360/* Copy the boot floppy contents into /stand */
361static void
362copy_self(void)
363{
364    int i;
365
366    msgWeHaveOutput("Copying the boot floppy to /stand on root filesystem");
367    i = vsystem("find -x /stand | cpio -pdmv /mnt");
368    if (i)
369	msgConfirm("Copy returned error status of %d!", i);
370    /* copy up the etc files */
371    (void)vsystem("(cd /mnt/stand; find etc) | cpio -pdmv /mnt");
372}
373
374static void loop_on_root_floppy();
375
376static void
377root_extract(void)
378{
379    int fd, status;
380
381    if (OnCDROM) {
382	fd = open("/floppies/root.flp", O_RDONLY);
383	mediaExtractDist("root.flp", "/", fd);
384	return;
385    }
386    if (mediaDevice) {
387	switch(mediaDevice->type) {
388
389	case DEVICE_TYPE_DOS:
390	case DEVICE_TYPE_FTP:
391	case DEVICE_TYPE_DISK:
392	case DEVICE_TYPE_NETWORK:
393	case DEVICE_TYPE_CDROM:
394	    if (mediaDevice->init)
395		if (!(*mediaDevice->init)(mediaDevice))
396		    break;
397	    fd = (*mediaDevice->get)("root.flp", "floppies/");
398	    if (fd != -1) {
399		msgNotify("Loading root floppy over %s", mediaDevice->name);
400		status = mediaExtractDist("root.flp", "/", fd);
401		if (mediaDevice->close)
402		    (*mediaDevice->close)(mediaDevice, fd);
403		else
404		    close(fd);
405	    }
406	    break;
407
408	case DEVICE_TYPE_FLOPPY:
409	default:
410	    loop_on_root_floppy();
411	    break;
412	}
413    }
414    else
415	loop_on_root_floppy();
416}
417
418static void
419loop_on_root_floppy(void)
420{
421    int fd;
422
423    fd = genericGetDist("root.flp", NULL, TRUE);
424    if (fd == -1)
425	return;
426    mediaExtractDist("root.flp", "/", fd);
427}
428