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