1 /* $NetBSD: util.c,v 1.161 2009/10/09 21:11:31 snj Exp $ */
4 * Copyright 1997 Piermont Information Systems Inc.
7 * Written by Philip A. Nelson for Piermont Information Systems Inc.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed for the NetBSD Project by
20 * Piermont Information Systems Inc.
21 * 4. The name of Piermont Information Systems Inc. may not be used to endorse
22 * or promote products derived from this software without specific prior
25 * THIS SOFTWARE IS PROVIDED BY PIERMONT INFORMATION SYSTEMS INC. ``AS IS''
26 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED. IN NO EVENT SHALL PIERMONT INFORMATION SYSTEMS INC. BE
29 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
35 * THE POSSIBILITY OF SUCH DAMAGE.
39 /* util.c -- routines that don't really fit anywhere else... */
44 #include <sys/types.h>
45 #include <sys/param.h>
46 #include <sys/sysctl.h>
48 #include <sys/statvfs.h>
56 #include "menu_defs.h"
58 #ifndef MD_SETS_SELECTED
59 #define MD_SETS_SELECTED SET_KERNEL_1, SET_SYSTEM, SET_X11, SET_MD
61 #ifndef MD_SETS_SELECTED_MINIMAL
62 #define MD_SETS_SELECTED_MINIMAL SET_KERNEL_1, SET_CORE
65 #define MD_SETS_VALID SET_KERNEL, SET_SYSTEM, SET_X11, SET_MD
68 static const char *msg_yes
, *msg_no
, *msg_all
, *msg_some
, *msg_none
;
69 static const char *msg_cur_distsets_row
;
70 static int select_menu_width
;
72 static uint8_t set_status
[SET_GROUP_END
];
73 #define SET_VALID 0x01
74 #define SET_SELECTED 0x02
75 #define SET_SKIPPED 0x04
76 #define SET_INSTALLED 0x08
87 distinfo dist_list
[] = {
88 #ifdef SET_KERNEL_1_NAME
89 {SET_KERNEL_1_NAME
, SET_KERNEL_1
, MSG_set_kernel_1
, NULL
},
91 #ifdef SET_KERNEL_2_NAME
92 {SET_KERNEL_2_NAME
, SET_KERNEL_2
, MSG_set_kernel_2
, NULL
},
94 #ifdef SET_KERNEL_3_NAME
95 {SET_KERNEL_3_NAME
, SET_KERNEL_3
, MSG_set_kernel_3
, NULL
},
97 #ifdef SET_KERNEL_4_NAME
98 {SET_KERNEL_4_NAME
, SET_KERNEL_4
, MSG_set_kernel_4
, NULL
},
100 #ifdef SET_KERNEL_5_NAME
101 {SET_KERNEL_5_NAME
, SET_KERNEL_5
, MSG_set_kernel_5
, NULL
},
103 #ifdef SET_KERNEL_6_NAME
104 {SET_KERNEL_6_NAME
, SET_KERNEL_6
, MSG_set_kernel_6
, NULL
},
106 #ifdef SET_KERNEL_7_NAME
107 {SET_KERNEL_7_NAME
, SET_KERNEL_7
, MSG_set_kernel_7
, NULL
},
109 #ifdef SET_KERNEL_8_NAME
110 {SET_KERNEL_8_NAME
, SET_KERNEL_8
, MSG_set_kernel_8
, NULL
},
113 {"modules", SET_MODULES
, MSG_set_modules
, NULL
},
114 {"base", SET_BASE
, MSG_set_base
, NULL
},
115 {"etc", SET_ETC
, MSG_set_system
, NULL
},
116 {"comp", SET_COMPILER
, MSG_set_compiler
, NULL
},
117 {"games", SET_GAMES
, MSG_set_games
, NULL
},
118 {"man", SET_MAN_PAGES
, MSG_set_man_pages
, NULL
},
119 {"misc", SET_MISC
, MSG_set_misc
, NULL
},
120 {"tests", SET_TESTS
, MSG_set_tests
, NULL
},
121 {"text", SET_TEXT_TOOLS
, MSG_set_text_tools
, NULL
},
123 {NULL
, SET_GROUP
, MSG_set_X11
, NULL
},
124 {"xbase", SET_X11_BASE
, MSG_set_X11_base
, NULL
},
125 {"xcomp", SET_X11_PROG
, MSG_set_X11_prog
, NULL
},
126 {"xetc", SET_X11_ETC
, MSG_set_X11_etc
, NULL
},
127 {"xfont", SET_X11_FONTS
, MSG_set_X11_fonts
, NULL
},
128 {"xserver", SET_X11_SERVERS
, MSG_set_X11_servers
, NULL
},
129 {NULL
, SET_GROUP_END
, NULL
, NULL
},
132 {SET_MD_1_NAME
, SET_MD_1
, MSG_set_md_1
, NULL
},
135 {SET_MD_2_NAME
, SET_MD_2
, MSG_set_md_2
, NULL
},
138 {SET_MD_3_NAME
, SET_MD_3
, MSG_set_md_3
, NULL
},
141 {SET_MD_4_NAME
, SET_MD_4
, MSG_set_md_4
, NULL
},
144 {NULL
, SET_LAST
, NULL
, NULL
},
151 static int check_for(unsigned int mode
, const char *pathname
);
154 init_set_status(int minimal
)
156 static const uint8_t sets_valid
[] = {MD_SETS_VALID
};
157 static const uint8_t sets_selected_full
[] = {MD_SETS_SELECTED
};
158 static const uint8_t sets_selected_minimal
[] = {MD_SETS_SELECTED_MINIMAL
};
159 static const uint8_t *sets_selected
;
160 unsigned int nelem_selected
;
165 sets_selected
= sets_selected_minimal
;
166 nelem_selected
= nelem(sets_selected_minimal
);
168 sets_selected
= sets_selected_full
;
169 nelem_selected
= nelem(sets_selected_full
);
172 for (i
= 0; i
< nelem(sets_valid
); i
++)
173 set_status
[sets_valid
[i
]] = SET_VALID
;
174 for (i
= 0; i
< nelem_selected
; i
++)
175 set_status
[sets_selected
[i
]] |= SET_SELECTED
;
177 set_status
[SET_GROUP
] = SET_VALID
;
179 /* Lookup some strings we need lots of times */
180 msg_yes
= msg_string(MSG_Yes
);
181 msg_no
= msg_string(MSG_No
);
182 msg_all
= msg_string(MSG_All
);
183 msg_some
= msg_string(MSG_Some
);
184 msg_none
= msg_string(MSG_None
);
185 msg_cur_distsets_row
= msg_string(MSG_cur_distsets_row
);
187 /* Find longest and use it to determine width of selection menu */
188 len
= strlen(msg_no
); longest
= msg_no
;
189 i
= strlen(msg_yes
); if (i
> len
) {len
= i
; longest
= msg_yes
; }
190 i
= strlen(msg_all
); if (i
> len
) {len
= i
; longest
= msg_all
; }
191 i
= strlen(msg_some
); if (i
> len
) {len
= i
; longest
= msg_some
; }
192 i
= strlen(msg_none
); if (i
> len
) {len
= i
; longest
= msg_none
; }
193 select_menu_width
= snprintf(NULL
, 0, msg_cur_distsets_row
, "",longest
);
195 /* Give the md code a chance to choose the right kernel, etc. */
196 md_init_set_status(minimal
);
200 dir_exists_p(const char *path
)
203 return file_mode_match(path
, S_IFDIR
);
207 file_exists_p(const char *path
)
210 return file_mode_match(path
, S_IFREG
);
214 file_mode_match(const char *path
, unsigned int mode
)
218 return (stat(path
, &st
) == 0 && (st
.st_mode
& S_IFMT
) == mode
);
225 size_t len
= sizeof ramsize
;
226 int mib
[2] = {CTL_HW
, HW_PHYSMEM64
};
228 sysctl(mib
, 2, &ramsize
, &len
, NULL
, 0);
230 /* Find out how many Megs ... round up. */
231 return (ramsize
+ MEG
- 1) / MEG
;
239 msg_display_add("\n\n");
240 msg_display_add(MSG_makedev
);
242 owd
= getcwd(NULL
, 0);
244 /* make /dev, in case the user didn't extract it. */
245 make_target_dir("/dev");
246 target_chdir_or_die("/dev");
247 run_program(0, "/bin/sh MAKEDEV all");
254 floppy_fetch(const char *set_name
)
260 const char *write_mode
= ">";
269 msg_display_add(MSG_fdmount
, set_name
, post
);
270 process_menu(menu
, &status
);
271 if (status
!= SET_CONTINUE
)
273 menu
= MENU_fdremount
;
274 errmsg
= MSG_fdremount
;
275 if (run_program(0, "/sbin/mount -r -t %s %s /mnt2",
279 errmsg
= MSG_fdnotfound
;
281 /* Display this because it might take a while.... */
282 if (run_program(RUN_DISPLAY
,
283 "sh -c '/bin/cat /mnt2/%s.%s %s %s/%s/%s%s'",
284 set_name
, post
, write_mode
,
285 target_prefix(), xfer_dir
, set_name
, dist_postfix
))
286 /* XXX: a read error will give a corrupt file! */
289 /* We got that file, advance to next fragment */
293 post
[1] = 'a', post
[0]++;
301 * Load files from floppy. Requires a /mnt2 directory for mounting them.
307 process_menu(MENU_floppysource
, NULL
);
309 fetch_fn
= floppy_fetch
;
311 /* Set ext_dir for absolute path. */
312 snprintf(ext_dir
, sizeof ext_dir
, "%s/%s", target_prefix(), xfer_dir
);
318 * Get from a CDROM distribution.
325 /* If root is a CD-ROM and we have sets, skip this step. */
326 if (statvfs(set_dir
, &sb
) == 0 &&
327 strcmp(sb
.f_fstypename
, "cd9660") == 0) {
328 strlcpy(ext_dir
, set_dir
, sizeof ext_dir
);
332 /* Get CD-rom device name and path within CD-rom */
333 process_menu(MENU_cdromsource
, NULL
);
336 if (run_program(0, "/sbin/mount -rt cd9660 /dev/%s /mnt2",
342 snprintf(ext_dir
, sizeof ext_dir
, "%s/%s", "/mnt2", set_dir
);
349 * Get from a pathname inside an unmounted local filesystem
350 * (e.g., where sets were preloaded onto a local DOS partition)
353 get_via_localfs(void)
356 /* Get device, filesystem, and filepath */
357 process_menu (MENU_localfssource
, NULL
);
360 if (run_program(0, "/sbin/mount -rt %s /dev/%s /mnt2",
361 localfs_fs
, localfs_dev
))
366 snprintf(ext_dir
, sizeof ext_dir
, "%s/%s/%s",
367 "/mnt2", localfs_dir
, set_dir
);
373 * Get from an already-mounted pathname.
377 get_via_localdir(void)
381 process_menu(MENU_localdirsource
, NULL
);
384 * We have to have an absolute path ('cos pax runs in a
385 * different directory), make it so.
387 snprintf(ext_dir
, sizeof ext_dir
, "/%s/%s", localfs_dir
, set_dir
);
394 * Support for custom distribution fetches / unpacks.
398 set_X11_selected(void)
402 for (i
= SET_X11_FIRST
; ++i
< SET_X11_LAST
;)
403 if (set_status
[i
] & SET_SELECTED
)
413 for (i
= SET_KERNEL_FIRST
; ++i
< SET_KERNEL_LAST
;)
414 if (set_status
[i
] & SET_SELECTED
)
420 set_kernel_set(unsigned int kernel_set
)
424 /* only one kernel set is allowed */
425 for (i
= SET_KERNEL_FIRST
; ++i
< SET_KERNEL_LAST
;)
426 set_status
[i
] &= ~SET_SELECTED
;
427 set_status
[kernel_set
] |= SET_SELECTED
;
431 set_toggle(menudesc
*menu
, void *arg
)
433 distinfo
**distp
= arg
;
434 int set
= distp
[menu
->cursel
]->set
;
436 if (set
> SET_KERNEL_FIRST
&& set
< SET_KERNEL_LAST
&&
437 !(set_status
[set
] & SET_SELECTED
))
440 set_status
[set
] ^= SET_SELECTED
;
445 set_all_none(menudesc
*menu
, void *arg
, int set
, int clr
)
447 distinfo
**distp
= arg
;
448 distinfo
*dist
= *distp
;
451 for (nested
= 0; dist
->set
!= SET_GROUP_END
|| nested
--; dist
++) {
452 if (dist
->set
== SET_GROUP
) {
456 set_status
[dist
->set
] = (set_status
[dist
->set
] & ~clr
) | set
;
462 set_all(menudesc
*menu
, void *arg
)
464 return set_all_none(menu
, arg
, SET_SELECTED
, 0);
468 set_none(menudesc
*menu
, void *arg
)
470 return set_all_none(menu
, arg
, 0, SET_SELECTED
);
474 set_label(menudesc
*menu
, int opt
, void *arg
)
476 distinfo
**distp
= arg
;
477 distinfo
*dist
= distp
[opt
];
478 const char *selected
;
484 if (dist
->set
!= SET_GROUP
)
485 selected
= set_status
[dist
->set
] & SET_SELECTED
? msg_yes
: msg_no
;
487 /* sub menu - display None/Some/All */
489 selected
= "unknown";
490 while ((++dist
)->set
!= SET_GROUP_END
|| nested
--) {
491 if (dist
->set
== SET_GROUP
) {
495 if (!(set_status
[dist
->set
] & SET_VALID
))
497 if (set_status
[dist
->set
] & SET_SELECTED
) {
498 if (selected
== msg_none
) {
504 if (selected
== msg_all
) {
513 wprintw(menu
->mw
, msg_cur_distsets_row
, msg_string(desc
), selected
);
516 static int set_sublist(menudesc
*menu
, void *arg
);
519 initialise_set_menu(distinfo
*dist
, menu_ent
*me
, distinfo
**de
, int all_none
)
525 for (sets
= 0; ; dist
++) {
527 if (set
== SET_LAST
|| set
== SET_GROUP_END
)
529 if (!(set_status
[set
] & SET_VALID
))
532 me
->opt_menu
= OPT_NOMENU
;
535 if (set
!= SET_GROUP
)
536 me
->opt_action
= set_toggle
;
538 /* Collapse sublist */
540 while ((++dist
)->set
!= SET_GROUP_END
|| nested
--) {
541 if (dist
->set
== SET_GROUP
)
544 me
->opt_action
= set_sublist
;
552 me
->opt_menu
= OPT_NOMENU
;
554 me
->opt_name
= MSG_select_all
;
555 me
->opt_action
= set_all
;
557 me
->opt_menu
= OPT_NOMENU
;
559 me
->opt_name
= MSG_select_none
;
560 me
->opt_action
= set_none
;
568 set_sublist(menudesc
*menu
, void *arg
)
570 distinfo
*de
[SET_LAST
];
571 menu_ent me
[SET_LAST
];
572 distinfo
**dist
= arg
;
576 sets
= initialise_set_menu(dist
[menu
->cursel
] + 1, me
, de
, 1);
578 menu_no
= new_menu(NULL
, me
, sets
, 20, 10, 0, select_menu_width
,
579 MC_SUBMENU
| MC_SCROLL
| MC_DFLTEXIT
,
580 NULL
, set_label
, NULL
, NULL
,
581 MSG_install_selected_sets
);
583 process_menu(menu_no
, de
);
592 distinfo
*de
[SET_LAST
];
593 menu_ent me
[SET_LAST
];
597 msg_display(MSG_cur_distsets
);
598 msg_table_add(MSG_cur_distsets_header
);
600 sets
= initialise_set_menu(dist_list
, me
, de
, 0);
602 menu_no
= new_menu(NULL
, me
, sets
, 0, 5, 0, select_menu_width
,
603 MC_SCROLL
| MC_NOBOX
| MC_DFLTEXIT
| MC_NOCLEAR
,
604 NULL
, set_label
, NULL
, NULL
,
605 MSG_install_selected_sets
);
607 process_menu(menu_no
, de
);
612 * Extract_file **REQUIRES** an absolute path in ext_dir. Any code
613 * that sets up xfer_dir for use by extract_file needs to put in the
614 * full path name to the directory.
618 extract_file(distinfo
*dist
, int update
)
624 /* If we might need to tidy up, ensure directory exists */
625 if (fetch_fn
!= NULL
)
626 make_target_dir(xfer_dir
);
628 (void)snprintf(path
, sizeof path
, "%s/%s%s",
629 ext_dir
, dist
->name
, dist_postfix
);
631 owd
= getcwd(NULL
, 0);
633 /* Do we need to fetch the file now? */
634 if (fetch_fn
!= NULL
) {
635 rval
= fetch_fn(dist
->name
);
640 /* check tarfile exists */
641 if (!file_exists_p(path
)) {
643 #ifdef SUPPORT_8_3_SOURCE_FILESYSTEM
645 * Update path to use dist->name tuncated to the first eight
646 * characters and check again
648 (void)snprintf(path
, sizeof path
, "%s/%.8s%.4s", /* 4 as includes '.' */
649 ext_dir
, dist
->name
, dist_postfix
);
650 if (!file_exists_p(path
)) {
651 #endif /* SUPPORT_8_3_SOURCE_FILESYSTEM */
653 tarstats
.nnotfound
++;
655 msg_display(MSG_notarfile
, path
);
656 process_menu(MENU_ok
, NULL
);
659 #ifdef SUPPORT_8_3_SOURCE_FILESYSTEM
661 #endif /* SUPPORT_8_3_SOURCE_FILESYSTEM */
664 /* cd to the target root. */
665 if (update
&& (dist
->set
== SET_ETC
|| dist
->set
== SET_X11_ETC
)) {
666 make_target_dir("/.sysinst");
667 target_chdir_or_die("/.sysinst");
669 target_chdir_or_die("/");
672 * /usr/X11R7/lib/X11/xkb/symbols/pc was a directory in 5.0
673 * but is a file in 5.1 and beyond, so on upgrades we need to
674 * delete it before extracting the xbase set.
676 if (update
&& dist
->set
== SET_X11_BASE
)
677 run_program(0, "rm -rf usr/X11R7/lib/X11/xkb/symbols/pc");
679 /* now extract set files into "./". */
680 rval
= run_program(RUN_DISPLAY
| RUN_PROGRESS
,
681 "progress -zf %s tar --chroot -xhepf -", path
);
686 /* Check rval for errors and give warning. */
689 msg_display(MSG_tarerror
, path
);
690 process_menu(MENU_ok
, NULL
);
694 if (fetch_fn
!= NULL
&& clean_xfer_dir
) {
695 run_program(0, "rm %s", path
);
696 /* Plausibly we should unlink an empty xfer_dir as well */
699 set_status
[dist
->set
] |= SET_INSTALLED
;
705 skip_set(distinfo
*dist
, int skip_type
)
711 while ((++dist
)->set
!= SET_GROUP_END
|| nested
--) {
713 if (set
== SET_GROUP
) {
719 if (set_status
[set
] == (SET_SELECTED
| SET_VALID
))
720 set_status
[set
] |= SET_SKIPPED
;
726 * Get and unpack the distribution.
727 * Show success_msg if installation completes.
728 * Otherwise show failure_msg and wait for the user to ack it before continuing.
729 * success_msg and failure_msg must both be 0-adic messages.
732 get_and_unpack_sets(int update
, msg setupdone_msg
, msg success_msg
, msg failure_msg
)
738 /* Ensure mountpoint for distribution files exists in current root. */
739 (void)mkdir("/mnt2", S_IRWXU
| S_IRGRP
|S_IXGRP
| S_IROTH
|S_IXOTH
);
741 (void)fprintf(script
, "mkdir -m 755 /mnt2\n");
743 /* reset failure/success counters */
744 memset(&tarstats
, 0, sizeof(tarstats
));
746 /* Find out which files to "get" if we get files. */
748 /* Accurately count selected sets */
749 for (dist
= dist_list
; (set
= dist
->set
) != SET_LAST
; dist
++) {
750 if ((set_status
[set
] & (SET_VALID
| SET_SELECTED
))
751 == (SET_VALID
| SET_SELECTED
))
752 tarstats
.nselected
++;
756 for (dist
= dist_list
; ; dist
++) {
760 if (dist
->name
== NULL
)
762 if (set_status
[set
] != (SET_VALID
| SET_SELECTED
))
765 if (status
!= SET_OK
) {
766 /* This might force a redraw.... */
770 /* Sort out the location of the set files */
773 msg_display(MSG_distmedium
, tarstats
.nselected
,
774 tarstats
.nsuccess
+ tarstats
.nskipped
,
777 process_menu(MENU_distmedium
, &status
);
778 } while (status
== SET_RETRY
);
780 if (status
== SET_SKIP
) {
781 set_status
[set
] |= SET_SKIPPED
;
785 if (status
== SET_SKIP_GROUP
) {
786 skip_set(dist
, status
);
789 if (status
!= SET_OK
) {
790 msg_display(failure_msg
);
791 process_menu(MENU_ok
, NULL
);
796 /* Try to extract this set */
797 status
= extract_file(dist
, update
);
798 if (status
== SET_RETRY
)
802 if (tarstats
.nerror
== 0 && tarstats
.nsuccess
== tarstats
.nselected
) {
803 msg_display(MSG_endtarok
);
804 /* Give user a chance to see the success message */
807 /* We encountered errors. Let the user know. */
808 msg_display(MSG_endtar
,
809 tarstats
.nselected
, tarstats
.nnotfound
, tarstats
.nskipped
,
810 tarstats
.nfound
, tarstats
.nsuccess
, tarstats
.nerror
);
811 process_menu(MENU_ok
, NULL
);
816 * postinstall needs to be run after extracting all sets, because
817 * otherwise /var/db/obsolete will only have current information
818 * from the base, comp, and etc sets.
820 if (update
&& (set_status
[SET_ETC
] & SET_INSTALLED
)) {
822 oldsendmail
= run_program(RUN_DISPLAY
| RUN_CHROOT
|
823 RUN_ERROR_OK
| RUN_PROGRESS
,
824 "/usr/sbin/postinstall -s /.sysinst -d / check mailerconf");
825 if (oldsendmail
== 1) {
826 msg_display(MSG_oldsendmail
);
827 process_menu(MENU_yesno
, NULL
);
829 run_program(RUN_DISPLAY
| RUN_CHROOT
,
830 "/usr/sbin/postinstall -s /.sysinst -d / fix mailerconf");
833 run_program(RUN_DISPLAY
| RUN_CHROOT
,
834 "/usr/sbin/postinstall -s /.sysinst -d / fix");
837 /* Configure the system */
838 if (set_status
[SET_BASE
] & SET_INSTALLED
)
841 /* Save keybard type */
844 /* Other configuration. */
847 /* Mounted dist dir? */
850 /* Install/Upgrade complete ... reboot or exit to script */
851 msg_display(success_msg
);
852 process_menu(MENU_ok
, NULL
);
861 run_program(RUN_SILENT
, "/sbin/umount /mnt2");
867 * Do a quick sanity check that the target can reboot.
868 * return 1 if everything OK, 0 if there is a problem.
869 * Uses a table of files we expect to find after a base install/upgrade.
872 /* test flag and pathname to check for after unpacking. */
873 struct check_table
{ unsigned int mode
; const char *path
;} checks
[] = {
874 { S_IFREG
, "/netbsd" },
876 { S_IFREG
, "/etc/fstab" },
877 { S_IFREG
, "/sbin/init" },
878 { S_IFREG
, "/bin/sh" },
879 { S_IFREG
, "/etc/rc" },
880 { S_IFREG
, "/etc/rc.subr" },
881 { S_IFREG
, "/etc/rc.conf" },
883 { S_IFCHR
, "/dev/console" },
884 /* XXX check for rootdev in target /dev? */
885 { S_IFREG
, "/etc/fstab" },
886 { S_IFREG
, "/sbin/fsck" },
887 { S_IFREG
, "/sbin/fsck_ffs" },
888 { S_IFREG
, "/sbin/mount" },
889 { S_IFREG
, "/sbin/mount_ffs" },
890 { S_IFREG
, "/sbin/mount_nfs" },
891 #if defined(DEBUG) || defined(DEBUG_CHECK)
892 { S_IFREG
, "/foo/bar" }, /* bad entry to exercise warning */
899 * Check target for a single file.
902 check_for(unsigned int mode
, const char *pathname
)
906 found
= (target_test(mode
, pathname
) == 0);
908 msg_display(MSG_rootmissing
, pathname
);
913 * Check that all the files in check_table are present in the
914 * target root. Warn if not found.
920 struct check_table
*p
;
922 for (p
= checks
; p
->path
; p
++) {
923 target_ok
= target_ok
&& check_for(p
->mode
, p
->path
);
928 /* Uh, oh. Something's missing. */
929 msg_display(MSG_badroot
);
930 process_menu(MENU_ok
, NULL
);
935 * Some globals to pass things back from callbacks
937 static char zoneinfo_dir
[STRSIZE
];
938 static int zonerootlen
;
939 static char *tz_selected
; /* timezonename (relative to share/zoneinfo */
940 static const char *tz_default
; /* UTC, or whatever /etc/localtime points to */
941 static char tz_env
[STRSIZE
];
942 static int save_cursel
, save_topline
;
945 * Callback from timezone menu
948 set_tz_select(menudesc
*m
, void *arg
)
953 if (m
&& strcmp(tz_selected
, m
->opts
[m
->cursel
].opt_name
) != 0) {
954 /* Change the displayed timezone */
955 new = strdup(m
->opts
[m
->cursel
].opt_name
);
960 snprintf(tz_env
, sizeof tz_env
, "%.*s%s",
961 zonerootlen
, zoneinfo_dir
, tz_selected
);
962 setenv("TZ", tz_env
, 1);
965 /* Warp curser to 'Exit' line on menu */
968 /* Update displayed time */
970 msg_display(MSG_choose_timezone
,
971 tz_default
, tz_selected
, ctime(&t
), localtime(&t
)->tm_zone
);
976 set_tz_back(menudesc
*m
, void *arg
)
979 zoneinfo_dir
[zonerootlen
] = 0;
980 m
->cursel
= save_cursel
;
981 m
->topline
= save_topline
;
986 set_tz_dir(menudesc
*m
, void *arg
)
989 strlcpy(zoneinfo_dir
+ zonerootlen
, m
->opts
[m
->cursel
].opt_name
,
990 sizeof zoneinfo_dir
- zonerootlen
);
991 save_cursel
= m
->cursel
;
992 save_topline
= m
->topline
;
999 * Alarm-handler to update example-display
1003 timezone_sig(int sig
)
1006 set_tz_select(NULL
, NULL
);
1011 tz_sort(const void *a
, const void *b
)
1013 return strcmp(((const menu_ent
*)a
)->opt_name
, ((const menu_ent
*)b
)->opt_name
);
1017 tzm_set_names(menudesc
*m
, void *arg
)
1022 static int maxfiles
= 32;
1023 static menu_ent
*tz_menu
;
1024 static char **tz_names
;
1030 if (tz_menu
== NULL
)
1031 tz_menu
= malloc(maxfiles
* sizeof *tz_menu
);
1032 if (tz_names
== NULL
)
1033 tz_names
= malloc(maxfiles
* sizeof *tz_names
);
1034 if (tz_menu
== NULL
|| tz_names
== NULL
)
1035 return; /* error - skip timezone setting */
1037 free(tz_names
[--nfiles
]);
1039 dir
= opendir(zoneinfo_dir
);
1040 fp
= strchr(zoneinfo_dir
, 0);
1041 if (fp
!= zoneinfo_dir
+ zonerootlen
) {
1043 tz_menu
[0].opt_name
= msg_string(MSG_tz_back
);
1044 tz_menu
[0].opt_menu
= OPT_NOMENU
;
1045 tz_menu
[0].opt_flags
= 0;
1046 tz_menu
[0].opt_action
= set_tz_back
;
1049 maxfname
= zoneinfo_dir
+ sizeof zoneinfo_dir
- fp
- 1;
1051 while ((dp
= readdir(dir
)) != NULL
) {
1052 if (dp
->d_namlen
> maxfname
|| dp
->d_name
[0] == '.')
1054 strlcpy(fp
, dp
->d_name
, maxfname
);
1055 if (stat(zoneinfo_dir
, &sb
) == -1)
1057 if (nfiles
>= maxfiles
) {
1058 p
= realloc(tz_menu
, 2 * maxfiles
* sizeof *tz_menu
);
1062 p
= realloc(tz_names
, 2 * maxfiles
* sizeof *tz_names
);
1068 if (S_ISREG(sb
.st_mode
))
1069 tz_menu
[nfiles
].opt_action
= set_tz_select
;
1070 else if (S_ISDIR(sb
.st_mode
)) {
1071 tz_menu
[nfiles
].opt_action
= set_tz_dir
;
1073 sizeof(zoneinfo_dir
) - (fp
- zoneinfo_dir
));
1076 tz_names
[nfiles
] = strdup(zoneinfo_dir
+ zonerootlen
);
1077 tz_menu
[nfiles
].opt_name
= tz_names
[nfiles
];
1078 tz_menu
[nfiles
].opt_menu
= OPT_NOMENU
;
1079 tz_menu
[nfiles
].opt_flags
= 0;
1087 m
->numopts
= nfiles
;
1088 qsort(tz_menu
, nfiles
, sizeof *tz_menu
, tz_sort
);
1092 * Choose from the files in usr/share/zoneinfo and set etc/localtime
1097 char localtime_link
[STRSIZE
];
1098 char localtime_target
[STRSIZE
];
1103 strlcpy(zoneinfo_dir
, target_expand("/usr/share/zoneinfo/"),
1104 sizeof zoneinfo_dir
- 1);
1105 zonerootlen
= strlen(zoneinfo_dir
);
1106 strlcpy(localtime_link
, target_expand("/etc/localtime"),
1107 sizeof localtime_link
);
1109 /* Add sanity check that /mnt/usr/share/zoneinfo contains
1113 rc
= readlink(localtime_link
, localtime_target
,
1114 sizeof(localtime_target
) - 1);
1116 /* error, default to UTC */
1119 localtime_target
[rc
] = '\0';
1120 tz_default
= strchr(strstr(localtime_target
, "zoneinfo"), '/') + 1;
1123 tz_selected
= strdup(tz_default
);
1124 snprintf(tz_env
, sizeof(tz_env
), "%s%s", zoneinfo_dir
, tz_selected
);
1125 setenv("TZ", tz_env
, 1);
1127 msg_display(MSG_choose_timezone
,
1128 tz_default
, tz_selected
, ctime(&t
), localtime(&t
)->tm_zone
);
1130 signal(SIGALRM
, timezone_sig
);
1133 menu_no
= new_menu(NULL
, NULL
, 14, 23, 9,
1134 12, 32, MC_ALWAYS_SCROLL
| MC_NOSHORTCUT
,
1135 tzm_set_names
, NULL
, NULL
,
1136 "\nPlease consult the install documents.", NULL
);
1138 goto done
; /* error - skip timezone setting */
1140 process_menu(menu_no
, NULL
);
1144 signal(SIGALRM
, SIG_IGN
);
1146 snprintf(localtime_target
, sizeof(localtime_target
),
1147 "/usr/share/zoneinfo/%s", tz_selected
);
1148 unlink(localtime_link
);
1149 symlink(localtime_target
, localtime_link
);
1156 set_crypt_type(void)
1161 msg_display(MSG_choose_crypt
);
1162 process_menu(MENU_crypttype
, NULL
);
1163 fn
= strdup(target_expand("/etc/passwd.conf"));
1171 rename(fn
, target_expand("/etc/passwd.conf.pre-sysinst"));
1172 pwc
= fopen(fn
, "w");
1175 " localcipher = old\n"
1176 " ypcipher = old\n");
1180 rename(fn
, target_expand("/etc/passwd.conf.pre-sysinst"));
1181 pwc
= fopen(fn
, "w");
1184 " localcipher = md5\n"
1185 " ypcipher = md5\n");
1188 case 3: /* blowfish 2^7 */
1189 rename(fn
, target_expand("/etc/passwd.conf.pre-sysinst"));
1190 pwc
= fopen(fn
, "w");
1193 " localcipher = blowfish,7\n"
1194 " ypcipher = blowfish,7\n");
1198 rename(fn
, target_expand("/etc/passwd.conf.pre-sysinst"));
1199 pwc
= fopen(fn
, "w");
1202 " localcipher = sha1\n"
1203 " ypcipher = sha1\n");
1213 set_root_password(void)
1216 msg_display(MSG_rootpw
);
1217 process_menu(MENU_yesno
, NULL
);
1219 run_program(RUN_DISPLAY
| RUN_PROGRESS
| RUN_CHROOT
,
1225 set_root_shell(void)
1227 const char *shellpath
;
1229 msg_display(MSG_rootsh
);
1230 process_menu(MENU_rootsh
, &shellpath
);
1231 run_program(RUN_DISPLAY
| RUN_CHROOT
, "chpass -s %s root", shellpath
);
1236 scripting_vfprintf(FILE *f
, const char *fmt
, va_list ap
)
1240 (void)vfprintf(f
, fmt
, ap
);
1242 (void)vfprintf(script
, fmt
, ap
);
1246 scripting_fprintf(FILE *f
, const char *fmt
, ...)
1251 scripting_vfprintf(f
, fmt
, ap
);
1256 add_rc_conf(const char *fmt
, ...)
1262 f
= target_fopen("/etc/rc.conf", "a");
1264 scripting_fprintf(NULL
, "cat <<EOF >>%s/etc/rc.conf\n",
1266 scripting_vfprintf(f
, fmt
, ap
);
1268 scripting_fprintf(NULL
, "EOF\n");
1274 add_sysctl_conf(const char *fmt
, ...)
1280 f
= target_fopen("/etc/sysctl.conf", "a");
1282 scripting_fprintf(NULL
, "cat <<EOF >>%s/etc/sysctl.conf\n",
1284 scripting_vfprintf(f
, fmt
, ap
);
1286 scripting_fprintf(NULL
, "EOF\n");
1292 enable_rc_conf(void)
1294 run_program(RUN_CHROOT
,
1295 "sed -an -e 's/^rc_configured=NO/rc_configured=YES/;"
1296 "H;$!d;g;w /etc/rc.conf' /etc/rc.conf");
1300 check_lfs_progs(void)
1303 return (access("/sbin/fsck_lfs", X_OK
) == 0 &&
1304 access("/sbin/mount_lfs", X_OK
) == 0 &&
1305 access("/sbin/newfs_lfs", X_OK
) == 0);