install.c revision 50917
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 * $FreeBSD: head/usr.sbin/sade/install.c 50917 1999-09-04 16:01:15Z jkh $
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#include <ufs/ufs/ufsmount.h>
48#include <msdosfs/msdosfsmount.h>
49#undef MSDOSFS
50#include <sys/stat.h>
51#include <sys/sysctl.h>
52#include <unistd.h>
53#include <termios.h>
54
55static void	create_termcap(void);
56static void	fixit_common(void);
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    /* Don't allow whinging if noWarn is set */
72    if (variable_get(VAR_NO_WARN))
73	whinge = FALSE;
74
75    status = TRUE;
76    *rdev = *sdev = *udev = *vdev = rootdev = swapdev = usrdev = vardev = NULL;
77
78    /* We don't need to worry about root/usr/swap if we're already multiuser */
79    if (!RunningAsInit)
80	return status;
81
82    devs = deviceFind(NULL, DEVICE_TYPE_DISK);
83    /* First verify that we have a root device */
84    for (i = 0; devs[i]; i++) {
85	if (!devs[i]->enabled)
86	    continue;
87	disk = (Disk *)devs[i]->private;
88	msgDebug("Scanning disk %s for root filesystem\n", disk->name);
89	if (!disk->chunks)
90	    msgFatal("No chunk list found for %s!", disk->name);
91	for (c1 = disk->chunks->part; c1; c1 = c1->next) {
92	    if (c1->type == freebsd) {
93		for (c2 = c1->part; c2; c2 = c2->next) {
94		    if (c2->type == part && c2->subtype != FS_SWAP && c2->private_data) {
95			if (!strcmp(((PartInfo *)c2->private_data)->mountpoint, "/")) {
96			    if (rootdev) {
97				if (whinge)
98				    msgConfirm("WARNING:  You have more than one root device set?!\n"
99					       "Using the first one found.");
100				continue;
101			    }
102			    else {
103				rootdev = c2;
104				if (isDebug())
105				    msgDebug("Found rootdev at %s!\n", rootdev->name);
106			    }
107			}
108			else if (!strcmp(((PartInfo *)c2->private_data)->mountpoint, "/usr")) {
109			    if (usrdev) {
110				if (whinge)
111				    msgConfirm("WARNING:  You have more than one /usr filesystem.\n"
112					       "Using the first one found.");
113				continue;
114			    }
115			    else {
116				usrdev = c2;
117				if (isDebug())
118				    msgDebug("Found usrdev at %s!\n", usrdev->name);
119			    }
120			}
121			else if (!strcmp(((PartInfo *)c2->private_data)->mountpoint, "/var")) {
122			    if (vardev) {
123				if (whinge)
124				    msgConfirm("WARNING:  You have more than one /var filesystem.\n"
125					       "Using the first one found.");
126				continue;
127			    }
128			    else {
129				vardev = c2;
130				if (isDebug())
131				    msgDebug("Found vardev at %s!\n", vardev->name);
132			    }
133			}
134		    }
135		}
136	    }
137	}
138    }
139
140    /* Now check for swap devices */
141    for (i = 0; devs[i]; i++) {
142	if (!devs[i]->enabled)
143	    continue;
144	disk = (Disk *)devs[i]->private;
145	msgDebug("Scanning disk %s for swap partitions\n", disk->name);
146	if (!disk->chunks)
147	    msgFatal("No chunk list found for %s!", disk->name);
148	for (c1 = disk->chunks->part; c1; c1 = c1->next) {
149	    if (c1->type == freebsd) {
150		for (c2 = c1->part; c2; c2 = c2->next) {
151		    if (c2->type == part && c2->subtype == FS_SWAP && !swapdev) {
152			swapdev = c2;
153			if (isDebug())
154			    msgDebug("Found swapdev at %s!\n", swapdev->name);
155			break;
156		    }
157		}
158	    }
159	}
160    }
161
162    /* Copy our values over */
163    *rdev = rootdev;
164    *sdev = swapdev;
165    *udev = usrdev;
166    *vdev = vardev;
167
168    if (!rootdev && whinge) {
169	msgConfirm("No root device found - you must label a partition as /\n"
170		   "in the label editor.");
171	status = FALSE;
172    }
173    if (!swapdev && whinge) {
174	msgConfirm("No swap devices found - you must create at least one\n"
175		   "swap partition.");
176	status = FALSE;
177    }
178    return status;
179}
180
181static int
182installInitial(void)
183{
184    static Boolean alreadyDone = FALSE;
185    int status = DITEM_SUCCESS;
186
187    if (alreadyDone)
188	return DITEM_SUCCESS;
189
190    if (!variable_get(DISK_LABELLED)) {
191	msgConfirm("You need to assign disk labels before you can proceed with\n"
192		   "the installation.");
193	return DITEM_FAILURE;
194    }
195    /* If it's labelled, assume it's also partitioned */
196    if (!variable_get(DISK_PARTITIONED))
197	variable_set2(DISK_PARTITIONED, "yes", 0);
198
199    /* If we refuse to proceed, bail. */
200    dialog_clear_norefresh();
201    if (!variable_get(VAR_NO_WARN))
202	if (msgYesNo(
203	    "Last Chance!  Are you SURE you want continue the installation?\n\n"
204	     "If you're running this on a disk with data you wish to save\n"
205	     "then WE STRONGLY ENCOURAGE YOU TO MAKE PROPER BACKUPS before\n"
206	     "proceeding!\n\n"
207	     "We can take no responsibility for lost disk contents!") != 0)
208	return DITEM_FAILURE | DITEM_RESTORE;
209
210    if (DITEM_STATUS(diskLabelCommit(NULL)) != DITEM_SUCCESS) {
211	msgConfirm("Couldn't make filesystems properly.  Aborting.");
212	return DITEM_FAILURE;
213    }
214
215    if (!copySelf()) {
216	msgConfirm("installInitial: Couldn't clone the boot floppy onto the\n"
217		   "root file system.  Aborting!");
218	return DITEM_FAILURE;
219    }
220
221    if (chroot("/mnt") == -1) {
222	msgConfirm("installInitial: Unable to chroot to %s - this is bad!",
223		   "/mnt");
224	return DITEM_FAILURE;
225    }
226
227    chdir("/");
228    variable_set2(RUNNING_ON_ROOT, "yes", 0);
229
230    /* Configure various files in /etc */
231    if (DITEM_STATUS(configResolv(NULL)) == DITEM_FAILURE)
232	status = DITEM_FAILURE;
233    if (DITEM_STATUS(configFstab(NULL)) == DITEM_FAILURE)
234	status = DITEM_FAILURE;
235
236    /* stick a helpful shell over on the 4th VTY */
237    systemCreateHoloshell();
238
239    alreadyDone = TRUE;
240    return status;
241}
242
243int
244installFixitHoloShell(dialogMenuItem *self)
245{
246    systemCreateHoloshell();
247    return DITEM_SUCCESS;
248}
249
250int
251installFixitCDROM(dialogMenuItem *self)
252{
253    struct stat sb;
254
255    if (!RunningAsInit)
256	return DITEM_SUCCESS;
257
258    variable_set2(SYSTEM_STATE, "fixit", 0);
259    (void)unlink("/mnt2");
260    (void)rmdir("/mnt2");
261
262    while (1) {
263	msgConfirm("Please insert a FreeBSD live filesystem CDROM and press return");
264	if (DITEM_STATUS(mediaSetCDROM(NULL)) != DITEM_SUCCESS || !mediaDevice || !mediaDevice->init(mediaDevice)) {
265	    /* If we can't initialize it, it's probably not a FreeBSD CDROM so punt on it */
266	    mediaClose();
267	    if (msgYesNo("Unable to mount the CDROM - do you want to try again?") != 0)
268		return DITEM_FAILURE;
269	}
270	else
271	    break;
272    }
273
274    /* Since the fixit code expects everything to be in /mnt2, and the CDROM mounting stuff /dist, do
275     * a little kludge dance here..
276     */
277    if (symlink("/dist", "/mnt2")) {
278	msgConfirm("Unable to symlink /mnt2 to the CDROM mount point.  Please report this\n"
279		   "unexpected failure to freebsd-bugs@FreeBSD.org.");
280	return DITEM_FAILURE;
281    }
282
283    /*
284     * If /tmp points to /mnt2/tmp from a previous fixit floppy session, it's
285     * not very good for us if we point it to the CDROM now.  Rather make it
286     * a directory in the root MFS then.  Experienced admins will still be
287     * able to mount their disk's /tmp over this if they need.
288     */
289    if (lstat("/tmp", &sb) == 0 && (sb.st_mode & S_IFMT) == S_IFLNK)
290	(void)unlink("/tmp");
291    Mkdir("/tmp");
292
293    /*
294     * Since setuid binaries ignore LD_LIBRARY_PATH, we indeed need the
295     * ld.so.hints file.  Fortunately, it's fairly small (~ 3 KB).
296     */
297    if (!file_readable("/var/run/ld.so.hints")) {
298	Mkdir("/var/run");
299	if (vsystem("/mnt2/sbin/ldconfig -s /mnt2/usr/lib")) {
300	    msgConfirm("Warning: ldconfig could not create the ld.so hints file.\n"
301		       "Dynamic executables from the CDROM likely won't work.");
302	}
303    }
304
305    /* Yet more iggly hardcoded pathnames. */
306    Mkdir("/usr/libexec");
307    if (!file_readable("/usr/libexec/ld.so")) {
308	if (symlink("/mnt2/usr/libexec/ld.so", "/usr/libexec/ld.so"))
309	    msgDebug("Couldn't link to ld.so - not necessarily a problem for ELF\n");
310    }
311    if (!file_readable("/usr/libexec/ld-elf.so.1")) {
312	if (symlink("/mnt2/usr/libexec/ld-elf.so.1", "/usr/libexec/ld-elf.so.1")) {
313	    msgConfirm("Warning: could not create the symlink for ld-elf.so.1\n"
314		       "Dynamic executables from the CDROM likely won't work.");
315	}
316    }
317    /* optional nicety */
318    if (!file_readable("/usr/bin/vi"))
319	symlink("/mnt2/usr/bin/vi", "/usr/bin/vi");
320    fixit_common();
321    mediaClose();
322    msgConfirm("Please remove the FreeBSD fixit CDROM now.");
323    return DITEM_SUCCESS;
324}
325
326int
327installFixitFloppy(dialogMenuItem *self)
328{
329    struct ufs_args args;
330    extern char *distWanted;
331
332    if (!RunningAsInit)
333	return DITEM_SUCCESS;
334
335    /* Try to open the floppy drive */
336    if (DITEM_STATUS(mediaSetFloppy(NULL)) == DITEM_FAILURE || !mediaDevice) {
337	msgConfirm("Unable to set media device to floppy.");
338	mediaClose();
339	return DITEM_FAILURE;
340    }
341
342    memset(&args, 0, sizeof(args));
343    args.fspec = mediaDevice->devname;
344    mediaDevice->private = "/mnt2";
345    distWanted = NULL;
346    Mkdir("/mnt2");
347
348    variable_set2(SYSTEM_STATE, "fixit", 0);
349
350    while (1) {
351	if (!mediaDevice->init(mediaDevice)) {
352	    if (msgYesNo("The attempt to mount the fixit floppy failed, bad floppy\n"
353			 "or unclean filesystem.  Do you want to try again?"))
354		return DITEM_FAILURE;
355	}
356	else
357	    break;
358    }
359    if (!directory_exists("/tmp"))
360	(void)symlink("/mnt2/tmp", "/tmp");
361    fixit_common();
362    mediaClose();
363    msgConfirm("Please remove the fixit floppy now.");
364    return DITEM_SUCCESS;
365}
366
367/*
368 * The common code for both fixit variants.
369 */
370static void
371fixit_common(void)
372{
373    pid_t child;
374    int waitstatus;
375
376    if (!directory_exists("/var/tmp/vi.recover")) {
377	if (DITEM_STATUS(Mkdir("/var/tmp/vi.recover")) != DITEM_SUCCESS) {
378	    msgConfirm("Warning:  Was unable to create a /var/tmp/vi.recover directory.\n"
379		       "vi will kvetch and moan about it as a result but should still\n"
380		       "be essentially usable.");
381	}
382    }
383    if (!directory_exists("/bin"))
384	(void)Mkdir("/bin");
385    (void)symlink("/stand/sh", "/bin/sh");
386    /* Link the /etc/ files */
387    if (DITEM_STATUS(Mkdir("/etc")) != DITEM_SUCCESS)
388	msgConfirm("Unable to create an /etc directory!  Things are weird on this floppy..");
389    else if ((symlink("/mnt2/etc/spwd.db", "/etc/spwd.db") == -1 && errno != EEXIST) ||
390	     (symlink("/mnt2/etc/protocols", "/etc/protocols") == -1 && errno != EEXIST) ||
391	     (symlink("/mnt2/etc/services", "/etc/services") == -1 && errno != EEXIST))
392	msgConfirm("Couldn't symlink the /etc/ files!  I'm not sure I like this..");
393    if (!file_readable(TERMCAP_FILE))
394	create_termcap();
395    if (!(child = fork())) {
396	int i, fd;
397	struct termios foo;
398	extern int login_tty(int);
399
400	ioctl(0, TIOCNOTTY, NULL);
401	for (i = getdtablesize(); i >= 0; --i)
402	    close(i);
403	fd = open("/dev/ttyv3", O_RDWR);
404	ioctl(0, TIOCSCTTY, &fd);
405	dup2(0, 1);
406	dup2(0, 2);
407	DebugFD = 2;
408	if (login_tty(fd) == -1)
409	    msgDebug("fixit: I can't set the controlling terminal.\n");
410
411	signal(SIGTTOU, SIG_IGN);
412	if (tcgetattr(0, &foo) != -1) {
413	    foo.c_cc[VERASE] = '\010';
414	    if (tcsetattr(0, TCSANOW, &foo) == -1)
415		msgDebug("fixit shell: Unable to set erase character.\n");
416	}
417	else
418	    msgDebug("fixit shell: Unable to get terminal attributes!\n");
419	setenv("PATH", "/bin:/sbin:/usr/bin:/usr/sbin:/stand:"
420	       "/mnt2/stand:/mnt2/bin:/mnt2/sbin:/mnt2/usr/bin:/mnt2/usr/sbin", 1);
421	/* use the .profile from the fixit medium */
422	setenv("HOME", "/mnt2", 1);
423	chdir("/mnt2");
424	execlp("sh", "-sh", 0);
425	msgDebug("fixit shell: Failed to execute shell!\n");
426	_exit(1);;
427    }
428    else {
429	msgNotify("Waiting for fixit shell to exit.  Go to VTY4 now by\n"
430		  "typing ALT-F4.  When you are done, type ``exit'' to exit\n"
431		  "the fixit shell and be returned here.");
432	(void)waitpid(child, &waitstatus, 0);
433    }
434    dialog_clear();
435}
436
437
438int
439installExpress(dialogMenuItem *self)
440{
441    int i;
442
443    variable_set2(SYSTEM_STATE, "express", 0);
444#ifndef __alpha__
445    if (DITEM_STATUS((i = diskPartitionEditor(self))) == DITEM_FAILURE)
446	return i;
447#endif
448
449    if (DITEM_STATUS((i = diskLabelEditor(self))) == DITEM_FAILURE)
450	return i;
451
452    dialog_clear_norefresh();
453    if (DITEM_STATUS((i = installCommit(self))) == DITEM_SUCCESS) {
454	i |= DITEM_LEAVE_MENU;
455	/* Give user the option of one last configuration spree */
456	installConfigure();
457    }
458    return i | DITEM_RESTORE;
459}
460
461/* Novice mode installation */
462int
463installNovice(dialogMenuItem *self)
464{
465    int i, tries = 0;
466    Device **devs;
467
468    variable_set2(SYSTEM_STATE, "novice", 0);
469#ifndef __alpha__
470    dialog_clear_norefresh();
471    msgConfirm("In the next menu, you will need to set up a DOS-style (\"fdisk\") partitioning\n"
472	       "scheme for your hard disk.  If you simply wish to devote all disk space\n"
473	       "to FreeBSD (overwriting anything else that might be on the disk(s) selected)\n"
474	       "then use the (A)ll command to select the default partitioning scheme followed\n"
475	       "by a (Q)uit.  If you wish to allocate only free space to FreeBSD, move to a\n"
476	       "partition marked \"unused\" and use the (C)reate command.");
477
478nodisks:
479    if (DITEM_STATUS(diskPartitionEditor(self)) == DITEM_FAILURE)
480	return DITEM_FAILURE;
481
482    if (diskGetSelectCount(&devs) <= 0 && tries < 3) {
483	msgConfirm("You need to select some disks to operate on!  Be sure to use SPACE\n"
484		   "instead of RETURN in the disk selection menu when selecting a disk.");
485	++tries;
486	goto nodisks;
487    }
488#endif
489
490    dialog_clear_norefresh();
491#ifdef __alpha__
492    msgConfirm("First, you need to create BSD partitions on the disk which you are\n"
493	       "installing to.  If you have a reasonable amount of disk space (200MB or more)\n"
494	       "and don't have any special requirements, simply use the (A)uto command to\n"
495	       "allocate space automatically.  If you have more specific needs or just don't\n"
496	       "care for the layout chosen by (A)uto, press F1 for more information on\n"
497	       "manual layout.");
498#else
499    msgConfirm("First, you need to create BSD partitions inside of the fdisk partition(s)\n"
500	       "just created.  If you have a reasonable amount of disk space (200MB or more)\n"
501	       "and don't have any special requirements, simply use the (A)uto command to\n"
502	       "allocate space automatically.  If you have more specific needs or just don't\n"
503	       "care for the layout chosen by (A)uto, press F1 for more information on\n"
504	       "manual layout.");
505#endif
506
507    if (DITEM_STATUS(diskLabelEditor(self)) == DITEM_FAILURE)
508	return DITEM_FAILURE;
509
510    dialog_clear_norefresh();
511    if (DITEM_STATUS((i = installCommit(self))) == DITEM_FAILURE) {
512	dialog_clear_norefresh();
513	msgConfirm("Installation completed with some errors.  You may wish to\n"
514		   "scroll through the debugging messages on VTY1 with the\n"
515		   "scroll-lock feature.  You can also chose \"No\" at the next\n"
516		   "prompt and go back into the installation menus to try and retry\n"
517		   "whichever operations have failed.");
518	return i | DITEM_RESTORE;
519
520    }
521    else {
522	dialog_clear_norefresh();
523	msgConfirm("Congratulations!  You now have FreeBSD installed on your system.\n\n"
524		   "We will now move on to the final configuration questions.\n"
525		   "For any option you do not wish to configure, simply select\n"
526		   "No.\n\n"
527		   "If you wish to re-enter this utility after the system is up, you\n"
528		   "may do so by typing: /stand/sysinstall.");
529    }
530    if (mediaDevice->type != DEVICE_TYPE_FTP && mediaDevice->type != DEVICE_TYPE_NFS) {
531	if (!msgYesNo("Would you like to configure any Ethernet or SLIP/PPP network devices?")) {
532	    Device *tmp;
533
534	    dialog_clear_norefresh();
535	    tmp = tcpDeviceSelect();
536	    dialog_clear_norefresh();
537	    if (tmp && !((DevInfo *)tmp->private)->use_dhcp && !msgYesNo("Would you like to bring the %s interface up right now?", tmp->name))
538		if (!tmp->init(tmp))
539		    msgConfirm("Initialization of %s device failed.", tmp->name);
540	}
541    }
542
543    dialog_clear_norefresh();
544    if (!msgYesNo("Will this machine be an IP gateway (e.g. will it forward packets\n"
545		  "between interfaces)?"))
546	variable_set2("gateway_enable", "YES", 1);
547
548    dialog_clear_norefresh();
549    if (!msgYesNo("Do you want to allow anonymous FTP connections to this machine?"))
550	configAnonFTP(self);
551
552    dialog_clear_norefresh();
553    if (!msgYesNo("Do you want to configure this machine as an NFS server?"))
554	configNFSServer(self);
555
556    dialog_clear_norefresh();
557    if (!msgYesNo("Do you want to configure this machine as an NFS client?"))
558	variable_set2("nfs_client_enable", "YES", 1);
559
560    dialog_clear_norefresh();
561    if (!msgYesNo("Would you like to customize your system console settings?")) {
562	WINDOW *w = savescr();
563
564	dmenuOpenSimple(&MenuSyscons, FALSE);
565	restorescr(w);
566    }
567
568    dialog_clear_norefresh();
569    if (!msgYesNo("Would you like to set this machine's time zone now?")) {
570	WINDOW *w = savescr();
571
572	dialog_clear();
573	systemExecute("tzsetup");
574	restorescr(w);
575    }
576
577#ifdef __i386__
578    dialog_clear_norefresh();
579    if (!msgYesNo("Would you like to enable Linux binary compatibility?"))
580	(void)configLinux(self);
581#endif
582
583    dialog_clear_norefresh();
584    if (!msgYesNo("Does this system have a mouse attached to it?")) {
585	WINDOW *w = savescr();
586
587	dmenuOpenSimple(&MenuMouse, FALSE);
588	restorescr(w);
589    }
590
591    /* Now would be a good time to checkpoint the configuration data */
592    configRC_conf();
593    sync();
594
595    if (directory_exists("/usr/X11R6")) {
596	dialog_clear_norefresh();
597	if (!msgYesNo("Would you like to configure your X server at this time?"))
598	    (void)configXSetup(self);
599    }
600
601    dialog_clear_norefresh();
602    if (!msgYesNo("The FreeBSD package collection is a collection of hundreds of ready-to-run\n"
603		  "applications, from text editors to games to WEB servers and more.  Would you\n"
604		  "like to browse the collection now?"))
605	(void)configPackages(self);
606
607    dialog_clear_norefresh();
608    if (!msgYesNo("Would you like to add any initial user accounts to the system?\n"
609		  "Adding at least one account for yourself at this stage is suggested\n"
610		  "since working as the \"root\" user is dangerous (it is easy to do\n"
611		  "things which adversely affect the entire system)."))
612	(void)configUsers(self);
613
614    dialog_clear_norefresh();
615    msgConfirm("Now you must set the system manager's password.\n"
616	       "This is the password you'll use to log in as \"root\".");
617    {
618	WINDOW *w = savescr();
619
620	if (!systemExecute("passwd root"))
621	    variable_set2("root_password", "YES", 0);
622	restorescr(w);
623    }
624
625    /* XXX Put whatever other nice configuration questions you'd like to ask the user here XXX */
626
627    /* Give user the option of one last configuration spree */
628    dialog_clear_norefresh();
629    installConfigure();
630
631    return DITEM_LEAVE_MENU | DITEM_RESTORE;
632}
633
634/* The version of commit we call from the Install Custom menu */
635int
636installCustomCommit(dialogMenuItem *self)
637{
638    int i;
639
640    dialog_clear_norefresh();
641    i = installCommit(self);
642    if (DITEM_STATUS(i) == DITEM_SUCCESS) {
643	/* Give user the option of one last configuration spree */
644	installConfigure();
645	return i;
646    }
647    else
648	msgConfirm("The commit operation completed with errors.  Not\n"
649		   "updating /etc files.");
650    return i;
651}
652
653/*
654 * What happens when we finally decide to going ahead with the installation.
655 *
656 * This is broken into multiple stages so that the user can do a full
657 * installation but come back here again to load more distributions,
658 * perhaps from a different media type.  This would allow, for
659 * example, the user to load the majority of the system from CDROM and
660 * then use ftp to load just the DES dist.
661 */
662int
663installCommit(dialogMenuItem *self)
664{
665    int i;
666    char *str;
667
668    if (!Dists)
669	distConfig(NULL);
670
671    if (!Dists)
672	if (!dmenuOpenSimple(&MenuDistributions, FALSE) && !Dists)
673	    return DITEM_FAILURE | DITEM_RESTORE;
674
675    if (!mediaVerify())
676	return DITEM_FAILURE | DITEM_RESTORE;
677
678    str = variable_get(SYSTEM_STATE);
679    if (isDebug())
680	msgDebug("installCommit: System state is `%s'\n", str);
681
682    /* Installation stuff we wouldn't do to a running system */
683    if (RunningAsInit && DITEM_STATUS((i = installInitial())) == DITEM_FAILURE)
684	return i;
685
686try_media:
687    if (!mediaDevice->init(mediaDevice)) {
688	if (!msgYesNo("Unable to initialize selected media. Would you like to\n"
689		      "adjust your media configuration and try again?")) {
690	    mediaDevice = NULL;
691	    if (!mediaVerify())
692		return DITEM_FAILURE | DITEM_RESTORE;
693	    else
694		goto try_media;
695	}
696	else
697	    return DITEM_FAILURE | DITEM_RESTORE;
698    }
699
700    /* Now go get it all */
701    i = distExtractAll(self);
702
703    /* When running as init, *now* it's safe to grab the rc.foo vars */
704    installEnvironment();
705
706    variable_set2(SYSTEM_STATE, DITEM_STATUS(i) == DITEM_FAILURE ? "error-install" : "full-install", 0);
707
708    return i | DITEM_RESTORE;
709}
710
711static void
712installConfigure(void)
713{
714    /* Final menu of last resort */
715    dialog_clear_norefresh();
716    if (!msgYesNo("Visit the general configuration menu for a chance to set\n"
717		  "any last options?")) {
718	WINDOW *w = savescr();
719
720	dmenuOpenSimple(&MenuConfigure, FALSE);
721	restorescr(w);
722    }
723    configRC_conf();
724    sync();
725}
726
727int
728installFixupBin(dialogMenuItem *self)
729{
730    Device **devs;
731    char *cp;
732    int i;
733
734    /* All of this is done only as init, just to be safe */
735    if (RunningAsInit) {
736	/* Fix up kernel first */
737	if (!file_readable("/kernel")) {
738	    char *generic_kernel = "/kernel.GENERIC";
739	    if (file_readable(generic_kernel)) {
740		if (vsystem("cp -p %s /kernel", generic_kernel)) {
741		    msgConfirm("Unable to copy /kernel into place!");
742		    return DITEM_FAILURE;
743		}
744#ifndef __alpha__
745                /* Snapshot any boot -c changes back to the new kernel */
746		cp = variable_get(VAR_KGET);
747		if (cp && (*cp == 'Y' || *cp == 'y')) {
748		    if (kget("/boot/kernel.conf")) {
749			msgConfirm("Kernel copied OK, but unable to save boot -c changes\n"
750				   "to it.  See the debug screen (ALT-F2) for details.");
751		    }
752		    else if (file_readable("/boot/kernel.conf")) {
753			FILE *fp;
754
755			if ((fp = fopen("/boot/loader.conf", "a")) != NULL) {
756			    fprintf(fp, "# -- sysinstall generated deltas -- #\n");
757			    fprintf(fp, "userconfig_script_load=\"YES\"\n");
758			    if (!OnVTY)
759				fprintf(fp, "console=\"serial\"\n");
760			    fclose(fp);
761			}
762		    }
763		}
764#endif
765	    }
766	    else {
767		msgConfirm("Can't find a kernel image to link to on the root file system!\n"
768			   "You're going to have a hard time getting this system to\n"
769			   "boot from the hard disk, I'm afraid!");
770		return DITEM_FAILURE;
771	    }
772	}
773
774	/* BOGON #1: Resurrect /dev after bin distribution screws it up */
775	msgNotify("Remaking all devices.. Please wait!");
776	if (vsystem("cd /dev; sh MAKEDEV all")) {
777	    msgConfirm("MAKEDEV returned non-zero status");
778	    return DITEM_FAILURE;
779	}
780
781	msgNotify("Resurrecting /dev entries for slices..");
782	devs = deviceFind(NULL, DEVICE_TYPE_DISK);
783	if (!devs)
784	    msgFatal("Couldn't get a disk device list!");
785
786	/* Resurrect the slices that the former clobbered */
787	for (i = 0; devs[i]; i++) {
788	    Disk *disk = (Disk *)devs[i]->private;
789	    Chunk *c1;
790
791	    if (!devs[i]->enabled)
792		continue;
793	    if (!disk->chunks)
794		msgFatal("No chunk list found for %s!", disk->name);
795	    for (c1 = disk->chunks->part; c1; c1 = c1->next) {
796		if (c1->type == freebsd) {
797		    msgNotify("Making slice entries for %s", c1->name);
798		    if (vsystem("cd /dev; sh MAKEDEV %sh", c1->name)) {
799			msgConfirm("Unable to make slice entries for %s!", c1->name);
800			return DITEM_FAILURE;
801		    }
802		}
803	    }
804	}
805
806	/* BOGON #2: We leave /etc in a bad state */
807	chmod("/etc", 0755);
808
809	/* BOGON #3: No /var/db/mountdtab complains */
810	Mkdir("/var/db");
811	creat("/var/db/mountdtab", 0644);
812
813	/* BOGON #4: /compat created by default in root fs */
814	Mkdir("/usr/compat");
815	vsystem("ln -s /usr/compat /compat");
816
817	/* BOGON #5: aliases database not build for bin */
818	vsystem("newaliases");
819
820	/* Now run all the mtree stuff to fix things up */
821        vsystem("mtree -deU -f /etc/mtree/BSD.root.dist -p /");
822        vsystem("mtree -deU -f /etc/mtree/BSD.var.dist -p /var");
823        vsystem("mtree -deU -f /etc/mtree/BSD.usr.dist -p /usr");
824
825	/* Do all the last ugly work-arounds here */
826    }
827    return DITEM_SUCCESS;
828}
829
830/* Fix side-effects from the the XFree86 installation */
831int
832installFixupXFree(dialogMenuItem *self)
833{
834    /* BOGON #1:  XFree86 requires various specialized fixups */
835    if (directory_exists("/usr/X11R6")) {
836	msgNotify("Fixing permissions in XFree86 tree..");
837	vsystem("chmod -R a+r /usr/X11R6");
838	vsystem("find /usr/X11R6 -type d | xargs chmod a+x");
839
840	/* Also do bogus minimal package registration so ports don't whine */
841	if (file_readable("/usr/X11R6/lib/X11/pkgreg.tar.gz")) {
842	    msgNotify("Installing package metainfo..");
843	    vsystem("tar xpzf /usr/X11R6/lib/X11/pkgreg.tar.gz -C / && rm /usr/X11R6/lib/X11/pkgreg.tar.gz");
844	}
845    }
846    return DITEM_SUCCESS;
847}
848
849/* Go newfs and/or mount all the filesystems we've been asked to */
850int
851installFilesystems(dialogMenuItem *self)
852{
853    int i;
854    Disk *disk;
855    Chunk *c1, *c2, *rootdev, *swapdev, *usrdev, *vardev;
856    Device **devs;
857    PartInfo *root;
858    char dname[80];
859    extern int MakeDevChunk(Chunk *c, char *n);
860    Boolean upgrade = FALSE;
861
862    /* If we've already done this, bail out */
863    if (!variable_cmp(DISK_LABELLED, "written"))
864	return DITEM_SUCCESS;
865
866    upgrade = !variable_cmp(SYSTEM_STATE, "upgrade");
867    if (!checkLabels(TRUE, &rootdev, &swapdev, &usrdev, &vardev))
868	return DITEM_FAILURE;
869
870    if (rootdev)
871	root = (PartInfo *)rootdev->private_data;
872    else
873	root = NULL;
874
875    command_clear();
876    if (swapdev && RunningAsInit) {
877	/* As the very first thing, try to get ourselves some swap space */
878	sprintf(dname, "/dev/%s", swapdev->name);
879	if (!Fake && (!MakeDevChunk(swapdev, "/dev") || !file_readable(dname))) {
880	    msgConfirm("Unable to make device node for %s in /dev!\n"
881		       "The creation of filesystems will be aborted.", dname);
882	    return DITEM_FAILURE;
883	}
884
885	if (!Fake) {
886	    if (!swapon(dname))
887		msgNotify("Added %s as initial swap device", dname);
888	    else
889		msgConfirm("WARNING!  Unable to swap to %s: %s\n"
890			   "This may cause the installation to fail at some point\n"
891			   "if you don't have a lot of memory.", dname, strerror(errno));
892	}
893    }
894
895    if (rootdev && RunningAsInit) {
896	/* Next, create and/or mount the root device */
897	sprintf(dname, "/dev/r%s", rootdev->name);
898	if (!Fake && (!MakeDevChunk(rootdev, "/dev") || !file_readable(dname))) {
899	    msgConfirm("Unable to make device node for %s in /dev!\n"
900		       "The creation of filesystems will be aborted.", dname);
901	    return DITEM_FAILURE;
902	}
903	if (strcmp(root->mountpoint, "/"))
904	    msgConfirm("Warning: %s is marked as a root partition but is mounted on %s", rootdev->name, root->mountpoint);
905
906	if (root->newfs && (!upgrade || !msgYesNo("You are upgrading - are you SURE you want to newfs the root partition?"))) {
907	    int i;
908
909	    msgNotify("Making a new root filesystem on %s", dname);
910	    i = vsystem("%s %s", root->newfs_cmd, dname);
911	    if (i) {
912		msgConfirm("Unable to make new root filesystem on %s!\n"
913			   "Command returned status %d", dname, i);
914		return DITEM_FAILURE;
915	    }
916	}
917	else {
918	    if (!upgrade) {
919		msgConfirm("Warning:  Using existing root partition.  It will be assumed\n"
920			   "that you have the appropriate device entries already in /dev.");
921	    }
922	    msgNotify("Checking integrity of existing %s filesystem.", dname);
923	    i = vsystem("fsck -y %s", dname);
924	    if (i)
925		msgConfirm("Warning: fsck returned status of %d for %s.\n"
926			   "This partition may be unsafe to use.", i, dname);
927	}
928
929	/* Switch to block device */
930	sprintf(dname, "/dev/%s", rootdev->name);
931	if (Mount("/mnt", dname)) {
932	    msgConfirm("Unable to mount the root file system on %s!  Giving up.", dname);
933	    return DITEM_FAILURE;
934	}
935    }
936
937    /* Now buzz through the rest of the partitions and mount them too */
938    devs = deviceFind(NULL, DEVICE_TYPE_DISK);
939    for (i = 0; devs[i]; i++) {
940	if (!devs[i]->enabled)
941	    continue;
942
943	disk = (Disk *)devs[i]->private;
944	if (!disk->chunks) {
945	    msgConfirm("No chunk list found for %s!", disk->name);
946	    return DITEM_FAILURE;
947	}
948	if (RunningAsInit && root && (root->newfs || upgrade)) {
949	    Mkdir("/mnt/dev");
950	    if (!Fake)
951		MakeDevDisk(disk, "/mnt/dev");
952	}
953	else if (!RunningAsInit && !Fake)
954	    MakeDevDisk(disk, "/dev");
955
956	for (c1 = disk->chunks->part; c1; c1 = c1->next) {
957	    if (c1->type == freebsd) {
958		for (c2 = c1->part; c2; c2 = c2->next) {
959		    if (c2->type == part && c2->subtype != FS_SWAP && c2->private_data) {
960			PartInfo *tmp = (PartInfo *)c2->private_data;
961
962			/* Already did root */
963			if (c2 == rootdev)
964			    continue;
965
966			if (tmp->newfs && (!upgrade || !msgYesNo("You are upgrading - are you SURE you want to newfs /dev/%s?", c2->name)))
967			    command_shell_add(tmp->mountpoint, "%s %s/dev/r%s", tmp->newfs_cmd, RunningAsInit ? "/mnt" : "", c2->name);
968			else
969			    command_shell_add(tmp->mountpoint, "fsck -y %s/dev/r%s", RunningAsInit ? "/mnt" : "", c2->name);
970			command_func_add(tmp->mountpoint, Mount, c2->name);
971		    }
972		    else if (c2->type == part && c2->subtype == FS_SWAP) {
973			char fname[80];
974			int i;
975
976			if (c2 == swapdev)
977			    continue;
978			sprintf(fname, "%s/dev/%s", RunningAsInit ? "/mnt" : "", c2->name);
979			i = (Fake || swapon(fname));
980			if (!i)
981			    msgNotify("Added %s as an additional swap device", fname);
982			else
983			    msgConfirm("Unable to add %s as a swap device: %s", fname, strerror(errno));
984		    }
985		}
986	    }
987	    else if (c1->type == fat && c1->private_data && (root->newfs || upgrade)) {
988		char name[FILENAME_MAX];
989
990		sprintf(name, "%s/%s", RunningAsInit ? "/mnt" : "", ((PartInfo *)c1->private_data)->mountpoint);
991		Mkdir(name);
992	    }
993	}
994    }
995
996    if (RunningAsInit) {
997	msgNotify("Copying initial device files..");
998	/* Copy the boot floppy's dev files */
999	if ((root->newfs || upgrade) && vsystem("find -x /dev | cpio %s -pdum /mnt", cpioVerbosity())) {
1000	    msgConfirm("Couldn't clone the /dev files!");
1001	    return DITEM_FAILURE;
1002	}
1003    }
1004
1005    command_sort();
1006    command_execute();
1007    return DITEM_SUCCESS;
1008}
1009
1010static char *
1011getRelname(void)
1012{
1013    static char buf[64];
1014    int sz = (sizeof buf) - 1;
1015
1016    if (sysctlbyname("kern.osrelease", buf, &sz, NULL, 0) != -1) {
1017	buf[sz] = '\0';
1018	return buf;
1019    }
1020    else
1021	return "<unknown>";
1022}
1023
1024/* Initialize various user-settable values to their defaults */
1025int
1026installVarDefaults(dialogMenuItem *self)
1027{
1028    char *cp;
1029
1030    /* Set default startup options */
1031    variable_set2(VAR_RELNAME,			getRelname(), 0);
1032    variable_set2(VAR_CPIO_VERBOSITY,		"high", 0);
1033    variable_set2(VAR_KGET,			"YES", 0);
1034    variable_set2(VAR_TAPE_BLOCKSIZE,		DEFAULT_TAPE_BLOCKSIZE, 0);
1035    variable_set2(VAR_INSTALL_ROOT,		"/", 0);
1036    variable_set2(VAR_INSTALL_CFG,		"install.cfg", 0);
1037    variable_set2(VAR_TRY_DHCP,			"NO", 0);	/* For now */
1038    cp = getenv("EDITOR");
1039    if (!cp)
1040	cp = "/usr/bin/ee";
1041    variable_set2(VAR_EDITOR,			cp, 0);
1042    variable_set2(VAR_FTP_USER,			"ftp", 0);
1043    variable_set2(VAR_BROWSER_PACKAGE,		"lynx", 0);
1044    variable_set2(VAR_BROWSER_BINARY,		"/usr/local/bin/lynx", 0);
1045    variable_set2(VAR_FTP_STATE,		"passive", 0);
1046    variable_set2(VAR_NFS_SECURE,		"NO", -1);
1047    variable_set2(VAR_PKG_TMPDIR,		"/usr/tmp", 0);
1048    variable_set2(VAR_MEDIA_TIMEOUT,		itoa(MEDIA_TIMEOUT), 0);
1049    if (getpid() != 1)
1050	variable_set2(SYSTEM_STATE,		"update", 0);
1051    else
1052	variable_set2(SYSTEM_STATE,		"init", 0);
1053    variable_set2(VAR_NEWFS_ARGS,		"-b 8192 -f 1024", 0);
1054    return DITEM_SUCCESS;
1055}
1056
1057/* Load the environment up from various system configuration files */
1058void
1059installEnvironment(void)
1060{
1061    configEnvironmentRC_conf();
1062    if (file_readable("/etc/resolv.conf"))
1063	configEnvironmentResolv("/etc/resolv.conf");
1064}
1065
1066/* Copy the boot floppy contents into /stand */
1067Boolean
1068copySelf(void)
1069{
1070    int i;
1071
1072    if (file_readable("/boot.help"))
1073	vsystem("cp /boot.help /mnt");
1074    msgWeHaveOutput("Copying the boot floppy to /stand on root filesystem");
1075    i = vsystem("find -x /stand | cpio %s -pdum /mnt", cpioVerbosity());
1076    if (i) {
1077	msgConfirm("Copy returned error status of %d!", i);
1078	return FALSE;
1079    }
1080
1081    /* Copy the /etc files into their rightful place */
1082    if (vsystem("cd /mnt/stand; find etc | cpio %s -pdum /mnt", cpioVerbosity())) {
1083	msgConfirm("Couldn't copy up the /etc files!");
1084	return TRUE;
1085    }
1086    return TRUE;
1087}
1088
1089static void
1090create_termcap(void)
1091{
1092    FILE *fp;
1093
1094    const char *caps[] = {
1095	termcap_vt100, termcap_cons25, termcap_cons25_m, termcap_cons25r,
1096	termcap_cons25r_m, termcap_cons25l1, termcap_cons25l1_m, NULL,
1097    };
1098    const char **cp;
1099
1100    if (!file_readable(TERMCAP_FILE)) {
1101	Mkdir("/usr/share/misc");
1102	fp = fopen(TERMCAP_FILE, "w");
1103	if (!fp) {
1104	    msgConfirm("Unable to initialize termcap file. Some screen-oriented\nutilities may not work.");
1105	    return;
1106	}
1107	cp = caps;
1108	while (*cp)
1109	    fprintf(fp, "%s\n", *(cp++));
1110	fclose(fp);
1111    }
1112}
1113