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