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