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