install.c revision 15091
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.81 1996/03/24 18:57:36 joerg 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 <ctype.h>
46#include <sys/disklabel.h>
47#include <sys/errno.h>
48#include <sys/ioctl.h>
49#include <sys/fcntl.h>
50#include <sys/wait.h>
51#include <sys/param.h>
52#define MSDOSFS
53#include <sys/mount.h>
54#undef MSDOSFS
55#include <sys/stat.h>
56#include <unistd.h>
57#include <sys/mount.h>
58
59static void	create_termcap(void);
60
61#define TERMCAP_FILE	"/usr/share/misc/termcap"
62
63static Boolean
64checkLabels(Chunk **rdev, Chunk **sdev, Chunk **udev)
65{
66    Device **devs;
67    Boolean status;
68    Disk *disk;
69    Chunk *c1, *c2, *rootdev, *swapdev, *usrdev;
70    int i;
71
72    status = TRUE;
73    *rdev = *sdev = *udev = rootdev = swapdev = usrdev = NULL;
74    devs = deviceFind(NULL, DEVICE_TYPE_DISK);
75    /* First verify that we have a root device */
76    for (i = 0; devs[i]; i++) {
77	if (!devs[i]->enabled)
78	    continue;
79	disk = (Disk *)devs[i]->private;
80	msgDebug("Scanning disk %s for root filesystem\n", disk->name);
81	if (!disk->chunks)
82	    msgFatal("No chunk list found for %s!", disk->name);
83	for (c1 = disk->chunks->part; c1; c1 = c1->next) {
84	    if (c1->type == freebsd) {
85		for (c2 = c1->part; c2; c2 = c2->next) {
86		    if (c2->type == part && c2->subtype != FS_SWAP && c2->private_data) {
87			if (c2->flags & CHUNK_IS_ROOT) {
88			    if (rootdev) {
89				dialog_clear();
90				msgConfirm("WARNING:  You have more than one root device set?!\n"
91					   "Using the first one found.");
92				continue;
93			    }
94			    rootdev = c2;
95			    if (isDebug())
96				msgDebug("Found rootdev at %s!\n", rootdev->name);
97			}
98			else if (!strcmp(((PartInfo *)c2->private_data)->mountpoint, "/usr")) {
99			    if (usrdev) {
100				dialog_clear();
101				msgConfirm("WARNING:  You have more than one /usr filesystem.\n"
102					   "Using the first one found.");
103				continue;
104			    }
105			    usrdev = c2;
106			    if (isDebug())
107				msgDebug("Found usrdev at %s!\n", usrdev->name);
108			}
109		    }
110		}
111	    }
112	}
113    }
114
115    swapdev = NULL;
116    /* Now check for swap devices */
117    for (i = 0; devs[i]; i++) {
118	if (!devs[i]->enabled)
119	    continue;
120	disk = (Disk *)devs[i]->private;
121	msgDebug("Scanning disk %s for swap partitions\n", disk->name);
122	if (!disk->chunks)
123	    msgFatal("No chunk list found for %s!", disk->name);
124	for (c1 = disk->chunks->part; c1; c1 = c1->next) {
125	    if (c1->type == freebsd) {
126		for (c2 = c1->part; c2; c2 = c2->next) {
127		    if (c2->type == part && c2->subtype == FS_SWAP && !swapdev) {
128			swapdev = c2;
129			if (isDebug())
130			    msgDebug("Found swapdev at %s!\n", swapdev->name);
131			break;
132		    }
133		}
134	    }
135	}
136    }
137
138    *rdev = rootdev;
139    if (!rootdev) {
140	dialog_clear();
141	msgConfirm("No root device found - you must label a partition as /\n"
142		   "in the label editor.");
143	status = FALSE;
144    }
145
146    *sdev = swapdev;
147    if (!swapdev) {
148	dialog_clear();
149	msgConfirm("No swap devices found - you must create at least one\n"
150		   "swap partition.");
151	status = FALSE;
152    }
153
154    *udev = usrdev;
155    if (!usrdev) {
156	dialog_clear();
157	msgConfirm("WARNING:  No /usr filesystem found.  This is not technically\n"
158		   "an error if your root filesystem is big enough (or you later\n"
159		   "intend to mount your /usr filesystem over NFS), but it may otherwise\n"
160		   "cause you trouble if you're not exactly sure what you are doing!");
161    }
162    return status;
163}
164
165static int
166installInitial(void)
167{
168    static Boolean alreadyDone = FALSE;
169
170    if (alreadyDone)
171	return RET_SUCCESS;
172
173    if (!variable_get(DISK_LABELLED)) {
174	dialog_clear();
175	msgConfirm("You need to assign disk labels before you can proceed with\nthe installation.");
176	return RET_FAIL;
177    }
178    /* If it's labelled, assume it's also partitioned */
179    if (!variable_get(DISK_PARTITIONED))
180	variable_set2(DISK_PARTITIONED, "yes");
181
182    /* If we refuse to proceed, bail. */
183    dialog_clear();
184    if (msgYesNo("Last Chance!  Are you SURE you want continue the installation?\n\n"
185		 "If you're running this on a disk with data you wish to save\n"
186		 "then WE STRONGLY ENCOURAGE YOU TO MAKE PROPER BACKUPS before\n"
187		 "proceeding!\n\n"
188		 "We can take no responsibility for lost disk contents!"))
189	return RET_FAIL;
190
191    if (diskLabelCommit(NULL) != RET_SUCCESS) {
192	dialog_clear();
193	msgConfirm("Couldn't make filesystems properly.  Aborting.");
194	return RET_FAIL;
195    }
196
197    if (!copySelf()) {
198	dialog_clear();
199	msgConfirm("Couldn't clone the boot floppy onto the root file system.\n"
200		   "Aborting.");
201	return RET_FAIL;
202    }
203
204    if (chroot("/mnt") == -1) {
205	dialog_clear();
206	msgConfirm("Unable to chroot to /mnt - this is bad!");
207	return RET_FAIL;
208    }
209
210    chdir("/");
211    variable_set2(RUNNING_ON_ROOT, "yes");
212
213    dialog_clear();
214    /* stick a helpful shell over on the 4th VTY */
215    systemCreateHoloshell();
216
217    alreadyDone = TRUE;
218    return RET_SUCCESS;
219}
220
221int
222installFixit(dialogMenuItem *self)
223{
224    struct ufs_args args;
225    pid_t child;
226    int waitstatus;
227
228    variable_set2(SYSTEM_STATE, "fixit");
229    memset(&args, 0, sizeof(args));
230    args.fspec = "/dev/fd0";
231    Mkdir("/mnt2", NULL);
232
233    while (1) {
234	dialog_clear();
235	msgConfirm("Please insert a writable fixit floppy and press return");
236	if (mount(MOUNT_UFS, "/mnt2", 0, (caddr_t)&args) != -1)
237	    break;
238	dialog_clear();
239	if (msgYesNo("Unable to mount the fixit floppy - do you want to try again?"))
240	    return RET_FAIL;
241    }
242    dialog_clear();
243    dialog_update();
244    end_dialog();
245    DialogActive = FALSE;
246    if (!directory_exists("/tmp"))
247	(void)symlink("/mnt2/tmp", "/tmp");
248    if (!directory_exists("/var/tmp/vi.recover")) {
249	if (Mkdir("/var/tmp/vi.recover", NULL) != RET_SUCCESS) {
250	    dialog_clear();
251	    msgConfirm("Warning:  Was unable to create a /var/tmp/vi.recover directory.\n"
252		       "vi will kvetch and moan about it as a result but should still\n"
253		       "be essentially usable.");
254	}
255    }
256    /* Link the spwd.db file */
257    if (Mkdir("/etc", NULL) != RET_SUCCESS) {
258	dialog_clear();
259	msgConfirm("Unable to create an /etc directory!  Things are weird on this floppy..");
260    }
261    else {
262	if (symlink("/mnt2/etc/spwd.db", "/etc/spwd.db") == -1) {
263	    dialog_clear();
264	    msgConfirm("Couldn't symlink the /etc/spwd.db file!  I'm not sure I like this..");
265	}
266    }
267    if (!file_readable(TERMCAP_FILE))
268	create_termcap();
269    if (!(child = fork())) {
270	struct termios foo;
271
272	signal(SIGTTOU, SIG_IGN);
273	if (tcgetattr(0, &foo) != -1) {
274	    foo.c_cc[VERASE] = '\010';
275	    if (tcsetattr(0, TCSANOW, &foo) == -1)
276		msgDebug("fixit shell: Unable to set erase character.\n");
277	}
278	else
279	    msgDebug("fixit shell: Unable to get terminal attributes!\n");
280	printf("When you're finished with this shell, please type exit.\n");
281	printf("The fixit floppy itself is mounted as /mnt2\n");
282	setenv("PATH", "/bin:/sbin:/usr/bin:/usr/sbin:/stand:/mnt2/stand", 1);
283	execlp("sh", "-sh", 0);
284	msgDebug("fixit shell: Failed to execute shell!\n");
285	return -1;
286    }
287    else
288	(void)waitpid(child, &waitstatus, 0);
289
290    DialogActive = TRUE;
291    clear();
292    dialog_clear();
293    dialog_update();
294    unmount("/mnt2", MNT_FORCE);
295    dialog_clear();
296    msgConfirm("Please remove the fixit floppy now.");
297    return RET_SUCCESS;
298}
299
300int
301installExpress(dialogMenuItem *self)
302{
303    variable_set2(SYSTEM_STATE, "express");
304    if (diskPartitionEditor(self) == RET_FAIL)
305	return RET_FAIL;
306
307    if (diskLabelEditor(self) == RET_FAIL)
308	return RET_FAIL;
309
310    if (!Dists) {
311	if (!dmenuOpenSimple(&MenuDistributions))
312	    return RET_FAIL;
313    }
314
315    if (!mediaDevice) {
316	if (!dmenuOpenSimple(&MenuMedia) || !mediaDevice)
317	    return RET_FAIL;
318    }
319
320    if (installCommit(self) == RET_FAIL)
321	return RET_FAIL;
322
323    return RET_DONE;
324}
325
326/* Novice mode installation */
327int
328installNovice(dialogMenuItem *self)
329{
330    variable_set2(SYSTEM_STATE, "novice");
331    dialog_clear();
332    msgConfirm("In the next menu, you will need to set up a DOS-style (\"fdisk\") partitioning\n"
333	       "scheme for your hard disk.  If you simply wish to devote all disk space\n"
334	       "to FreeBSD (overwritting anything else that might be on the disk(s) selected)\n"
335	       "then use the (A)ll command to select the default partitioning scheme followed\n"
336	       "by a (Q)uit.  If you wish to allocate only free space to FreeBSD, move to a\n"
337	       "partition marked \"unused\" and use the (C)reate command.");
338
339    if (diskPartitionEditor(self) == RET_FAIL)
340	return RET_FAIL;
341
342    dialog_clear();
343    msgConfirm("Next, you need to create BSD partitions inside of the fdisk partition(s)\n"
344	       "just created.  If you have a reasonable amount of disk space (200MB or more)\n"
345	       "and don't have any special requirements, simply use the (A)uto command to\n"
346	       "allocate space automatically.  If you have more specific needs or just don't\n"
347	       "care for the layout chosen by (A)uto, press F1 for more information on\n"
348	       "manual layout.");
349
350    if (diskLabelEditor(self) == RET_FAIL)
351	return RET_FAIL;
352
353    dialog_clear();
354    msgConfirm("Now it is time to select an installation subset.  There are a number of\n"
355	       "canned distribution sets, ranging from minimal installation sets to full\n"
356	       "X11 developer oriented configurations.  You can also select a custom set\n"
357	       "of distributions if none of the provided ones are suitable.");
358    while (1) {
359	if (!dmenuOpenSimple(&MenuDistributions))
360	    return RET_FAIL;
361
362	if (Dists || !msgYesNo("No distributions selected.  Are you sure you wish to continue?"))
363	    break;
364    }
365
366    if (!mediaDevice) {
367	dialog_clear();
368	msgConfirm("Finally, you must specify an installation medium.");
369	if (!dmenuOpenSimple(&MenuMedia) || !mediaDevice)
370	    return RET_FAIL;
371    }
372
373    if (installCommit(self) == RET_FAIL)
374	return RET_FAIL;
375
376    return RET_DONE;
377}
378
379/*
380 * What happens when we select "Commit" in the custom installation menu.
381 *
382 * This is broken into multiple stages so that the user can do a full installation but come back here
383 * again to load more distributions, perhaps from a different media type.  This would allow, for
384 * example, the user to load the majority of the system from CDROM and then use ftp to load just the
385 * DES dist.
386 */
387int
388installCommit(dialogMenuItem *self)
389{
390    int i;
391    extern int cdromMounted;
392    char *str;
393
394    if (!mediaVerify())
395	return RET_FAIL;
396
397    str = variable_get(SYSTEM_STATE);
398    i = RET_DONE;
399    if (RunningAsInit) {
400	if (installInitial() == RET_FAIL)
401	    return RET_FAIL;
402	if (configFstab() == RET_FAIL)
403	    return RET_FAIL;
404	if (!rootExtract()) {
405	    dialog_clear();
406	    msgConfirm("Failed to load the ROOT distribution.  Please correct\n"
407		       "this problem and try again.");
408	    return RET_FAIL;
409	}
410    }
411
412    if (distExtractAll(self) == RET_FAIL)
413	i = RET_FAIL;
414
415    if (installFixup(self) == RET_FAIL)
416	i = RET_FAIL;
417
418    if (i != RET_FAIL && !strcmp(str, "novice")) {
419	dialog_clear();
420	msgConfirm("Since you're running the novice installation, a few post-configuration\n"
421		   "questions will be asked at this point.  For any option you do not wish\n"
422		   "to configure, select Cancel.");
423
424	if (mediaDevice->type != DEVICE_TYPE_FTP && mediaDevice->type != DEVICE_TYPE_NFS) {
425	    dialog_clear();
426	    if (!msgYesNo("Would you like to configure this machine's network interfaces?")) {
427		Device *save = mediaDevice;
428
429		/* This will also set the media device, which we don't want */
430		tcpDeviceSelect();
431		mediaDevice = save;
432	    }
433	}
434
435	dialog_clear();
436	if (!msgYesNo("Would you like to configure Samba for connecting NETBUI clients to this\n"
437		      "machine?  Windows 95, Windows NT and Windows for Workgroups\n"
438		      "machines can use NETBUI transport for disk and printer sharing."))
439	    configSamba(self);
440
441	dialog_clear();
442	if (!msgYesNo("Will this machine be an IP gateway (e.g. will it forward packets\n"
443		      "between interfaces)?"))
444	    variable_set2("gateway", "YES");
445
446	dialog_clear();
447	if (!msgYesNo("Do you want to allow anonymous FTP connections to this machine?"))
448	    configAnonFTP(self);
449
450	dialog_clear();
451	if (!msgYesNo("Do you want to configure this machine as an NFS server?"))
452	    configNFSServer(self);
453
454	dialog_clear();
455	if (!msgYesNo("Do you want to configure this machine as an NFS client?"))
456	    variable_set2("nfs_client", "YES");
457
458	dialog_clear();
459	if (!msgYesNo("Do you want to configure this machine as a WEB server?"))
460	    configApache(self);
461
462	dialog_clear();
463	if (!msgYesNo("Would you like to customize your system console settings?"))
464	    dmenuOpenSimple(&MenuSyscons);
465
466	dialog_clear();
467	if (!msgYesNo("Would you like to set this machine's time zone now?"))
468	    systemExecute("rm -f /etc/wall_cmos_clock /etc/localtime; tzsetup");
469
470	dialog_clear();
471	if (!msgYesNo("Does this system have a mouse attached to it?"))
472	    dmenuOpenSimple(&MenuMouse);
473
474	if (directory_exists("/usr/X11R6")) {
475	    dialog_clear();
476	    if (!msgYesNo("Would you like to configure your X server at this time?"))
477		systemExecute("/usr/X11R6/bin/xf86config");
478	}
479
480	if (cdromMounted) {
481	    dialog_clear();
482	    if (!msgYesNo("Would you like to link to the ports tree on your CDROM?\n\n"
483			  "This will require that you have your FreeBSD CD in the CDROM\n"
484			  "drive to use the ports collection, but at a substantial savings\n"
485			  "in disk space (NOTE:  This may take as long as 15 or 20 minutes\n"
486			  "depending on the speed of your CDROM drive)."))
487		configPorts(self);
488	}
489
490	dialog_clear();
491	if (!msgYesNo("The FreeBSD package collection is a collection of over 300 ready-to-run\n"
492		      "applications, from text editors to games to WEB servers.  Would you like\n"
493		      "to browse the collection now?"))
494	    configPackages(self);
495
496	/* XXX Put whatever other nice configuration questions you'd like to ask the user here XXX */
497
498    }
499
500    /* Final menu of last resort */
501    dialog_clear();
502    if (!msgYesNo("Would you like to go to the general configuration menu for a chance to set\n"
503		  "any last configuration options?"))
504	dmenuOpenSimple(&MenuConfigure);
505
506    /* Write out any changes .. */
507    configResolv();
508    configSysconfig();
509
510    /* Don't print this if we're express or novice installing */
511    if (strcmp(str, "express") && strcmp(str, "novice")) {
512	if (Dists || i == RET_FAIL) {
513	    dialog_clear();
514	    msgConfirm("Installation completed with some errors.  You may wish to\n"
515		       "scroll through the debugging messages on VTY1 with the\n"
516		       "scroll-lock feature.");
517	}
518	else {
519	    dialog_clear();
520	    msgConfirm("Installation completed successfully.\n\n"
521		       "If you have any network devices you have not yet configured,\n"
522		       "see the Interfaces configuration item on the Configuration menu.");
523	}
524    }
525    else if (!strcmp(str, "novice")) {
526	if (Dists || i == RET_FAIL) {
527	    dialog_clear();
528	    msgConfirm("Installation completed with some errors.  You may wish to\n"
529		       "scroll through the debugging messages on VTY1 with the\n"
530		       "scroll-lock feature.  You can also chose \"No\" at the next\n"
531		       "prompt and go back into the installation menus to try and retry\n"
532		       "whichever operations have failed.");
533	}
534	else {
535	    dialog_clear();
536	    msgConfirm("Congradulations!  You now have FreeBSD installed on your system.\n"
537		       "At this stage, there shouldn't be much left to do from this\n"
538		       "installation utility so if you wish to come up from the hard disk\n"
539		       "now, simply select \"Yes\" at the next prompt to reboot.\n"
540		       "If you wish to re-enter this utility after the system is up, you\n"
541		       "may do so by typing: /stand/sysinstall.");
542	}
543    }
544    variable_set2(SYSTEM_STATE, i == RET_FAIL ? "error-install" : "full-install");
545
546    return i;
547}
548
549int
550installFixup(dialogMenuItem *self)
551{
552    Device **devs;
553    int i;
554
555    if (!file_readable("/kernel")) {
556	if (file_readable("/kernel.GENERIC")) {
557	    if (vsystem("cp -p /kernel.GENERIC /kernel")) {
558		dialog_clear();
559		msgConfirm("Unable to link /kernel into place!");
560		return RET_FAIL;
561	    }
562	}
563	else {
564	    dialog_clear();
565	    msgConfirm("Can't find a kernel image to link to on the root file system!\n"
566		       "You're going to have a hard time getting this system to\n"
567		       "boot from the hard disk, I'm afraid!");
568	    return RET_FAIL;
569	}
570    }
571    /* Resurrect /dev after bin distribution screws it up */
572    if (RunningAsInit) {
573	msgNotify("Remaking all devices.. Please wait!");
574	if (vsystem("cd /dev; sh MAKEDEV all")) {
575	    dialog_clear();
576	    msgConfirm("MAKEDEV returned non-zero status");
577	    return RET_FAIL;
578	}
579
580	msgNotify("Resurrecting /dev entries for slices..");
581	devs = deviceFind(NULL, DEVICE_TYPE_DISK);
582	if (!devs)
583	    msgFatal("Couldn't get a disk device list!");
584
585	/* Resurrect the slices that the former clobbered */
586	for (i = 0; devs[i]; i++) {
587	    Disk *disk = (Disk *)devs[i]->private;
588	    Chunk *c1;
589
590	    if (!devs[i]->enabled)
591		continue;
592	    if (!disk->chunks)
593		msgFatal("No chunk list found for %s!", disk->name);
594	    for (c1 = disk->chunks->part; c1; c1 = c1->next) {
595		if (c1->type == freebsd) {
596		    msgNotify("Making slice entries for %s", c1->name);
597		    if (vsystem("cd /dev; sh MAKEDEV %sh", c1->name)) {
598			dialog_clear();
599			msgConfirm("Unable to make slice entries for %s!", c1->name);
600			return RET_FAIL;
601		    }
602		}
603	    }
604	}
605	/* XXX Do all the last ugly work-arounds here which we'll try and excise someday right?? XXX */
606
607	msgNotify("Fixing permissions..");
608	/* BOGON #1:  XFree86 extracting /usr/X11R6 with root-only perms */
609	if (directory_exists("/usr/X11R6")) {
610	    system("chmod -R a+r /usr/X11R6");
611	    system("find /usr/X11R6 -type d | xargs chmod a+x");
612	}
613	/* BOGON #2: We leave /etc in a bad state */
614	chmod("/etc", 0755);
615
616	/* BOGON #3: No /var/db/mountdtab complains */
617	Mkdir("/var/db", NULL);
618	creat("/var/db/mountdtab", 0644);
619
620	/* Now run all the mtree stuff to fix things up */
621        vsystem("mtree -deU -f /etc/mtree/BSD.root.dist -p /");
622        vsystem("mtree -deU -f /etc/mtree/BSD.var.dist -p /var");
623        vsystem("mtree -deU -f /etc/mtree/BSD.usr.dist -p /usr");
624    }
625    return RET_SUCCESS;
626}
627
628/* Go newfs and/or mount all the filesystems we've been asked to */
629int
630installFilesystems(dialogMenuItem *self)
631{
632    int i;
633    Disk *disk;
634    Chunk *c1, *c2, *rootdev, *swapdev, *usrdev;
635    Device **devs;
636    PartInfo *root;
637    char dname[80], *str;
638    extern int MakeDevChunk(Chunk *c, char *n);
639    Boolean upgrade = FALSE;
640
641    str = variable_get(SYSTEM_STATE);
642
643    if (!checkLabels(&rootdev, &swapdev, &usrdev))
644	return RET_FAIL;
645
646    root = (PartInfo *)rootdev->private_data;
647    command_clear();
648    upgrade = str && !strcmp(str, "upgrade");
649
650    /* As the very first thing, try to get ourselves some swap space */
651    sprintf(dname, "/dev/%s", swapdev->name);
652    if (!MakeDevChunk(swapdev, "/dev") || !file_readable(dname)) {
653	dialog_clear();
654	msgConfirm("Unable to make device node for %s in /dev!\n"
655		   "The creation of filesystems will be aborted.", dname);
656	return RET_FAIL;
657    }
658    if (!swapon(dname))
659	msgNotify("Added %s as initial swap device", dname);
660    else
661	msgConfirm("WARNING!  Unable to swap to %s: %s\n"
662		   "This may cause the installation to fail at some point\n"
663		   "if you don't have a lot of memory.", dname, strerror(errno));
664
665    /* Next, create and/or mount the root device */
666    sprintf(dname, "/dev/r%sa", rootdev->disk->name);
667    if (!MakeDevChunk(rootdev, "/dev") || !file_readable(dname)) {
668	dialog_clear();
669	msgConfirm("Unable to make device node for %s in /dev!\n"
670		   "The creation of filesystems will be aborted.", dname);
671	return RET_FAIL;
672    }
673
674    if (strcmp(root->mountpoint, "/")) {
675	dialog_clear();
676	msgConfirm("Warning: %s is marked as a root partition but is mounted on %s", rootdev->name, root->mountpoint);
677    }
678
679    if (root->newfs) {
680	int i;
681
682	msgNotify("Making a new root filesystem on %s", dname);
683	i = vsystem("%s %s", root->newfs_cmd, dname);
684	if (i) {
685	    dialog_clear();
686	    msgConfirm("Unable to make new root filesystem on %s!\n"
687		       "Command returned status %d", dname, i);
688	    return RET_FAIL;
689	}
690    }
691    else {
692	if (!upgrade) {
693	    dialog_clear();
694	    msgConfirm("Warning:  Root device is selected read-only.  It will be assumed\n"
695		       "that you have the appropriate device entries already in /dev.");
696	}
697	msgNotify("Checking integrity of existing %s filesystem.", dname);
698	i = vsystem("fsck -y %s", dname);
699	if (i) {
700	    dialog_clear();
701	    msgConfirm("Warning: fsck returned status of %d for %s.\n"
702		       "This partition may be unsafe to use.", i, dname);
703	}
704    }
705    /* Switch to block device */
706    sprintf(dname, "/dev/%sa", rootdev->disk->name);
707    if (Mount("/mnt", dname)) {
708	dialog_clear();
709	msgConfirm("Unable to mount the root file system on %s!  Giving up.", dname);
710	return RET_FAIL;
711    }
712
713    /* Now buzz through the rest of the partitions and mount them too */
714    devs = deviceFind(NULL, DEVICE_TYPE_DISK);
715    for (i = 0; devs[i]; i++) {
716	if (!devs[i]->enabled)
717	    continue;
718
719	disk = (Disk *)devs[i]->private;
720	if (!disk->chunks) {
721	    dialog_clear();
722	    msgConfirm("No chunk list found for %s!", disk->name);
723	    return RET_FAIL;
724	}
725	if (root->newfs || upgrade) {
726	    Mkdir("/mnt/dev", NULL);
727	    MakeDevDisk(disk, "/mnt/dev");
728	}
729
730	for (c1 = disk->chunks->part; c1; c1 = c1->next) {
731	    if (c1->type == freebsd) {
732		for (c2 = c1->part; c2; c2 = c2->next) {
733		    if (c2->type == part && c2->subtype != FS_SWAP && c2->private_data) {
734			PartInfo *tmp = (PartInfo *)c2->private_data;
735
736			/* Already did root */
737			if (c2 == rootdev)
738			    continue;
739
740			if (tmp->newfs)
741			    command_shell_add(tmp->mountpoint, "%s /mnt/dev/r%s", tmp->newfs_cmd, c2->name);
742			else
743			    command_shell_add(tmp->mountpoint, "fsck -y /mnt/dev/r%s", c2->name);
744			command_func_add(tmp->mountpoint, Mount, c2->name);
745		    }
746		    else if (c2->type == part && c2->subtype == FS_SWAP) {
747			char fname[80];
748			int i;
749
750			if (c2 == swapdev)
751			    continue;
752			sprintf(fname, "/mnt/dev/%s", c2->name);
753			i = swapon(fname);
754			if (!i)
755			    msgNotify("Added %s as an additional swap device", fname);
756			else {
757			    dialog_clear();
758			    msgConfirm("Unable to add %s as a swap device: %s", fname, strerror(errno));
759			}
760		    }
761		}
762	    }
763	    else if (c1->type == fat && c1->private_data && (root->newfs || upgrade)) {
764		char name[FILENAME_MAX];
765
766		sprintf(name, "/mnt%s", ((PartInfo *)c1->private_data)->mountpoint);
767		Mkdir(name, NULL);
768	    }
769	}
770    }
771
772    msgNotify("Copying initial device files..");
773    /* Copy the boot floppy's dev files */
774    if ((root->newfs || upgrade) && vsystem("find -x /dev | cpio -pdumv /mnt")) {
775	dialog_clear();
776	msgConfirm("Couldn't clone the /dev files!");
777	return RET_FAIL;
778    }
779
780    command_sort();
781    command_execute();
782    return RET_SUCCESS;
783}
784
785int
786installVarDefaults(dialogMenuItem *self)
787{
788    /* Set default startup options */
789    variable_set2(VAR_ROUTEDFLAGS,		"-q");
790    variable_set2(VAR_RELNAME,			RELEASE_NAME);
791    variable_set2(VAR_CPIO_VERBOSITY,		"high");
792    variable_set2(VAR_TAPE_BLOCKSIZE,		DEFAULT_TAPE_BLOCKSIZE);
793    variable_set2(VAR_EDITOR,			"/stand/ee");
794    variable_set2(VAR_FTP_USER,			"ftp");
795    variable_set2(VAR_BROWSER_PACKAGE,		"lynx-2.4fm");
796    variable_set2(VAR_BROWSER_BINARY,		"/usr/local/bin/lynx");
797    variable_set2(VAR_CONFIG_FILE,		"freebsd.cfg");
798    variable_set2(VAR_FTP_STATE,		"passive");
799    variable_set2(VAR_FTP_ONERROR,		"abort");
800    variable_set2(VAR_FTP_RETRIES,		MAX_FTP_RETRIES);
801    if (getpid() != 1)
802	variable_set2(SYSTEM_STATE,		"update");
803    else
804	variable_set2(SYSTEM_STATE,		"init");
805    return RET_SUCCESS;
806}
807
808/* Copy the boot floppy contents into /stand */
809Boolean
810copySelf(void)
811{
812    int i;
813
814    msgWeHaveOutput("Copying the boot floppy to /stand on root filesystem");
815    i = vsystem("find -x /stand | cpio -pdumv /mnt");
816    if (i) {
817	dialog_clear();
818	msgConfirm("Copy returned error status of %d!", i);
819	return FALSE;
820    }
821
822    /* Copy the /etc files into their rightful place */
823    if (vsystem("cd /mnt/stand; find etc | cpio -pdumv /mnt")) {
824	dialog_clear();
825	msgConfirm("Couldn't copy up the /etc files!");
826	return TRUE;
827    }
828    return TRUE;
829}
830
831static Boolean loop_on_root_floppy(void);
832
833Boolean
834rootExtract(void)
835{
836    int fd;
837    static Boolean alreadyExtracted = FALSE;
838
839    if (alreadyExtracted)
840	return TRUE;
841
842    if (mediaDevice) {
843	if (isDebug())
844	    msgDebug("Attempting to extract root image from %s\n", mediaDevice->name);
845	switch(mediaDevice->type) {
846
847	case DEVICE_TYPE_FLOPPY:
848	    alreadyExtracted = loop_on_root_floppy();
849	    break;
850
851	default:
852	    if (!mediaDevice->init(mediaDevice))
853		break;
854	    fd = mediaDevice->get(mediaDevice, "floppies/root.flp", FALSE);
855	    if (fd < 0) {
856		dialog_clear();
857		msgConfirm("Couldn't get root image from %s!\n"
858			   "Will try to get it from floppy.", mediaDevice->name);
859		mediaDevice->shutdown(mediaDevice);
860	        alreadyExtracted = loop_on_root_floppy();
861	    }
862	    else {
863		msgNotify("Loading root image from:\n%s", mediaDevice->name);
864		alreadyExtracted = mediaExtractDist("/", fd);
865		mediaDevice->close(mediaDevice, fd);
866	    }
867	    break;
868	}
869    }
870    else
871	alreadyExtracted = loop_on_root_floppy();
872    return alreadyExtracted;
873}
874
875static Boolean
876loop_on_root_floppy(void)
877{
878    int fd;
879    int status = FALSE;
880
881    while (1) {
882	fd = getRootFloppy();
883	if (fd != -1) {
884	    msgNotify("Extracting root floppy..");
885	    status = mediaExtractDist("/", fd);
886	    close(fd);
887	    break;
888	}
889    }
890    return status;
891}
892
893static void
894create_termcap(void)
895{
896    FILE *fp;
897
898    const char *caps[] = {
899	termcap_vt100, termcap_cons25, termcap_cons25_m, termcap_cons25r,
900	termcap_cons25r_m, termcap_cons25l1, termcap_cons25l1_m, NULL,
901    };
902    const char **cp;
903
904    if (!file_readable(TERMCAP_FILE)) {
905	Mkdir("/usr/share/misc", NULL);
906	fp = fopen(TERMCAP_FILE, "w");
907	if (!fp) {
908	    dialog_clear();
909	    msgConfirm("Unable to initialize termcap file. Some screen-oriented\nutilities may not work.");
910	    return;
911	}
912	cp = caps;
913	while (*cp)
914	    fprintf(fp, "%s\n", *(cp++));
915	fclose(fp);
916    }
917}
918
919