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