xref: /netbsd-src/usr.sbin/sysinst/util.c (revision 050294fac10bef29540f5ac349394b33ebe9398d)
1*050294faShannken /*	$NetBSD: util.c,v 1.77 2024/04/25 11:25:08 hannken Exp $	*/
250dbef1aSdholland 
350dbef1aSdholland /*
450dbef1aSdholland  * Copyright 1997 Piermont Information Systems Inc.
550dbef1aSdholland  * All rights reserved.
650dbef1aSdholland  *
750dbef1aSdholland  * Written by Philip A. Nelson for Piermont Information Systems Inc.
850dbef1aSdholland  *
950dbef1aSdholland  * Redistribution and use in source and binary forms, with or without
1050dbef1aSdholland  * modification, are permitted provided that the following conditions
1150dbef1aSdholland  * are met:
1250dbef1aSdholland  * 1. Redistributions of source code must retain the above copyright
1350dbef1aSdholland  *    notice, this list of conditions and the following disclaimer.
1450dbef1aSdholland  * 2. Redistributions in binary form must reproduce the above copyright
1550dbef1aSdholland  *    notice, this list of conditions and the following disclaimer in the
1650dbef1aSdholland  *    documentation and/or other materials provided with the distribution.
1750dbef1aSdholland  * 3. The name of Piermont Information Systems Inc. may not be used to endorse
1850dbef1aSdholland  *    or promote products derived from this software without specific prior
1950dbef1aSdholland  *    written permission.
2050dbef1aSdholland  *
2150dbef1aSdholland  * THIS SOFTWARE IS PROVIDED BY PIERMONT INFORMATION SYSTEMS INC. ``AS IS''
2250dbef1aSdholland  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2350dbef1aSdholland  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2450dbef1aSdholland  * ARE DISCLAIMED. IN NO EVENT SHALL PIERMONT INFORMATION SYSTEMS INC. BE
2550dbef1aSdholland  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2650dbef1aSdholland  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2750dbef1aSdholland  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2850dbef1aSdholland  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2950dbef1aSdholland  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
3050dbef1aSdholland  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
3150dbef1aSdholland  * THE POSSIBILITY OF SUCH DAMAGE.
3250dbef1aSdholland  *
3350dbef1aSdholland  */
3450dbef1aSdholland 
3550dbef1aSdholland /* util.c -- routines that don't really fit anywhere else... */
3650dbef1aSdholland 
37ac730b51Smartin #include <assert.h>
38ac730b51Smartin #include <inttypes.h>
3950dbef1aSdholland #include <stdio.h>
4050dbef1aSdholland #include <stdarg.h>
4150dbef1aSdholland #include <string.h>
4250dbef1aSdholland #include <unistd.h>
4350dbef1aSdholland #include <sys/mount.h>
4450dbef1aSdholland #include <sys/dkio.h>
4550dbef1aSdholland #include <sys/ioctl.h>
4650dbef1aSdholland #include <sys/types.h>
4750dbef1aSdholland #include <sys/param.h>
4850dbef1aSdholland #include <sys/sysctl.h>
4950dbef1aSdholland #include <sys/stat.h>
5050dbef1aSdholland #include <sys/statvfs.h>
5150dbef1aSdholland #include <isofs/cd9660/iso.h>
5250dbef1aSdholland #include <curses.h>
5350dbef1aSdholland #include <err.h>
5450dbef1aSdholland #include <errno.h>
5550dbef1aSdholland #include <dirent.h>
5650dbef1aSdholland #include <util.h>
5750dbef1aSdholland #include "defs.h"
5850dbef1aSdholland #include "md.h"
594103857bSmartin #include "defsizes.h"
6050dbef1aSdholland #include "msg_defs.h"
6150dbef1aSdholland #include "menu_defs.h"
62249ed7a6Smartin #ifdef MD_MAY_SWAP_TO
63249ed7a6Smartin #include <sys/drvctlio.h>
64249ed7a6Smartin #endif
65043e812bSmartin #ifdef CHECK_ENTROPY
66043e812bSmartin #include <sha2.h>
67043e812bSmartin #include <paths.h>
68043e812bSmartin #endif
6950dbef1aSdholland 
7050dbef1aSdholland #define MAX_CD_DEVS	256	/* how many cd drives do we expect to attach */
7150dbef1aSdholland #define ISO_BLKSIZE	ISO_DEFAULT_BLOCK_SIZE
7250dbef1aSdholland 
7350dbef1aSdholland static const char *msg_yes, *msg_no, *msg_all, *msg_some, *msg_none;
7450dbef1aSdholland static int select_menu_width;
7550dbef1aSdholland 
76fe2acef4Schristos static uint8_t set_status[SET_GROUP_END];
7750dbef1aSdholland #define SET_VALID	0x01
7850dbef1aSdholland #define SET_SELECTED	0x02
7950dbef1aSdholland #define SET_SKIPPED	0x04
8050dbef1aSdholland #define SET_INSTALLED	0x08
81249ed7a6Smartin #define	SET_NO_EXTRACT	0x10
8250dbef1aSdholland 
8350dbef1aSdholland struct  tarstats {
8450dbef1aSdholland 	int nselected;
8550dbef1aSdholland 	int nfound;
8650dbef1aSdholland 	int nnotfound;
8750dbef1aSdholland 	int nerror;
8850dbef1aSdholland 	int nsuccess;
8950dbef1aSdholland 	int nskipped;
9050dbef1aSdholland } tarstats;
9150dbef1aSdholland 
9250dbef1aSdholland distinfo dist_list[] = {
9350dbef1aSdholland #ifdef SET_KERNEL_1_NAME
940ef20e92Smartin 	{SET_KERNEL_1_NAME,	SET_KERNEL_1,		false, MSG_set_kernel_1, NULL},
9550dbef1aSdholland #endif
9650dbef1aSdholland #ifdef SET_KERNEL_2_NAME
970ef20e92Smartin 	{SET_KERNEL_2_NAME,	SET_KERNEL_2,		false, MSG_set_kernel_2, NULL},
9850dbef1aSdholland #endif
9950dbef1aSdholland #ifdef SET_KERNEL_3_NAME
1000ef20e92Smartin 	{SET_KERNEL_3_NAME,	SET_KERNEL_3,		false, MSG_set_kernel_3, NULL},
10150dbef1aSdholland #endif
10250dbef1aSdholland #ifdef SET_KERNEL_4_NAME
1030ef20e92Smartin 	{SET_KERNEL_4_NAME,	SET_KERNEL_4,		false, MSG_set_kernel_4, NULL},
10450dbef1aSdholland #endif
10550dbef1aSdholland #ifdef SET_KERNEL_5_NAME
1060ef20e92Smartin 	{SET_KERNEL_5_NAME,	SET_KERNEL_5,		false, MSG_set_kernel_5, NULL},
10750dbef1aSdholland #endif
10850dbef1aSdholland #ifdef SET_KERNEL_6_NAME
1090ef20e92Smartin 	{SET_KERNEL_6_NAME,	SET_KERNEL_6,		false, MSG_set_kernel_6, NULL},
11050dbef1aSdholland #endif
11150dbef1aSdholland #ifdef SET_KERNEL_7_NAME
1120ef20e92Smartin 	{SET_KERNEL_7_NAME,	SET_KERNEL_7,		false, MSG_set_kernel_7, NULL},
11350dbef1aSdholland #endif
11450dbef1aSdholland #ifdef SET_KERNEL_8_NAME
1150ef20e92Smartin 	{SET_KERNEL_8_NAME,	SET_KERNEL_8,		false, MSG_set_kernel_8, NULL},
11650dbef1aSdholland #endif
11750dbef1aSdholland #ifdef SET_KERNEL_9_NAME
1180ef20e92Smartin 	{SET_KERNEL_9_NAME,	SET_KERNEL_9,		false, MSG_set_kernel_9, NULL},
11950dbef1aSdholland #endif
12050dbef1aSdholland 
121bfb6e561Smartin #ifdef HAVE_MODULES
1220ef20e92Smartin 	{"modules",		SET_MODULES,		false, MSG_set_modules, NULL},
123bfb6e561Smartin #endif
1240ef20e92Smartin 	{"base",		SET_BASE,		false, MSG_set_base, NULL},
125545236f4Snia #ifdef HAVE_BASE32
126545236f4Snia 	{"base32",		SET_BASE32,		false, MSG_set_base32, NULL},
127545236f4Snia #endif
128f7dfb798Snia #ifdef HAVE_BASE64
129f7dfb798Snia 	{"base64",		SET_BASE64,		false, MSG_set_base64, NULL},
130f7dfb798Snia #endif
131043d88a7Sjmcneill #ifdef HAVE_DTB
132043d88a7Sjmcneill 	{"dtb",			SET_DTB,		false, MSG_set_dtb, NULL},
133043d88a7Sjmcneill #endif
1340ef20e92Smartin 	{"etc",			SET_ETC,		false, MSG_set_system, NULL},
1350ef20e92Smartin 	{"comp",		SET_COMPILER,		false, MSG_set_compiler, NULL},
1360ef20e92Smartin 	{"games",		SET_GAMES,		false, MSG_set_games, NULL},
137f54624bdSmaya 	{"gpufw",		SET_GPUFW,		false, MSG_set_gpufw, NULL},
1380ef20e92Smartin 	{"man",			SET_MAN_PAGES,		false, MSG_set_man_pages, NULL},
139545236f4Snia 	{"manhtml",		SET_MAN_PAGES_HTML,	false, MSG_set_man_pages_html, NULL},
1400ef20e92Smartin 	{"misc",		SET_MISC,		false, MSG_set_misc, NULL},
14150f74585Smaya 	{"rescue",		SET_RESCUE,		false, MSG_set_rescue, NULL},
1420ef20e92Smartin 	{"tests",		SET_TESTS,		false, MSG_set_tests, NULL},
1430ef20e92Smartin 	{"text",		SET_TEXT_TOOLS,		false, MSG_set_text_tools, NULL},
14450dbef1aSdholland 
1450ef20e92Smartin 	{NULL,			SET_GROUP,		false, MSG_set_X11, NULL},
1460ef20e92Smartin 	{"xbase",		SET_X11_BASE,		false, MSG_set_X11_base, NULL},
1470ef20e92Smartin 	{"xcomp",		SET_X11_PROG,		false, MSG_set_X11_prog, NULL},
1480ef20e92Smartin 	{"xetc",		SET_X11_ETC,		false, MSG_set_X11_etc, NULL},
1490ef20e92Smartin 	{"xfont",		SET_X11_FONTS,		false, MSG_set_X11_fonts, NULL},
1500ef20e92Smartin 	{"xserver",		SET_X11_SERVERS,	false, MSG_set_X11_servers, NULL},
1510ef20e92Smartin 	{NULL,			SET_GROUP_END,		false, NULL, NULL},
15250dbef1aSdholland 
15350dbef1aSdholland #ifdef SET_MD_1_NAME
1540ef20e92Smartin 	{SET_MD_1_NAME,		SET_MD_1,		false, MSG_set_md_1, NULL},
15550dbef1aSdholland #endif
15650dbef1aSdholland #ifdef SET_MD_2_NAME
1570ef20e92Smartin 	{SET_MD_2_NAME,		SET_MD_2,		false, MSG_set_md_2, NULL},
15850dbef1aSdholland #endif
15950dbef1aSdholland #ifdef SET_MD_3_NAME
1600ef20e92Smartin 	{SET_MD_3_NAME,		SET_MD_3,		false, MSG_set_md_3, NULL},
16150dbef1aSdholland #endif
16250dbef1aSdholland #ifdef SET_MD_4_NAME
1630ef20e92Smartin 	{SET_MD_4_NAME,		SET_MD_4,		false, MSG_set_md_4, NULL},
16450dbef1aSdholland #endif
16550dbef1aSdholland 
1660ef20e92Smartin 	{NULL,			SET_GROUP,		true, MSG_set_source, NULL},
1670ef20e92Smartin 	{"syssrc",		SET_SYSSRC,		true, MSG_set_syssrc, NULL},
1680ef20e92Smartin 	{"src",			SET_SRC,		true, MSG_set_src, NULL},
1690ef20e92Smartin 	{"sharesrc",		SET_SHARESRC,		true, MSG_set_sharesrc, NULL},
1700ef20e92Smartin 	{"gnusrc",		SET_GNUSRC,		true, MSG_set_gnusrc, NULL},
1710ef20e92Smartin 	{"xsrc",		SET_XSRC,		true, MSG_set_xsrc, NULL},
1720ef20e92Smartin 	{"debug",		SET_DEBUG,		false, MSG_set_debug, NULL},
173545236f4Snia #ifdef HAVE_DEBUG32
174545236f4Snia 	{"debug32",		SET_DEBUG32,		false, MSG_set_debug32, NULL},
175545236f4Snia #endif
176f7dfb798Snia #ifdef HAVE_DEBUG64
177f7dfb798Snia 	{"debug64",		SET_DEBUG64,		false, MSG_set_debug64, NULL},
178f7dfb798Snia #endif
1790ef20e92Smartin 	{"xdebug",		SET_X11_DEBUG,		false, MSG_set_xdebug, NULL},
1800ef20e92Smartin 	{NULL,			SET_GROUP_END,		false, NULL, NULL},
18150dbef1aSdholland 
1820ef20e92Smartin 	{NULL,			SET_LAST,		false, NULL, NULL},
18350dbef1aSdholland };
18450dbef1aSdholland 
18550dbef1aSdholland #define MAX_CD_INFOS	16	/* how many media can be found? */
18650dbef1aSdholland struct cd_info {
18750dbef1aSdholland 	char device_name[16];
18850dbef1aSdholland 	char menu[100];
18950dbef1aSdholland };
19050dbef1aSdholland static struct cd_info cds[MAX_CD_INFOS];
19150dbef1aSdholland 
1924103857bSmartin /* flags whether to offer the respective options (depending on helper
1934103857bSmartin    programs available on install media */
1944103857bSmartin int have_raid, have_vnd, have_cgd, have_lvm, have_gpt, have_dk;
1954103857bSmartin 
19650dbef1aSdholland /*
19750dbef1aSdholland  * local prototypes
19850dbef1aSdholland  */
19950dbef1aSdholland 
20050dbef1aSdholland static int check_for(unsigned int mode, const char *pathname);
201ea2cbdfdSmrg static int get_iso9660_volname(int dev, int sess, char *volname,
202ea2cbdfdSmrg 		size_t volnamelen);
20350dbef1aSdholland static int get_available_cds(void);
2044103857bSmartin static int binary_available(const char *prog);
20550dbef1aSdholland 
20650dbef1aSdholland void
init_set_status(int flags)20750dbef1aSdholland init_set_status(int flags)
20850dbef1aSdholland {
20950dbef1aSdholland 	static const uint8_t sets_valid[] = {MD_SETS_VALID};
21050dbef1aSdholland 	static const uint8_t sets_selected_full[] = {MD_SETS_SELECTED};
21150dbef1aSdholland 	static const uint8_t sets_selected_minimal[] = {MD_SETS_SELECTED_MINIMAL};
21250dbef1aSdholland 	static const uint8_t sets_selected_nox[] = {MD_SETS_SELECTED_NOX};
21350dbef1aSdholland 	static const uint8_t *sets_selected;
21450dbef1aSdholland 	unsigned int nelem_selected;
21550dbef1aSdholland 	unsigned int i, len;
21650dbef1aSdholland 	const char *longest;
21750dbef1aSdholland 
21850dbef1aSdholland 	if (flags & SFLAG_MINIMAL) {
21950dbef1aSdholland 		sets_selected = sets_selected_minimal;
2204103857bSmartin 		nelem_selected = __arraycount(sets_selected_minimal);
22150dbef1aSdholland 	} else if (flags & SFLAG_NOX) {
22250dbef1aSdholland 		sets_selected = sets_selected_nox;
2234103857bSmartin 		nelem_selected = __arraycount(sets_selected_nox);
22450dbef1aSdholland 	} else {
22550dbef1aSdholland 		sets_selected = sets_selected_full;
2264103857bSmartin 		nelem_selected = __arraycount(sets_selected_full);
22750dbef1aSdholland 	}
22850dbef1aSdholland 
2294103857bSmartin 	for (i = 0; i < __arraycount(sets_valid); i++)
23050dbef1aSdholland 		set_status[sets_valid[i]] = SET_VALID;
23150dbef1aSdholland 	for (i = 0; i < nelem_selected; i++)
23250dbef1aSdholland 		set_status[sets_selected[i]] |= SET_SELECTED;
23350dbef1aSdholland 
23450dbef1aSdholland 	set_status[SET_GROUP] = SET_VALID;
23550dbef1aSdholland 
23650dbef1aSdholland 	/* Lookup some strings we need lots of times */
23750dbef1aSdholland 	msg_yes = msg_string(MSG_Yes);
23850dbef1aSdholland 	msg_no = msg_string(MSG_No);
23950dbef1aSdholland 	msg_all = msg_string(MSG_All);
24050dbef1aSdholland 	msg_some = msg_string(MSG_Some);
24150dbef1aSdholland 	msg_none = msg_string(MSG_None);
24250dbef1aSdholland 
24350dbef1aSdholland 	/* Find longest and use it to determine width of selection menu */
24450dbef1aSdholland 	len = strlen(msg_no); longest = msg_no;
24550dbef1aSdholland 	i = strlen(msg_yes); if (i > len) {len = i; longest = msg_yes; }
24650dbef1aSdholland 	i = strlen(msg_all); if (i > len) {len = i; longest = msg_all; }
24750dbef1aSdholland 	i = strlen(msg_some); if (i > len) {len = i; longest = msg_some; }
24850dbef1aSdholland 	i = strlen(msg_none); if (i > len) {len = i; longest = msg_none; }
249*050294faShannken 	select_menu_width = snprintf(NULL, 0, "%-40s %s", "", longest);
25050dbef1aSdholland 
25150dbef1aSdholland 	/* Give the md code a chance to choose the right kernel, etc. */
25250dbef1aSdholland 	md_init_set_status(flags);
25350dbef1aSdholland }
25450dbef1aSdholland 
25550dbef1aSdholland int
dir_exists_p(const char * path)25650dbef1aSdholland dir_exists_p(const char *path)
25750dbef1aSdholland {
25850dbef1aSdholland 
25950dbef1aSdholland 	return file_mode_match(path, S_IFDIR);
26050dbef1aSdholland }
26150dbef1aSdholland 
26250dbef1aSdholland int
file_exists_p(const char * path)26350dbef1aSdholland file_exists_p(const char *path)
26450dbef1aSdholland {
26550dbef1aSdholland 
26650dbef1aSdholland 	return file_mode_match(path, S_IFREG);
26750dbef1aSdholland }
26850dbef1aSdholland 
26950dbef1aSdholland int
file_mode_match(const char * path,unsigned int mode)27050dbef1aSdholland file_mode_match(const char *path, unsigned int mode)
27150dbef1aSdholland {
27250dbef1aSdholland 	struct stat st;
27350dbef1aSdholland 
27450dbef1aSdholland 	return (stat(path, &st) == 0 && (st.st_mode & S_IFMT) == mode);
27550dbef1aSdholland }
27650dbef1aSdholland 
2774103857bSmartin /* return ram size in MB */
2784103857bSmartin uint64_t
get_ramsize(void)27950dbef1aSdholland get_ramsize(void)
28050dbef1aSdholland {
28164e2b749Smartin 	static uint64_t ramsize;
28264e2b749Smartin 
28364e2b749Smartin 	if (ramsize == 0) {
28450dbef1aSdholland 		size_t len = sizeof ramsize;
28550dbef1aSdholland 		int mib[2] = {CTL_HW, HW_PHYSMEM64};
28650dbef1aSdholland 
28750dbef1aSdholland 		sysctl(mib, 2, &ramsize, &len, NULL, 0);
28864e2b749Smartin 	}
28950dbef1aSdholland 
29050dbef1aSdholland 	/* Find out how many Megs ... round up. */
29150dbef1aSdholland 	return (ramsize + MEG - 1) / MEG;
29250dbef1aSdholland }
29350dbef1aSdholland 
29450dbef1aSdholland void
run_makedev(void)29550dbef1aSdholland run_makedev(void)
29650dbef1aSdholland {
29750dbef1aSdholland 	char *owd;
29850dbef1aSdholland 
29950dbef1aSdholland 	msg_display_add("\n\n");
30050dbef1aSdholland 	msg_display_add(MSG_makedev);
30150dbef1aSdholland 
30250dbef1aSdholland 	owd = getcwd(NULL, 0);
30350dbef1aSdholland 
30450dbef1aSdholland 	/* make /dev, in case the user  didn't extract it. */
30550dbef1aSdholland 	make_target_dir("/dev");
30650dbef1aSdholland 	target_chdir_or_die("/dev");
30750dbef1aSdholland 	run_program(0, "/bin/sh MAKEDEV all");
30850dbef1aSdholland 
30950dbef1aSdholland 	chdir(owd);
31050dbef1aSdholland 	free(owd);
31150dbef1aSdholland }
31250dbef1aSdholland 
31350dbef1aSdholland /*
31450dbef1aSdholland  * Performs in-place replacement of a set of patterns in a file that lives
31550dbef1aSdholland  * inside the installed system.  The patterns must be separated by a semicolon.
31650dbef1aSdholland  * For example:
31750dbef1aSdholland  *
31850dbef1aSdholland  * replace("/etc/some-file.conf", "s/prop1=NO/prop1=YES/;s/foo/bar/");
31950dbef1aSdholland  */
32050dbef1aSdholland void
replace(const char * path,const char * patterns,...)32150dbef1aSdholland replace(const char *path, const char *patterns, ...)
32250dbef1aSdholland {
32350dbef1aSdholland 	char *spatterns;
32450dbef1aSdholland 	va_list ap;
32550dbef1aSdholland 
32650dbef1aSdholland 	va_start(ap, patterns);
32750dbef1aSdholland 	vasprintf(&spatterns, patterns, ap);
32850dbef1aSdholland 	va_end(ap);
32950dbef1aSdholland 	if (spatterns == NULL)
33050dbef1aSdholland 		err(1, "vasprintf(&spatterns, \"%s\", ...)", patterns);
33150dbef1aSdholland 
33250dbef1aSdholland 	run_program(RUN_CHROOT, "sed -an -e '%s;H;$!d;g;w %s' %s", spatterns,
33350dbef1aSdholland 	    path, path);
33450dbef1aSdholland 
33550dbef1aSdholland 	free(spatterns);
33650dbef1aSdholland }
33750dbef1aSdholland 
33850dbef1aSdholland static int
floppy_fetch(const char * set_name)33950dbef1aSdholland floppy_fetch(const char *set_name)
34050dbef1aSdholland {
34150dbef1aSdholland 	char post[4];
34250dbef1aSdholland 	msg errmsg;
34350dbef1aSdholland 	int menu;
34450dbef1aSdholland 	int status;
34550dbef1aSdholland 	const char *write_mode = ">";
34650dbef1aSdholland 
34750dbef1aSdholland 	strcpy(post, "aa");
34850dbef1aSdholland 
34950dbef1aSdholland 	errmsg = "";
35050dbef1aSdholland 	menu = MENU_fdok;
35150dbef1aSdholland 	for (;;) {
35250dbef1aSdholland 		umount_mnt2();
35350dbef1aSdholland 		msg_display(errmsg);
35424ecf24eSchristos 		msg_fmt_display_add(MSG_fdmount, "%s%s", set_name, post);
35550dbef1aSdholland 		process_menu(menu, &status);
35650dbef1aSdholland 		if (status != SET_CONTINUE)
35750dbef1aSdholland 			return status;
35850dbef1aSdholland 		menu = MENU_fdremount;
35950dbef1aSdholland 		errmsg = MSG_fdremount;
36050dbef1aSdholland 		if (run_program(0, "/sbin/mount -r -t %s %s /mnt2",
36150dbef1aSdholland 							fd_type, fd_dev))
36250dbef1aSdholland 			continue;
36350dbef1aSdholland 		mnt2_mounted = 1;
36450dbef1aSdholland 		errmsg = MSG_fdnotfound;
36550dbef1aSdholland 
36650dbef1aSdholland 		/* Display this because it might take a while.... */
36750dbef1aSdholland 		if (run_program(RUN_DISPLAY,
36850dbef1aSdholland 			    "sh -c '/bin/cat /mnt2/%s.%s %s %s/%s/%s%s'",
36950dbef1aSdholland 			    set_name, post, write_mode,
3700ef20e92Smartin 			    target_prefix(), xfer_dir, set_name,
3710ef20e92Smartin 			    set_postfix(set_name)))
37250dbef1aSdholland 			/* XXX: a read error will give a corrupt file! */
37350dbef1aSdholland 			continue;
37450dbef1aSdholland 
37550dbef1aSdholland 		/* We got that file, advance to next fragment */
37650dbef1aSdholland 		if (post[1] < 'z')
37750dbef1aSdholland 			post[1]++;
37850dbef1aSdholland 		else
37950dbef1aSdholland 			post[1] = 'a', post[0]++;
38050dbef1aSdholland 		write_mode = ">>";
38150dbef1aSdholland 		errmsg = "";
38250dbef1aSdholland 		menu = MENU_fdok;
38350dbef1aSdholland 	}
38450dbef1aSdholland }
38550dbef1aSdholland 
38650dbef1aSdholland /*
38750dbef1aSdholland  * Load files from floppy.  Requires a /mnt2 directory for mounting them.
38850dbef1aSdholland  */
38950dbef1aSdholland int
get_via_floppy(void)39050dbef1aSdholland get_via_floppy(void)
39150dbef1aSdholland {
392e21052b4Smartin 	int rv = -1;
393e21052b4Smartin 
394e21052b4Smartin 	process_menu(MENU_floppysource, &rv);
395e21052b4Smartin 	if (rv == SET_RETRY)
3964b2364d9Smartin 		return SET_RETRY;
39750dbef1aSdholland 
39850dbef1aSdholland 	fetch_fn = floppy_fetch;
39950dbef1aSdholland 
40050dbef1aSdholland 	/* Set ext_dir for absolute path. */
40150dbef1aSdholland 	snprintf(ext_dir_bin, sizeof ext_dir_bin, "%s/%s", target_prefix(), xfer_dir);
40250dbef1aSdholland 	snprintf(ext_dir_src, sizeof ext_dir_src, "%s/%s", target_prefix(), xfer_dir);
40350dbef1aSdholland 
40450dbef1aSdholland 	return SET_OK;
40550dbef1aSdholland }
40650dbef1aSdholland 
40750dbef1aSdholland /*
40850dbef1aSdholland  * Get the volume name of a ISO9660 file system
40950dbef1aSdholland  */
41050dbef1aSdholland static int
get_iso9660_volname(int dev,int sess,char * volname,size_t volnamelen)411ea2cbdfdSmrg get_iso9660_volname(int dev, int sess, char *volname, size_t volnamelen)
41250dbef1aSdholland {
41350dbef1aSdholland 	int blkno, error, last;
414a018a4a9Smartin 	static char buf[ISO_BLKSIZE] __aligned(8);
41550dbef1aSdholland 	struct iso_volume_descriptor *vd = NULL;
41650dbef1aSdholland 	struct iso_primary_descriptor *pd = NULL;
41750dbef1aSdholland 
41850dbef1aSdholland 	for (blkno = sess+16; blkno < sess+16+100; blkno++) {
41950dbef1aSdholland 		error = pread(dev, buf, ISO_BLKSIZE, blkno*ISO_BLKSIZE);
42050dbef1aSdholland 		if (error == -1)
42150dbef1aSdholland 			return -1;
42250dbef1aSdholland 		vd = (struct iso_volume_descriptor *)&buf;
42350dbef1aSdholland 		if (memcmp(vd->id, ISO_STANDARD_ID, sizeof(vd->id)) != 0)
42450dbef1aSdholland 			return -1;
42550dbef1aSdholland 		if (isonum_711((const unsigned char *)&vd->type)
42650dbef1aSdholland 		     == ISO_VD_PRIMARY) {
42750dbef1aSdholland 			pd = (struct iso_primary_descriptor*)buf;
428ea2cbdfdSmrg 			strncpy(volname, pd->volume_id, volnamelen - 1);
429ea2cbdfdSmrg 			volname[volnamelen - 1] = '\0';
430ea2cbdfdSmrg 			last = volnamelen - 1;
43150dbef1aSdholland 			while (last >= 0
43250dbef1aSdholland 			    && (volname[last] == ' ' || volname[last] == 0))
43350dbef1aSdholland 				last--;
43450dbef1aSdholland 			volname[last+1] = 0;
43550dbef1aSdholland 			return 0;
43650dbef1aSdholland 		}
43750dbef1aSdholland 	}
43850dbef1aSdholland 	return -1;
43950dbef1aSdholland }
44050dbef1aSdholland 
44150dbef1aSdholland /*
4421c2e5b02Smartin  * Local state while iterating CDs and collecting volumes
44350dbef1aSdholland  */
4441c2e5b02Smartin struct get_available_cds_state {
44504645caaSmartin 	size_t num_mounted;
44604645caaSmartin 	struct statvfs *mounted;
4471c2e5b02Smartin 	struct cd_info *info;
4481c2e5b02Smartin 	size_t count;
4491c2e5b02Smartin };
45050dbef1aSdholland 
4511c2e5b02Smartin /*
4521c2e5b02Smartin  * Callback function: if this is a CD, enumerate all volumes on it
4531c2e5b02Smartin  */
4541c2e5b02Smartin static bool
get_available_cds_helper(void * arg,const char * device)4551c2e5b02Smartin get_available_cds_helper(void *arg, const char *device)
4561c2e5b02Smartin {
4571c2e5b02Smartin 	struct get_available_cds_state *state = arg;
45804645caaSmartin 	char dname[16], tname[16], volname[80], *t;
4591c2e5b02Smartin 	struct disklabel label;
46004645caaSmartin 	int part, dev, error, sess, ready, tlen;
4611c2e5b02Smartin 
46257cf8237Smartin 	if (!is_cdrom_device(device, false))
4631c2e5b02Smartin 		return true;
4641c2e5b02Smartin 
4651c2e5b02Smartin 	sprintf(dname, "/dev/r%s%c", device, 'a'+RAW_PART);
46604645caaSmartin 	tlen = sprintf(tname, "/dev/%s", device);
46704645caaSmartin 
46804645caaSmartin 	/* check if this is mounted already */
46904645caaSmartin 	for (size_t i = 0; i < state->num_mounted; i++) {
47004645caaSmartin 		if (strncmp(state->mounted[i].f_mntfromname, tname, tlen)
47104645caaSmartin 		    == 0) {
47204645caaSmartin 			t = state->mounted[i].f_mntfromname + tlen;
47304645caaSmartin 			if (t[0] >= 'a' && t[0] <= 'z' && t[1] == 0)
47404645caaSmartin 				return true;
47504645caaSmartin 		}
47604645caaSmartin 	}
47704645caaSmartin 
47850dbef1aSdholland 	dev = open(dname, O_RDONLY, 0);
47950dbef1aSdholland 	if (dev == -1)
4801c2e5b02Smartin 		return true;
4811c2e5b02Smartin 
48250dbef1aSdholland 	ready = 0;
48350dbef1aSdholland 	error = ioctl(dev, DIOCTUR, &ready);
48450dbef1aSdholland 	if (error != 0 || ready == 0) {
48550dbef1aSdholland 		close(dev);
4861c2e5b02Smartin 		return true;
48750dbef1aSdholland 	}
48850dbef1aSdholland 	error = ioctl(dev, DIOCGDINFO, &label);
48950dbef1aSdholland 	close(dev);
4901c2e5b02Smartin 	if (error != 0)
4911c2e5b02Smartin 		return true;
4921c2e5b02Smartin 
4931c2e5b02Smartin 	for (part = 0; part < label.d_npartitions; part++) {
4941c2e5b02Smartin 
4951c2e5b02Smartin 		if (label.d_partitions[part].p_fstype == FS_UNUSED
49650dbef1aSdholland 		    || label.d_partitions[part].p_size == 0)
49750dbef1aSdholland 			continue;
4981c2e5b02Smartin 
4991c2e5b02Smartin 		if (label.d_partitions[part].p_fstype == FS_ISO9660) {
5001c2e5b02Smartin 			sess = label.d_partitions[part].p_cdsession;
5011c2e5b02Smartin 			sprintf(dname, "/dev/r%s%c", device, 'a'+part);
50250dbef1aSdholland 			dev = open(dname, O_RDONLY, 0);
50350dbef1aSdholland 			if (dev == -1)
50450dbef1aSdholland 				continue;
505ea2cbdfdSmrg 			error = get_iso9660_volname(dev, sess, volname,
506ea2cbdfdSmrg 			    sizeof volname);
50750dbef1aSdholland 			close(dev);
5081c2e5b02Smartin 			if (error)
5091c2e5b02Smartin 				continue;
5101c2e5b02Smartin 			sprintf(state->info->device_name,
5111c2e5b02Smartin 			    "%s%c", device, 'a'+part);
5121c2e5b02Smartin 			sprintf(state->info->menu, "%s (%s)",
5131c2e5b02Smartin 			    state->info->device_name, volname);
51450dbef1aSdholland 		} else {
51550dbef1aSdholland 			/*
51650dbef1aSdholland 			 * All install CDs use partition
51750dbef1aSdholland 			 * a for the sets.
51850dbef1aSdholland 			 */
51950dbef1aSdholland 			if (part > 0)
52050dbef1aSdholland 				continue;
5211c2e5b02Smartin 			sprintf(state->info->device_name,
5221c2e5b02Smartin 			    "%s%c", device, 'a'+part);
5231c2e5b02Smartin 			strcpy(state->info->menu, state->info->device_name);
52450dbef1aSdholland 		}
5251c2e5b02Smartin 		state->info++;
5261c2e5b02Smartin 		if (++state->count >= MAX_CD_INFOS)
5271c2e5b02Smartin 			return false;
52850dbef1aSdholland 	}
5291c2e5b02Smartin 
5301c2e5b02Smartin 	return true;
53150dbef1aSdholland }
5321c2e5b02Smartin 
5331c2e5b02Smartin /*
5341c2e5b02Smartin  * Get a list of all available CD media (not drives!), return
5351c2e5b02Smartin  * the number of entries collected.
5361c2e5b02Smartin  */
5371c2e5b02Smartin static int
get_available_cds(void)5381c2e5b02Smartin get_available_cds(void)
5391c2e5b02Smartin {
5401c2e5b02Smartin 	struct get_available_cds_state data;
541a4668228Smartin 	int n, m;
5421c2e5b02Smartin 
54304645caaSmartin 	memset(&data, 0, sizeof data);
5441c2e5b02Smartin 	data.info = cds;
54504645caaSmartin 
54604645caaSmartin 	n = getvfsstat(NULL, 0, ST_NOWAIT);
54704645caaSmartin 	if (n > 0) {
54804645caaSmartin 		data.mounted = calloc(n, sizeof(*data.mounted));
549a4668228Smartin 		m = getvfsstat(data.mounted, n*sizeof(*data.mounted),
55004645caaSmartin 		    ST_NOWAIT);
551a4668228Smartin 		assert(m >= 0 && m <= n);
552a4668228Smartin 		data.num_mounted = m;
55304645caaSmartin 	}
5541c2e5b02Smartin 
5551c2e5b02Smartin 	enumerate_disks(&data, get_available_cds_helper);
5561c2e5b02Smartin 
55704645caaSmartin 	free(data.mounted);
55804645caaSmartin 
5591c2e5b02Smartin 	return data.count;
56050dbef1aSdholland }
56150dbef1aSdholland 
56250dbef1aSdholland static int
cd_has_sets(void)56350dbef1aSdholland cd_has_sets(void)
56450dbef1aSdholland {
565da165701Smartin 
566da165701Smartin 	/* sanity check */
567da165701Smartin 	if (cdrom_dev[0] == 0)
568da165701Smartin 		return 0;
569da165701Smartin 
57050dbef1aSdholland 	/* Mount it */
57150dbef1aSdholland 	if (run_program(RUN_SILENT, "/sbin/mount -rt cd9660 /dev/%s /mnt2",
57250dbef1aSdholland 	    cdrom_dev) != 0)
57350dbef1aSdholland 		return 0;
57450dbef1aSdholland 
57550dbef1aSdholland 	mnt2_mounted = 1;
57650dbef1aSdholland 
57750dbef1aSdholland 	snprintf(ext_dir_bin, sizeof ext_dir_bin, "%s/%s", "/mnt2", set_dir_bin);
57850dbef1aSdholland 	snprintf(ext_dir_src, sizeof ext_dir_src, "%s/%s", "/mnt2", set_dir_src);
57950dbef1aSdholland 	return dir_exists_p(ext_dir_bin);
58050dbef1aSdholland }
58150dbef1aSdholland 
58250dbef1aSdholland /*
58350dbef1aSdholland  * Check whether we can remove the boot media.
58450dbef1aSdholland  * If it is not a local filesystem, return -1.
58550dbef1aSdholland  * If we can not decide for sure (can not tell MD content from plain ffs
58650dbef1aSdholland  * on hard disk, for example), return 0.
58750dbef1aSdholland  * If it is a CD/DVD, return 1.
58850dbef1aSdholland  */
58950dbef1aSdholland int
boot_media_still_needed(void)59050dbef1aSdholland boot_media_still_needed(void)
59150dbef1aSdholland {
59250dbef1aSdholland 	struct statvfs sb;
59350dbef1aSdholland 
59450dbef1aSdholland 	if (statvfs("/", &sb) == 0) {
59550dbef1aSdholland 		if (!(sb.f_flag & ST_LOCAL))
59650dbef1aSdholland 			return -1;
59750dbef1aSdholland 		if (strcmp(sb.f_fstypename, MOUNT_CD9660) == 0
59850dbef1aSdholland 			   || strcmp(sb.f_fstypename, MOUNT_UDF) == 0)
59950dbef1aSdholland 			return 1;
60050dbef1aSdholland 	}
60150dbef1aSdholland 
60250dbef1aSdholland 	return 0;
60350dbef1aSdholland }
60450dbef1aSdholland 
60532ccf04cSmartin bool
root_is_read_only(void)60632ccf04cSmartin root_is_read_only(void)
60732ccf04cSmartin {
60832ccf04cSmartin 	struct statvfs sb;
60932ccf04cSmartin 
61032ccf04cSmartin 	if (statvfs("/", &sb) == 0)
61132ccf04cSmartin 		return sb.f_flag & ST_RDONLY;
61232ccf04cSmartin 
61332ccf04cSmartin 	return false;
61432ccf04cSmartin }
61532ccf04cSmartin 
61650dbef1aSdholland /*
61750dbef1aSdholland  * Get from a CDROM distribution.
61850dbef1aSdholland  * Also used on "installation using bootable install media"
61950dbef1aSdholland  * as the default option in the "distmedium" menu.
62050dbef1aSdholland  */
62150dbef1aSdholland int
get_via_cdrom(void)62250dbef1aSdholland get_via_cdrom(void)
62350dbef1aSdholland {
62450dbef1aSdholland 	menu_ent cd_menu[MAX_CD_INFOS];
62550dbef1aSdholland 	struct stat sb;
626e21052b4Smartin 	int rv, num_cds, menu_cd, i, selected_cd = 0;
62750dbef1aSdholland 	int mib[2];
62850dbef1aSdholland 	char rootdev[SSTRSIZE] = "";
62950dbef1aSdholland 	size_t varlen;
63050dbef1aSdholland 
63150dbef1aSdholland 	/* If root is not md(4) and we have set dir, skip this step. */
63250dbef1aSdholland 	mib[0] = CTL_KERN;
63350dbef1aSdholland 	mib[1] = KERN_ROOT_DEVICE;
63450dbef1aSdholland 	varlen = sizeof(rootdev);
63550dbef1aSdholland 	(void)sysctl(mib, 2, rootdev, &varlen, NULL, 0);
63650dbef1aSdholland 	if (stat(set_dir_bin, &sb) == 0 && S_ISDIR(sb.st_mode) &&
63750dbef1aSdholland 	    strncmp("md", rootdev, 2) != 0) {
63850dbef1aSdholland 	    	strlcpy(ext_dir_bin, set_dir_bin, sizeof ext_dir_bin);
63950dbef1aSdholland 	    	strlcpy(ext_dir_src, set_dir_src, sizeof ext_dir_src);
64050dbef1aSdholland 		return SET_OK;
64150dbef1aSdholland 	}
64250dbef1aSdholland 
643ce713491Schristos 	memset(cd_menu, 0, sizeof(cd_menu));
64450dbef1aSdholland 	num_cds = get_available_cds();
64550dbef1aSdholland 	if (num_cds <= 0) {
646da165701Smartin 		msg_display(MSG_No_cd_found);
647da165701Smartin 		cdrom_dev[0] = 0;
64850dbef1aSdholland 	} else if (num_cds == 1) {
64950dbef1aSdholland 		/* single CD found, check for sets on it */
65050dbef1aSdholland 		strcpy(cdrom_dev, cds[0].device_name);
65150dbef1aSdholland 		if (cd_has_sets())
65250dbef1aSdholland 			return SET_OK;
65350dbef1aSdholland 	} else {
65450dbef1aSdholland 		for (i = 0; i< num_cds; i++) {
65550dbef1aSdholland 			cd_menu[i].opt_name = cds[i].menu;
65650dbef1aSdholland 			cd_menu[i].opt_flags = OPT_EXIT;
6574b2364d9Smartin 			cd_menu[i].opt_action = set_menu_select;
65850dbef1aSdholland 		}
65950dbef1aSdholland 		/* create a menu offering available choices */
66050dbef1aSdholland 		menu_cd = new_menu(MSG_Available_cds,
66150dbef1aSdholland 			cd_menu, num_cds, -1, 4, 0, 0,
66250dbef1aSdholland 			MC_SCROLL | MC_NOEXITOPT,
66350dbef1aSdholland 			NULL, NULL, NULL, NULL, NULL);
66450dbef1aSdholland 		if (menu_cd == -1)
66550dbef1aSdholland 			return SET_RETRY;
66650dbef1aSdholland 		msg_display(MSG_ask_cd);
66750dbef1aSdholland 		process_menu(menu_cd, &selected_cd);
66850dbef1aSdholland 		free_menu(menu_cd);
66950dbef1aSdholland 		strcpy(cdrom_dev, cds[selected_cd].device_name);
67050dbef1aSdholland 		if (cd_has_sets())
67150dbef1aSdholland 			return SET_OK;
67250dbef1aSdholland 	}
67350dbef1aSdholland 
674da165701Smartin 	if (num_cds >= 1 && mnt2_mounted) {
67550dbef1aSdholland 		umount_mnt2();
6764103857bSmartin 		hit_enter_to_continue(MSG_cd_path_not_found, NULL);
67750dbef1aSdholland 	}
67850dbef1aSdholland 
67950dbef1aSdholland 	/* ask for paths on the CD */
680e21052b4Smartin 	rv = -1;
681e21052b4Smartin 	process_menu(MENU_cdromsource, &rv);
682da165701Smartin 	if (rv == SET_RETRY || rv == SET_ABANDON)
683da165701Smartin 		return rv;
68450dbef1aSdholland 
68550dbef1aSdholland 	if (cd_has_sets())
68650dbef1aSdholland 		return SET_OK;
68750dbef1aSdholland 
68850dbef1aSdholland 	return SET_RETRY;
68950dbef1aSdholland }
69050dbef1aSdholland 
69150dbef1aSdholland 
69250dbef1aSdholland /*
69350dbef1aSdholland  * Get from a pathname inside an unmounted local filesystem
69450dbef1aSdholland  * (e.g., where sets were preloaded onto a local DOS partition)
69550dbef1aSdholland  */
69650dbef1aSdholland int
get_via_localfs(void)69750dbef1aSdholland get_via_localfs(void)
69850dbef1aSdholland {
699e21052b4Smartin 	int rv = -1;
700e21052b4Smartin 
70150dbef1aSdholland 	/* Get device, filesystem, and filepath */
702e21052b4Smartin 	process_menu (MENU_localfssource, &rv);
703e21052b4Smartin 	if (rv == SET_RETRY)
7044b2364d9Smartin 		return SET_RETRY;
70550dbef1aSdholland 
70650dbef1aSdholland 	/* Mount it */
70750dbef1aSdholland 	if (run_program(0, "/sbin/mount -rt %s /dev/%s /mnt2",
70850dbef1aSdholland 	    localfs_fs, localfs_dev))
70950dbef1aSdholland 		return SET_RETRY;
71050dbef1aSdholland 
71150dbef1aSdholland 	mnt2_mounted = 1;
71250dbef1aSdholland 
71350dbef1aSdholland 	snprintf(ext_dir_bin, sizeof ext_dir_bin, "%s/%s/%s",
71450dbef1aSdholland 		"/mnt2", localfs_dir, set_dir_bin);
71550dbef1aSdholland 	snprintf(ext_dir_src, sizeof ext_dir_src, "%s/%s/%s",
71650dbef1aSdholland 		"/mnt2", localfs_dir, set_dir_src);
71750dbef1aSdholland 
71850dbef1aSdholland 	return SET_OK;
71950dbef1aSdholland }
72050dbef1aSdholland 
72150dbef1aSdholland /*
72250dbef1aSdholland  * Get from an already-mounted pathname.
72350dbef1aSdholland  */
72450dbef1aSdholland 
72550dbef1aSdholland int
get_via_localdir(void)72650dbef1aSdholland get_via_localdir(void)
72750dbef1aSdholland {
728e21052b4Smartin 	int rv = -1;
729e21052b4Smartin 
73050dbef1aSdholland 	/* Get filepath */
731e21052b4Smartin 	process_menu(MENU_localdirsource, &rv);
732e21052b4Smartin 	if (rv == SET_RETRY)
7334b2364d9Smartin 		return SET_RETRY;
73450dbef1aSdholland 
73550dbef1aSdholland 	/*
73650dbef1aSdholland 	 * We have to have an absolute path ('cos pax runs in a
73750dbef1aSdholland 	 * different directory), make it so.
73850dbef1aSdholland 	 */
73950dbef1aSdholland 	snprintf(ext_dir_bin, sizeof ext_dir_bin, "/%s/%s", localfs_dir, set_dir_bin);
74050dbef1aSdholland 	snprintf(ext_dir_src, sizeof ext_dir_src, "/%s/%s", localfs_dir, set_dir_src);
74150dbef1aSdholland 
74250dbef1aSdholland 	return SET_OK;
74350dbef1aSdholland }
74450dbef1aSdholland 
74550dbef1aSdholland 
74650dbef1aSdholland /*
74750dbef1aSdholland  * Support for custom distribution fetches / unpacks.
74850dbef1aSdholland  */
74950dbef1aSdholland 
75050dbef1aSdholland unsigned int
set_X11_selected(void)75150dbef1aSdholland set_X11_selected(void)
75250dbef1aSdholland {
75350dbef1aSdholland 	int i;
75450dbef1aSdholland 
75550dbef1aSdholland 	for (i = SET_X11_FIRST; ++i < SET_X11_LAST;)
75650dbef1aSdholland 		if (set_status[i] & SET_SELECTED)
75750dbef1aSdholland 			return 1;
75850dbef1aSdholland 	return 0;
75950dbef1aSdholland }
76050dbef1aSdholland 
76150dbef1aSdholland unsigned int
get_kernel_set(void)76250dbef1aSdholland get_kernel_set(void)
76350dbef1aSdholland {
76450dbef1aSdholland 	int i;
76550dbef1aSdholland 
76650dbef1aSdholland 	for (i = SET_KERNEL_FIRST; ++i < SET_KERNEL_LAST;)
76750dbef1aSdholland 		if (set_status[i] & SET_SELECTED)
76850dbef1aSdholland 			return i;
76950dbef1aSdholland 	return SET_NONE;
77050dbef1aSdholland }
77150dbef1aSdholland 
77250dbef1aSdholland void
set_kernel_set(unsigned int kernel_set)77350dbef1aSdholland set_kernel_set(unsigned int kernel_set)
77450dbef1aSdholland {
77550dbef1aSdholland 	int i;
77650dbef1aSdholland 
77750dbef1aSdholland 	/* only one kernel set is allowed */
77850dbef1aSdholland 	for (i = SET_KERNEL_FIRST; ++i < SET_KERNEL_LAST;)
77950dbef1aSdholland 		set_status[i] &= ~SET_SELECTED;
78050dbef1aSdholland 	set_status[kernel_set] |= SET_SELECTED;
78150dbef1aSdholland }
78250dbef1aSdholland 
783249ed7a6Smartin void
set_noextract_set(unsigned int set)784249ed7a6Smartin set_noextract_set(unsigned int set)
785249ed7a6Smartin {
786249ed7a6Smartin 
787249ed7a6Smartin 	set_status[set] |= SET_NO_EXTRACT;
788249ed7a6Smartin }
789249ed7a6Smartin 
79050dbef1aSdholland static int
set_toggle(menudesc * menu,void * arg)79150dbef1aSdholland set_toggle(menudesc *menu, void *arg)
79250dbef1aSdholland {
79350dbef1aSdholland 	distinfo **distp = arg;
79450dbef1aSdholland 	int set = distp[menu->cursel]->set;
79550dbef1aSdholland 
79650dbef1aSdholland 	if (set > SET_KERNEL_FIRST && set < SET_KERNEL_LAST &&
79750dbef1aSdholland 	    !(set_status[set] & SET_SELECTED))
79850dbef1aSdholland 		set_kernel_set(set);
79950dbef1aSdholland 	else
80050dbef1aSdholland 		set_status[set] ^= SET_SELECTED;
80150dbef1aSdholland 	return 0;
80250dbef1aSdholland }
80350dbef1aSdholland 
80450dbef1aSdholland static int
set_all_none(menudesc * menu,void * arg,int set,int clr)80550dbef1aSdholland set_all_none(menudesc *menu, void *arg, int set, int clr)
80650dbef1aSdholland {
80750dbef1aSdholland 	distinfo **distp = arg;
80850dbef1aSdholland 	distinfo *dist = *distp;
80950dbef1aSdholland 	int nested;
81050dbef1aSdholland 
81150dbef1aSdholland 	for (nested = 0; dist->set != SET_GROUP_END || nested--; dist++) {
81250dbef1aSdholland 		if (dist->set == SET_GROUP) {
81350dbef1aSdholland 			nested++;
81450dbef1aSdholland 			continue;
81550dbef1aSdholland 		}
81650dbef1aSdholland 		set_status[dist->set] = (set_status[dist->set] & ~clr) | set;
81750dbef1aSdholland 	}
81850dbef1aSdholland 	return 0;
81950dbef1aSdholland }
82050dbef1aSdholland 
82150dbef1aSdholland static int
set_all(menudesc * menu,void * arg)82250dbef1aSdholland set_all(menudesc *menu, void *arg)
82350dbef1aSdholland {
82450dbef1aSdholland 	return set_all_none(menu, arg, SET_SELECTED, 0);
82550dbef1aSdholland }
82650dbef1aSdholland 
82750dbef1aSdholland static int
set_none(menudesc * menu,void * arg)82850dbef1aSdholland set_none(menudesc *menu, void *arg)
82950dbef1aSdholland {
83050dbef1aSdholland 	return set_all_none(menu, arg, 0, SET_SELECTED);
83150dbef1aSdholland }
83250dbef1aSdholland 
83350dbef1aSdholland static void
set_label(menudesc * menu,int opt,void * arg)83450dbef1aSdholland set_label(menudesc *menu, int opt, void *arg)
83550dbef1aSdholland {
83650dbef1aSdholland 	distinfo **distp = arg;
83750dbef1aSdholland 	distinfo *dist = distp[opt];
83850dbef1aSdholland 	const char *selected;
83950dbef1aSdholland 	const char *desc;
84050dbef1aSdholland 	int nested;
84150dbef1aSdholland 
84250dbef1aSdholland 	desc = dist->desc;
84350dbef1aSdholland 
84450dbef1aSdholland 	if (dist->set != SET_GROUP)
84550dbef1aSdholland 		selected = set_status[dist->set] & SET_SELECTED ? msg_yes : msg_no;
84650dbef1aSdholland 	else {
84750dbef1aSdholland 		/* sub menu - display None/Some/All */
84850dbef1aSdholland 		nested = 0;
84950dbef1aSdholland 		selected = "unknown";
85050dbef1aSdholland 		while ((++dist)->set != SET_GROUP_END || nested--) {
85150dbef1aSdholland 			if (dist->set == SET_GROUP) {
85250dbef1aSdholland 				nested++;
85350dbef1aSdholland 				continue;
85450dbef1aSdholland 			}
85550dbef1aSdholland 			if (!(set_status[dist->set] & SET_VALID))
85650dbef1aSdholland 				continue;
85750dbef1aSdholland 			if (set_status[dist->set] & SET_SELECTED) {
85850dbef1aSdholland 				if (selected == msg_none) {
85950dbef1aSdholland 					selected = msg_some;
86050dbef1aSdholland 					break;
86150dbef1aSdholland 				}
86250dbef1aSdholland 				selected = msg_all;
86350dbef1aSdholland 			} else {
86450dbef1aSdholland 				if (selected == msg_all) {
86550dbef1aSdholland 					selected = msg_some;
86650dbef1aSdholland 					break;
86750dbef1aSdholland 				}
86850dbef1aSdholland 				selected = msg_none;
86950dbef1aSdholland 			}
87050dbef1aSdholland 		}
87150dbef1aSdholland 	}
87250dbef1aSdholland 
873*050294faShannken 	wprintw(menu->mw, "%-40s %s", msg_string(desc), selected);
87450dbef1aSdholland }
87550dbef1aSdholland 
87650dbef1aSdholland static int set_sublist(menudesc *menu, void *arg);
87750dbef1aSdholland 
87850dbef1aSdholland static int
initialise_set_menu(distinfo * dist,menu_ent * me,distinfo ** de,int all_none)87950dbef1aSdholland initialise_set_menu(distinfo *dist, menu_ent *me, distinfo **de, int all_none)
88050dbef1aSdholland {
88150dbef1aSdholland 	int set;
88250dbef1aSdholland 	int sets;
88350dbef1aSdholland 	int nested;
88450dbef1aSdholland 
88550dbef1aSdholland 	for (sets = 0; ; dist++) {
88650dbef1aSdholland 		set = dist->set;
88750dbef1aSdholland 		if (set == SET_LAST || set == SET_GROUP_END)
88850dbef1aSdholland 			break;
88950dbef1aSdholland 		if (!(set_status[set] & SET_VALID))
89050dbef1aSdholland 			continue;
89150dbef1aSdholland 		*de = dist;
892ce713491Schristos 		memset(me, 0, sizeof(*me));
89350dbef1aSdholland 		if (set != SET_GROUP)
89450dbef1aSdholland 			me->opt_action = set_toggle;
89550dbef1aSdholland 		else {
89650dbef1aSdholland 			/* Collapse sublist */
89750dbef1aSdholland 			nested = 0;
89850dbef1aSdholland 			while ((++dist)->set != SET_GROUP_END || nested--) {
89950dbef1aSdholland 				if (dist->set == SET_GROUP)
90050dbef1aSdholland 					nested++;
90150dbef1aSdholland 			}
90250dbef1aSdholland 			me->opt_action = set_sublist;
90350dbef1aSdholland 		}
90450dbef1aSdholland 		sets++;
90550dbef1aSdholland 		de++;
90650dbef1aSdholland 		me++;
90750dbef1aSdholland 	}
90850dbef1aSdholland 
90950dbef1aSdholland 	if (all_none) {
91050dbef1aSdholland 		me->opt_name = MSG_select_all;
91150dbef1aSdholland 		me->opt_action = set_all;
91250dbef1aSdholland 		me++;
91350dbef1aSdholland 		me->opt_name = MSG_select_none;
91450dbef1aSdholland 		me->opt_action = set_none;
91550dbef1aSdholland 		sets += 2;
91650dbef1aSdholland 	}
91750dbef1aSdholland 
91850dbef1aSdholland 	return sets;
91950dbef1aSdholland }
92050dbef1aSdholland 
92150dbef1aSdholland static int
set_sublist(menudesc * menu,void * arg)92250dbef1aSdholland set_sublist(menudesc *menu, void *arg)
92350dbef1aSdholland {
92450dbef1aSdholland 	distinfo *de[SET_LAST];
92550dbef1aSdholland 	menu_ent me[SET_LAST];
92650dbef1aSdholland 	distinfo **dist = arg;
92750dbef1aSdholland 	int menu_no;
92850dbef1aSdholland 	int sets;
92950dbef1aSdholland 
930ce713491Schristos 	memset(me, 0, sizeof(me));
93150dbef1aSdholland 	sets = initialise_set_menu(dist[menu->cursel] + 1, me, de, 1);
93250dbef1aSdholland 
93350dbef1aSdholland 	menu_no = new_menu(NULL, me, sets, 20, 10, 0, select_menu_width,
93450dbef1aSdholland 		MC_SUBMENU | MC_SCROLL | MC_DFLTEXIT,
93550dbef1aSdholland 		NULL, set_label, NULL, NULL,
93650dbef1aSdholland 		MSG_install_selected_sets);
93750dbef1aSdholland 
93850dbef1aSdholland 	process_menu(menu_no, de);
93950dbef1aSdholland 	free_menu(menu_no);
94050dbef1aSdholland 
94150dbef1aSdholland 	return 0;
94250dbef1aSdholland }
94350dbef1aSdholland 
94450dbef1aSdholland void
customise_sets(void)94550dbef1aSdholland customise_sets(void)
94650dbef1aSdholland {
94750dbef1aSdholland 	distinfo *de[SET_LAST];
94850dbef1aSdholland 	menu_ent me[SET_LAST];
94950dbef1aSdholland 	int sets;
95050dbef1aSdholland 	int menu_no;
95150dbef1aSdholland 
95250dbef1aSdholland 	msg_display(MSG_cur_distsets);
95350dbef1aSdholland 	msg_table_add(MSG_cur_distsets_header);
95450dbef1aSdholland 
955ce713491Schristos 	memset(me, 0, sizeof(me));
95650dbef1aSdholland 	sets = initialise_set_menu(dist_list, me, de, 0);
95750dbef1aSdholland 
95850dbef1aSdholland 	menu_no = new_menu(NULL, me, sets, 0, 5, 0, select_menu_width,
95950dbef1aSdholland 		MC_SCROLL | MC_NOBOX | MC_DFLTEXIT | MC_NOCLEAR,
96050dbef1aSdholland 		NULL, set_label, NULL, NULL,
96150dbef1aSdholland 		MSG_install_selected_sets);
96250dbef1aSdholland 
96350dbef1aSdholland 	process_menu(menu_no, de);
96450dbef1aSdholland 	free_menu(menu_no);
96550dbef1aSdholland }
96650dbef1aSdholland 
96750dbef1aSdholland /*
96850dbef1aSdholland  * Extract_file **REQUIRES** an absolute path in ext_dir.  Any code
96950dbef1aSdholland  * that sets up xfer_dir for use by extract_file needs to put in the
97050dbef1aSdholland  * full path name to the directory.
97150dbef1aSdholland  */
97250dbef1aSdholland 
97350dbef1aSdholland int
extract_file(distinfo * dist,int update)97450dbef1aSdholland extract_file(distinfo *dist, int update)
97550dbef1aSdholland {
976249ed7a6Smartin 	const char *dest_dir = NULL;
977249ed7a6Smartin 
978249ed7a6Smartin 	if (update && (dist->set == SET_ETC || dist->set == SET_X11_ETC)) {
979249ed7a6Smartin 		dest_dir = "/.sysinst";
980249ed7a6Smartin 		make_target_dir(dest_dir);
981249ed7a6Smartin 	} else if (dist->set == SET_PKGSRC)
982249ed7a6Smartin 		dest_dir = "/usr";
983249ed7a6Smartin 	else
984249ed7a6Smartin 		dest_dir = "/";
985249ed7a6Smartin 
986249ed7a6Smartin 	return extract_file_to(dist, update, dest_dir, NULL, true);
987249ed7a6Smartin }
988249ed7a6Smartin 
989249ed7a6Smartin int
extract_file_to(distinfo * dist,int update,const char * dest_dir,const char * extr_pattern,bool do_stats)990249ed7a6Smartin extract_file_to(distinfo *dist, int update, const char *dest_dir,
991249ed7a6Smartin     const char *extr_pattern, bool do_stats)
992249ed7a6Smartin {
99350dbef1aSdholland 	char path[STRSIZE];
99450dbef1aSdholland 	char *owd;
99550dbef1aSdholland 	int   rval;
99650dbef1aSdholland 
99750dbef1aSdholland 	/* If we might need to tidy up, ensure directory exists */
99850dbef1aSdholland 	if (fetch_fn != NULL)
99950dbef1aSdholland 		make_target_dir(xfer_dir);
100050dbef1aSdholland 
100150dbef1aSdholland 	(void)snprintf(path, sizeof path, "%s/%s%s",
10020ef20e92Smartin 	    ext_dir_for_set(dist->name), dist->name, set_postfix(dist->name));
100350dbef1aSdholland 
100450dbef1aSdholland 	owd = getcwd(NULL, 0);
100550dbef1aSdholland 
100650dbef1aSdholland 	/* Do we need to fetch the file now? */
100750dbef1aSdholland 	if (fetch_fn != NULL) {
100850dbef1aSdholland 		rval = fetch_fn(dist->name);
100950dbef1aSdholland 		if (rval != SET_OK)
101050dbef1aSdholland 			return rval;
101150dbef1aSdholland 	}
101250dbef1aSdholland 
101350dbef1aSdholland 	/* check tarfile exists */
101450dbef1aSdholland 	if (!file_exists_p(path)) {
101550dbef1aSdholland 
101650dbef1aSdholland #ifdef SUPPORT_8_3_SOURCE_FILESYSTEM
101750dbef1aSdholland 		/*
101850dbef1aSdholland 		 * Update path to use dist->name truncated to the first eight
101950dbef1aSdholland 		 * characters and check again
102050dbef1aSdholland 		 */
10211b565566Smartin 		(void)snprintf(path, sizeof path,
10221b565566Smartin 		    "%s/%.8s%.4s", /* 4 as includes '.' */
10231b565566Smartin 		    ext_dir_for_set(dist->name), dist->name,
10241b565566Smartin 		    set_postfix(dist->name));
10251b565566Smartin 
102650dbef1aSdholland 		if (!file_exists_p(path)) {
102750dbef1aSdholland #endif /* SUPPORT_8_3_SOURCE_FILESYSTEM */
1028249ed7a6Smartin 			if (do_stats)
102950dbef1aSdholland 				tarstats.nnotfound++;
103050dbef1aSdholland 
10311b565566Smartin 			char *err = str_arg_subst(msg_string(MSG_notarfile),
10321b565566Smartin 			    1, &dist->name);
10331b565566Smartin 			hit_enter_to_continue(err, NULL);
10341b565566Smartin 			free(err);
103531a289cdSmartin 			free(owd);
103650dbef1aSdholland 			return SET_RETRY;
103750dbef1aSdholland 		}
103850dbef1aSdholland #ifdef SUPPORT_8_3_SOURCE_FILESYSTEM
103950dbef1aSdholland 	}
104050dbef1aSdholland #endif /* SUPPORT_8_3_SOURCE_FILESYSTEM */
104150dbef1aSdholland 
1042249ed7a6Smartin 	if (do_stats)
104350dbef1aSdholland 		tarstats.nfound++;
104450dbef1aSdholland 	/* cd to the target root. */
1045249ed7a6Smartin 	target_chdir_or_die(dest_dir);
104650dbef1aSdholland 
104750dbef1aSdholland 	/*
104850dbef1aSdholland 	 * /usr/X11R7/lib/X11/xkb/symbols/pc was a directory in 5.0
104950dbef1aSdholland 	 * but is a file in 5.1 and beyond, so on upgrades we need to
105050dbef1aSdholland 	 * delete it before extracting the xbase set.
105150dbef1aSdholland 	 */
105250dbef1aSdholland 	if (update && dist->set == SET_X11_BASE)
105350dbef1aSdholland 		run_program(0, "rm -rf usr/X11R7/lib/X11/xkb/symbols/pc");
105450dbef1aSdholland 
105550dbef1aSdholland 	/* now extract set files into "./". */
1056249ed7a6Smartin 	if (extr_pattern != NULL) {
1057249ed7a6Smartin 		rval = run_program(RUN_DISPLAY | RUN_PROGRESS,
1058249ed7a6Smartin 				"progress -zf %s tar --chroot "
1059249ed7a6Smartin 				TAR_EXTRACT_FLAGS " - '%s'",
1060249ed7a6Smartin 				path, extr_pattern);
1061249ed7a6Smartin 	} else {
106250dbef1aSdholland 		rval = run_program(RUN_DISPLAY | RUN_PROGRESS,
1063b76c9f8fSmartin 				"progress -zf %s tar --chroot "
1064b76c9f8fSmartin 				TAR_EXTRACT_FLAGS " -", path);
1065249ed7a6Smartin 	}
106650dbef1aSdholland 
106750dbef1aSdholland 	chdir(owd);
106850dbef1aSdholland 	free(owd);
106950dbef1aSdholland 
107050dbef1aSdholland 	/* Check rval for errors and give warning. */
107150dbef1aSdholland 	if (rval != 0) {
1072249ed7a6Smartin 		if (do_stats)
107350dbef1aSdholland 			tarstats.nerror++;
107424ecf24eSchristos 		msg_fmt_display(MSG_tarerror, "%s", path);
10754103857bSmartin 		hit_enter_to_continue(NULL, NULL);
107650dbef1aSdholland 		return SET_RETRY;
107750dbef1aSdholland 	}
107850dbef1aSdholland 
107950dbef1aSdholland 	if (fetch_fn != NULL && clean_xfer_dir) {
108050dbef1aSdholland 		run_program(0, "rm %s", path);
108150dbef1aSdholland 		/* Plausibly we should unlink an empty xfer_dir as well */
108250dbef1aSdholland 	}
108350dbef1aSdholland 
108450dbef1aSdholland 	set_status[dist->set] |= SET_INSTALLED;
1085249ed7a6Smartin 	if (do_stats)
108650dbef1aSdholland 		tarstats.nsuccess++;
108750dbef1aSdholland 	return SET_OK;
108850dbef1aSdholland }
108950dbef1aSdholland 
109050dbef1aSdholland static void
skip_set(distinfo * dist,int skip_type)109150dbef1aSdholland skip_set(distinfo *dist, int skip_type)
109250dbef1aSdholland {
109350dbef1aSdholland 	int nested;
109450dbef1aSdholland 	int set;
109550dbef1aSdholland 
109650dbef1aSdholland 	nested = 0;
109750dbef1aSdholland 	while ((++dist)->set != SET_GROUP_END || nested--) {
109850dbef1aSdholland 		set = dist->set;
109950dbef1aSdholland 		if (set == SET_GROUP) {
110050dbef1aSdholland 			nested++;
110150dbef1aSdholland 			continue;
110250dbef1aSdholland 		}
110350dbef1aSdholland 		if (set == SET_LAST)
110450dbef1aSdholland 			break;
110550dbef1aSdholland 		if (set_status[set] == (SET_SELECTED | SET_VALID))
110650dbef1aSdholland 			set_status[set] |= SET_SKIPPED;
110750dbef1aSdholland 		tarstats.nskipped++;
110850dbef1aSdholland 	}
110950dbef1aSdholland }
111050dbef1aSdholland 
1111249ed7a6Smartin distinfo*
get_set_distinfo(int opt)1112249ed7a6Smartin get_set_distinfo(int opt)
1113249ed7a6Smartin {
1114249ed7a6Smartin 	distinfo *dist;
1115249ed7a6Smartin 	int set;
1116249ed7a6Smartin 
1117249ed7a6Smartin 	for (dist = dist_list; (set = dist->set) != SET_LAST; dist++) {
1118249ed7a6Smartin 		if (set != opt)
1119249ed7a6Smartin 			continue;
1120249ed7a6Smartin 		if (dist->name == NULL)
1121249ed7a6Smartin 			continue;
1122249ed7a6Smartin 		if ((set_status[set] & (SET_VALID | SET_SELECTED))
1123249ed7a6Smartin 		    != (SET_VALID | SET_SELECTED))
1124249ed7a6Smartin 			continue;
1125249ed7a6Smartin 		return dist;
1126249ed7a6Smartin 	}
1127249ed7a6Smartin 
1128249ed7a6Smartin 	return NULL;
1129249ed7a6Smartin }
1130249ed7a6Smartin 
1131043e812bSmartin #ifdef CHECK_ENTROPY
1132043e812bSmartin 
1133043e812bSmartin char entropy_file[PATH_MAX];
1134043e812bSmartin 
1135043e812bSmartin /*
1136043e812bSmartin  * Are we short of entropy?
1137043e812bSmartin  */
113803af0822Smartin size_t
entropy_needed(void)1139043e812bSmartin entropy_needed(void)
1140043e812bSmartin {
1141043e812bSmartin 	int needed;
1142043e812bSmartin 	size_t len;
1143043e812bSmartin 
1144043e812bSmartin 	len = sizeof(needed);
1145043e812bSmartin 	if (sysctlbyname("kern.entropy.needed", &needed, &len, NULL, 0))
1146043e812bSmartin 		return 0;
1147043e812bSmartin 
1148043e812bSmartin 	if (needed < 0)
1149043e812bSmartin 		return 0;
1150043e812bSmartin 
1151043e812bSmartin 	return needed;
1152043e812bSmartin }
1153043e812bSmartin 
1154043e812bSmartin static void
entropy_write_to_kernel(const uint8_t * data,size_t len)1155043e812bSmartin entropy_write_to_kernel(const uint8_t *data, size_t len)
1156043e812bSmartin {
1157043e812bSmartin 	int fd;
1158043e812bSmartin 
1159043e812bSmartin 	fd = open(_PATH_RANDOM, O_RDWR, 0);
1160043e812bSmartin 	if (fd >= 0) {
1161043e812bSmartin 		write(fd, data, len);
1162043e812bSmartin 		close(fd);
1163043e812bSmartin 	}
1164043e812bSmartin }
1165043e812bSmartin 
1166043e812bSmartin static void
entropy_add_manual(void)1167043e812bSmartin entropy_add_manual(void)
1168043e812bSmartin {
1169043e812bSmartin 	SHA256_CTX ctx;
117003af0822Smartin 	char buf[256];
1171043e812bSmartin 	uint8_t digest[SHA256_DIGEST_LENGTH];
11721e0c64adSmartin 	static const char prompt[] = "> ";
117303af0822Smartin 	size_t l;
117418183f70Smartin 	int txt_y;
1175043e812bSmartin 
1176043e812bSmartin 	msg_display(MSG_entropy_enter_manual1);
1177043e812bSmartin 	msg_printf("\n\n");
1178043e812bSmartin 	msg_display_add(MSG_entropy_enter_manual2);
117918183f70Smartin 	msg_printf("\n\n   dd if=/dev/random bs=32 count=1 | openssl base64\n\n");
1180043e812bSmartin 	msg_display_add(MSG_entropy_enter_manual3);
1181043e812bSmartin 	msg_printf("\n\n");
1182043e812bSmartin 	SHA256_Init(&ctx);
118318183f70Smartin 	txt_y = getcury(mainwin)+1;
118403af0822Smartin 
118503af0822Smartin 	echo();
118603af0822Smartin 	wmove(mainwin, txt_y, 0);
11871e0c64adSmartin 	msg_fmt_table_add(prompt, prompt);
118803af0822Smartin 	mvwgetnstr(mainwin, txt_y, 2, buf, sizeof buf);
1189043e812bSmartin 	l = strlen(buf);
1190043e812bSmartin 	if (l > 0)
1191043e812bSmartin 		SHA256_Update(&ctx, (const uint8_t*)buf, l);
119203af0822Smartin 	noecho();
1193043e812bSmartin 	SHA256_Final(digest, &ctx);
1194043e812bSmartin 
119518183f70Smartin 	wmove(mainwin, txt_y-1, 0);
119603af0822Smartin 	wclrtobot(mainwin);
119703af0822Smartin 	wrefresh(mainwin);
119803af0822Smartin 
1199043e812bSmartin 	entropy_write_to_kernel(digest, sizeof digest);
1200043e812bSmartin }
1201043e812bSmartin 
1202043e812bSmartin /*
1203d56a0f03Sgson  * Get a file by some means and return a (potentially only
1204043e812bSmartin  * temporary valid) path to the local copy.
1205043e812bSmartin  * If mountpt is nonempty, the caller should unmount that
1206043e812bSmartin  * directory after processing the file.
1207043e812bSmartin  * Return success if the file is available, or failure if
1208d56a0f03Sgson  * the user cancelled the request or network transfer failed.
1209043e812bSmartin  */
1210043e812bSmartin static bool
entropy_get_file(bool use_netbsd_seed,char * path)1211043e812bSmartin entropy_get_file(bool use_netbsd_seed, char *path)
1212043e812bSmartin {
1213043e812bSmartin 	static struct ftpinfo server = { .user = "ftp" };
121478ab2ae0Smartin 	char url[STRSIZE], tmpf[PATH_MAX], mountpt[PATH_MAX];
1215043e812bSmartin 	const char *ftp_opt;
1216043e812bSmartin 	arg_rv arg;
1217043e812bSmartin 	int rv = 0;
1218043e812bSmartin 	const char *file_desc = msg_string(use_netbsd_seed ?
1219043e812bSmartin 	    MSG_entropy_seed : MSG_entropy_data);
1220043e812bSmartin 	char *dir;
1221043e812bSmartin 
1222043e812bSmartin 	path[0] = 0;
1223043e812bSmartin 	mountpt[0] = 0;
1224043e812bSmartin 
122578ab2ae0Smartin 	sprintf(tmpf, "/tmp/entr.%06x", getpid());
1226043e812bSmartin 
1227043e812bSmartin 	msg_display(use_netbsd_seed ?
1228043e812bSmartin 	    MSG_entropy_seed_hdr : MSG_entropy_data_hdr);
1229043e812bSmartin 	msg_printf("\n\n    %s\n\n",
1230043e812bSmartin 	    use_netbsd_seed ?
1231043e812bSmartin 	    "rndctl -S /tmp/entropy-file" :
1232043e812bSmartin 	    "dd if=/dev/random bs=32 count=1 of=/tmp/random.tmp");
1233043e812bSmartin 	strcpy(entropy_file, use_netbsd_seed ?
1234043e812bSmartin 	    "entropy-file" : "random.tmp");
1235043e812bSmartin 	process_menu(MENU_entropy_select_file, &rv);
1236043e812bSmartin 	switch (rv) {
1237043e812bSmartin 	case 1:
1238043e812bSmartin 	case 2:
1239043e812bSmartin #ifndef DEBUG
1240043e812bSmartin 		if (!network_up)
1241a4e88c60Smartin 			config_network(0);
1242043e812bSmartin #endif
1243043e812bSmartin 		server.xfer = rv == 1 ? XFER_HTTP : XFER_FTP;
1244043e812bSmartin 		arg.arg = &server;
1245043e812bSmartin 		arg.rv = -1;
1246043e812bSmartin 		msg_display_add_subst(MSG_entropy_via_download, 1, file_desc);
1247043e812bSmartin 		msg_printf("\n\n");
1248043e812bSmartin 		process_menu(MENU_entropy_ftpsource, &arg);
1249043e812bSmartin 		if (arg.rv == SET_RETRY)
1250043e812bSmartin 			return false;
1251043e812bSmartin 		make_url(url, &server, entropy_file);
1252043e812bSmartin 		if (server.xfer == XFER_FTP &&
1253043e812bSmartin 		    strcmp("ftp", server.user) == 0 && server.pass[0] == 0) {
1254043e812bSmartin 			/* do anon ftp */
1255043e812bSmartin 			ftp_opt = "-a ";
1256043e812bSmartin 		} else {
1257043e812bSmartin 			ftp_opt = "";
1258043e812bSmartin 		}
1259043e812bSmartin 		rv = run_program(RUN_DISPLAY | RUN_PROGRESS,
1260043e812bSmartin 		    "/usr/bin/ftp %s -o %s %s",
126178ab2ae0Smartin 		    ftp_opt, tmpf, url);
126278ab2ae0Smartin 		strcpy(path, tmpf);
1263043e812bSmartin 		return rv == 0;
1264043e812bSmartin 	case 3:
1265043e812bSmartin #ifndef DEBUG
1266043e812bSmartin 		if (!network_up)
1267a4e88c60Smartin 			config_network(0);
1268043e812bSmartin #endif
1269043e812bSmartin 		rv = -1;
1270043e812bSmartin 		msg_display_add_subst(MSG_entropy_via_nfs, 1, file_desc);
1271043e812bSmartin 		msg_printf("\n\n");
1272043e812bSmartin 		process_menu(MENU_entropy_nfssource, &rv);
1273043e812bSmartin 		if (rv == SET_RETRY)
1274043e812bSmartin 			return false;
1275043e812bSmartin 		if (nfs_host[0] != 0 && nfs_dir[0] != 0 &&
1276043e812bSmartin 		    entropy_file[0] != 0) {
1277043e812bSmartin 			strcpy(mountpt, "/tmp/ent-mnt.XXXXXX");
1278043e812bSmartin 			dir = mkdtemp(mountpt);
1279043e812bSmartin 			if (dir == NULL)
1280043e812bSmartin 				return false;
1281043e812bSmartin 			sprintf(path, "%s/%s", mountpt, entropy_file);
1282043e812bSmartin 			if (run_program(RUN_SILENT,
1283043e812bSmartin 			    "mount -t nfs -r %s:/%s %s",
1284043e812bSmartin 			    nfs_host, nfs_dir, mountpt) == 0) {
1285043e812bSmartin 				run_program(RUN_SILENT,
128678ab2ae0Smartin 				    "cp %s %s", path, tmpf);
1287043e812bSmartin 				run_program(RUN_SILENT,
1288043e812bSmartin 				    "umount %s", mountpt);
1289043e812bSmartin 				rmdir(mountpt);
129078ab2ae0Smartin 				strcpy(path, tmpf);
1291043e812bSmartin 			}
1292043e812bSmartin 		}
1293043e812bSmartin 		break;
1294043e812bSmartin 	case 4:
1295043e812bSmartin 		rv = -1;
1296043e812bSmartin 		/* Get device, filesystem, and filepath */
1297043e812bSmartin 		process_menu (MENU_entropy_localfs, &rv);
1298043e812bSmartin 		if (rv == SET_RETRY)
1299043e812bSmartin 			return false;
1300043e812bSmartin 		if (localfs_dev[0] != 0 && localfs_fs[0] != 0 &&
1301043e812bSmartin 		    entropy_file[0] != 0) {
1302043e812bSmartin 			strcpy(mountpt, "/tmp/ent-mnt.XXXXXX");
1303043e812bSmartin 			dir = mkdtemp(mountpt);
1304043e812bSmartin 			if (dir == NULL)
1305043e812bSmartin 				return false;
1306043e812bSmartin 			sprintf(path, "%s/%s", mountpt, entropy_file);
1307043e812bSmartin 			if (run_program(RUN_SILENT,
1308043e812bSmartin 			    "mount -t %s -r /dev/%s %s",
1309043e812bSmartin 			    localfs_fs, localfs_dev, mountpt) == 0) {
1310043e812bSmartin 				run_program(RUN_SILENT,
131178ab2ae0Smartin 				    "cp %s %s", path, tmpf);
1312043e812bSmartin 				run_program(RUN_SILENT,
1313043e812bSmartin 				    "umount %s", mountpt);
1314043e812bSmartin 				rmdir(mountpt);
131578ab2ae0Smartin 				strcpy(path, tmpf);
1316043e812bSmartin 			}
1317043e812bSmartin 		}
1318043e812bSmartin 		break;
1319043e812bSmartin 	}
1320043e812bSmartin 	return path[0] != 0;
1321043e812bSmartin }
1322043e812bSmartin 
1323043e812bSmartin static void
entropy_add_bin_file(void)1324043e812bSmartin entropy_add_bin_file(void)
1325043e812bSmartin {
1326043e812bSmartin 	char fname[PATH_MAX];
1327043e812bSmartin 
1328043e812bSmartin 	if (!entropy_get_file(false, fname))
1329043e812bSmartin 		return;
1330043e812bSmartin 	if (access(fname, R_OK) == 0)
1331043e812bSmartin 		run_program(RUN_SILENT, "dd if=%s of=" _PATH_RANDOM,
1332043e812bSmartin 		    fname);
1333043e812bSmartin }
1334043e812bSmartin 
1335043e812bSmartin static void
entropy_add_seed(void)1336043e812bSmartin entropy_add_seed(void)
1337043e812bSmartin {
1338043e812bSmartin 	char fname[PATH_MAX];
1339043e812bSmartin 
1340043e812bSmartin 	if (!entropy_get_file(true, fname))
1341043e812bSmartin 		return;
1342043e812bSmartin 	if (access(fname, R_OK) == 0)
1343043e812bSmartin 		run_program(RUN_SILENT, "rndctl -L %s", fname);
1344043e812bSmartin }
1345043e812bSmartin 
1346043e812bSmartin /*
1347043e812bSmartin  * return true if we have enough entropy
1348043e812bSmartin  */
1349043e812bSmartin bool
do_add_entropy(void)135003af0822Smartin do_add_entropy(void)
1351043e812bSmartin {
1352043e812bSmartin 	int rv;
1353043e812bSmartin 
1354043e812bSmartin 	if (entropy_needed() == 0)
1355043e812bSmartin 		return true;
1356043e812bSmartin 
13571219ba36Smartin 	for (;;) {
13581219ba36Smartin 		if (entropy_needed() == 0)
13591219ba36Smartin 			break;
13601219ba36Smartin 
1361043e812bSmartin 		msg_clear();
1362043e812bSmartin 		rv = 0;
1363043e812bSmartin 		process_menu(MENU_not_enough_entropy, &rv);
1364043e812bSmartin 		switch (rv) {
1365043e812bSmartin 		case 0:
1366043e812bSmartin 			return false;
1367043e812bSmartin 		case 1:
1368043e812bSmartin 			entropy_add_manual();
1369043e812bSmartin 			break;
1370043e812bSmartin 		case 2:
1371043e812bSmartin 			entropy_add_seed();
1372043e812bSmartin 			break;
1373043e812bSmartin 		case 3:
1374043e812bSmartin 			entropy_add_bin_file();
1375043e812bSmartin 			break;
1376043e812bSmartin 		default:
1377043e812bSmartin 			/*
1378043e812bSmartin 			 * retry after small delay to give a new USB device
1379043e812bSmartin 			 * a chance to attach and do deliver some
1380043e812bSmartin 			 * entropy
1381043e812bSmartin 			 */
1382043e812bSmartin 			msg_display(".");
1383043e812bSmartin 			for (size_t i = 0; i < 10; i++) {
1384043e812bSmartin 				if (entropy_needed() == 0)
1385043e812bSmartin 					return true;
1386043e812bSmartin 				sleep(1);
1387043e812bSmartin 				msg_display_add(".");
1388043e812bSmartin 			}
1389043e812bSmartin 		}
1390043e812bSmartin 	}
13911219ba36Smartin 
13921219ba36Smartin 	/*
13931219ba36Smartin 	 * Save entropy (maybe again) to give the seed file a good
13941219ba36Smartin 	 * entropy estimate.
13951219ba36Smartin 	 */
13961219ba36Smartin 	run_program(RUN_SILENT | RUN_CHROOT | RUN_ERROR_OK,
13971219ba36Smartin 	    "/etc/rc.d/random_seed stop");
13981219ba36Smartin 
13991219ba36Smartin 	return true;
1400043e812bSmartin }
1401043e812bSmartin #endif
1402043e812bSmartin 
1403043e812bSmartin 
1404249ed7a6Smartin 
140550dbef1aSdholland /*
140650dbef1aSdholland  * Get and unpack the distribution.
140750dbef1aSdholland  * Show success_msg if installation completes.
140850dbef1aSdholland  * Otherwise show failure_msg and wait for the user to ack it before continuing.
140950dbef1aSdholland  * success_msg and failure_msg must both be 0-adic messages.
141050dbef1aSdholland  */
141150dbef1aSdholland int
get_and_unpack_sets(int update,msg setupdone_msg,msg success_msg,msg failure_msg)141250dbef1aSdholland get_and_unpack_sets(int update, msg setupdone_msg, msg success_msg, msg failure_msg)
141350dbef1aSdholland {
141450dbef1aSdholland 	distinfo *dist;
141550dbef1aSdholland 	int status;
141653d0b64dSmartin 	int set, olderror, oldfound;
14170466f288Smartin 	bool entropy_loaded = false;
141850dbef1aSdholland 
141950dbef1aSdholland 	/* Ensure mountpoint for distribution files exists in current root. */
142050dbef1aSdholland 	(void)mkdir("/mnt2", S_IRWXU| S_IRGRP|S_IXGRP | S_IROTH|S_IXOTH);
142150dbef1aSdholland 	if (script)
142250dbef1aSdholland 		(void)fprintf(script, "mkdir -m 755 /mnt2\n");
142350dbef1aSdholland 
142450dbef1aSdholland 	/* reset failure/success counters */
142550dbef1aSdholland 	memset(&tarstats, 0, sizeof(tarstats));
142650dbef1aSdholland 
142750dbef1aSdholland 	/* Find out which files to "get" if we get files. */
142850dbef1aSdholland 
142950dbef1aSdholland 	/* Accurately count selected sets */
143050dbef1aSdholland 	for (dist = dist_list; (set = dist->set) != SET_LAST; dist++) {
1431fe2acef4Schristos 		if (dist->name == NULL)
1432fe2acef4Schristos 			continue;
1433249ed7a6Smartin 		if (set_status[set] & SET_NO_EXTRACT)
1434249ed7a6Smartin 			continue;
143550dbef1aSdholland 		if ((set_status[set] & (SET_VALID | SET_SELECTED))
143650dbef1aSdholland 		    == (SET_VALID | SET_SELECTED))
143750dbef1aSdholland 			tarstats.nselected++;
143850dbef1aSdholland 	}
143950dbef1aSdholland 
144050dbef1aSdholland 	status = SET_RETRY;
1441fe2acef4Schristos 	for (dist = dist_list; (set = dist->set) != SET_LAST; dist++) {
144250dbef1aSdholland 		if (dist->name == NULL)
144350dbef1aSdholland 			continue;
144450dbef1aSdholland 		if (set_status[set] != (SET_VALID | SET_SELECTED))
144550dbef1aSdholland 			continue;
144650dbef1aSdholland 
144753d0b64dSmartin 		/* save stats, in case we will retry */
144853d0b64dSmartin 		oldfound = tarstats.nfound;
144953d0b64dSmartin 		olderror = tarstats.nerror;
145053d0b64dSmartin 
145150dbef1aSdholland 		if (status != SET_OK) {
145250dbef1aSdholland 			/* This might force a redraw.... */
145350dbef1aSdholland 			clearok(curscr, 1);
145450dbef1aSdholland 			touchwin(stdscr);
145550dbef1aSdholland 			wrefresh(stdscr);
145650dbef1aSdholland 			/* Sort out the location of the set files */
145750dbef1aSdholland 			do {
145850dbef1aSdholland 				umount_mnt2();
145924ecf24eSchristos 				msg_fmt_display(MSG_distmedium, "%d%d%s",
146024ecf24eSchristos 				    tarstats.nselected,
146150dbef1aSdholland 				    tarstats.nsuccess + tarstats.nskipped,
146250dbef1aSdholland 				    dist->name);
146350dbef1aSdholland 				fetch_fn = NULL;
146450dbef1aSdholland 				process_menu(MENU_distmedium, &status);
146550dbef1aSdholland 			} while (status == SET_RETRY);
146650dbef1aSdholland 
146750dbef1aSdholland 			if (status == SET_SKIP) {
146850dbef1aSdholland 				set_status[set] |= SET_SKIPPED;
146950dbef1aSdholland 				tarstats.nskipped++;
147050dbef1aSdholland 				continue;
147150dbef1aSdholland 			}
147250dbef1aSdholland 			if (status == SET_SKIP_GROUP) {
147350dbef1aSdholland 				skip_set(dist, status);
147450dbef1aSdholland 				continue;
147550dbef1aSdholland 			}
147650dbef1aSdholland 			if (status != SET_OK) {
14774103857bSmartin 				hit_enter_to_continue(failure_msg, NULL);
147850dbef1aSdholland 				return 1;
147950dbef1aSdholland 			}
148050dbef1aSdholland 		}
148150dbef1aSdholland 
1482249ed7a6Smartin 		if (set_status[set] & SET_NO_EXTRACT)
1483249ed7a6Smartin 			continue;
1484249ed7a6Smartin 
148550dbef1aSdholland 		/* Try to extract this set */
148650dbef1aSdholland 		status = extract_file(dist, update);
148753d0b64dSmartin 		if (status == SET_RETRY) {
148853d0b64dSmartin 			/* do this set again */
148950dbef1aSdholland 			dist--;
149053d0b64dSmartin 			/* and reset statistics to what we had before this
149153d0b64dSmartin 			 * set */
149253d0b64dSmartin 			tarstats.nfound = oldfound;
149353d0b64dSmartin 			tarstats.nerror = olderror;
149453d0b64dSmartin 		}
149550dbef1aSdholland 	}
149650dbef1aSdholland 
1497249ed7a6Smartin #ifdef MD_SET_EXTRACT_FINALIZE
1498249ed7a6Smartin 	MD_SET_EXTRACT_FINALIZE(update);
1499249ed7a6Smartin #endif
1500249ed7a6Smartin 
150150dbef1aSdholland 	if (tarstats.nerror == 0 && tarstats.nsuccess == tarstats.nselected) {
150250dbef1aSdholland 		msg_display(MSG_endtarok);
150350dbef1aSdholland 		/* Give user a chance to see the success message */
150450dbef1aSdholland 		sleep(1);
150550dbef1aSdholland 	} else {
150650dbef1aSdholland 		/* We encountered errors. Let the user know. */
150724ecf24eSchristos 		msg_fmt_display(MSG_endtar, "%d%d%d%d%d%d",
150850dbef1aSdholland 		    tarstats.nselected, tarstats.nnotfound, tarstats.nskipped,
150950dbef1aSdholland 		    tarstats.nfound, tarstats.nsuccess, tarstats.nerror);
15104103857bSmartin 		hit_enter_to_continue(NULL, NULL);
151150dbef1aSdholland 	}
151250dbef1aSdholland 
151350dbef1aSdholland 	/*
151450dbef1aSdholland 	 * postinstall needs to be run after extracting all sets, because
151550dbef1aSdholland 	 * otherwise /var/db/obsolete will only have current information
151650dbef1aSdholland 	 * from the base, comp, and etc sets.
151750dbef1aSdholland 	 */
151850dbef1aSdholland 	if (update && (set_status[SET_ETC] & SET_INSTALLED)) {
151950dbef1aSdholland 		int oldsendmail;
152050dbef1aSdholland 		oldsendmail = run_program(RUN_DISPLAY | RUN_CHROOT |
152150dbef1aSdholland 					  RUN_ERROR_OK | RUN_PROGRESS,
152250dbef1aSdholland 					  "/usr/sbin/postinstall -s /.sysinst -d / check mailerconf");
152350dbef1aSdholland 		if (oldsendmail == 1) {
152450dbef1aSdholland 			msg_display(MSG_oldsendmail);
1525e21052b4Smartin 			if (ask_yesno(NULL)) {
152650dbef1aSdholland 				run_program(RUN_DISPLAY | RUN_CHROOT,
152750dbef1aSdholland 					    "/usr/sbin/postinstall -s /.sysinst -d / fix mailerconf");
152850dbef1aSdholland 			}
152950dbef1aSdholland 		}
153050dbef1aSdholland 		run_program(RUN_DISPLAY | RUN_CHROOT,
153150dbef1aSdholland 			"/usr/sbin/postinstall -s /.sysinst -d / fix");
1532ea6af427Stls 
1533ea6af427Stls 		/* Don't discard the system's old entropy if any */
1534ea6af427Stls 		run_program(RUN_CHROOT | RUN_SILENT,
1535ea6af427Stls 		    "/etc/rc.d/random_seed start");
15360466f288Smartin 		entropy_loaded = true;
153750dbef1aSdholland 	}
153850dbef1aSdholland 
153950dbef1aSdholland 	/* Configure the system */
1540b3b874d0Sriastradh 	if (set_status[SET_BASE] & SET_INSTALLED) {
154150dbef1aSdholland 		run_makedev();
1542b3b874d0Sriastradh 		if (!update) {
1543b3b874d0Sriastradh 			run_program(RUN_CHROOT|RUN_DISPLAY,
1544b3b874d0Sriastradh 			    "/usr/sbin/certctl rehash");
1545b3b874d0Sriastradh 		}
1546b3b874d0Sriastradh 	}
154750dbef1aSdholland 
154803af0822Smartin 	if (!update) {
1549ea6af427Stls 		struct stat sb1, sb2;
1550ea6af427Stls 
1551722a22e4Smartin 		if (stat(target_expand("/"), &sb1) == 0
1552722a22e4Smartin 		    && stat(target_expand("/var"), &sb2) == 0
1553722a22e4Smartin 		    && sb1.st_dev != sb2.st_dev) {
1554ea6af427Stls 			add_rc_conf("random_file=/etc/entropy-file\n");
1555ea6af427Stls 			if (target_file_exists_p("/boot.cfg")) {
1556ea6af427Stls 				run_program(RUN_CHROOT|RUN_FATAL,
1557ea6af427Stls 					    "sh -c 'sed -e s./var/db/./etc/. "
1558ea6af427Stls 					    "< /boot.cfg "
1559ea6af427Stls 					    "> /tmp/boot.cfg.tmp'");
1560ea6af427Stls 				mv_within_target_or_die("/tmp/boot.cfg.tmp",
1561ea6af427Stls 							"/boot.cfg");
15622f0931afSmartin 
1563ea6af427Stls 			}
1564ea6af427Stls 		}
1565ea6af427Stls 
15662f0931afSmartin #ifdef MD_BOOT_CFG_FINALIZE
15672f0931afSmartin 		if (target_file_exists_p("/boot.cfg")) {
15682f0931afSmartin 			MD_BOOT_CFG_FINALIZE("/boot.cfg");
15692f0931afSmartin 		}
15702f0931afSmartin #endif
15712f0931afSmartin 
1572ea6af427Stls 		/* Save keyboard type */
157350dbef1aSdholland 		save_kb_encoding();
157450dbef1aSdholland 
157550dbef1aSdholland 		/* Other configuration. */
157650dbef1aSdholland 		mnt_net_config();
157750dbef1aSdholland 	}
157850dbef1aSdholland 
157950dbef1aSdholland 	/* Mounted dist dir? */
158050dbef1aSdholland 	umount_mnt2();
158150dbef1aSdholland 
1582043e812bSmartin #ifdef CHECK_ENTROPY
1583043e812bSmartin 	entropy_loaded |= entropy_needed() == 0;
1584043e812bSmartin #endif
1585043e812bSmartin 
1586ea6af427Stls 	/* Save entropy -- on some systems it's ~all we'll ever get */
15870466f288Smartin 	if (!update || entropy_loaded)
15880466f288Smartin 		run_program(RUN_SILENT | RUN_CHROOT | RUN_ERROR_OK,
1589ea6af427Stls 		    "/etc/rc.d/random_seed stop");
159050dbef1aSdholland 	/* Install/Upgrade complete ... reboot or exit to script */
15914103857bSmartin 	hit_enter_to_continue(success_msg, NULL);
159250dbef1aSdholland 	return 0;
159350dbef1aSdholland }
159450dbef1aSdholland 
159550dbef1aSdholland void
umount_mnt2(void)159650dbef1aSdholland umount_mnt2(void)
159750dbef1aSdholland {
159850dbef1aSdholland 	if (!mnt2_mounted)
159950dbef1aSdholland 		return;
160050dbef1aSdholland 	run_program(RUN_SILENT, "/sbin/umount /mnt2");
160150dbef1aSdholland 	mnt2_mounted = 0;
160250dbef1aSdholland }
160350dbef1aSdholland 
160450dbef1aSdholland 
160550dbef1aSdholland /*
160650dbef1aSdholland  * Do a quick sanity check that  the target can reboot.
160750dbef1aSdholland  * return 1 if everything OK, 0 if there is a problem.
160850dbef1aSdholland  * Uses a table of files we expect to find after a base install/upgrade.
160950dbef1aSdholland  */
161050dbef1aSdholland 
161150dbef1aSdholland /* test flag and pathname to check for after unpacking. */
161250dbef1aSdholland struct check_table { unsigned int mode; const char *path;} checks[] = {
161350dbef1aSdholland   { S_IFREG, "/netbsd" },
161450dbef1aSdholland   { S_IFDIR, "/etc" },
161550dbef1aSdholland   { S_IFREG, "/etc/fstab" },
161650dbef1aSdholland   { S_IFREG, "/sbin/init" },
161750dbef1aSdholland   { S_IFREG, "/bin/sh" },
161850dbef1aSdholland   { S_IFREG, "/etc/rc" },
161950dbef1aSdholland   { S_IFREG, "/etc/rc.subr" },
162050dbef1aSdholland   { S_IFREG, "/etc/rc.conf" },
162150dbef1aSdholland   { S_IFDIR, "/dev" },
162250dbef1aSdholland   { S_IFCHR, "/dev/console" },
162350dbef1aSdholland /* XXX check for rootdev in target /dev? */
162450dbef1aSdholland   { S_IFREG, "/sbin/fsck" },
162550dbef1aSdholland   { S_IFREG, "/sbin/fsck_ffs" },
162650dbef1aSdholland   { S_IFREG, "/sbin/mount" },
162750dbef1aSdholland   { S_IFREG, "/sbin/mount_ffs" },
162850dbef1aSdholland   { S_IFREG, "/sbin/mount_nfs" },
162950dbef1aSdholland #if defined(DEBUG) || defined(DEBUG_CHECK)
163050dbef1aSdholland   { S_IFREG, "/foo/bar" },		/* bad entry to exercise warning */
163150dbef1aSdholland #endif
163250dbef1aSdholland   { 0, 0 }
163350dbef1aSdholland 
163450dbef1aSdholland };
163550dbef1aSdholland 
163650dbef1aSdholland /*
163750dbef1aSdholland  * Check target for a single file.
163850dbef1aSdholland  */
163950dbef1aSdholland static int
check_for(unsigned int mode,const char * pathname)164050dbef1aSdholland check_for(unsigned int mode, const char *pathname)
164150dbef1aSdholland {
164250dbef1aSdholland 	int found;
164350dbef1aSdholland 
164450dbef1aSdholland 	found = (target_test(mode, pathname) == 0);
164550dbef1aSdholland 	if (found == 0)
164624ecf24eSchristos 		msg_fmt_display(MSG_rootmissing, "%s", pathname);
164750dbef1aSdholland 	return found;
164850dbef1aSdholland }
164950dbef1aSdholland 
165050dbef1aSdholland /*
165150dbef1aSdholland  * Check that all the files in check_table are present in the
165250dbef1aSdholland  * target root. Warn if not found.
165350dbef1aSdholland  */
165450dbef1aSdholland int
sanity_check(void)165550dbef1aSdholland sanity_check(void)
165650dbef1aSdholland {
165750dbef1aSdholland 	int target_ok = 1;
165850dbef1aSdholland 	struct check_table *p;
165950dbef1aSdholland 
166050dbef1aSdholland 	for (p = checks; p->path; p++) {
166150dbef1aSdholland 		target_ok = target_ok && check_for(p->mode, p->path);
166250dbef1aSdholland 	}
166350dbef1aSdholland 	if (target_ok)
166450dbef1aSdholland 		return 0;
166550dbef1aSdholland 
166650dbef1aSdholland 	/* Uh, oh. Something's missing. */
16674103857bSmartin 	hit_enter_to_continue(MSG_badroot, NULL);
166850dbef1aSdholland 	return 1;
166950dbef1aSdholland }
167050dbef1aSdholland 
167150dbef1aSdholland /*
167250dbef1aSdholland  * Some globals to pass things back from callbacks
167350dbef1aSdholland  */
167450dbef1aSdholland static char zoneinfo_dir[STRSIZE];
167550dbef1aSdholland static int zonerootlen;
167650dbef1aSdholland static char *tz_selected;	/* timezonename (relative to share/zoneinfo */
167750dbef1aSdholland const char *tz_default;		/* UTC, or whatever /etc/localtime points to */
167850dbef1aSdholland static char tz_env[STRSIZE];
167950dbef1aSdholland static int save_cursel, save_topline;
168022988562Smartin static int time_menu = -1;
168122988562Smartin 
168222988562Smartin static void
update_time_display(void)168322988562Smartin update_time_display(void)
168422988562Smartin {
168522988562Smartin 	time_t t;
168622988562Smartin 	struct tm *tm;
168722988562Smartin 	char cur_time[STRSIZE], *p;
168822988562Smartin 
168922988562Smartin 	t = time(NULL);
169022988562Smartin 	tm = localtime(&t);
169122988562Smartin 	strlcpy(cur_time, safectime(&t), sizeof cur_time);
169222988562Smartin 	p = strchr(cur_time, '\n');
169322988562Smartin 	if (p != NULL)
169422988562Smartin 		*p = 0;
169522988562Smartin 
169622988562Smartin 	msg_clear();
169722988562Smartin 	msg_fmt_table_add(MSG_choose_timezone, "%s%s%s%s",
169822988562Smartin 	    tz_default, tz_selected, cur_time, tm ? tm->tm_zone : "?");
169922988562Smartin }
170050dbef1aSdholland 
170150dbef1aSdholland /*
170250dbef1aSdholland  * Callback from timezone menu
170350dbef1aSdholland  */
170450dbef1aSdholland static int
set_tz_select(menudesc * m,void * arg)170550dbef1aSdholland set_tz_select(menudesc *m, void *arg)
170650dbef1aSdholland {
170750dbef1aSdholland 	char *new;
170850dbef1aSdholland 
170950dbef1aSdholland 	if (m && strcmp(tz_selected, m->opts[m->cursel].opt_name) != 0) {
171050dbef1aSdholland 		/* Change the displayed timezone */
171150dbef1aSdholland 		new = strdup(m->opts[m->cursel].opt_name);
171250dbef1aSdholland 		if (new == NULL)
171350dbef1aSdholland 			return 0;
171450dbef1aSdholland 		free(tz_selected);
171550dbef1aSdholland 		tz_selected = new;
171650dbef1aSdholland 		snprintf(tz_env, sizeof tz_env, "%.*s%s",
171750dbef1aSdholland 			 zonerootlen, zoneinfo_dir, tz_selected);
171850dbef1aSdholland 		setenv("TZ", tz_env, 1);
171950dbef1aSdholland 	}
172050dbef1aSdholland 	if (m)
172150dbef1aSdholland 		/* Warp curser to 'Exit' line on menu */
172250dbef1aSdholland 		m->cursel = -1;
172350dbef1aSdholland 
172422988562Smartin 	update_time_display();
172522988562Smartin 	if (time_menu >= 1) {
172622988562Smartin 		WINDOW *w = get_menudesc(time_menu)->mw;
172722988562Smartin 		if (w != NULL) {
172822988562Smartin 			touchwin(w);
172922988562Smartin 			wrefresh(w);
173022988562Smartin 		}
173122988562Smartin 	}
173250dbef1aSdholland 	return 0;
173350dbef1aSdholland }
173450dbef1aSdholland 
173550dbef1aSdholland static int
set_tz_back(menudesc * m,void * arg)173650dbef1aSdholland set_tz_back(menudesc *m, void *arg)
173750dbef1aSdholland {
173850dbef1aSdholland 
173950dbef1aSdholland 	zoneinfo_dir[zonerootlen] = 0;
174050dbef1aSdholland 	m->cursel = save_cursel;
174150dbef1aSdholland 	m->topline = save_topline;
174250dbef1aSdholland 	return 0;
174350dbef1aSdholland }
174450dbef1aSdholland 
174550dbef1aSdholland static int
set_tz_dir(menudesc * m,void * arg)174650dbef1aSdholland set_tz_dir(menudesc *m, void *arg)
174750dbef1aSdholland {
174850dbef1aSdholland 
174950dbef1aSdholland 	strlcpy(zoneinfo_dir + zonerootlen, m->opts[m->cursel].opt_name,
175050dbef1aSdholland 		sizeof zoneinfo_dir - zonerootlen);
175150dbef1aSdholland 	save_cursel = m->cursel;
175250dbef1aSdholland 	save_topline = m->topline;
175350dbef1aSdholland 	m->cursel = 0;
175450dbef1aSdholland 	m->topline = 0;
175550dbef1aSdholland 	return 0;
175650dbef1aSdholland }
175750dbef1aSdholland 
175850dbef1aSdholland /*
175950dbef1aSdholland  * Alarm-handler to update example-display
176050dbef1aSdholland  */
176150dbef1aSdholland static void
176250dbef1aSdholland /*ARGSUSED*/
timezone_sig(int sig)176350dbef1aSdholland timezone_sig(int sig)
176450dbef1aSdholland {
176550dbef1aSdholland 
176650dbef1aSdholland 	set_tz_select(NULL, NULL);
176750dbef1aSdholland 	alarm(60);
176850dbef1aSdholland }
176950dbef1aSdholland 
177050dbef1aSdholland static int
tz_sort(const void * a,const void * b)177150dbef1aSdholland tz_sort(const void *a, const void *b)
177250dbef1aSdholland {
177350dbef1aSdholland 	return strcmp(((const menu_ent *)a)->opt_name, ((const menu_ent *)b)->opt_name);
177450dbef1aSdholland }
177550dbef1aSdholland 
177650dbef1aSdholland static void
tzm_set_names(menudesc * m,void * arg)177750dbef1aSdholland tzm_set_names(menudesc *m, void *arg)
177850dbef1aSdholland {
177950dbef1aSdholland 	DIR *dir;
178050dbef1aSdholland 	struct dirent *dp;
178150dbef1aSdholland 	static int nfiles;
178250dbef1aSdholland 	static int maxfiles = 32;
178350dbef1aSdholland 	static menu_ent *tz_menu;
178450dbef1aSdholland 	static char **tz_names;
178550dbef1aSdholland 	void *p;
178650dbef1aSdholland 	int maxfname;
178750dbef1aSdholland 	char *fp;
178850dbef1aSdholland 	struct stat sb;
178950dbef1aSdholland 
179050dbef1aSdholland 	if (tz_menu == NULL)
1791ce713491Schristos 		tz_menu = calloc(maxfiles, sizeof *tz_menu);
179250dbef1aSdholland 	if (tz_names == NULL)
179350dbef1aSdholland 		tz_names = malloc(maxfiles * sizeof *tz_names);
179450dbef1aSdholland 	if (tz_menu == NULL || tz_names == NULL)
179550dbef1aSdholland 		return;	/* error - skip timezone setting */
179650dbef1aSdholland 	while (nfiles > 0)
179750dbef1aSdholland 		free(tz_names[--nfiles]);
179850dbef1aSdholland 
179950dbef1aSdholland 	dir = opendir(zoneinfo_dir);
180050dbef1aSdholland 	fp = strchr(zoneinfo_dir, 0);
180150dbef1aSdholland 	if (fp != zoneinfo_dir + zonerootlen) {
180250dbef1aSdholland 		tz_names[0] = 0;
180350dbef1aSdholland 		tz_menu[0].opt_name = msg_string(MSG_tz_back);
180450dbef1aSdholland 		tz_menu[0].opt_action = set_tz_back;
180550dbef1aSdholland 		nfiles = 1;
180650dbef1aSdholland 	}
180750dbef1aSdholland 	maxfname = zoneinfo_dir + sizeof zoneinfo_dir - fp - 1;
180850dbef1aSdholland 	if (dir != NULL) {
180950dbef1aSdholland 		while ((dp = readdir(dir)) != NULL) {
181050dbef1aSdholland 			if (dp->d_namlen > maxfname || dp->d_name[0] == '.')
181150dbef1aSdholland 				continue;
181250dbef1aSdholland 			strlcpy(fp, dp->d_name, maxfname);
181350dbef1aSdholland 			if (stat(zoneinfo_dir, &sb) == -1)
181450dbef1aSdholland 				continue;
181550dbef1aSdholland 			if (nfiles >= maxfiles) {
18169caaf9d7Smartin 				p = realloc(tz_menu,
18179caaf9d7Smartin 				    2 * maxfiles * sizeof *tz_menu);
181850dbef1aSdholland 				if (p == NULL)
181950dbef1aSdholland 					break;
182050dbef1aSdholland 				tz_menu = p;
18219caaf9d7Smartin 				memset(tz_menu + maxfiles, 0,
18229caaf9d7Smartin 				    maxfiles * sizeof *tz_menu);
18239caaf9d7Smartin 				p = realloc(tz_names,
18249caaf9d7Smartin 				    2 * maxfiles * sizeof *tz_names);
182550dbef1aSdholland 				if (p == NULL)
182650dbef1aSdholland 					break;
182750dbef1aSdholland 				tz_names = p;
18289caaf9d7Smartin 				memset(tz_names + maxfiles, 0,
18299caaf9d7Smartin 				    maxfiles * sizeof *tz_names);
183050dbef1aSdholland 				maxfiles *= 2;
183150dbef1aSdholland 			}
183250dbef1aSdholland 			if (S_ISREG(sb.st_mode))
183350dbef1aSdholland 				tz_menu[nfiles].opt_action = set_tz_select;
183450dbef1aSdholland 			else if (S_ISDIR(sb.st_mode)) {
183550dbef1aSdholland 				tz_menu[nfiles].opt_action = set_tz_dir;
183650dbef1aSdholland 				strlcat(fp, "/",
183750dbef1aSdholland 				    sizeof(zoneinfo_dir) - (fp - zoneinfo_dir));
183850dbef1aSdholland 			} else
183950dbef1aSdholland 				continue;
184050dbef1aSdholland 			tz_names[nfiles] = strdup(zoneinfo_dir + zonerootlen);
184150dbef1aSdholland 			tz_menu[nfiles].opt_name = tz_names[nfiles];
184250dbef1aSdholland 			nfiles++;
184350dbef1aSdholland 		}
184450dbef1aSdholland 		closedir(dir);
184550dbef1aSdholland 	}
184650dbef1aSdholland 	*fp = 0;
184750dbef1aSdholland 
184850dbef1aSdholland 	m->opts = tz_menu;
184950dbef1aSdholland 	m->numopts = nfiles;
185050dbef1aSdholland 	qsort(tz_menu, nfiles, sizeof *tz_menu, tz_sort);
185150dbef1aSdholland }
185250dbef1aSdholland 
185350dbef1aSdholland void
get_tz_default(void)185450dbef1aSdholland get_tz_default(void)
185550dbef1aSdholland {
185650dbef1aSdholland 	char localtime_link[STRSIZE];
185750dbef1aSdholland 	static char localtime_target[STRSIZE];
185850dbef1aSdholland 	int rc;
185950dbef1aSdholland 
186050dbef1aSdholland 	strlcpy(localtime_link, target_expand("/etc/localtime"),
186150dbef1aSdholland 	    sizeof localtime_link);
186250dbef1aSdholland 
186350dbef1aSdholland 	/* Add sanity check that /mnt/usr/share/zoneinfo contains
186450dbef1aSdholland 	 * something useful
186550dbef1aSdholland 	 */
186650dbef1aSdholland 
186750dbef1aSdholland 	rc = readlink(localtime_link, localtime_target,
186850dbef1aSdholland 		      sizeof(localtime_target) - 1);
186950dbef1aSdholland 	if (rc < 0) {
187050dbef1aSdholland 		/* error, default to UTC */
187150dbef1aSdholland 		tz_default = "UTC";
187250dbef1aSdholland 	} else {
187350dbef1aSdholland 		localtime_target[rc] = '\0';
187450dbef1aSdholland 		tz_default = strchr(strstr(localtime_target, "zoneinfo"), '/') + 1;
187550dbef1aSdholland 	}
187650dbef1aSdholland }
187750dbef1aSdholland 
187850dbef1aSdholland /*
187950dbef1aSdholland  * Choose from the files in usr/share/zoneinfo and set etc/localtime
188050dbef1aSdholland  */
188150dbef1aSdholland int
set_timezone(void)188250dbef1aSdholland set_timezone(void)
188350dbef1aSdholland {
188450dbef1aSdholland 	char localtime_link[STRSIZE];
188550dbef1aSdholland 	char localtime_target[STRSIZE];
188650dbef1aSdholland 	int menu_no;
188750dbef1aSdholland 
188850dbef1aSdholland 	strlcpy(zoneinfo_dir, target_expand("/usr/share/zoneinfo/"),
188950dbef1aSdholland 	    sizeof zoneinfo_dir - 1);
189050dbef1aSdholland 	zonerootlen = strlen(zoneinfo_dir);
189150dbef1aSdholland 
189250dbef1aSdholland 	get_tz_default();
189350dbef1aSdholland 
189450dbef1aSdholland 	tz_selected = strdup(tz_default);
189550dbef1aSdholland 	snprintf(tz_env, sizeof(tz_env), "%s%s", zoneinfo_dir, tz_selected);
189650dbef1aSdholland 	setenv("TZ", tz_env, 1);
189722988562Smartin 	update_time_display();
189850dbef1aSdholland 
189950dbef1aSdholland 	signal(SIGALRM, timezone_sig);
190050dbef1aSdholland 	alarm(60);
190150dbef1aSdholland 
190250dbef1aSdholland 	menu_no = new_menu(NULL, NULL, 14, 23, 9,
190350dbef1aSdholland 			   12, 32, MC_ALWAYS_SCROLL | MC_NOSHORTCUT,
190450dbef1aSdholland 			   tzm_set_names, NULL, NULL,
19057ca7eecaSmartin 			   "\nPlease consult the install documents.",
19067ca7eecaSmartin 			   MSG_exit_menu_generic);
1907fa635f7dSmartin 	if (menu_no >= 0) {
190822988562Smartin 		time_menu = menu_no;
190950dbef1aSdholland 		process_menu(menu_no, NULL);
191022988562Smartin 		time_menu = -1;
191150dbef1aSdholland 
191250dbef1aSdholland 		free_menu(menu_no);
1913fa635f7dSmartin 	}
191450dbef1aSdholland 
1915fa635f7dSmartin 	alarm(0);
191650dbef1aSdholland 	signal(SIGALRM, SIG_IGN);
191750dbef1aSdholland 
1918fa635f7dSmartin 	if (menu_no >= 0) {
191950dbef1aSdholland 		snprintf(localtime_target, sizeof(localtime_target),
192050dbef1aSdholland 			 "/usr/share/zoneinfo/%s", tz_selected);
192150dbef1aSdholland 		strlcpy(localtime_link, target_expand("/etc/localtime"),
192250dbef1aSdholland 		    sizeof localtime_link);
192350dbef1aSdholland 		unlink(localtime_link);
192450dbef1aSdholland 		symlink(localtime_target, localtime_link);
1925fa635f7dSmartin 	}
192650dbef1aSdholland 
192750dbef1aSdholland 	return 1;
192850dbef1aSdholland }
192950dbef1aSdholland 
193050dbef1aSdholland void
scripting_vfprintf(FILE * f,const char * fmt,va_list ap)193150dbef1aSdholland scripting_vfprintf(FILE *f, const char *fmt, va_list ap)
193250dbef1aSdholland {
19332ab231eeSmartin 	va_list ap2;
193450dbef1aSdholland 
19352ab231eeSmartin 	va_copy(ap2, ap);
193650dbef1aSdholland 	if (f)
193750dbef1aSdholland 		(void)vfprintf(f, fmt, ap);
193850dbef1aSdholland 	if (script)
19392ab231eeSmartin 		(void)vfprintf(script, fmt, ap2);
194050dbef1aSdholland }
194150dbef1aSdholland 
194250dbef1aSdholland void
scripting_fprintf(FILE * f,const char * fmt,...)194350dbef1aSdholland scripting_fprintf(FILE *f, const char *fmt, ...)
194450dbef1aSdholland {
194550dbef1aSdholland 	va_list ap;
194650dbef1aSdholland 
194750dbef1aSdholland 	va_start(ap, fmt);
194850dbef1aSdholland 	scripting_vfprintf(f, fmt, ap);
194950dbef1aSdholland 	va_end(ap);
195050dbef1aSdholland }
195150dbef1aSdholland 
195250dbef1aSdholland void
add_rc_conf(const char * fmt,...)195350dbef1aSdholland add_rc_conf(const char *fmt, ...)
195450dbef1aSdholland {
195550dbef1aSdholland 	FILE *f;
195650dbef1aSdholland 	va_list ap;
195750dbef1aSdholland 
195850dbef1aSdholland 	va_start(ap, fmt);
195950dbef1aSdholland 	f = target_fopen("/etc/rc.conf", "a");
196050dbef1aSdholland 	if (f != 0) {
196150dbef1aSdholland 		scripting_fprintf(NULL, "cat <<EOF >>%s/etc/rc.conf\n",
196250dbef1aSdholland 		    target_prefix());
196350dbef1aSdholland 		scripting_vfprintf(f, fmt, ap);
196450dbef1aSdholland 		fclose(f);
196550dbef1aSdholland 		scripting_fprintf(NULL, "EOF\n");
196650dbef1aSdholland 	}
196750dbef1aSdholland 	va_end(ap);
196850dbef1aSdholland }
196950dbef1aSdholland 
197050dbef1aSdholland int
del_rc_conf(const char * value)197150dbef1aSdholland del_rc_conf(const char *value)
197250dbef1aSdholland {
197350dbef1aSdholland 	FILE *fp, *nfp;
197450dbef1aSdholland 	char buf[4096]; /* Ridiculously high, but should be enough in any way */
197550dbef1aSdholland 	char *rcconf, *tempname = NULL, *bakname = NULL;
197650dbef1aSdholland 	char *cp;
197750dbef1aSdholland 	int done = 0;
197850dbef1aSdholland 	int fd;
197950dbef1aSdholland 	int retval = 0;
198050dbef1aSdholland 
198150dbef1aSdholland 	/* The paths might seem strange, but using /tmp would require copy instead
198250dbef1aSdholland 	 * of rename operations. */
198350dbef1aSdholland 	if (asprintf(&rcconf, "%s", target_expand("/etc/rc.conf")) < 0
198450dbef1aSdholland 			|| asprintf(&tempname, "%s", target_expand("/etc/rc.conf.tmp.XXXXXX")) < 0
198550dbef1aSdholland 			|| asprintf(&bakname, "%s", target_expand("/etc/rc.conf.bak.XXXXXX")) < 0) {
198650dbef1aSdholland 		if (rcconf)
198750dbef1aSdholland 			free(rcconf);
198850dbef1aSdholland 		if (tempname)
198950dbef1aSdholland 			free(tempname);
199024ecf24eSchristos 		msg_fmt_display(MSG_rcconf_delete_failed, "%s", value);
19914103857bSmartin 		hit_enter_to_continue(NULL, NULL);
199250dbef1aSdholland 		return -1;
199350dbef1aSdholland 	}
199450dbef1aSdholland 
199550dbef1aSdholland 	if ((fd = mkstemp(bakname)) < 0) {
199624ecf24eSchristos 		msg_fmt_display(MSG_rcconf_delete_failed, "%s", value);
19974103857bSmartin 		hit_enter_to_continue(NULL, NULL);
199850dbef1aSdholland 		return -1;
199950dbef1aSdholland 	}
200050dbef1aSdholland 	close(fd);
200150dbef1aSdholland 
200250dbef1aSdholland 	if (!(fp = fopen(rcconf, "r+")) || (fd = mkstemp(tempname)) < 0) {
200350dbef1aSdholland 		if (fp)
200450dbef1aSdholland 			fclose(fp);
200524ecf24eSchristos 		msg_fmt_display(MSG_rcconf_delete_failed, "%s", value);
20064103857bSmartin 		hit_enter_to_continue(NULL, NULL);
200750dbef1aSdholland 		return -1;
200850dbef1aSdholland 	}
200950dbef1aSdholland 
201050dbef1aSdholland 	nfp = fdopen(fd, "w");
201150dbef1aSdholland 	if (!nfp) {
201250dbef1aSdholland 		fclose(fp);
201350dbef1aSdholland 		close(fd);
201424ecf24eSchristos 		msg_fmt_display(MSG_rcconf_delete_failed, "%s", value);
20154103857bSmartin 		hit_enter_to_continue(NULL, NULL);
201650dbef1aSdholland 		return -1;
201750dbef1aSdholland 	}
201850dbef1aSdholland 
201950dbef1aSdholland 	while (fgets(buf, sizeof buf, fp) != NULL) {
202050dbef1aSdholland 
202150dbef1aSdholland 		cp = buf + strspn(buf, " \t"); /* Skip initial spaces */
202250dbef1aSdholland 		if (strncmp(cp, value, strlen(value)) == 0) {
202350dbef1aSdholland 			cp += strlen(value);
202450dbef1aSdholland 			if (*cp != '=')
202550dbef1aSdholland 				scripting_fprintf(nfp, "%s", buf);
202650dbef1aSdholland 			else
202750dbef1aSdholland 				done = 1;
202850dbef1aSdholland 		} else {
202950dbef1aSdholland 			scripting_fprintf(nfp, "%s", buf);
203050dbef1aSdholland 		}
203150dbef1aSdholland 	}
203250dbef1aSdholland 	fclose(fp);
203350dbef1aSdholland 	fclose(nfp);
203450dbef1aSdholland 
203550dbef1aSdholland 	if (done) {
203650dbef1aSdholland 		if (rename(rcconf, bakname)) {
203750dbef1aSdholland 			msg_display(MSG_rcconf_backup_failed);
2038e21052b4Smartin 			if (!ask_noyes(NULL)) {
203950dbef1aSdholland 				retval = -1;
204050dbef1aSdholland 				goto done;
204150dbef1aSdholland 			}
204250dbef1aSdholland 		}
204350dbef1aSdholland 
204450dbef1aSdholland 		if (rename(tempname, rcconf)) {
204550dbef1aSdholland 			if (rename(bakname, rcconf)) {
20464103857bSmartin 				hit_enter_to_continue(MSG_rcconf_restore_failed,
20474103857bSmartin 				    NULL);
204850dbef1aSdholland 			} else {
20494103857bSmartin 				hit_enter_to_continue(MSG_rcconf_delete_failed,
20504103857bSmartin 				    NULL);
205150dbef1aSdholland 			}
205250dbef1aSdholland 		} else {
205350dbef1aSdholland 			(void)unlink(bakname);
205450dbef1aSdholland 		}
205550dbef1aSdholland 	}
205650dbef1aSdholland 
205750dbef1aSdholland done:
205850dbef1aSdholland 	(void)unlink(tempname);
205950dbef1aSdholland 	free(rcconf);
206050dbef1aSdholland 	free(tempname);
206150dbef1aSdholland 	free(bakname);
206250dbef1aSdholland 	return retval;
206350dbef1aSdholland }
206450dbef1aSdholland 
206550dbef1aSdholland void
add_sysctl_conf(const char * fmt,...)206650dbef1aSdholland add_sysctl_conf(const char *fmt, ...)
206750dbef1aSdholland {
206850dbef1aSdholland 	FILE *f;
206950dbef1aSdholland 	va_list ap;
207050dbef1aSdholland 
207150dbef1aSdholland 	va_start(ap, fmt);
207250dbef1aSdholland 	f = target_fopen("/etc/sysctl.conf", "a");
207350dbef1aSdholland 	if (f != 0) {
207450dbef1aSdholland 		scripting_fprintf(NULL, "cat <<EOF >>%s/etc/sysctl.conf\n",
207550dbef1aSdholland 		    target_prefix());
207650dbef1aSdholland 		scripting_vfprintf(f, fmt, ap);
207750dbef1aSdholland 		fclose(f);
207850dbef1aSdholland 		scripting_fprintf(NULL, "EOF\n");
207950dbef1aSdholland 	}
208050dbef1aSdholland 	va_end(ap);
208150dbef1aSdholland }
208250dbef1aSdholland 
208350dbef1aSdholland void
enable_rc_conf(void)208450dbef1aSdholland enable_rc_conf(void)
208550dbef1aSdholland {
208650dbef1aSdholland 
208750dbef1aSdholland 	replace("/etc/rc.conf", "s/^rc_configured=NO/rc_configured=YES/");
208850dbef1aSdholland }
208950dbef1aSdholland 
209050dbef1aSdholland int
check_lfs_progs(void)209150dbef1aSdholland check_lfs_progs(void)
209250dbef1aSdholland {
209350dbef1aSdholland 
209450dbef1aSdholland #ifndef NO_LFS
20954b2364d9Smartin 	return binary_available("fsck_lfs") && binary_available("mount_lfs")
20964b2364d9Smartin 	    && binary_available("newfs_lfs");
209750dbef1aSdholland #else
209850dbef1aSdholland 	return 0;
209950dbef1aSdholland #endif
210050dbef1aSdholland }
210150dbef1aSdholland 
210250dbef1aSdholland int
set_is_source(const char * set_name)210350dbef1aSdholland set_is_source(const char *set_name) {
210450dbef1aSdholland 	int len = strlen(set_name);
210550dbef1aSdholland 	return len >= 3 && memcmp(set_name + len - 3, "src", 3) == 0;
210650dbef1aSdholland }
210750dbef1aSdholland 
210850dbef1aSdholland const char *
set_dir_for_set(const char * set_name)210950dbef1aSdholland set_dir_for_set(const char *set_name) {
211050dbef1aSdholland 	if (strcmp(set_name, "pkgsrc") == 0)
211150dbef1aSdholland 		return pkgsrc_dir;
211250dbef1aSdholland 	return set_is_source(set_name) ? set_dir_src : set_dir_bin;
211350dbef1aSdholland }
211450dbef1aSdholland 
211550dbef1aSdholland const char *
ext_dir_for_set(const char * set_name)211650dbef1aSdholland ext_dir_for_set(const char *set_name) {
211750dbef1aSdholland 	if (strcmp(set_name, "pkgsrc") == 0)
211850dbef1aSdholland 		return ext_dir_pkgsrc;
211950dbef1aSdholland 	return set_is_source(set_name) ? ext_dir_src : ext_dir_bin;
212050dbef1aSdholland }
212150dbef1aSdholland 
21224b2364d9Smartin void
do_coloring(unsigned int fg,unsigned int bg)21234b2364d9Smartin do_coloring(unsigned int fg, unsigned int bg) {
21244b2364d9Smartin 	if (bg > COLOR_WHITE)
21254b2364d9Smartin 		bg = COLOR_BLUE;
21264b2364d9Smartin 	if (fg > COLOR_WHITE)
21274b2364d9Smartin 		fg = COLOR_WHITE;
21284b2364d9Smartin 	if (fg != bg && has_colors()) {
21294b2364d9Smartin 		init_pair(1, fg, bg);
21304b2364d9Smartin 		wbkgd(stdscr, COLOR_PAIR(1));
21314b2364d9Smartin 		wbkgd(mainwin, COLOR_PAIR(1));
21324b2364d9Smartin 		wattrset(stdscr, COLOR_PAIR(1));
21334b2364d9Smartin 		wattrset(mainwin, COLOR_PAIR(1));
21344b2364d9Smartin 	}
21354b2364d9Smartin 	/* redraw screen */
21364b2364d9Smartin 	touchwin(stdscr);
21374b2364d9Smartin 	touchwin(mainwin);
21384b2364d9Smartin 	wrefresh(stdscr);
21394b2364d9Smartin 	wrefresh(mainwin);
21404b2364d9Smartin 	return;
21414b2364d9Smartin }
21424b2364d9Smartin 
21434b2364d9Smartin int
set_menu_select(menudesc * m,void * arg)21444b2364d9Smartin set_menu_select(menudesc *m, void *arg)
21454b2364d9Smartin {
21464b2364d9Smartin 	*(int *)arg = m->cursel;
21474b2364d9Smartin 	return 1;
21484b2364d9Smartin }
21494b2364d9Smartin 
21504b2364d9Smartin /*
215137a23ecfSmsaitoh  * check whether a binary is available somewhere in PATH,
21524b2364d9Smartin  * return 1 if found, 0 if not.
21534b2364d9Smartin  */
21544103857bSmartin static int
binary_available(const char * prog)21554b2364d9Smartin binary_available(const char *prog)
21564b2364d9Smartin {
2157c623d359Skamil         char *p, tmp[MAXPATHLEN], *path = getenv("PATH"), *opath;
21584b2364d9Smartin 
21594b2364d9Smartin         if (path == NULL)
21604b2364d9Smartin                 return access(prog, X_OK) == 0;
21614b2364d9Smartin         path = strdup(path);
21624b2364d9Smartin         if (path == NULL)
21634b2364d9Smartin                 return 0;
21644b2364d9Smartin 
2165c623d359Skamil 	opath = path;
2166c623d359Skamil 
21674b2364d9Smartin         while ((p = strsep(&path, ":")) != NULL) {
21684b2364d9Smartin                 if (strlcpy(tmp, p, MAXPATHLEN) >= MAXPATHLEN)
21694b2364d9Smartin                         continue;
21704b2364d9Smartin                 if (strlcat(tmp, "/", MAXPATHLEN) >= MAXPATHLEN)
21714b2364d9Smartin                         continue;
21724b2364d9Smartin                 if (strlcat(tmp, prog, MAXPATHLEN) >= MAXPATHLEN)
21734b2364d9Smartin                         continue;
21744b2364d9Smartin                 if (access(tmp, X_OK) == 0) {
2175c623d359Skamil                         free(opath);
21764b2364d9Smartin                         return 1;
21774b2364d9Smartin                 }
21784b2364d9Smartin         }
2179c623d359Skamil         free(opath);
21804b2364d9Smartin         return 0;
21814b2364d9Smartin }
21824b2364d9Smartin 
2183e47dca20Schristos const char *
safectime(time_t * t)2184e47dca20Schristos safectime(time_t *t)
2185e47dca20Schristos {
2186e47dca20Schristos 	const char *s = ctime(t);
2187e47dca20Schristos 	if (s != NULL)
2188e47dca20Schristos 		return s;
2189e47dca20Schristos 
2190e47dca20Schristos 	// Debugging.
2191e47dca20Schristos 	fprintf(stderr, "Can't convert to localtime 0x%jx (%s)\n",
2192e47dca20Schristos 	    (intmax_t)*t, strerror(errno));
2193e47dca20Schristos 	      /*123456789012345678901234*/
2194e47dca20Schristos 	return "preposterous clock time\n";
2195e47dca20Schristos }
2196e21052b4Smartin 
2197e21052b4Smartin int
ask_yesno(const char * msgtxt)21985270515fSmartin ask_yesno(const char* msgtxt)
2199e21052b4Smartin {
2200e21052b4Smartin 	arg_rv p;
2201e21052b4Smartin 
2202b77ea2f7Sjoerg 	p.arg = __UNCONST(msgtxt);
2203e21052b4Smartin 	p.rv = -1;
2204e21052b4Smartin 
2205e21052b4Smartin 	process_menu(MENU_yesno, &p);
2206e21052b4Smartin 	return p.rv;
2207e21052b4Smartin }
2208e21052b4Smartin 
2209e21052b4Smartin int
ask_noyes(const char * msgtxt)22105270515fSmartin ask_noyes(const char *msgtxt)
2211e21052b4Smartin {
2212e21052b4Smartin 	arg_rv p;
2213e21052b4Smartin 
2214b77ea2f7Sjoerg 	p.arg = __UNCONST(msgtxt);
2215e21052b4Smartin 	p.rv = -1;
2216e21052b4Smartin 
2217e21052b4Smartin 	process_menu(MENU_noyes, &p);
2218e21052b4Smartin 	return p.rv;
2219e21052b4Smartin }
22200ef20e92Smartin 
22214103857bSmartin int
ask_reedit(const struct disk_partitions * parts)22224103857bSmartin ask_reedit(const struct disk_partitions *parts)
22234103857bSmartin {
22244103857bSmartin 	const char *args[2];
22254103857bSmartin 	arg_rep_int arg;
22264103857bSmartin 
22274103857bSmartin 	args[0] = msg_string(parts->pscheme->name);
22284103857bSmartin 	args[1] = msg_string(parts->pscheme->short_name);
22294103857bSmartin 	arg.args.argv = args;
22304103857bSmartin 	arg.args.argc = 2;
22314103857bSmartin 	arg.rv = 0;
22324103857bSmartin 	process_menu(MENU_reedit, &arg);
22334103857bSmartin 
22344103857bSmartin 	return arg.rv;
22354103857bSmartin }
22364103857bSmartin 
22370ef20e92Smartin bool
use_tgz_for_set(const char * set_name)22380ef20e92Smartin use_tgz_for_set(const char *set_name)
22390ef20e92Smartin {
22400ef20e92Smartin 	const struct distinfo *dist;
22410ef20e92Smartin 
22420ef20e92Smartin 	for (dist = dist_list; dist->set != SET_LAST; dist++) {
22430ef20e92Smartin 		if (dist->name == NULL)
22440ef20e92Smartin 			continue;
22450ef20e92Smartin 		if (strcmp(set_name, dist->name) == 0)
22460ef20e92Smartin 			return dist->force_tgz;
22470ef20e92Smartin 	}
22480ef20e92Smartin 
2249b57ba1ecSmartin 	return true;
22500ef20e92Smartin }
22510ef20e92Smartin 
22520ef20e92Smartin /* Return the postfix used for a given set */
2253b57ba1ecSmartin const char *
set_postfix(const char * set_name)2254b57ba1ecSmartin set_postfix(const char *set_name)
22550ef20e92Smartin {
22560ef20e92Smartin 	return use_tgz_for_set(set_name) ? dist_tgz_postfix : dist_postfix;
22570ef20e92Smartin }
22580ef20e92Smartin 
2259ac730b51Smartin /*
2260b978e7a9Smartin  * Replace positional arguments (encoded as $0 .. $N) in the string
2261b978e7a9Smartin  * passed by the contents of the passed argument array.
2262b978e7a9Smartin  * Caller must free() the result string.
2263ac730b51Smartin  */
2264b978e7a9Smartin char*
str_arg_subst(const char * src,size_t argc,const char ** argv)2265b978e7a9Smartin str_arg_subst(const char *src, size_t argc, const char **argv)
2266ac730b51Smartin {
2267b978e7a9Smartin 	const char *p, *last;
2268ac730b51Smartin 	char *out, *t;
2269ac730b51Smartin 	size_t len;
2270ac730b51Smartin 
2271ac730b51Smartin 	len = strlen(src);
2272ac730b51Smartin 	for (p = strchr(src, '$'); p; p = strchr(p+1, '$')) {
2273ac730b51Smartin 		char *endp = NULL;
2274ac730b51Smartin 		size_t n;
2275ac730b51Smartin 		int e;
2276ac730b51Smartin 
2277ac730b51Smartin 		/* $ followed by a correct numeric position? */
2278ac730b51Smartin 		n = strtou(p+1, &endp, 10, 0, INT_MAX, &e);
2279ac730b51Smartin 		if ((e == 0 || e == ENOTSUP) && n < argc) {
2280b978e7a9Smartin 			len += strlen(argv[n]);
2281ac730b51Smartin 			len -= endp-p;
2282ac730b51Smartin 			p = endp-1;
2283ac730b51Smartin 		}
2284ac730b51Smartin 	}
2285ac730b51Smartin 
2286ac730b51Smartin 	out = malloc(len+1);
2287b978e7a9Smartin 	if (out == NULL)
2288b978e7a9Smartin 		return NULL;
2289ac730b51Smartin 
2290ac730b51Smartin 	t = out;
2291ac730b51Smartin 	for (last = src, p = strchr(src, '$'); p; p = strchr(p+1, '$')) {
2292ac730b51Smartin 		char *endp = NULL;
2293ac730b51Smartin 		size_t n;
2294ac730b51Smartin 		int e;
2295ac730b51Smartin 
2296ac730b51Smartin 		/* $ followed by a correct numeric position? */
2297ac730b51Smartin 		n = strtou(p+1, &endp, 10, 0, INT_MAX, &e);
2298ac730b51Smartin 		if ((e == 0 || e == ENOTSUP) && n < argc) {
2299ac730b51Smartin 			size_t l = p-last;
2300ac730b51Smartin 			memcpy(t, last, l);
2301ac730b51Smartin 			t += l;
2302b978e7a9Smartin 			strcpy(t, argv[n]);
2303b978e7a9Smartin 			t += strlen(argv[n]);
2304ac730b51Smartin 			last = endp;
2305ac730b51Smartin 		}
2306ac730b51Smartin 	}
2307ac730b51Smartin 	if (*last) {
2308ac730b51Smartin 		strcpy(t, last);
2309ac730b51Smartin 		t += strlen(last);
2310ac730b51Smartin 	} else {
2311ac730b51Smartin 		*t = 0;
2312ac730b51Smartin 	}
2313ac730b51Smartin 	assert((size_t)(t-out) == len);
2314ac730b51Smartin 
2315b978e7a9Smartin 	return out;
2316b978e7a9Smartin }
2317ac730b51Smartin 
2318b978e7a9Smartin /*
23194103857bSmartin  * Does this string have any positional args that need expanding?
2320b978e7a9Smartin  */
23214103857bSmartin bool
needs_expanding(const char * src,size_t argc)23224103857bSmartin needs_expanding(const char *src, size_t argc)
2323b978e7a9Smartin {
23244103857bSmartin 	const char *p;
23254103857bSmartin 
23264103857bSmartin 	for (p = strchr(src, '$'); p; p = strchr(p+1, '$')) {
23274103857bSmartin 		char *endp = NULL;
23284103857bSmartin 		size_t n;
23294103857bSmartin 		int e;
23304103857bSmartin 
23314103857bSmartin 		/* $ followed by a correct numeric position? */
23324103857bSmartin 		n = strtou(p+1, &endp, 10, 0, INT_MAX, &e);
23334103857bSmartin 		if ((e == 0 || e == ENOTSUP) && n < argc)
23344103857bSmartin 			return true;
23354103857bSmartin 	}
23364103857bSmartin 	return false;
23374103857bSmartin }
23384103857bSmartin 
23394103857bSmartin /*
23404103857bSmartin  * Replace positional arguments (encoded as $0 .. $N) in the
23414103857bSmartin  * message by the strings passed as ... and call outfunc
23424103857bSmartin  * with the result.
23434103857bSmartin  */
23444103857bSmartin static void
msg_display_subst_internal(void (* outfunc)(msg),const char * master,size_t argc,va_list ap)234524ecf24eSchristos msg_display_subst_internal(void (*outfunc)(msg),
234624ecf24eSchristos     const char *master, size_t argc, va_list ap)
23474103857bSmartin {
2348b978e7a9Smartin 	const char **args, **arg;
2349b978e7a9Smartin 	char *out;
2350b978e7a9Smartin 
235124ecf24eSchristos 	args = calloc(argc, sizeof(*args));
2352b978e7a9Smartin 	if (args == NULL)
2353b978e7a9Smartin 		return;
2354b978e7a9Smartin 
2355b978e7a9Smartin 	arg = args;
2356b978e7a9Smartin 	for (size_t i = 0; i < argc; i++)
2357b978e7a9Smartin 		*arg++ = va_arg(ap, const char*);
2358b978e7a9Smartin 
2359b978e7a9Smartin 	out = str_arg_subst(msg_string(master), argc, args);
2360b978e7a9Smartin 	if (out != NULL) {
23614103857bSmartin 		outfunc(out);
2362ac730b51Smartin 		free(out);
2363b978e7a9Smartin 	}
2364ac730b51Smartin 	free(args);
2365ac730b51Smartin }
2366ac730b51Smartin 
23674103857bSmartin /*
23684103857bSmartin  * Replace positional arguments (encoded as $0 .. $N) in the
23694103857bSmartin  * message by the strings passed as ...
23704103857bSmartin  */
23714103857bSmartin void
msg_display_subst(const char * master,size_t argc,...)23724103857bSmartin msg_display_subst(const char *master, size_t argc, ...)
23734103857bSmartin {
23744103857bSmartin 	va_list ap;
23754103857bSmartin 
23764103857bSmartin 	va_start(ap, argc);
23774103857bSmartin 	msg_display_subst_internal(msg_display, master, argc, ap);
23784103857bSmartin 	va_end(ap);
23794103857bSmartin }
23804103857bSmartin 
23814103857bSmartin /*
23824103857bSmartin  * Same as above, but add to message instead of starting a new one
23834103857bSmartin  */
23844103857bSmartin void
msg_display_add_subst(const char * master,size_t argc,...)23854103857bSmartin msg_display_add_subst(const char *master, size_t argc, ...)
23864103857bSmartin {
23874103857bSmartin 	va_list ap;
23884103857bSmartin 
23894103857bSmartin 	va_start(ap, argc);
23904103857bSmartin 	msg_display_subst_internal(msg_display_add, master, argc, ap);
23914103857bSmartin 	va_end(ap);
23924103857bSmartin }
23934103857bSmartin 
23944103857bSmartin /* initialize have_* variables */
23954103857bSmartin void
check_available_binaries(void)239670b74d30Stsutsui check_available_binaries(void)
23974103857bSmartin {
23984103857bSmartin 	static int did_test = false;
23994103857bSmartin 
24004103857bSmartin 	if (did_test) return;
24014103857bSmartin 	did_test = 1;
24024103857bSmartin 
24034103857bSmartin 	have_raid = binary_available("raidctl");
24044103857bSmartin 	have_vnd = binary_available("vndconfig");
24054103857bSmartin 	have_cgd = binary_available("cgdconfig");
24064103857bSmartin 	have_lvm = binary_available("lvm");
24074103857bSmartin 	have_gpt = binary_available("gpt");
24084103857bSmartin 	have_dk = binary_available("dkctl");
24094103857bSmartin }
24104103857bSmartin 
24114103857bSmartin /*
24124103857bSmartin  * Wait for enter and immediately clear the screen after user response
24134103857bSmartin  * (in case some longer action follows, so the user has instant feedback)
24144103857bSmartin  */
24154103857bSmartin void
hit_enter_to_continue(const char * prompt,const char * title)24164103857bSmartin hit_enter_to_continue(const char *prompt, const char *title)
24174103857bSmartin {
24184103857bSmartin 	if (prompt != NULL)
24194103857bSmartin 		msg_display(prompt);
24204103857bSmartin         process_menu(MENU_ok, __UNCONST(title));
24214103857bSmartin 	msg_clear();
24224103857bSmartin 	wrefresh(mainwin);
24234103857bSmartin }
24244103857bSmartin 
24254103857bSmartin /*
24264103857bSmartin  * On auto pilot:
24274103857bSmartin  * convert an existing set of partitions ot a list of part_usage_info
24284103857bSmartin  * so that we "want" exactly what is there already.
24294103857bSmartin  */
24304103857bSmartin static bool
usage_info_list_from_parts(struct part_usage_info ** list,size_t * count,struct disk_partitions * parts)24314103857bSmartin usage_info_list_from_parts(struct part_usage_info **list, size_t *count,
24324103857bSmartin     struct disk_partitions *parts)
24334103857bSmartin {
24344103857bSmartin 	struct disk_part_info info;
24354103857bSmartin 	part_id pno;
24364103857bSmartin 	size_t no, num;
24374103857bSmartin 
24384103857bSmartin 	num = 0;
24394103857bSmartin 	for (pno = 0; pno < parts->num_part; pno++) {
24404103857bSmartin 		if (!parts->pscheme->get_part_info(parts, pno, &info))
24414103857bSmartin 			continue;
24424103857bSmartin 		num++;
24434103857bSmartin 	}
24444103857bSmartin 
24454103857bSmartin 	*list = calloc(num, sizeof(**list));
24464103857bSmartin 	if (*list == NULL)
24474103857bSmartin 		return false;
24484103857bSmartin 
24494103857bSmartin 	*count = num;
24504103857bSmartin 	for (no = pno = 0; pno < parts->num_part && no < num; pno++) {
24514103857bSmartin 		if (!parts->pscheme->get_part_info(parts, pno, &info))
24524103857bSmartin 			continue;
24534103857bSmartin 		(*list)[no].size = info.size;
24544103857bSmartin 		if (info.last_mounted != NULL && *info.last_mounted != 0) {
24554103857bSmartin 			strlcpy((*list)[no].mount, info.last_mounted,
24564103857bSmartin 			    sizeof((*list)[no].mount));
24574103857bSmartin 			(*list)[no].instflags |= PUIINST_MOUNT;
24584103857bSmartin 		}
24594103857bSmartin 		(*list)[no].parts = parts;
24604103857bSmartin 		(*list)[no].cur_part_id = pno;
24614103857bSmartin 		(*list)[no].cur_start = info.start;
24624103857bSmartin 		(*list)[no].cur_flags = info.flags;
24634103857bSmartin 		(*list)[no].type = info.nat_type->generic_ptype;
24644103857bSmartin 		if ((*list)[no].type == PT_swap) {
24654103857bSmartin 			(*list)[no].fs_type = FS_SWAP;
24664103857bSmartin 			(*list)[no].fs_version = 0;
24674103857bSmartin 		} else {
24684103857bSmartin 			(*list)[no].fs_type = info.fs_type;
24694103857bSmartin 			(*list)[no].fs_version = info.fs_sub_type;
24704103857bSmartin 		}
2471cb429b90Smartin 		(*list)[no].fs_opt1 = info.fs_opt1;
2472cb429b90Smartin 		(*list)[no].fs_opt2 = info.fs_opt2;
2473cb429b90Smartin 		(*list)[no].fs_opt3 = info.fs_opt3;
24744103857bSmartin 		no++;
24754103857bSmartin 	}
24764103857bSmartin 	return true;
24774103857bSmartin }
24784103857bSmartin 
24794103857bSmartin bool
empty_usage_set_from_parts(struct partition_usage_set * wanted,struct disk_partitions * parts)2480ec5e52a9Smartin empty_usage_set_from_parts(struct partition_usage_set *wanted,
2481ec5e52a9Smartin     struct disk_partitions *parts)
2482ec5e52a9Smartin {
2483bd887569Smartin 	usage_set_from_parts(wanted, parts);
2484ec5e52a9Smartin 	return true;
2485ec5e52a9Smartin }
2486ec5e52a9Smartin 
2487ec5e52a9Smartin bool
usage_set_from_parts(struct partition_usage_set * wanted,struct disk_partitions * parts)24884103857bSmartin usage_set_from_parts(struct partition_usage_set *wanted,
24894103857bSmartin     struct disk_partitions *parts)
24904103857bSmartin {
24914103857bSmartin 	memset(wanted, 0, sizeof(*wanted));
24924103857bSmartin 	wanted->parts = parts;
24934103857bSmartin 
24944103857bSmartin 	return usage_info_list_from_parts(&wanted->infos, &wanted->num, parts);
24954103857bSmartin }
24964103857bSmartin 
2497c38850fbSmartin bool
usage_set_from_install_desc(struct partition_usage_set * pset,const struct install_partition_desc * install,struct disk_partitions * parts)2498c38850fbSmartin usage_set_from_install_desc(struct partition_usage_set *pset,
2499c38850fbSmartin     const struct install_partition_desc *install,
2500c38850fbSmartin     struct disk_partitions *parts)
2501c38850fbSmartin {
2502c38850fbSmartin 	size_t cnt, i;
2503c38850fbSmartin 
2504c38850fbSmartin 	memset(pset, 0, sizeof(*pset));
2505c38850fbSmartin 	pset->parts = parts;
2506c38850fbSmartin 
2507c38850fbSmartin 	if (!install->infos || !install->num)
2508c38850fbSmartin 		return false;
2509c38850fbSmartin 
2510c38850fbSmartin 	for (cnt = 0, i = 0; i < install->num; i++) {
2511c38850fbSmartin 		if (install->infos[i].parts != parts)
2512c38850fbSmartin 			continue;
2513c38850fbSmartin 		cnt++;
2514c38850fbSmartin 	}
2515c38850fbSmartin 	if (!cnt)
2516c38850fbSmartin 		return false;
2517c38850fbSmartin 	pset->num = cnt;
2518c38850fbSmartin 	pset->infos = calloc(cnt, sizeof(*pset->infos));
2519c38850fbSmartin 	if (!pset->infos)
2520c38850fbSmartin 		return false;
2521c38850fbSmartin 	for (cnt = 0, i = 0; i < install->num; i++) {
2522c38850fbSmartin 		if (install->infos[i].parts != parts)
2523c38850fbSmartin 			continue;
2524c38850fbSmartin 		pset->infos[cnt] = install->infos[i];
2525c38850fbSmartin 		cnt++;
2526c38850fbSmartin 	}
2527c38850fbSmartin 	return true;
2528c38850fbSmartin }
2529c38850fbSmartin 
2530c38850fbSmartin bool
merge_usage_set_into_install_desc(struct install_partition_desc * install,const struct partition_usage_set * pset)2531c38850fbSmartin merge_usage_set_into_install_desc(struct install_partition_desc *install,
2532c38850fbSmartin     const struct partition_usage_set *pset)
2533c38850fbSmartin {
2534c38850fbSmartin 	// XXX
2535c38850fbSmartin 	return false;
2536c38850fbSmartin }
2537c38850fbSmartin 
2538f77b58b1Smartin struct disk_partitions *
get_inner_parts(struct disk_partitions * parts)2539f77b58b1Smartin get_inner_parts(struct disk_partitions *parts)
25404103857bSmartin {
2541bfaf0e51Smartin 	daddr_t start, size;
2542bfaf0e51Smartin 	part_id pno;
2543bfaf0e51Smartin 	struct disk_part_info info;
2544bfaf0e51Smartin 
2545f77b58b1Smartin 	if (parts->pscheme->secondary_scheme == NULL)
2546f77b58b1Smartin 		return NULL;
25474103857bSmartin 
2548bfaf0e51Smartin 	start = -1;
2549bfaf0e51Smartin 	size = -1;
2550f77b58b1Smartin 	if (parts->pscheme->guess_install_target == NULL ||
2551f77b58b1Smartin 	    !parts->pscheme->guess_install_target(parts, &start, &size)) {
2552bfaf0e51Smartin 		for (pno = 0; pno < parts->num_part; pno++) {
2553f77b58b1Smartin 			if (!parts->pscheme->get_part_info(parts, pno, &info))
2554bfaf0e51Smartin 				continue;
2555bfaf0e51Smartin 			if (!(info.flags & PTI_SEC_CONTAINER))
2556bfaf0e51Smartin 				continue;
2557bfaf0e51Smartin 			start = info.start;
2558bfaf0e51Smartin 			size = info.size;
2559bfaf0e51Smartin 		}
2560bfaf0e51Smartin 	}
2561f77b58b1Smartin 
2562f77b58b1Smartin 	if (size > 0)
2563f77b58b1Smartin 		return parts->pscheme->secondary_partitions(parts, start,
2564f77b58b1Smartin 		    false);
2565f77b58b1Smartin 
2566f77b58b1Smartin 	return NULL;
2567f77b58b1Smartin }
2568f77b58b1Smartin 
2569f77b58b1Smartin bool
install_desc_from_parts(struct install_partition_desc * install,struct disk_partitions * parts)2570f77b58b1Smartin install_desc_from_parts(struct install_partition_desc *install,
2571f77b58b1Smartin     struct disk_partitions *parts)
2572f77b58b1Smartin {
2573f77b58b1Smartin 	struct disk_partitions *inner_parts;
2574f77b58b1Smartin 
2575f77b58b1Smartin 	memset(install, 0, sizeof(*install));
2576f77b58b1Smartin 	inner_parts = get_inner_parts(parts);
2577bfaf0e51Smartin 	if (inner_parts != NULL)
2578bfaf0e51Smartin 		parts = inner_parts;
2579bfaf0e51Smartin 
25804103857bSmartin 	return usage_info_list_from_parts(&install->infos, &install->num,
25814103857bSmartin 	    parts);
25824103857bSmartin }
25834103857bSmartin 
25844103857bSmartin void
free_usage_set(struct partition_usage_set * wanted)25854103857bSmartin free_usage_set(struct partition_usage_set *wanted)
25864103857bSmartin {
2587f77b58b1Smartin 	/* XXX - free parts? free clone src? */
2588194d5a77Smartin 	free(wanted->write_back);
25894103857bSmartin 	free(wanted->menu_opts);
25904103857bSmartin 	free(wanted->infos);
25914103857bSmartin }
25924103857bSmartin 
25934103857bSmartin void
free_install_desc(struct install_partition_desc * install)25944103857bSmartin free_install_desc(struct install_partition_desc *install)
25954103857bSmartin {
2596f77b58b1Smartin 	size_t i, j;
2597f77b58b1Smartin 
25988bb96d39Smartin #ifndef NO_CLONES
2599f77b58b1Smartin 	for (i = 0; i < install->num; i++) {
2600f77b58b1Smartin 		struct selected_partitions *src = install->infos[i].clone_src;
2601f77b58b1Smartin 		if (!(install->infos[i].flags & PUIFLG_CLONE_PARTS) ||
2602f77b58b1Smartin 		    src == NULL)
2603f77b58b1Smartin 			continue;
2604f77b58b1Smartin 		free_selected_partitions(src);
2605f77b58b1Smartin 		for (j = i+1; j < install->num; j++)
2606f77b58b1Smartin 			if (install->infos[j].clone_src == src)
2607f77b58b1Smartin 				install->infos[j].clone_src = NULL;
2608f77b58b1Smartin 	}
2609485d5309Smartin #endif
26108bb96d39Smartin 
26118bb96d39Smartin 	for (i = 0; i < install->num; i++) {
26128bb96d39Smartin 		struct disk_partitions * parts = install->infos[i].parts;
26138bb96d39Smartin 
26148bb96d39Smartin 		if (parts == NULL)
26158bb96d39Smartin 			continue;
26168bb96d39Smartin 
26178bb96d39Smartin 		if (parts->pscheme->free)
26188bb96d39Smartin 			parts->pscheme->free(parts);
26198bb96d39Smartin 
26208bb96d39Smartin 		/* NULL all other references to this parts */
26218bb96d39Smartin 		for (j = i+1; j < install->num; j++)
26228bb96d39Smartin 			if (install->infos[j].parts == parts)
26238bb96d39Smartin 				install->infos[j].parts = NULL;
26248bb96d39Smartin 	}
26258bb96d39Smartin 
2626194d5a77Smartin 	free(install->write_back);
26274103857bSmartin 	free(install->infos);
26284103857bSmartin }
26294103857bSmartin 
2630249ed7a6Smartin #ifdef MD_MAY_SWAP_TO
2631249ed7a6Smartin bool
may_swap_if_not_sdmmc(const char * disk)2632249ed7a6Smartin may_swap_if_not_sdmmc(const char *disk)
2633249ed7a6Smartin {
2634249ed7a6Smartin 	int fd, res;
2635249ed7a6Smartin 	prop_dictionary_t command_dict, args_dict, results_dict, data_dict;
2636249ed7a6Smartin 	prop_string_t string;
2637249ed7a6Smartin 	prop_number_t number;
2638249ed7a6Smartin 	const char *parent = "";
2639249ed7a6Smartin 
2640249ed7a6Smartin 	fd = open(DRVCTLDEV, O_RDONLY, 0);
2641249ed7a6Smartin 	if (fd == -1)
2642249ed7a6Smartin 		return true;
2643249ed7a6Smartin 
2644249ed7a6Smartin 	command_dict = prop_dictionary_create();
2645249ed7a6Smartin 	args_dict = prop_dictionary_create();
2646249ed7a6Smartin 
264778ab2ae0Smartin 	string = prop_string_create_nocopy("get-properties");
2648249ed7a6Smartin 	prop_dictionary_set(command_dict, "drvctl-command", string);
2649249ed7a6Smartin 	prop_object_release(string);
2650249ed7a6Smartin 
265178ab2ae0Smartin 	string = prop_string_create_copy(disk);
2652249ed7a6Smartin 	prop_dictionary_set(args_dict, "device-name", string);
2653249ed7a6Smartin 	prop_object_release(string);
2654249ed7a6Smartin 
2655249ed7a6Smartin 	prop_dictionary_set(command_dict, "drvctl-arguments",
2656249ed7a6Smartin 	    args_dict);
2657249ed7a6Smartin 	prop_object_release(args_dict);
2658249ed7a6Smartin 
2659249ed7a6Smartin 	res = prop_dictionary_sendrecv_ioctl(command_dict, fd,
2660249ed7a6Smartin 	    DRVCTLCOMMAND, &results_dict);
2661249ed7a6Smartin 	prop_object_release(command_dict);
2662249ed7a6Smartin 	close(fd);
2663249ed7a6Smartin 	if (res)
2664249ed7a6Smartin 		return true;
2665249ed7a6Smartin 
2666249ed7a6Smartin 	number = prop_dictionary_get(results_dict, "drvctl-error");
266778ab2ae0Smartin 	if (prop_number_signed_value(number) == 0) {
2668249ed7a6Smartin 		data_dict = prop_dictionary_get(results_dict,
2669249ed7a6Smartin 		    "drvctl-result-data");
2670249ed7a6Smartin 		if (data_dict != NULL) {
2671249ed7a6Smartin 			string = prop_dictionary_get(data_dict,
2672249ed7a6Smartin 			    "device-parent");
2673249ed7a6Smartin 			if (string != NULL)
267478ab2ae0Smartin 				parent = prop_string_value(string);
2675249ed7a6Smartin 		}
2676249ed7a6Smartin 	}
2677249ed7a6Smartin 
2678249ed7a6Smartin 	prop_object_release(results_dict);
2679249ed7a6Smartin 
2680249ed7a6Smartin 	if (parent == NULL)
2681249ed7a6Smartin 		return true;
2682249ed7a6Smartin 
2683249ed7a6Smartin 	return strncmp(parent, "sdmmc", 5) != 0;
2684249ed7a6Smartin }
2685249ed7a6Smartin #endif
2686