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