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