]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/sade/install.c
Use #elif defined(__alpha__) instead of #elif __alpha__.
[FreeBSD/FreeBSD.git] / usr.sbin / sade / 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$
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/uio.h>
45 #include <sys/param.h>
46 #define MSDOSFS
47 #include <sys/mount.h>
48 #include <ufs/ufs/ufsmount.h>
49 #include <fs/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         if (strcmp(variable_get(VAR_FIXIT_TTY), "serial") == 0) {
485             printf("Waiting for fixit shell to exit.\n"
486                 "When you are done, type ``exit'' to exit\n"
487                 "the fixit shell and be returned here.\n\n");
488             fflush(stdout);
489         }
490
491         /* use the .profile from the fixit medium */
492         setenv("HOME", "/mnt2", 1);
493         chdir("/mnt2");
494         execlp("sh", "-sh", (char *)0);
495         msgDebug("fixit shell: Failed to execute shell!\n");
496         _exit(1);;
497     }
498     else {
499         if (strcmp(variable_get(VAR_FIXIT_TTY), "standard") == 0) {
500             dialog_clear_norefresh();
501             msgNotify("Waiting for fixit shell to exit.  Go to VTY4 now by\n"
502                 "typing ALT-F4.  When you are done, type ``exit'' to exit\n"
503                 "the fixit shell and be returned here\n.");
504         }
505         (void)waitpid(child, &waitstatus, 0);
506         if (strcmp(variable_get(VAR_FIXIT_TTY), "serial") == 0)
507             systemResumeDialog();
508     }
509     dialog_clear();
510 }
511
512
513 int
514 installExpress(dialogMenuItem *self)
515 {
516     int i;
517
518     dialog_clear_norefresh();
519     variable_set2(SYSTEM_STATE, "express", 0);
520 #if defined(__i386__) || defined(__ia64__)
521     if (DITEM_STATUS((i = diskPartitionEditor(self))) == DITEM_FAILURE)
522         return i;
523 #endif
524     
525     if (DITEM_STATUS((i = diskLabelEditor(self))) == DITEM_FAILURE)
526         return i;
527
528     if (DITEM_STATUS((i = installCommit(self))) == DITEM_SUCCESS) {
529         i |= DITEM_LEAVE_MENU;
530         /* Set default security level */
531         configSecurityModerate(NULL);
532
533         /* Give user the option of one last configuration spree */
534         installConfigure();
535     }
536     return i;
537 }
538
539 /* Standard mode installation */
540 int
541 installStandard(dialogMenuItem *self)
542 {
543     int i, tries = 0;
544     Device **devs;
545
546     variable_set2(SYSTEM_STATE, "standard", 0);
547     dialog_clear_norefresh();
548 #if defined(__i386__) || defined(__ia64__)
549     msgConfirm("In the next menu, you will need to set up a DOS-style (\"fdisk\") partitioning\n"
550                "scheme for your hard disk.  If you simply wish to devote all disk space\n"
551                "to FreeBSD (overwriting anything else that might be on the disk(s) selected)\n"
552                "then use the (A)ll command to select the default partitioning scheme followed\n"
553                "by a (Q)uit.  If you wish to allocate only free space to FreeBSD, move to a\n"
554                "partition marked \"unused\" and use the (C)reate command.");
555
556 nodisks:
557     if (DITEM_STATUS(diskPartitionEditor(self)) == DITEM_FAILURE)
558         return DITEM_FAILURE;
559
560     if (diskGetSelectCount(&devs) <= 0 && tries < 3) {
561         msgConfirm("You need to select some disks to operate on!  Be sure to use SPACE\n"
562                    "instead of RETURN in the disk selection menu when selecting a disk.");
563         ++tries;
564         goto nodisks;
565     }
566 #endif
567
568 #if defined(__i386__) || defined(__ia64__)
569     msgConfirm("Now you need to create BSD partitions inside of the fdisk partition(s)\n"
570                "just created.  If you have a reasonable amount of disk space (200MB or more)\n"
571                "and don't have any special requirements, simply use the (A)uto command to\n"
572                "allocate space automatically.  If you have more specific needs or just don't\n"
573                "care for the layout chosen by (A)uto, press F1 for more information on\n"
574                "manual layout.");
575 #else
576     msgConfirm("Now you need to create BSD partitions on the disk which you are\n"
577                "installing to.  If you have a reasonable amount of disk space (200MB or more)\n"
578                "and don't have any special requirements, simply use the (A)uto command to\n"
579                "allocate space automatically.  If you have more specific needs or just don't\n"
580                "care for the layout chosen by (A)uto, press F1 for more information on\n"
581                "manual layout.");
582 #endif
583
584     if (DITEM_STATUS(diskLabelEditor(self)) == DITEM_FAILURE)
585         return DITEM_FAILURE;
586
587     if (DITEM_STATUS((i = installCommit(self))) == DITEM_FAILURE) {
588         dialog_clear();
589         msgConfirm("Installation completed with some errors.  You may wish to\n"
590                    "scroll through the debugging messages on VTY1 with the\n"
591                    "scroll-lock feature.  You can also choose \"No\" at the next\n"
592                    "prompt and go back into the installation menus to try and retry\n"
593                    "whichever operations have failed.");
594         return i;
595
596     }
597     else {
598         dialog_clear();
599         msgConfirm("Congratulations!  You now have FreeBSD installed on your system.\n\n"
600                    "We will now move on to the final configuration questions.\n"
601                    "For any option you do not wish to configure, simply select\n"
602                    "No.\n\n"
603                    "If you wish to re-enter this utility after the system is up, you\n"
604                    "may do so by typing: /usr/sbin/sysinstall.");
605     }
606     if (mediaDevice->type != DEVICE_TYPE_FTP && mediaDevice->type != DEVICE_TYPE_NFS) {
607         if (!msgYesNo("Would you like to configure any Ethernet or SLIP/PPP network devices?")) {
608             Device *tmp = tcpDeviceSelect();
609
610             if (tmp && !((DevInfo *)tmp->private)->use_dhcp && !msgYesNo("Would you like to bring the %s interface up right now?", tmp->name))
611                 if (!DEVICE_INIT(tmp))
612                     msgConfirm("Initialization of %s device failed.", tmp->name);
613         }
614         dialog_clear_norefresh();
615     }
616
617     if (!msgNoYes("Do you want this machine to function as a network gateway?"))
618         variable_set2("gateway_enable", "YES", 1);
619
620     dialog_clear_norefresh();
621     if (!msgNoYes("Do you want to configure inetd and the network services that it provides?"))
622         configInetd(self);
623
624     dialog_clear_norefresh();
625     if (!msgNoYes("Do you want to have anonymous FTP access to this machine?"))
626         configAnonFTP(self);
627
628     dialog_clear_norefresh();
629     if (!msgNoYes("Do you want to configure this machine as an NFS server?"))
630         configNFSServer(self);
631
632     dialog_clear_norefresh();
633     if (!msgNoYes("Do you want to configure this machine as an NFS client?"))
634         variable_set2("nfs_client_enable", "YES", 1);
635
636     if (!msgNoYes("Do you want to select a default security profile for\n"
637                  "this host (select No for \"moderate\" security)?"))
638         configSecurityProfile(self);
639     else
640         configSecurityModerate(self);
641
642     dialog_clear_norefresh();
643     if (!msgNoYes("Would you like to customize your system console settings?"))
644         dmenuOpenSimple(&MenuSyscons, FALSE);
645
646     dialog_clear_norefresh();
647     if (!msgYesNo("Would you like to set this machine's time zone now?"))
648         systemExecute("tzsetup");
649
650 #ifdef __i386__
651     dialog_clear_norefresh();
652     if (!msgYesNo("Would you like to enable Linux binary compatibility?"))
653         (void)configLinux(self);
654 #endif
655
656     dialog_clear_norefresh();
657     if (!msgNoYes("Does this system have a non-USB mouse attached to it?"))
658         dmenuOpenSimple(&MenuMouse, FALSE);
659
660     /* Now would be a good time to checkpoint the configuration data */
661     configRC_conf();
662     sync();
663
664     if (directory_exists("/usr/X11R6")) {
665         dialog_clear_norefresh();
666         if (!msgYesNo("Would you like to configure your X server at this time?"))
667             (void)configXSetup(self);
668     }
669
670     dialog_clear_norefresh();
671     if (!msgYesNo("The FreeBSD package collection is a collection of thousands of ready-to-run\n"
672                   "applications, from text editors to games to WEB servers and more.  Would you\n"
673                   "like to browse the collection now?")) {
674         (void)configPackages(self);
675     }
676
677     if (!msgYesNo("Would you like to add any initial user accounts to the system?\n"
678                   "Adding at least one account for yourself at this stage is suggested\n"
679                   "since working as the \"root\" user is dangerous (it is easy to do\n"
680                   "things which adversely affect the entire system)."))
681         (void)configUsers(self);
682
683     msgConfirm("Now you must set the system manager's password.\n"
684                "This is the password you'll use to log in as \"root\".");
685     if (!systemExecute("passwd root"))
686         variable_set2("root_password", "YES", 0);
687
688     /* XXX Put whatever other nice configuration questions you'd like to ask the user here XXX */
689
690     /* Give user the option of one last configuration spree */
691     dialog_clear_norefresh();
692     installConfigure();
693     return DITEM_LEAVE_MENU;
694 }
695
696 /* The version of commit we call from the Install Custom menu */
697 int
698 installCustomCommit(dialogMenuItem *self)
699 {
700     int i;
701
702     i = installCommit(self);
703     if (DITEM_STATUS(i) == DITEM_SUCCESS) {
704         /* Set default security level */
705         configSecurityModerate(NULL);
706
707         /* Give user the option of one last configuration spree */
708         installConfigure();
709         return i;
710     }
711     else
712         msgConfirm("The commit operation completed with errors.  Not\n"
713                    "updating /etc files.");
714     return i;
715 }
716
717 /*
718  * What happens when we finally decide to going ahead with the installation.
719  *
720  * This is broken into multiple stages so that the user can do a full
721  * installation but come back here again to load more distributions,
722  * perhaps from a different media type.  This would allow, for
723  * example, the user to load the majority of the system from CDROM and
724  * then use ftp to load just the CRYPTO dist.
725  */
726 int
727 installCommit(dialogMenuItem *self)
728 {
729     int i;
730     char *str;
731
732     dialog_clear_norefresh();
733     if (!Dists)
734         distConfig(NULL);
735
736     if (!Dists) {
737         (void)dmenuOpenSimple(&MenuDistributions, FALSE);
738         /* select reasonable defaults if necessary */
739         if (!Dists)
740             Dists = _DIST_USER;
741     }
742
743     if (!mediaVerify())
744         return DITEM_FAILURE;
745
746     str = variable_get(SYSTEM_STATE);
747     if (isDebug())
748         msgDebug("installCommit: System state is `%s'\n", str);
749
750     /* Installation stuff we wouldn't do to a running system */
751     if (RunningAsInit && DITEM_STATUS((i = installInitial())) == DITEM_FAILURE)
752         return i;
753
754 try_media:
755     if (!DEVICE_INIT(mediaDevice)) {
756         if (!msgYesNo("Unable to initialize selected media. Would you like to\n"
757                       "adjust your media configuration and try again?")) {
758             mediaDevice = NULL;
759             if (!mediaVerify())
760                 return DITEM_FAILURE;
761             else
762                 goto try_media;
763         }
764         else
765             return DITEM_FAILURE;
766     }
767
768     /* Now go get it all */
769     i = distExtractAll(self);
770
771     /* When running as init, *now* it's safe to grab the rc.foo vars */
772     installEnvironment();
773
774     variable_set2(SYSTEM_STATE, DITEM_STATUS(i) == DITEM_FAILURE ? "error-install" : "full-install", 0);
775
776     return i;
777 }
778
779 static void
780 installConfigure(void)
781 {
782     /* Final menu of last resort */
783     if (!msgNoYes("Visit the general configuration menu for a chance to set\n"
784                   "any last options?"))
785         dmenuOpenSimple(&MenuConfigure, FALSE);
786     configRC_conf();
787     sync();
788 }
789
790 int
791 installFixupBin(dialogMenuItem *self)
792 {
793     Device **devs;
794     char *cp;
795     int i;
796     FILE *fp;
797     int kstat = 1;
798
799     /* All of this is done only as init, just to be safe */
800     if (RunningAsInit) {
801 #ifdef __i386__
802         if ((fp = fopen("/boot/loader.conf", "a")) != NULL) {
803             if (!kstat || !OnVTY)
804                 fprintf(fp, "# -- sysinstall generated deltas -- #\n");
805             if (!kstat)
806                 fprintf(fp, "userconfig_script_load=\"YES\"\n");
807             if (!OnVTY)
808                 fprintf(fp, "console=\"comconsole\"\n");
809             fclose(fp);
810         }
811 #endif
812         
813         /* BOGON #2: We leave /etc in a bad state */
814         chmod("/etc", 0755);
815         
816         /* BOGON #3: No /var/db/mountdtab complains */
817         Mkdir("/var/db");
818         creat("/var/db/mountdtab", 0644);
819         
820         /* BOGON #4: /compat created by default in root fs */
821         Mkdir("/usr/compat");
822         vsystem("ln -s usr/compat /compat");
823
824         /* BOGON #5: aliases database not build for bin */
825         vsystem("newaliases");
826
827         /* Now run all the mtree stuff to fix things up */
828         vsystem("mtree -deU -f /etc/mtree/BSD.root.dist -p /");
829         vsystem("mtree -deU -f /etc/mtree/BSD.var.dist -p /var");
830         vsystem("mtree -deU -f /etc/mtree/BSD.usr.dist -p /usr");
831
832         /* Do all the last ugly work-arounds here */
833     }
834     return DITEM_SUCCESS | DITEM_RESTORE;
835 }
836
837 #ifdef X_AS_PKG
838 int
839 installX11package(dialogMenuItem *self)
840 {
841     WINDOW *w = savescr();
842     int i;
843
844     dialog_clear_norefresh();
845     msgNotify("Installing XFree86 package...");
846     i = package_add("XFree86-4");
847     restorescr(w);
848     return i;
849 }
850 #endif
851
852 /* Fix side-effects from the the XFree86 installation */
853 int
854 installFixupXFree(dialogMenuItem *self)
855 {
856     /* BOGON #1:  XFree86 requires various specialized fixups */
857     if (directory_exists("/usr/X11R6")) {
858         dialog_clear_norefresh();
859         msgNotify("Fixing permissions in XFree86 tree..");
860         vsystem("chmod -R a+r /usr/X11R6");
861         vsystem("find /usr/X11R6 -type d | xargs chmod a+x");
862
863 #ifndef X_AS_PKG
864         /* Also do bogus minimal package registration so ports don't whine */
865         if (file_readable("/usr/X11R6/lib/X11/pkgreg.tar.gz")) {
866             dialog_clear_norefresh();
867             msgNotify("Installing package metainfo..");
868             vsystem("tar xpzf /usr/X11R6/lib/X11/pkgreg.tar.gz -C / && rm /usr/X11R6/lib/X11/pkgreg.tar.gz");
869         }
870 #endif
871     }
872     return DITEM_SUCCESS | DITEM_RESTORE;
873 }
874
875 /* Go newfs and/or mount all the filesystems we've been asked to */
876 int
877 installFilesystems(dialogMenuItem *self)
878 {
879     int i;
880     Disk *disk;
881     Chunk *c1, *c2, *rootdev, *swapdev;
882     Device **devs;
883     PartInfo *root;
884     char dname[80];
885     Boolean upgrade = FALSE;
886
887     /* If we've already done this, bail out */
888     if (!variable_cmp(DISK_LABELLED, "written"))
889         return DITEM_SUCCESS;
890
891     upgrade = !variable_cmp(SYSTEM_STATE, "upgrade");
892     if (!checkLabels(TRUE, &rootdev, &swapdev, NULL, NULL, NULL, NULL))
893         return DITEM_FAILURE;
894
895     if (rootdev)
896         root = (PartInfo *)rootdev->private_data;
897     else
898         root = NULL;
899
900     command_clear();
901     if (swapdev && RunningAsInit) {
902         /* As the very first thing, try to get ourselves some swap space */
903         sprintf(dname, "/dev/%s", swapdev->name);
904         if (!Fake && !file_readable(dname)) {
905             msgConfirm("Unable to find device node for %s in /dev!\n"
906                        "The creation of filesystems will be aborted.", dname);
907             return DITEM_FAILURE;
908         }
909
910         if (!Fake) {
911             if (!swapon(dname)) {
912                 dialog_clear_norefresh();
913                 msgNotify("Added %s as initial swap device", dname);
914             }
915             else {
916                 msgConfirm("WARNING!  Unable to swap to %s: %s\n"
917                            "This may cause the installation to fail at some point\n"
918                            "if you don't have a lot of memory.", dname, strerror(errno));
919             }
920         }
921     }
922
923     if (rootdev && RunningAsInit) {
924         /* Next, create and/or mount the root device */
925         sprintf(dname, "/dev/%s", rootdev->name);
926         if (!Fake && !file_readable(dname)) {
927             msgConfirm("Unable to make device node for %s in /dev!\n"
928                        "The creation of filesystems will be aborted.", dname);
929             return DITEM_FAILURE | DITEM_RESTORE;
930         }
931         if (strcmp(root->mountpoint, "/"))
932             msgConfirm("Warning: %s is marked as a root partition but is mounted on %s", rootdev->name, root->mountpoint);
933
934         if (root->newfs && (!upgrade || !msgNoYes("You are upgrading - are you SURE you want to newfs the root partition?"))) {
935             int i;
936
937             dialog_clear_norefresh();
938             msgNotify("Making a new root filesystem on %s", dname);
939             i = vsystem("%s %s", root->newfs_cmd, dname);
940             if (i) {
941                 msgConfirm("Unable to make new root filesystem on %s!\n"
942                            "Command returned status %d", dname, i);
943                 return DITEM_FAILURE | DITEM_RESTORE;
944             }
945         }
946         else {
947             if (!upgrade) {
948                 msgConfirm("Warning:  Using existing root partition.  It will be assumed\n"
949                            "that you have the appropriate device entries already in /dev.");
950             }
951             dialog_clear_norefresh();
952             msgNotify("Checking integrity of existing %s filesystem.", dname);
953             i = vsystem("fsck_ffs -y %s", dname);
954             if (i)
955                 msgConfirm("Warning: fsck returned status of %d for %s.\n"
956                            "This partition may be unsafe to use.", i, dname);
957         }
958         if (root->soft) {
959             i = vsystem("tunefs -n enable %s", dname);
960             if (i)
961                 msgConfirm("Warning:  Unable to enable softupdates for root filesystem on %s", dname);
962         }
963
964         /* Switch to block device */
965         sprintf(dname, "/dev/%s", rootdev->name);
966         if (Mount("/mnt", dname)) {
967             msgConfirm("Unable to mount the root file system on %s!  Giving up.", dname);
968             return DITEM_FAILURE | DITEM_RESTORE;
969         }
970
971         /* Mount devfs for other partitions to mount */
972         Mkdir("/mnt/dev");
973         if (!Fake) {
974             struct iovec iov[4];
975
976             iov[0].iov_base = "fstype";
977             iov[0].iov_len = strlen(iov[0].iov_base) + 1;
978             iov[1].iov_base = "devfs";
979             iov[1].iov_len = strlen(iov[1].iov_base) + 1;
980             iov[2].iov_base = "fspath";
981             iov[2].iov_len = strlen(iov[2].iov_base) + 1;
982             iov[3].iov_base = "/mnt/dev";
983             iov[3].iov_len = strlen(iov[3].iov_base) + 1;
984             i = nmount(iov, 4, 0);
985
986             if (i) {
987                 dialog_clear_norefresh();
988                 msgConfirm("Unable to mount DEVFS (error %d)", errno);
989                 return DITEM_FAILURE | DITEM_RESTORE;
990             }
991         }
992     }
993
994     /* Now buzz through the rest of the partitions and mount them too */
995     devs = deviceFind(NULL, DEVICE_TYPE_DISK);
996     for (i = 0; devs[i]; i++) {
997         if (!devs[i]->enabled)
998             continue;
999
1000         disk = (Disk *)devs[i]->private;
1001         if (!disk->chunks) {
1002             msgConfirm("No chunk list found for %s!", disk->name);
1003             return DITEM_FAILURE | DITEM_RESTORE;
1004         }
1005         for (c1 = disk->chunks->part; c1; c1 = c1->next) {
1006             if (c1->type == freebsd) {
1007                 for (c2 = c1->part; c2; c2 = c2->next) {
1008                     if (c2->type == part && c2->subtype != FS_SWAP && c2->private_data) {
1009                         PartInfo *tmp = (PartInfo *)c2->private_data;
1010
1011                         /* Already did root */
1012                         if (c2 == rootdev)
1013                             continue;
1014
1015                         if (tmp->newfs && (!upgrade || !msgNoYes("You are upgrading - are you SURE you want to newfs /dev/%s?", c2->name)))
1016                             command_shell_add(tmp->mountpoint, "%s %s/dev/%s", tmp->newfs_cmd, RunningAsInit ? "/mnt" : "", c2->name);
1017                         else
1018                             command_shell_add(tmp->mountpoint, "fsck_ffs -y %s/dev/%s", RunningAsInit ? "/mnt" : "", c2->name);
1019                         if (tmp->soft)
1020                             command_shell_add(tmp->mountpoint, "tunefs -n enable %s/dev/%s", RunningAsInit ? "/mnt" : "", c2->name);
1021                         command_func_add(tmp->mountpoint, Mount, c2->name);
1022                     }
1023                     else if (c2->type == part && c2->subtype == FS_SWAP) {
1024                         char fname[80];
1025                         int i;
1026
1027                         if (c2 == swapdev)
1028                             continue;
1029                         sprintf(fname, "%s/dev/%s", RunningAsInit ? "/mnt" : "", c2->name);
1030                         i = (Fake || swapon(fname));
1031                         if (!i) {
1032                             dialog_clear_norefresh();
1033                             msgNotify("Added %s as an additional swap device", fname);
1034                         }
1035                         else {
1036                             msgConfirm("Unable to add %s as a swap device: %s", fname, strerror(errno));
1037                         }
1038                     }
1039                 }
1040             }
1041             else if (c1->type == fat && c1->private_data && (root->newfs || upgrade)) {
1042                 char name[FILENAME_MAX];
1043
1044                 sprintf(name, "%s/%s", RunningAsInit ? "/mnt" : "", ((PartInfo *)c1->private_data)->mountpoint);
1045                 Mkdir(name);
1046             }
1047 #if defined(__ia64__)
1048             else if (c1->type == efi && c1->private_data) {
1049                 char bootdir[FILENAME_MAX];
1050                 char efi_bootdir[FILENAME_MAX];
1051                 PartInfo *pi = (PartInfo *)c1->private_data;
1052
1053                 if (pi->newfs && (!upgrade || !msgNoYes("You are upgrading - are you SURE you want to newfs /dev/%s?", c1->name)))
1054                     command_shell_add(pi->mountpoint, "%s %s/dev/%s", pi->newfs_cmd, RunningAsInit ? "/mnt" : "", c1->name);
1055
1056                 command_func_add(pi->mountpoint, Mount, c1->name);
1057
1058                 /*
1059                  * Create a directory boot on the EFI filesystem and create a
1060                  * link boot on the root filesystem pointing to the one on the
1061                  * EFI filesystem. That way, we install the loader, kernel
1062                  * and modules on the EFI filesystem.
1063                  */
1064                 sprintf(bootdir, "%s", RunningAsInit ? "/mnt" : "");
1065                 sprintf(efi_bootdir, "%s/%s", bootdir, pi->mountpoint);
1066                 strcat(bootdir, "/boot");
1067                 strcat(efi_bootdir, "/boot");
1068                 Mkdir(efi_bootdir);
1069                 symlink(efi_bootdir, bootdir);
1070             }
1071 #endif
1072         }
1073     }
1074
1075     command_sort();
1076     command_execute();
1077     dialog_clear_norefresh();
1078     return DITEM_SUCCESS | DITEM_RESTORE;
1079 }
1080
1081 static char *
1082 getRelname(void)
1083 {
1084     static char buf[64];
1085     size_t sz = (sizeof buf) - 1;
1086
1087     if (sysctlbyname("kern.osrelease", buf, &sz, NULL, 0) != -1) {
1088         buf[sz] = '\0';
1089         return buf;
1090     }
1091     else
1092         return "<unknown>";
1093 }
1094
1095 /* Initialize various user-settable values to their defaults */
1096 int
1097 installVarDefaults(dialogMenuItem *self)
1098 {
1099     char *cp;
1100
1101     /* Set default startup options */
1102     variable_set2(VAR_RELNAME,                  getRelname(), 0);
1103     variable_set2(VAR_CPIO_VERBOSITY,           "high", 0);
1104     variable_set2(VAR_TAPE_BLOCKSIZE,           DEFAULT_TAPE_BLOCKSIZE, 0);
1105     variable_set2(VAR_INSTALL_ROOT,             "/", 0);
1106     variable_set2(VAR_INSTALL_CFG,              "install.cfg", 0);
1107     cp = getenv("EDITOR");
1108     if (!cp)
1109         cp = "/usr/bin/ee";
1110     variable_set2(VAR_EDITOR,                   cp, 0);
1111     variable_set2(VAR_FTP_USER,                 "ftp", 0);
1112     variable_set2(VAR_BROWSER_PACKAGE,          "links", 0);
1113     variable_set2(VAR_BROWSER_BINARY,           "/usr/local/bin/links", 0);
1114     variable_set2(VAR_FTP_STATE,                "passive", 0);
1115     variable_set2(VAR_NFS_SECURE,               "NO", -1);
1116     if (OnVTY)
1117             variable_set2(VAR_FIXIT_TTY,                "standard", 0);
1118     else
1119             variable_set2(VAR_FIXIT_TTY,                "serial", 0);
1120     variable_set2(VAR_PKG_TMPDIR,               "/var/tmp", 0);
1121     variable_set2(VAR_MEDIA_TIMEOUT,            itoa(MEDIA_TIMEOUT), 0);
1122     if (getpid() != 1)
1123         variable_set2(SYSTEM_STATE,             "update", 0);
1124     else
1125         variable_set2(SYSTEM_STATE,             "init", 0);
1126     variable_set2(VAR_NEWFS_ARGS,               "-b 16384 -f 2048", 0);
1127     variable_set2(VAR_CONSTERM,                 "NO", 0);
1128     return DITEM_SUCCESS;
1129 }
1130
1131 /* Load the environment up from various system configuration files */
1132 void
1133 installEnvironment(void)
1134 {
1135     configEnvironmentRC_conf();
1136     if (file_readable("/etc/resolv.conf"))
1137         configEnvironmentResolv("/etc/resolv.conf");
1138 }
1139
1140 /* Copy the boot floppy contents into /stand */
1141 Boolean
1142 copySelf(void)
1143 {
1144     int i;
1145
1146     if (file_readable("/boot.help"))
1147         vsystem("cp /boot.help /mnt");
1148     msgWeHaveOutput("Copying the boot floppy to /stand on root filesystem");
1149     i = vsystem("find -x /stand | cpio %s -pdum /mnt", cpioVerbosity());
1150     if (i) {
1151         msgConfirm("Copy returned error status of %d!", i);
1152         return FALSE;
1153     }
1154
1155     /* Copy the /etc files into their rightful place */
1156     if (vsystem("cd /mnt/stand; find etc | cpio %s -pdum /mnt", cpioVerbosity())) {
1157         msgConfirm("Couldn't copy up the /etc files!");
1158         return TRUE;
1159     }
1160     return TRUE;
1161 }
1162
1163 static void
1164 create_termcap(void)
1165 {
1166     FILE *fp;
1167
1168     const char *caps[] = {
1169         termcap_vt100, termcap_cons25, termcap_cons25_m, termcap_cons25r,
1170         termcap_cons25r_m, termcap_cons25l1, termcap_cons25l1_m,
1171         termcap_xterm, NULL,
1172     };
1173     const char **cp;
1174
1175     if (!file_readable(TERMCAP_FILE)) {
1176         Mkdir("/usr/share/misc");
1177         fp = fopen(TERMCAP_FILE, "w");
1178         if (!fp) {
1179             msgConfirm("Unable to initialize termcap file. Some screen-oriented\nutilities may not work.");
1180             return;
1181         }
1182         cp = caps;
1183         while (*cp)
1184             fprintf(fp, "%s\n", *(cp++));
1185         fclose(fp);
1186     }
1187 }