]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - usr.sbin/sysinstall/install.c
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.git] / usr.sbin / 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$
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/consio.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/uio.h>
46 #include <sys/param.h>
47 #define MSDOSFS
48 #include <sys/mount.h>
49 #include <ufs/ufs/ufsmount.h>
50 #include <fs/msdosfs/msdosfsmount.h>
51 #undef MSDOSFS
52 #include <sys/stat.h>
53 #include <sys/sysctl.h>
54 #include <libdisk.h>
55 #include <limits.h>
56 #include <unistd.h>
57 #include <termios.h>
58
59 /* Hack for rsaref package add, which displays interactive license.
60  * Used by package.c
61  */
62 int _interactiveHack;
63 int FixItMode = 0;
64 int NCpus;
65
66 static void     create_termcap(void);
67 static void     fixit_common(void);
68 int             fixit_livefs_common(dialogMenuItem *self);
69
70 #define TERMCAP_FILE    "/usr/share/misc/termcap"
71
72 static void     installConfigure(void);
73
74 Boolean
75 checkLabels(Boolean whinge)
76 {
77     Device **devs;
78     Boolean status;
79     Disk *disk;
80     PartInfo *pi;
81     Chunk *c1, *c2;
82     int i;
83
84     /* Don't allow whinging if noWarn is set */
85     if (variable_get(VAR_NO_WARN))
86         whinge = FALSE;
87
88     status = TRUE;
89     HomeChunk = RootChunk = SwapChunk = NULL;
90     TmpChunk = UsrChunk = VarChunk = NULL;
91 #ifdef __ia64__
92     EfiChunk = NULL;
93 #endif
94
95     /* We don't need to worry about root/usr/swap if we're already multiuser */
96     if (!RunningAsInit)
97         return status;
98
99     devs = deviceFind(NULL, DEVICE_TYPE_DISK);
100     /* First verify that we have a root device */
101     for (i = 0; devs[i]; i++) {
102         if (!devs[i]->enabled)
103             continue;
104         disk = (Disk *)devs[i]->private;
105         msgDebug("Scanning disk %s for root filesystem\n", disk->name);
106         if (!disk->chunks)
107             msgFatal("No chunk list found for %s!", disk->name);
108         for (c1 = disk->chunks->part; c1; c1 = c1->next) {
109 #ifdef __ia64__
110             c2 = c1;
111 #elif defined(__powerpc__)
112             if (c1->type == apple) {
113                 for (c2 = c1->part; c2; c2 = c2->next) {
114 #else
115             if (c1->type == freebsd) {
116                 for (c2 = c1->part; c2; c2 = c2->next) {
117 #endif
118
119                     pi = (PartInfo *)c2->private_data;
120                     if (c2->type == part && c2->subtype != FS_SWAP && pi != NULL) {
121                         if (!strcmp(pi->mountpoint, "/")) {
122                             if (RootChunk) {
123                                 if (whinge)
124                                     msgConfirm("WARNING:  You have more than one root device set?!\n"
125                                                "Using the first one found.");
126                                 continue;
127                             }
128                             else {
129                                 RootChunk = c2;
130                                 if (isDebug())
131                                     msgDebug("Found rootdev at %s!\n", RootChunk->name);
132                             }
133                         }
134                         else if (!strcmp(pi->mountpoint, "/usr")) {
135                             if (UsrChunk) {
136                                 if (whinge)
137                                     msgConfirm("WARNING:  You have more than one /usr filesystem.\n"
138                                                "Using the first one found.");
139                                 continue;
140                             }
141                             else {
142                                 UsrChunk = c2;
143                                 if (isDebug())
144                                     msgDebug("Found usrdev at %s!\n", UsrChunk->name);
145                             }
146                         }
147                         else if (!strcmp(pi->mountpoint, "/var")) {
148                             if (VarChunk) {
149                                 if (whinge)
150                                     msgConfirm("WARNING:  You have more than one /var filesystem.\n"
151                                                "Using the first one found.");
152                                 continue;
153                             }
154                             else {
155                                 VarChunk = c2;
156                                 if (isDebug())
157                                     msgDebug("Found vardev at %s!\n", VarChunk->name);
158                             }
159                         } else if (!strcmp(pi->mountpoint, "/tmp")) {
160                             if (TmpChunk) {
161                                 if (whinge)
162                                     msgConfirm("WARNING:  You have more than one /tmp filesystem.\n"
163                                                "Using the first one found.");
164                                 continue;
165                             }
166                             else {
167                                 TmpChunk = c2;
168                                 if (isDebug())
169                                     msgDebug("Found tmpdev at %s!\n", TmpChunk->name);
170                             }
171                         } else if (!strcmp(pi->mountpoint, "/home")) {
172                             if (HomeChunk) {
173                                 if (whinge)
174                                     msgConfirm("WARNING:  You have more than one /home filesystem.\n"
175                                                "Using the first one found.");
176                                 continue;
177                             }
178                             else {
179                                 HomeChunk = c2;
180                                 if (isDebug())
181                                     msgDebug("Found homedev at %s!\n", HomeChunk->name);
182                             }
183                         }
184                     }
185 #ifndef __ia64__
186                 }
187             }
188 #endif
189         }
190     }
191
192     /* Now check for swap devices */
193     for (i = 0; devs[i]; i++) {
194         if (!devs[i]->enabled)
195             continue;
196         disk = (Disk *)devs[i]->private;
197         msgDebug("Scanning disk %s for swap partitions\n", disk->name);
198         if (!disk->chunks)
199             msgFatal("No chunk list found for %s!", disk->name);
200         for (c1 = disk->chunks->part; c1; c1 = c1->next) {
201
202 #ifdef __ia64__
203             c2 = c1;
204 #elif defined(__powerpc__)
205             if (c1->type == apple) {
206                 for (c2 = c1->part; c2; c2 = c2->next) {
207 #else
208             if (c1->type == freebsd) {
209                 for (c2 = c1->part; c2; c2 = c2->next) {
210 #endif
211                     if (c2->type == part && c2->subtype == FS_SWAP && !SwapChunk) {
212                         SwapChunk = c2;
213                         if (isDebug())
214                             msgDebug("Found swapdev at %s!\n", SwapChunk->name);
215                         break;
216                     }
217 #ifndef __ia64__
218                 }
219             }
220 #endif
221         }
222     }
223
224 #ifdef __ia64__
225     for (i = 0; devs[i] != NULL; i++) {
226         if (!devs[i]->enabled)
227             continue;
228         disk = (Disk *)devs[i]->private;
229         for (c1 = disk->chunks->part; c1 != NULL; c1 = c1->next) {
230                 pi = (PartInfo *)c1->private_data;
231             if (c1->type == efi && pi != NULL && pi->mountpoint[0] == '/')
232                 EfiChunk = c1;
233         }
234     }
235 #endif
236
237     if (!RootChunk && whinge) {
238         msgConfirm("No root device found - you must label a partition as /\n"
239                    "in the label editor.");
240         status = FALSE;
241     }
242     if (!SwapChunk && whinge) {
243         if (msgYesNo("No swap devices found - you should create at least one\n"
244                      "swap partition.  Without swap, the install will fail\n"
245                      "if you do not have enough RAM.  Continue anyway?"))
246             status = FALSE;
247     }
248 #ifdef __ia64__
249     if (EfiChunk == NULL && whinge) {
250         if (msgYesNo("No (mounted) EFI system partition found. Is this what you want?"))
251             status = FALSE;
252     }
253 #endif
254     return status;
255 }
256
257 static int
258 installInitial(void)
259 {
260     static Boolean alreadyDone = FALSE;
261     int status = DITEM_SUCCESS;
262
263     if (alreadyDone)
264         return DITEM_SUCCESS;
265
266     if (!variable_get(DISK_LABELLED)) {
267         msgConfirm("You need to assign disk labels before you can proceed with\n"
268                    "the installation.");
269         return DITEM_FAILURE;
270     }
271     /* If it's labelled, assume it's also partitioned */
272     if (!variable_get(DISK_PARTITIONED))
273         variable_set2(DISK_PARTITIONED, "yes", 0);
274
275     /* If we refuse to proceed, bail. */
276     dialog_clear_norefresh();
277     if (!variable_get(VAR_NO_WARN)) {
278         if (msgYesNo(
279             "Last Chance!  Are you SURE you want continue the installation?\n\n"
280             "If you're running this on a disk with data you wish to save\n"
281             "then WE STRONGLY ENCOURAGE YOU TO MAKE PROPER BACKUPS before\n"
282             "proceeding!\n\n"
283             "We can take no responsibility for lost disk contents!") != 0)
284         return DITEM_FAILURE;
285     }
286
287     if (DITEM_STATUS(diskLabelCommit(NULL)) != DITEM_SUCCESS) {
288         msgConfirm("Couldn't make filesystems properly.  Aborting.");
289         return DITEM_FAILURE;
290     }
291
292     if (!copySelf()) {
293         msgConfirm("installInitial: Couldn't clone the boot floppy onto the\n"
294                    "root file system.  Aborting!");
295         return DITEM_FAILURE;
296     }
297
298     if (!Restarting && chroot("/mnt") == -1) {
299         msgConfirm("installInitial: Unable to chroot to %s - this is bad!",
300                    "/mnt");
301         return DITEM_FAILURE;
302     }
303
304     chdir("/");
305     variable_set2(RUNNING_ON_ROOT, "yes", 0);
306
307     /* Configure various files in /etc */
308     if (DITEM_STATUS(configResolv(NULL)) == DITEM_FAILURE)
309         status = DITEM_FAILURE;
310     if (DITEM_STATUS(configFstab(NULL)) == DITEM_FAILURE)
311         status = DITEM_FAILURE;
312
313     /* stick a helpful shell over on the 4th VTY */
314     if (!variable_get(VAR_NO_HOLOSHELL))
315         systemCreateHoloshell();
316
317     alreadyDone = TRUE;
318     return status;
319 }
320
321 int
322 installFixitHoloShell(dialogMenuItem *self)
323 {
324     FixItMode = 1;
325     systemCreateHoloshell();
326     FixItMode = 0;
327     return DITEM_SUCCESS;
328 }
329
330 /*
331  * Load the live filesystem from USB media.
332  */
333 int
334 installFixitUSB(dialogMenuItem *self)
335 {
336         if (!RunningAsInit)
337                 return (DITEM_SUCCESS);
338
339         variable_set2(SYSTEM_STATE, "fixit", 0);
340
341         if (DITEM_STATUS(mediaSetUSB(NULL)) != DITEM_SUCCESS ||
342             !DEVICE_INIT(mediaDevice)) {
343                 msgConfirm("No USB devices found!");
344                 return (DITEM_FAILURE);
345         } else if (!file_readable("/dist/rescue/ldconfig")) {
346                 msgConfirm("Unable to find a FreeBSD live filesystem.");
347                 return (DITEM_FAILURE);
348         }
349
350         if (DITEM_STATUS(fixit_livefs_common(self)) == DITEM_FAILURE)
351                 return (DITEM_FAILURE);
352
353         mediaClose();
354         return (DITEM_SUCCESS);
355 }
356
357 int
358 installFixitCDROM(dialogMenuItem *self)
359 {
360     struct stat sb;
361     int need_eject;
362
363     if (!RunningAsInit)
364         return DITEM_SUCCESS;
365
366     variable_set2(SYSTEM_STATE, "fixit", 0);
367     need_eject = 0;
368     CDROMInitQuiet = 1;
369     while (1) {
370         if (need_eject)
371             msgConfirm(
372         "Please insert a FreeBSD live filesystem CD/DVD and press return");
373         if (DITEM_STATUS(mediaSetCDROM(NULL)) != DITEM_SUCCESS
374             || !DEVICE_INIT(mediaDevice)) {
375             /* If we can't initialize it, it's probably not a FreeBSD CDROM so punt on it */
376             mediaClose();
377             if (need_eject && msgYesNo("Unable to mount the disc. Do you want to try again?") != 0)
378                 return DITEM_FAILURE;
379         } else if (!file_readable("/dist/rescue/ldconfig")) {
380                 mediaClose();
381                 if (need_eject &&
382                     msgYesNo("Unable to find a FreeBSD live filesystem. Do you want to try again?") != 0)
383                     return DITEM_FAILURE;
384         } else
385             break;
386         CDROMInitQuiet = 0;
387         need_eject = 1;
388     }
389     CDROMInitQuiet = 0;
390
391     if (DITEM_STATUS(fixit_livefs_common(self)) == DITEM_FAILURE)
392         return (DITEM_FAILURE);
393
394     mediaClose();
395     if (need_eject)
396         msgConfirm("Please remove the FreeBSD fixit CDROM/DVD now.");
397     return DITEM_SUCCESS;
398 }
399
400 int
401 installFixitFloppy(dialogMenuItem *self)
402 {
403     struct ufs_args args;
404     extern char *distWanted;
405
406     if (!RunningAsInit)
407         return DITEM_SUCCESS;
408
409     /* Try to open the floppy drive */
410     if (DITEM_STATUS(mediaSetFloppy(NULL)) == DITEM_FAILURE || !mediaDevice) {
411         msgConfirm("Unable to set media device to floppy.");
412         mediaClose();
413         return DITEM_FAILURE;
414     }
415
416     memset(&args, 0, sizeof(args));
417     args.fspec = mediaDevice->devname;
418     mediaDevice->private = "/mnt2";
419     distWanted = NULL;
420     Mkdir("/mnt2");
421
422     variable_set2(SYSTEM_STATE, "fixit", 0);
423
424     while (1) {
425         if (!DEVICE_INIT(mediaDevice)) {
426             if (msgYesNo("The attempt to mount the fixit floppy failed, bad floppy\n"
427                          "or unclean filesystem.  Do you want to try again?"))
428                 return DITEM_FAILURE;
429         }
430         else
431             break;
432     }
433     if (!directory_exists("/tmp"))
434         (void)symlink("/mnt2/tmp", "/tmp");
435     fixit_common();
436     mediaClose();
437     msgConfirm("Please remove the fixit floppy now.");
438     return DITEM_SUCCESS;
439 }
440
441 /*
442  * The common code for both fixit variants.
443  */
444 static void
445 fixit_common(void)
446 {
447     pid_t child;
448     int waitstatus;
449
450     if (!directory_exists("/var/tmp/vi.recover")) {
451         if (DITEM_STATUS(Mkdir("/var/tmp/vi.recover")) != DITEM_SUCCESS) {
452             msgConfirm("Warning:  Was unable to create a /var/tmp/vi.recover directory.\n"
453                        "vi will kvetch and moan about it as a result but should still\n"
454                        "be essentially usable.");
455         }
456     }
457     if (!directory_exists("/bin"))
458         (void)Mkdir("/bin");
459     (void)symlink("/stand/sh", "/bin/sh");
460     /* Link the /etc/ files */
461     if (DITEM_STATUS(Mkdir("/etc")) != DITEM_SUCCESS)
462         msgConfirm("Unable to create an /etc directory!  Things are weird on this floppy..");
463     else if ((symlink("/mnt2/etc/spwd.db", "/etc/spwd.db") == -1 && errno != EEXIST) ||
464              (symlink("/mnt2/etc/protocols", "/etc/protocols") == -1 && errno != EEXIST) ||
465              (symlink("/mnt2/etc/group", "/etc/group") == -1 && errno != EEXIST) ||
466              (symlink("/mnt2/etc/services", "/etc/services") == -1 && errno != EEXIST))
467         msgConfirm("Couldn't symlink the /etc/ files!  I'm not sure I like this..");
468     if (!file_readable(TERMCAP_FILE))
469         create_termcap();
470     if (strcmp(variable_get(VAR_FIXIT_TTY), "serial") == 0) 
471         systemSuspendDialog();  /* must be before the fork() */
472     if (!(child = fork())) {
473         int i, fd;
474         struct termios foo;
475         extern int login_tty(int);
476
477         ioctl(0, TIOCNOTTY, NULL);
478         for (i = getdtablesize(); i >= 0; --i)
479             close(i);
480
481         if (strcmp(variable_get(VAR_FIXIT_TTY), "serial") == 0) 
482             fd = open("/dev/console", O_RDWR);
483         else
484             fd = open("/dev/ttyv3", O_RDWR);
485         ioctl(0, TIOCSCTTY, &fd);
486         dup2(0, 1);
487         dup2(0, 2);
488         DebugFD = 2;
489         if (login_tty(fd) == -1)
490             msgDebug("fixit: I can't set the controlling terminal.\n");
491
492         signal(SIGTTOU, SIG_IGN);
493         if (tcgetattr(0, &foo) != -1) {
494             foo.c_cc[VERASE] = '\010';
495             if (tcsetattr(0, TCSANOW, &foo) == -1)
496                 msgDebug("fixit shell: Unable to set erase character.\n");
497         }
498         else
499             msgDebug("fixit shell: Unable to get terminal attributes!\n");
500         setenv("PATH", "/bin:/sbin:/usr/bin:/usr/sbin:/stand:"
501                "/mnt2/stand:/mnt2/bin:/mnt2/sbin:/mnt2/usr/bin:/mnt2/usr/sbin", 1);
502         if (strcmp(variable_get(VAR_FIXIT_TTY), "serial") == 0) {
503             printf("Waiting for fixit shell to exit.\n"
504                 "When you are done, type ``exit'' to exit\n"
505                 "the fixit shell and be returned here.\n\n");
506             fflush(stdout);
507         } else {
508             ioctl(fd, VT_ACTIVATE, 0);
509         }
510
511         /* use the .profile from the fixit medium */
512         setenv("HOME", "/mnt2", 1);
513         chdir("/mnt2");
514         execlp("sh", "-sh", (char *)0);
515         msgDebug("fixit shell: Failed to execute shell!\n");
516         _exit(1);;
517     }
518     else {
519         if (strcmp(variable_get(VAR_FIXIT_TTY), "standard") == 0) {
520             dialog_clear_norefresh();
521             msgNotify("Waiting for fixit shell to exit.  Go to VTY4 now by\n"
522                 "typing ALT-F4.  When you are done, type ``exit'' to exit\n"
523                 "the fixit shell and be returned here.\n");
524         }
525         (void)waitpid(child, &waitstatus, 0);
526         if (strcmp(variable_get(VAR_FIXIT_TTY), "serial") == 0)
527             systemResumeDialog();
528         else if (OnVTY) {
529             ioctl(0, VT_ACTIVATE, 0);
530             msgInfo(NULL);
531         }
532     }
533     dialog_clear();
534 }
535
536 /*
537  * Some path/lib setup is required for the livefs fixit image. Since there's
538  * more than one media type for livefs now, this has been broken off into it's
539  * own function.
540  */
541 int
542 fixit_livefs_common(dialogMenuItem *self)
543 {
544         struct stat sb;
545
546         /*
547          * USB and CDROM media get mounted to /dist, but fixit code looks in
548          * /mnt2.
549          */
550         unlink("/mnt2");
551         rmdir("/mnt2");
552
553         if (symlink("/dist", "/mnt2")) {
554                 msgConfirm("Unable to symlink /mnt2 to the disc mount point.");
555                 return (DITEM_FAILURE);
556         }
557
558         /*
559          * If /tmp points to /mnt2/tmp from a previous fixit floppy session,
560          * recreate it.
561          */
562         if (lstat("/tmp", &sb) == 0 && (sb.st_mode & S_IFMT) == S_IFLNK)
563                 unlink("/tmp");
564         Mkdir("/tmp");
565
566         /* Generate a new ld.so.hints */
567         if (!file_readable("/var/run/ld.so.hints")) {
568                 Mkdir("/var/run");
569                 if (vsystem("/mnt2/rescue/ldconfig -s /mnt2/lib "
570                     "/mnt2/usr/lib")) {
571                         msgConfirm("Warning: ldconfig could not create the "
572                             "ld.so hints file.\nDynamic executables from the "
573                             "disc likely won't work.");
574                 }
575         }
576
577         /* Create required libexec symlinks. */
578         Mkdir("/libexec");
579         if (!file_readable("/libexec/ld.so") &&
580             file_readable("/mnt2/libexec/ld.so")) {
581                 if (symlink("/mnt2/libexec/ld.so", "/libexec/ld.so"))
582                         msgDebug("Couldn't link to ld.so\n");
583         }
584
585         if (!file_readable("/libexec/ld-elf.so.1")) {
586                 if (symlink("/mnt2/libexec/ld-elf.so.1",
587                     "/libexec/ld-elf.so.1")) {
588                         msgConfirm("Warning: could not create the symlink for "
589                             "ld-elf.so.1\nDynamic executables from the disc "
590                             "likely won't work.");
591                 }
592         }
593
594         /* $PATH doesn't include /mnt2 by default. Create convenient symlink. */
595         if (!file_readable("/usr/bin/vi"))
596                 symlink("/mnt2/usr/bin/vi", "/usr/bin/vi");
597
598         /* Shared code used by all fixit types. */
599         fixit_common();
600
601         return (DITEM_SUCCESS);
602 }
603
604 int
605 installExpress(dialogMenuItem *self)
606 {
607     int i;
608
609     dialog_clear_norefresh();
610     variable_set2(SYSTEM_STATE, "express", 0);
611 #ifdef WITH_SLICES
612     if (DITEM_STATUS((i = diskPartitionEditor(self))) == DITEM_FAILURE)
613         return i;
614 #endif
615     
616     if (DITEM_STATUS((i = diskLabelEditor(self))) == DITEM_FAILURE)
617         return i;
618
619     if (DITEM_STATUS((i = installCommit(self))) == DITEM_SUCCESS) {
620         i |= DITEM_LEAVE_MENU;
621
622         /* Give user the option of one last configuration spree */
623         installConfigure();
624     }
625     return i;
626 }
627
628 /* Standard mode installation */
629 int
630 installStandard(dialogMenuItem *self)
631 {
632     int i, tries = 0;
633     Device **devs;
634
635     variable_set2(SYSTEM_STATE, "standard", 0);
636     dialog_clear_norefresh();
637 #ifdef WITH_SLICES
638     msgConfirm("In the next menu, you will need to set up a DOS-style (\"fdisk\") partitioning\n"
639                "scheme for your hard disk.  If you simply wish to devote all disk space\n"
640                "to FreeBSD (overwriting anything else that might be on the disk(s) selected)\n"
641                "then use the (A)ll command to select the default partitioning scheme followed\n"
642                "by a (Q)uit.  If you wish to allocate only free space to FreeBSD, move to a\n"
643                "partition marked \"unused\" and use the (C)reate command.");
644
645 nodisks:
646     if (DITEM_STATUS(diskPartitionEditor(self)) == DITEM_FAILURE)
647         return DITEM_FAILURE;
648
649     if (diskGetSelectCount(&devs) <= 0 && tries < 3) {
650         msgConfirm("You need to select some disks to operate on!  Be sure to use SPACE\n"
651                    "instead of RETURN in the disk selection menu when selecting a disk.");
652         ++tries;
653         goto nodisks;
654     }
655
656     msgConfirm("Now you need to create BSD partitions inside of the fdisk partition(s)\n"
657                "just created.  If you have a reasonable amount of disk space (1GB or more)\n"
658                "and don't have any special requirements, simply use the (A)uto command to\n"
659                "allocate space automatically.  If you have more specific needs or just don't\n"
660                "care for the layout chosen by (A)uto, press F1 for more information on\n"
661                "manual layout.");
662 #else
663     msgConfirm("First you need to create BSD partitions on the disk which you are\n"
664                "installing to.  If you have a reasonable amount of disk space (1GB or more)\n"
665                "and don't have any special requirements, simply use the (A)uto command to\n"
666                "allocate space automatically.  If you have more specific needs or just don't\n"
667                "care for the layout chosen by (A)uto, press F1 for more information on\n"
668                "manual layout.");
669 #endif
670
671     if (DITEM_STATUS(diskLabelEditor(self)) == DITEM_FAILURE)
672         return DITEM_FAILURE;
673
674     if (DITEM_STATUS((i = installCommit(self))) == DITEM_FAILURE) {
675         dialog_clear();
676         msgConfirm("Installation completed with some errors.  You may wish to\n"
677                    "scroll through the debugging messages on VTY1 with the\n"
678                    "scroll-lock feature.  You can also choose \"No\" at the next\n"
679                    "prompt and go back into the installation menus to retry\n"
680                    "whichever operations have failed.");
681         return i;
682
683     }
684     else {
685         dialog_clear();
686         msgConfirm("Congratulations!  You now have FreeBSD installed on your system.\n\n"
687                    "We will now move on to the final configuration questions.\n"
688                    "For any option you do not wish to configure, simply select\n"
689                    "No.\n\n"
690                    "If you wish to re-enter this utility after the system is up, you\n"
691                    "may do so by typing: /usr/sbin/sysinstall.");
692     }
693     if (mediaDevice->type != DEVICE_TYPE_FTP && mediaDevice->type != DEVICE_TYPE_NFS) {
694         if (!msgYesNo("Would you like to configure any Ethernet or SLIP/PPP network devices?")) {
695             Device *tmp = tcpDeviceSelect();
696
697             if (tmp && !((DevInfo *)tmp->private)->use_dhcp && !msgYesNo("Would you like to bring the %s interface up right now?", tmp->name))
698                 if (!DEVICE_INIT(tmp))
699                     msgConfirm("Initialization of %s device failed.", tmp->name);
700         }
701         dialog_clear_norefresh();
702     }
703
704     if (!msgNoYes("Do you want this machine to function as a network gateway?"))
705         variable_set2("gateway_enable", "YES", 1);
706
707     dialog_clear_norefresh();
708     if (!msgNoYes("Do you want to configure inetd and the network services that it provides?"))
709         configInetd(self);
710
711     dialog_clear_norefresh();
712     if (!msgNoYes("Would you like to enable SSH login?"))
713         variable_set2("sshd_enable", "YES", 1);
714
715     dialog_clear_norefresh();
716     if (!msgNoYes("Do you want to have anonymous FTP access to this machine?"))
717         configAnonFTP(self);
718
719     dialog_clear_norefresh();
720     if (!msgNoYes("Do you want to configure this machine as an NFS server?"))
721         configNFSServer(self);
722
723     dialog_clear_norefresh();
724     if (!msgNoYes("Do you want to configure this machine as an NFS client?"))
725         variable_set2("nfs_client_enable", "YES", 1);
726
727 #ifdef WITH_SYSCONS
728     dialog_clear_norefresh();
729     if (!msgNoYes("Would you like to customize your system console settings?"))
730         dmenuOpenSimple(&MenuSyscons, FALSE);
731 #endif
732
733     dialog_clear_norefresh();
734     if (!msgYesNo("Would you like to set this machine's time zone now?"))
735         systemExecute("tzsetup");
736
737 #ifdef WITH_MICE
738     dialog_clear_norefresh();
739     if (!msgNoYes("Does this system have a PS/2, serial, or bus mouse?"))
740         dmenuOpenSimple(&MenuMouse, FALSE);
741 #endif
742
743 #ifdef __i386__
744     if (checkLoaderACPI() != 0) {
745         dialog_clear_norefresh();
746         if (!msgNoYes("ACPI was disabled during boot.\n"
747                       "Would you like to disable it permanently?"))
748                 (void)configLoaderACPI(1 /*disable*/);
749     }
750 #endif
751
752     /* Now would be a good time to checkpoint the configuration data */
753     configRC_conf();
754     sync();
755
756     dialog_clear_norefresh();
757     if (!msgYesNo("The FreeBSD package collection is a collection of thousands of ready-to-run\n"
758                   "applications, from text editors to games to WEB servers and more.  Would you\n"
759                   "like to browse the collection now?")) {
760         (void)configPackages(self);
761     }
762
763     if (!msgYesNo("Would you like to add any initial user accounts to the system?\n"
764                   "Adding at least one account for yourself at this stage is suggested\n"
765                   "since working as the \"root\" user is dangerous (it is easy to do\n"
766                   "things which adversely affect the entire system)."))
767         (void)configUsers(self);
768
769     msgConfirm("Now you must set the system manager's password.\n"
770                "This is the password you'll use to log in as \"root\".");
771     if (!systemExecute("passwd root"))
772         variable_set2("root_password", "YES", 0);
773
774     /* XXX Put whatever other nice configuration questions you'd like to ask the user here XXX */
775
776     /* Give user the option of one last configuration spree */
777     dialog_clear_norefresh();
778     installConfigure();
779     return DITEM_LEAVE_MENU;
780 }
781
782 /* The version of commit we call from the Install Custom menu */
783 int
784 installCustomCommit(dialogMenuItem *self)
785 {
786     int i;
787
788     i = installCommit(self);
789     if (DITEM_STATUS(i) == DITEM_SUCCESS) {
790         /* Give user the option of one last configuration spree */
791         installConfigure();
792         return i;
793     }
794     else
795         msgConfirm("The commit operation completed with errors.  Not\n"
796                    "updating /etc files.");
797     return i;
798 }
799
800 /*
801  * What happens when we finally decide to going ahead with the installation.
802  *
803  * This is broken into multiple stages so that the user can do a full
804  * installation but come back here again to load more distributions,
805  * perhaps from a different media type.  This would allow, for
806  * example, the user to load the majority of the system from CDROM and
807  * then use ftp to load a different dist.
808  */
809 int
810 installCommit(dialogMenuItem *self)
811 {
812     int i;
813     char *str;
814
815     dialog_clear_norefresh();
816     if (!Dists)
817         distConfig(NULL);
818
819     if (!Dists) {
820         (void)dmenuOpenSimple(&MenuDistributions, FALSE);
821         /* select reasonable defaults if necessary */
822         if (!Dists)
823             Dists = _DIST_USER;
824         if (!KernelDists)
825             KernelDists = selectKernel();
826     }
827
828     if (!mediaVerify())
829         return DITEM_FAILURE;
830
831     str = variable_get(SYSTEM_STATE);
832     if (isDebug())
833         msgDebug("installCommit: System state is `%s'\n", str);
834
835     /* Installation stuff we wouldn't do to a running system */
836     if (RunningAsInit && DITEM_STATUS((i = installInitial())) == DITEM_FAILURE)
837         return i;
838
839 try_media:
840     if (!DEVICE_INIT(mediaDevice)) {
841         if (!msgYesNo("Unable to initialize selected media. Would you like to\n"
842                       "adjust your media configuration and try again?")) {
843             mediaDevice = NULL;
844             if (!mediaVerify())
845                 return DITEM_FAILURE;
846             else
847                 goto try_media;
848         }
849         else
850             return DITEM_FAILURE;
851     }
852
853     /* Now go get it all */
854     i = distExtractAll(self);
855
856     /* When running as init, *now* it's safe to grab the rc.foo vars */
857     installEnvironment();
858
859     variable_set2(SYSTEM_STATE, DITEM_STATUS(i) == DITEM_FAILURE ? "error-install" : "full-install", 0);
860
861     return i;
862 }
863
864 static void
865 installConfigure(void)
866 {
867     /* Final menu of last resort */
868     if (!msgNoYes("Visit the general configuration menu for a chance to set\n"
869                   "any last options?"))
870         dmenuOpenSimple(&MenuConfigure, FALSE);
871     configRC_conf();
872     sync();
873 }
874
875 int
876 installFixupBase(dialogMenuItem *self)
877 {
878     FILE *fp;
879 #ifdef __ia64__
880     const char *efi_mntpt;
881 #endif
882
883     /* All of this is done only as init, just to be safe */
884     if (RunningAsInit) {
885 #if defined(__i386__) || defined(__amd64__)
886         if ((fp = fopen("/boot/loader.conf", "a")) != NULL) {
887             if (!OnVTY) {
888                 fprintf(fp, "# -- sysinstall generated deltas -- #\n");
889                 fprintf(fp, "console=\"comconsole\"\n");
890             }
891             fclose(fp);
892         }
893 #endif
894         
895         /* BOGON #2: We leave /etc in a bad state */
896         chmod("/etc", 0755);
897         
898         /* BOGON #3: No /var/db/mountdtab complains */
899         Mkdir("/var/db");
900         creat("/var/db/mountdtab", 0644);
901         
902         /* BOGON #4: /compat created by default in root fs */
903         Mkdir("/usr/compat");
904         vsystem("ln -s usr/compat /compat");
905
906         /* BOGON #5: aliases database not built for bin */
907         vsystem("newaliases");
908
909         /* BOGON #6: Remove /stand (finally) */
910         vsystem("rm -rf /stand");
911
912         /* Now run all the mtree stuff to fix things up */
913         vsystem("mtree -deU -f /etc/mtree/BSD.root.dist -p /");
914         vsystem("mtree -deU -f /etc/mtree/BSD.var.dist -p /var");
915         vsystem("mtree -deU -f /etc/mtree/BSD.usr.dist -p /usr");
916
917 #ifdef __ia64__
918         /* Move /boot to the the EFI partition and make /boot a link to it. */
919         efi_mntpt = (EfiChunk != NULL) ? ((PartInfo *)EfiChunk->private_data)->mountpoint : NULL;
920         if (efi_mntpt != NULL) {
921                 vsystem("if [ ! -L /boot ]; then mv /boot %s; fi", efi_mntpt);
922                 vsystem("if [ ! -e /boot ]; then ln -sf %s/boot /boot; fi",
923                     efi_mntpt + 1);     /* Skip leading '/' */
924                 /* Make sure the kernel knows which partition is the root file system. */
925                 vsystem("echo 'vfs.root.mountfrom=\"ufs:/dev/%s\"' >> /boot/loader.conf", RootChunk->name);
926         }
927 #endif
928
929         /* Do all the last ugly work-arounds here */
930     }
931     return DITEM_SUCCESS | DITEM_RESTORE;
932 }
933
934 int
935 installFixupKernel(dialogMenuItem *self, int dists)
936 {
937
938     /* All of this is done only as init, just to be safe */
939     if (RunningAsInit) {
940         /*
941          * Install something as /boot/kernel.  Prefer SMP
942          * over GENERIC--this should handle the case where
943          * both SMP and GENERIC are installed (otherwise we
944          * select the one kernel that was installed).
945          *
946          * NB: we assume any existing kernel has been saved
947          *     already and the /boot/kernel we remove is empty.
948          */
949         vsystem("rm -rf /boot/kernel");
950 #if WITH_SMP
951         if (dists & DIST_KERNEL_SMP)
952                 vsystem("mv /boot/SMP /boot/kernel");
953         else
954 #endif
955                 vsystem("mv /boot/GENERIC /boot/kernel");
956     }
957     return DITEM_SUCCESS | DITEM_RESTORE;
958 }
959
960 #define QUEUE_YES       1
961 #define QUEUE_NO        0
962 static int
963 performNewfs(PartInfo *pi, char *dname, int queue)
964 {
965         char buffer[LINE_MAX];
966
967         if (pi->do_newfs) {
968                 switch(pi->newfs_type) {
969                 case NEWFS_UFS:
970                         snprintf(buffer, LINE_MAX, "%s %s %s %s %s",
971                             NEWFS_UFS_CMD,
972                             pi->newfs_data.newfs_ufs.softupdates ?  "-U" : "",
973                             pi->newfs_data.newfs_ufs.ufs1 ? "-O1" : "-O2",
974                             pi->newfs_data.newfs_ufs.user_options,
975                             dname);
976                         break;
977
978                 case NEWFS_MSDOS:
979                         snprintf(buffer, LINE_MAX, "%s %s", NEWFS_MSDOS_CMD,
980                             dname);
981                         break;
982
983                 case NEWFS_CUSTOM:
984                         snprintf(buffer, LINE_MAX, "%s %s",
985                             pi->newfs_data.newfs_custom.command, dname);
986                         break;
987                 }
988
989                 if (queue == QUEUE_YES) {
990                         command_shell_add(pi->mountpoint, buffer);
991                         return (0);
992                 } else
993                         return (vsystem(buffer));
994         }
995         return (0);
996 }
997
998 /* Go newfs and/or mount all the filesystems we've been asked to */
999 int
1000 installFilesystems(dialogMenuItem *self)
1001 {
1002     int i;
1003     Disk *disk;
1004     Chunk *c1, *c2;
1005     Device **devs;
1006     PartInfo *root;
1007     char dname[80];
1008     Boolean upgrade = FALSE;
1009
1010     /* If we've already done this, bail out */
1011     if (!variable_cmp(DISK_LABELLED, "written"))
1012         return DITEM_SUCCESS;
1013
1014     upgrade = !variable_cmp(SYSTEM_STATE, "upgrade");
1015     if (!checkLabels(TRUE))
1016         return DITEM_FAILURE;
1017
1018     root = (RootChunk != NULL) ? (PartInfo *)RootChunk->private_data : NULL;
1019
1020     command_clear();
1021     if (SwapChunk && RunningAsInit) {
1022         /* As the very first thing, try to get ourselves some swap space */
1023         sprintf(dname, "/dev/%s", SwapChunk->name);
1024         if (!Fake && !file_readable(dname)) {
1025             msgConfirm("Unable to find device node for %s in /dev!\n"
1026                        "The creation of filesystems will be aborted.", dname);
1027             return DITEM_FAILURE;
1028         }
1029
1030         if (!Fake) {
1031             if (!swapon(dname)) {
1032                 dialog_clear_norefresh();
1033                 msgNotify("Added %s as initial swap device", dname);
1034             }
1035             else {
1036                 msgConfirm("WARNING!  Unable to swap to %s: %s\n"
1037                            "This may cause the installation to fail at some point\n"
1038                            "if you don't have a lot of memory.", dname, strerror(errno));
1039             }
1040         }
1041     }
1042
1043     if (RootChunk && RunningAsInit) {
1044         /* Next, create and/or mount the root device */
1045         sprintf(dname, "/dev/%s", RootChunk->name);
1046         if (!Fake && !file_readable(dname)) {
1047             msgConfirm("Unable to make device node for %s in /dev!\n"
1048                        "The creation of filesystems will be aborted.", dname);
1049             return DITEM_FAILURE | DITEM_RESTORE;
1050         }
1051         if (strcmp(root->mountpoint, "/"))
1052             msgConfirm("Warning: %s is marked as a root partition but is mounted on %s", RootChunk->name, root->mountpoint);
1053
1054         if (root->do_newfs && (!upgrade ||
1055             !msgNoYes("You are upgrading - are you SURE you want to newfs "
1056             "the root partition?"))) {
1057             int i;
1058
1059             dialog_clear_norefresh();
1060             msgNotify("Making a new root filesystem on %s", dname);
1061             i = performNewfs(root, dname, QUEUE_NO);
1062             if (i) {
1063                 msgConfirm("Unable to make new root filesystem on %s!\n"
1064                            "Command returned status %d", dname, i);
1065                 return DITEM_FAILURE | DITEM_RESTORE;
1066             }
1067         }
1068         else {
1069             if (!upgrade) {
1070                 msgConfirm("Warning:  Using existing root partition.");
1071             }
1072             dialog_clear_norefresh();
1073             msgNotify("Checking integrity of existing %s filesystem.", dname);
1074             i = vsystem("fsck_ffs -y %s", dname);
1075             if (i)
1076                 msgConfirm("Warning: fsck returned status of %d for %s.\n"
1077                            "This partition may be unsafe to use.", i, dname);
1078         }
1079
1080         /*
1081          * If soft updates was enabled in the editor but we didn't newfs,
1082          * use tunefs to update the soft updates flag on the file system.
1083          */
1084         if (!root->do_newfs && root->newfs_type == NEWFS_UFS &&
1085             root->newfs_data.newfs_ufs.softupdates) {
1086                 i = vsystem("tunefs -n enable %s", dname);
1087                 if (i)
1088                         msgConfirm("Warning: Unable to enable soft updates"
1089                             " for root file system on %s", dname);
1090         }
1091
1092         /* Switch to block device */
1093         sprintf(dname, "/dev/%s", RootChunk->name);
1094         if (Mount("/mnt", dname)) {
1095             msgConfirm("Unable to mount the root file system on %s!  Giving up.", dname);
1096             return DITEM_FAILURE | DITEM_RESTORE;
1097         }
1098
1099         /* Mount devfs for other partitions to mount */
1100         Mkdir("/mnt/dev");
1101         if (!Fake) {
1102             struct iovec iov[4];
1103
1104             iov[0].iov_base = "fstype";
1105             iov[0].iov_len = strlen(iov[0].iov_base) + 1;
1106             iov[1].iov_base = "devfs";
1107             iov[1].iov_len = strlen(iov[1].iov_base) + 1;
1108             iov[2].iov_base = "fspath";
1109             iov[2].iov_len = strlen(iov[2].iov_base) + 1;
1110             iov[3].iov_base = "/mnt/dev";
1111             iov[3].iov_len = strlen(iov[3].iov_base) + 1;
1112             i = nmount(iov, 4, 0);
1113
1114             if (i) {
1115                 dialog_clear_norefresh();
1116                 msgConfirm("Unable to mount DEVFS (error %d)", errno);
1117                 return DITEM_FAILURE | DITEM_RESTORE;
1118             }
1119         }
1120     }
1121
1122     /* Now buzz through the rest of the partitions and mount them too */
1123     devs = deviceFind(NULL, DEVICE_TYPE_DISK);
1124     for (i = 0; devs[i]; i++) {
1125         if (!devs[i]->enabled)
1126             continue;
1127
1128         disk = (Disk *)devs[i]->private;
1129         if (!disk->chunks) {
1130             msgConfirm("No chunk list found for %s!", disk->name);
1131             return DITEM_FAILURE | DITEM_RESTORE;
1132         }
1133         for (c1 = disk->chunks->part; c1; c1 = c1->next) {
1134 #ifdef __ia64__
1135         if (c1->type == part) {
1136                 c2 = c1;
1137                 {
1138 #elif defined(__powerpc__)
1139             if (c1->type == apple) {
1140                 for (c2 = c1->part; c2; c2 = c2->next) {
1141 #else
1142             if (c1->type == freebsd) {
1143                 for (c2 = c1->part; c2; c2 = c2->next) {
1144 #endif
1145                     if (c2->type == part && c2->subtype != FS_SWAP && c2->private_data) {
1146                         PartInfo *tmp = (PartInfo *)c2->private_data;
1147
1148                         /* Already did root */
1149                         if (c2 == RootChunk)
1150                             continue;
1151
1152                         sprintf(dname, "%s/dev/%s",
1153                             RunningAsInit ? "/mnt" : "", c2->name);
1154
1155                         if (tmp->do_newfs && (!upgrade ||
1156                             !msgNoYes("You are upgrading - are you SURE you"
1157                             " want to newfs /dev/%s?", c2->name)))
1158                                 performNewfs(tmp, dname, QUEUE_YES);
1159                         else
1160                             command_shell_add(tmp->mountpoint,
1161                                 "fsck_ffs -y %s/dev/%s", RunningAsInit ?
1162                                 "/mnt" : "", c2->name);
1163 #if 0
1164                         if (tmp->soft)
1165                             command_shell_add(tmp->mountpoint,
1166                             "tunefs -n enable %s/dev/%s", RunningAsInit ?
1167                             "/mnt" : "", c2->name);
1168 #endif
1169                         command_func_add(tmp->mountpoint, Mount, c2->name);
1170                     }
1171                     else if (c2->type == part && c2->subtype == FS_SWAP) {
1172                         char fname[80];
1173                         int i;
1174
1175                         if (c2 == SwapChunk)
1176                             continue;
1177                         sprintf(fname, "%s/dev/%s", RunningAsInit ? "/mnt" : "", c2->name);
1178                         i = (Fake || swapon(fname));
1179                         if (!i) {
1180                             dialog_clear_norefresh();
1181                             msgNotify("Added %s as an additional swap device", fname);
1182                         }
1183                         else {
1184                             msgConfirm("Unable to add %s as a swap device: %s", fname, strerror(errno));
1185                         }
1186                     }
1187                 }
1188             }
1189             else if (c1->type == fat && c1->private_data &&
1190                 (root->do_newfs || upgrade)) {
1191                 char name[FILENAME_MAX];
1192
1193                 sprintf(name, "%s/%s", RunningAsInit ? "/mnt" : "", ((PartInfo *)c1->private_data)->mountpoint);
1194                 Mkdir(name);
1195             }
1196 #if defined(__ia64__)
1197             else if (c1->type == efi && c1->private_data) {
1198                 char bootdir[FILENAME_MAX];
1199                 PartInfo *pi = (PartInfo *)c1->private_data;
1200                 char *p;
1201
1202                 sprintf(dname, "%s/dev/%s", RunningAsInit ? "/mnt" : "",
1203                     c1->name);
1204
1205                 if (pi->do_newfs && (!upgrade ||
1206                     !msgNoYes("You are upgrading - are you SURE you want to "
1207                     "newfs /dev/%s?", c1->name)))
1208                         performNewfs(pi, dname, QUEUE_YES);
1209
1210                 command_func_add(pi->mountpoint, Mount_msdosfs, c1->name);
1211             }
1212 #endif
1213         }
1214     }
1215
1216     command_sort();
1217     command_execute();
1218     dialog_clear_norefresh();
1219     return DITEM_SUCCESS | DITEM_RESTORE;
1220 }
1221
1222 /* Initialize various user-settable values to their defaults */
1223 int
1224 installVarDefaults(dialogMenuItem *self)
1225 {
1226     char *cp, ncpus[10];
1227
1228     /* Set default startup options */
1229     cp = getsysctlbyname("kern.osrelease");
1230     variable_set2(VAR_RELNAME,                  cp, 0);
1231     free(cp);
1232     variable_set2(VAR_CPIO_VERBOSITY,           "high", 0);
1233     variable_set2(VAR_INSTALL_ROOT,             "/", 0);
1234     variable_set2(VAR_INSTALL_CFG,              "install.cfg", 0);
1235     cp = getenv("EDITOR");
1236     if (!cp)
1237         cp = "/usr/bin/ee";
1238     variable_set2(VAR_EDITOR,                   cp, 0);
1239     variable_set2(VAR_FTP_USER,                 "ftp", 0);
1240     variable_set2(VAR_BROWSER_PACKAGE,          "links", 0);
1241     variable_set2(VAR_BROWSER_BINARY,           "/usr/local/bin/links", 0);
1242     variable_set2(VAR_FTP_STATE,                "passive", 0);
1243     variable_set2(VAR_NFS_SECURE,               "NO", -1);
1244     variable_set2(VAR_NFS_TCP,                  "NO", -1);
1245     variable_set2(VAR_NFS_V3,                   "YES", -1);
1246     if (OnVTY)
1247             variable_set2(VAR_FIXIT_TTY,                "standard", 0);
1248     else
1249             variable_set2(VAR_FIXIT_TTY,                "serial", 0);
1250     variable_set2(VAR_PKG_TMPDIR,               "/var/tmp", 0);
1251     variable_set2(VAR_MEDIA_TIMEOUT,            itoa(MEDIA_TIMEOUT), 0);
1252     if (getpid() != 1)
1253         variable_set2(SYSTEM_STATE,             "update", 0);
1254     else
1255         variable_set2(SYSTEM_STATE,             "init", 0);
1256     variable_set2(VAR_NEWFS_ARGS,               "-b 16384 -f 2048", 0);
1257     variable_set2(VAR_CONSTERM,                 "NO", 0);
1258 #if (defined(__i386__) && !defined(PC98)) || defined(__amd64__)
1259     NCpus = acpi_detect();
1260     if (NCpus == -1)
1261         NCpus = biosmptable_detect();
1262 #endif
1263     if (NCpus <= 0)
1264         NCpus = 1;
1265     snprintf(ncpus, sizeof(ncpus), "%u", NCpus);
1266     variable_set2(VAR_NCPUS,                    ncpus, 0);
1267     return DITEM_SUCCESS;
1268 }
1269
1270 /* Load the environment up from various system configuration files */
1271 void
1272 installEnvironment(void)
1273 {
1274     configEnvironmentRC_conf();
1275     if (file_readable("/etc/resolv.conf"))
1276         configEnvironmentResolv("/etc/resolv.conf");
1277 }
1278
1279 /* Copy the boot floppy contents into /stand */
1280 Boolean
1281 copySelf(void)
1282 {
1283     int i;
1284
1285     if (file_readable("/boot.help"))
1286         vsystem("cp /boot.help /mnt");
1287     msgWeHaveOutput("Copying the boot floppy to /stand on root filesystem");
1288     i = vsystem("find -x /stand | cpio %s -pdum /mnt", cpioVerbosity());
1289     if (i) {
1290         msgConfirm("Copy returned error status of %d!", i);
1291         return FALSE;
1292     }
1293
1294     /* Copy the /etc files into their rightful place */
1295     if (vsystem("cd /mnt/stand; find etc | cpio %s -pdum /mnt", cpioVerbosity())) {
1296         msgConfirm("Couldn't copy up the /etc files!");
1297         return TRUE;
1298     }
1299     return TRUE;
1300 }
1301
1302 static void
1303 create_termcap(void)
1304 {
1305     FILE *fp;
1306
1307     const char *caps[] = {
1308         termcap_vt100, termcap_cons25, termcap_cons25_m, termcap_cons25r,
1309         termcap_cons25r_m, termcap_cons25l1, termcap_cons25l1_m,
1310         termcap_xterm, NULL,
1311     };
1312     const char **cp;
1313
1314     if (!file_readable(TERMCAP_FILE)) {
1315         Mkdir("/usr/share/misc");
1316         fp = fopen(TERMCAP_FILE, "w");
1317         if (!fp) {
1318             msgConfirm("Unable to initialize termcap file. Some screen-oriented\nutilities may not work.");
1319             return;
1320         }
1321         cp = caps;
1322         while (*cp)
1323             fprintf(fp, "%s\n", *(cp++));
1324         fclose(fp);
1325     }
1326 }