xref: /netbsd-src/usr.sbin/sysinst/disks.c (revision d7f55bad98e40f24004308d3468abcc8e704cd5b)
1*d7f55badSmartin /*	$NetBSD: disks.c,v 1.51 2019/08/20 06:38:17 martin 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 /* disks.c -- routines to deal with finding disks and labeling disks. */
3650dbef1aSdholland 
3750dbef1aSdholland 
384103857bSmartin #include <assert.h>
3950dbef1aSdholland #include <errno.h>
407a391039Smartin #include <inttypes.h>
4150dbef1aSdholland #include <stdio.h>
4250dbef1aSdholland #include <stdlib.h>
4350dbef1aSdholland #include <unistd.h>
4450dbef1aSdholland #include <fcntl.h>
454bb5c537Smartin #include <fnmatch.h>
4650dbef1aSdholland #include <util.h>
474b2364d9Smartin #include <uuid.h>
484103857bSmartin #include <paths.h>
49a7267d53Smartin #include <fstab.h>
5050dbef1aSdholland 
5150dbef1aSdholland #include <sys/param.h>
5250dbef1aSdholland #include <sys/sysctl.h>
5350dbef1aSdholland #include <sys/swap.h>
544103857bSmartin #include <sys/disklabel_gpt.h>
5550dbef1aSdholland #include <ufs/ufs/dinode.h>
5650dbef1aSdholland #include <ufs/ffs/fs.h>
5750dbef1aSdholland 
5850dbef1aSdholland #include <dev/scsipi/scsipi_all.h>
5950dbef1aSdholland #include <sys/scsiio.h>
6050dbef1aSdholland 
6150dbef1aSdholland #include <dev/ata/atareg.h>
6250dbef1aSdholland #include <sys/ataio.h>
6350dbef1aSdholland 
6450dbef1aSdholland #include "defs.h"
6550dbef1aSdholland #include "md.h"
6650dbef1aSdholland #include "msg_defs.h"
6750dbef1aSdholland #include "menu_defs.h"
6850dbef1aSdholland #include "txtwalk.h"
6950dbef1aSdholland 
70d396d9d8Smartin /* #define DEBUG_VERBOSE	1 */
714103857bSmartin 
7250dbef1aSdholland /* Disk descriptions */
7350dbef1aSdholland struct disk_desc {
7450dbef1aSdholland 	char	dd_name[SSTRSIZE];
7537649e40Smrg 	char	dd_descr[256];
762575b4dcSmartin 	bool	dd_no_mbr, dd_no_part;
7750dbef1aSdholland 	uint	dd_cyl;
7850dbef1aSdholland 	uint	dd_head;
7950dbef1aSdholland 	uint	dd_sec;
8050dbef1aSdholland 	uint	dd_secsize;
814103857bSmartin 	daddr_t	dd_totsec;
824b2364d9Smartin };
834b2364d9Smartin 
84a7267d53Smartin #define	NAME_PREFIX	"NAME="
85a7267d53Smartin static const char name_prefix[] = NAME_PREFIX;
86a7267d53Smartin 
87a7267d53Smartin /* things we could have as /sbin/newfs_* and /sbin/fsck_* */
88a7267d53Smartin static const char *extern_fs_with_chk[] = {
89a7267d53Smartin 	"ext2fs", "lfs", "msdos", "v7fs"
90a7267d53Smartin };
91a7267d53Smartin 
92a7267d53Smartin /* things we could have as /sbin/newfs_* but not /sbin/fsck_* */
93a7267d53Smartin static const char *extern_fs_newfs_only[] = {
94a7267d53Smartin 	"sysvbfs", "udf"
95a7267d53Smartin };
966de47033Smartin 
9750dbef1aSdholland /* Local prototypes */
98a7267d53Smartin static int found_fs(struct data *, size_t, const struct lookfor*);
99a7267d53Smartin static int found_fs_nocheck(struct data *, size_t, const struct lookfor*);
1004103857bSmartin static int fsck_preen(const char *, const char *, bool silent);
1014103857bSmartin static void fixsb(const char *, const char *);
10250dbef1aSdholland 
10350dbef1aSdholland 
10450dbef1aSdholland static bool tmpfs_on_var_shm(void);
10550dbef1aSdholland 
10650dbef1aSdholland const char *
1074103857bSmartin getfslabelname(uint f, uint f_version)
10850dbef1aSdholland {
1094103857bSmartin 	if (f == FS_TMPFS)
1104103857bSmartin 		return "tmpfs";
1114103857bSmartin 	else if (f == FS_MFS)
1124103857bSmartin 		return "mfs";
1134103857bSmartin 	else if (f == FS_BSDFFS && f_version > 0)
1144103857bSmartin 		return f_version == 2 ?
1154103857bSmartin 		    msg_string(MSG_fs_type_ffsv2) : msg_string(MSG_fs_type_ffs);
1164103857bSmartin 	else if (f >= __arraycount(fstypenames) || fstypenames[f] == NULL)
11750dbef1aSdholland 		return "invalid";
11850dbef1aSdholland 	return fstypenames[f];
11950dbef1aSdholland }
12050dbef1aSdholland 
12150dbef1aSdholland /*
12250dbef1aSdholland  * Decide wether we want to mount a tmpfs on /var/shm: we do this always
12350dbef1aSdholland  * when the machine has more than 16 MB of user memory. On smaller machines,
12450dbef1aSdholland  * shm_open() and friends will not perform well anyway.
12550dbef1aSdholland  */
12650dbef1aSdholland static bool
12750dbef1aSdholland tmpfs_on_var_shm()
12850dbef1aSdholland {
12950dbef1aSdholland 	uint64_t ram;
13050dbef1aSdholland 	size_t len;
13150dbef1aSdholland 
13250dbef1aSdholland 	len = sizeof(ram);
13350dbef1aSdholland 	if (sysctlbyname("hw.usermem64", &ram, &len, NULL, 0))
13450dbef1aSdholland 		return false;
13550dbef1aSdholland 
13672cf5c53Smartin 	return ram > 16 * MEG;
13750dbef1aSdholland }
13850dbef1aSdholland 
13950dbef1aSdholland /* from src/sbin/atactl/atactl.c
14050dbef1aSdholland  * extract_string: copy a block of bytes out of ataparams and make
14150dbef1aSdholland  * a proper string out of it, truncating trailing spaces and preserving
14250dbef1aSdholland  * strict typing. And also, not doing unaligned accesses.
14350dbef1aSdholland  */
14450dbef1aSdholland static void
14550dbef1aSdholland ata_extract_string(char *buf, size_t bufmax,
14650dbef1aSdholland 		   uint8_t *bytes, unsigned numbytes,
14750dbef1aSdholland 		   int needswap)
14850dbef1aSdholland {
14950dbef1aSdholland 	unsigned i;
15050dbef1aSdholland 	size_t j;
15150dbef1aSdholland 	unsigned char ch1, ch2;
15250dbef1aSdholland 
15350dbef1aSdholland 	for (i = 0, j = 0; i < numbytes; i += 2) {
15450dbef1aSdholland 		ch1 = bytes[i];
15550dbef1aSdholland 		ch2 = bytes[i+1];
15650dbef1aSdholland 		if (needswap && j < bufmax-1) {
15750dbef1aSdholland 			buf[j++] = ch2;
15850dbef1aSdholland 		}
15950dbef1aSdholland 		if (j < bufmax-1) {
16050dbef1aSdholland 			buf[j++] = ch1;
16150dbef1aSdholland 		}
16250dbef1aSdholland 		if (!needswap && j < bufmax-1) {
16350dbef1aSdholland 			buf[j++] = ch2;
16450dbef1aSdholland 		}
16550dbef1aSdholland 	}
16650dbef1aSdholland 	while (j > 0 && buf[j-1] == ' ') {
16750dbef1aSdholland 		j--;
16850dbef1aSdholland 	}
16950dbef1aSdholland 	buf[j] = '\0';
17050dbef1aSdholland }
17150dbef1aSdholland 
17250dbef1aSdholland /*
17350dbef1aSdholland  * from src/sbin/scsictl/scsi_subr.c
17450dbef1aSdholland  */
17550dbef1aSdholland #define STRVIS_ISWHITE(x) ((x) == ' ' || (x) == '\0' || (x) == (u_char)'\377')
17650dbef1aSdholland 
17750dbef1aSdholland static void
17850dbef1aSdholland scsi_strvis(char *sdst, size_t dlen, const char *ssrc, size_t slen)
17950dbef1aSdholland {
18050dbef1aSdholland 	u_char *dst = (u_char *)sdst;
18150dbef1aSdholland 	const u_char *src = (const u_char *)ssrc;
18250dbef1aSdholland 
18350dbef1aSdholland 	/* Trim leading and trailing blanks and NULs. */
18450dbef1aSdholland 	while (slen > 0 && STRVIS_ISWHITE(src[0]))
18550dbef1aSdholland 		++src, --slen;
18650dbef1aSdholland 	while (slen > 0 && STRVIS_ISWHITE(src[slen - 1]))
18750dbef1aSdholland 		--slen;
18850dbef1aSdholland 
18950dbef1aSdholland 	while (slen > 0) {
19050dbef1aSdholland 		if (*src < 0x20 || *src >= 0x80) {
19150dbef1aSdholland 			/* non-printable characters */
19250dbef1aSdholland 			dlen -= 4;
19350dbef1aSdholland 			if (dlen < 1)
19450dbef1aSdholland 				break;
19550dbef1aSdholland 			*dst++ = '\\';
19650dbef1aSdholland 			*dst++ = ((*src & 0300) >> 6) + '0';
19750dbef1aSdholland 			*dst++ = ((*src & 0070) >> 3) + '0';
19850dbef1aSdholland 			*dst++ = ((*src & 0007) >> 0) + '0';
19950dbef1aSdholland 		} else if (*src == '\\') {
20050dbef1aSdholland 			/* quote characters */
20150dbef1aSdholland 			dlen -= 2;
20250dbef1aSdholland 			if (dlen < 1)
20350dbef1aSdholland 				break;
20450dbef1aSdholland 			*dst++ = '\\';
20550dbef1aSdholland 			*dst++ = '\\';
20650dbef1aSdholland 		} else {
20750dbef1aSdholland 			/* normal characters */
20850dbef1aSdholland 			if (--dlen < 1)
20950dbef1aSdholland 				break;
21050dbef1aSdholland 			*dst++ = *src;
21150dbef1aSdholland 		}
21250dbef1aSdholland 		++src, --slen;
21350dbef1aSdholland 	}
21450dbef1aSdholland 
21550dbef1aSdholland 	*dst++ = 0;
21650dbef1aSdholland }
21750dbef1aSdholland 
21850dbef1aSdholland 
21950dbef1aSdholland static int
22072ea5dbaSchristos get_descr_scsi(struct disk_desc *dd)
22150dbef1aSdholland {
22250dbef1aSdholland 	struct scsipi_inquiry_data inqbuf;
22350dbef1aSdholland 	struct scsipi_inquiry cmd;
22450dbef1aSdholland 	scsireq_t req;
22550dbef1aSdholland         /* x4 in case every character is escaped, +1 for NUL. */
22650dbef1aSdholland 	char vendor[(sizeof(inqbuf.vendor) * 4) + 1],
22750dbef1aSdholland 	     product[(sizeof(inqbuf.product) * 4) + 1],
22850dbef1aSdholland 	     revision[(sizeof(inqbuf.revision) * 4) + 1];
22950dbef1aSdholland 	char size[5];
23050dbef1aSdholland 
23150dbef1aSdholland 	memset(&inqbuf, 0, sizeof(inqbuf));
23250dbef1aSdholland 	memset(&cmd, 0, sizeof(cmd));
23350dbef1aSdholland 	memset(&req, 0, sizeof(req));
23450dbef1aSdholland 
23550dbef1aSdholland 	cmd.opcode = INQUIRY;
23650dbef1aSdholland 	cmd.length = sizeof(inqbuf);
23750dbef1aSdholland 	memcpy(req.cmd, &cmd, sizeof(cmd));
23850dbef1aSdholland 	req.cmdlen = sizeof(cmd);
23950dbef1aSdholland 	req.databuf = &inqbuf;
24050dbef1aSdholland 	req.datalen = sizeof(inqbuf);
24150dbef1aSdholland 	req.timeout = 10000;
24250dbef1aSdholland 	req.flags = SCCMD_READ;
24350dbef1aSdholland 	req.senselen = SENSEBUFLEN;
24450dbef1aSdholland 
24572ea5dbaSchristos 	if (!disk_ioctl(dd->dd_name, SCIOCCOMMAND, &req)
24672ea5dbaSchristos 	    || req.retsts != SCCMD_OK)
24750dbef1aSdholland 		return 0;
24850dbef1aSdholland 
24950dbef1aSdholland 	scsi_strvis(vendor, sizeof(vendor), inqbuf.vendor,
25050dbef1aSdholland 	    sizeof(inqbuf.vendor));
25150dbef1aSdholland 	scsi_strvis(product, sizeof(product), inqbuf.product,
25250dbef1aSdholland 	    sizeof(inqbuf.product));
25350dbef1aSdholland 	scsi_strvis(revision, sizeof(revision), inqbuf.revision,
25450dbef1aSdholland 	    sizeof(inqbuf.revision));
25550dbef1aSdholland 
25650dbef1aSdholland 	humanize_number(size, sizeof(size),
25750dbef1aSdholland 	    (uint64_t)dd->dd_secsize * (uint64_t)dd->dd_totsec,
25850dbef1aSdholland 	    "", HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL);
25950dbef1aSdholland 
26050dbef1aSdholland 	snprintf(dd->dd_descr, sizeof(dd->dd_descr),
26150dbef1aSdholland 	    "%s (%s, %s %s)",
26250dbef1aSdholland 	    dd->dd_name, size, vendor, product);
26350dbef1aSdholland 
26450dbef1aSdholland 	return 1;
26550dbef1aSdholland }
26650dbef1aSdholland 
26750dbef1aSdholland static int
26872ea5dbaSchristos get_descr_ata(struct disk_desc *dd)
26950dbef1aSdholland {
27050dbef1aSdholland 	struct atareq req;
27150dbef1aSdholland 	static union {
27250dbef1aSdholland 		unsigned char inbuf[DEV_BSIZE];
27350dbef1aSdholland 		struct ataparams inqbuf;
27450dbef1aSdholland 	} inbuf;
27550dbef1aSdholland 	struct ataparams *inqbuf = &inbuf.inqbuf;
27650dbef1aSdholland 	char model[sizeof(inqbuf->atap_model)+1];
27750dbef1aSdholland 	char size[5];
27872ea5dbaSchristos 	int needswap = 0;
27950dbef1aSdholland 
28050dbef1aSdholland 	memset(&inbuf, 0, sizeof(inbuf));
28150dbef1aSdholland 	memset(&req, 0, sizeof(req));
28250dbef1aSdholland 
28350dbef1aSdholland 	req.flags = ATACMD_READ;
28450dbef1aSdholland 	req.command = WDCC_IDENTIFY;
28550dbef1aSdholland 	req.databuf = (void *)&inbuf;
28650dbef1aSdholland 	req.datalen = sizeof(inbuf);
28750dbef1aSdholland 	req.timeout = 1000;
28850dbef1aSdholland 
28972ea5dbaSchristos 	if (!disk_ioctl(dd->dd_name, ATAIOCCOMMAND, &req)
29072ea5dbaSchristos 	    || req.retsts != ATACMD_OK)
29150dbef1aSdholland 		return 0;
29250dbef1aSdholland 
29350dbef1aSdholland #if BYTE_ORDER == LITTLE_ENDIAN
29450dbef1aSdholland 	/*
29550dbef1aSdholland 	 * On little endian machines, we need to shuffle the string
29650dbef1aSdholland 	 * byte order.  However, we don't have to do this for NEC or
29750dbef1aSdholland 	 * Mitsumi ATAPI devices
29850dbef1aSdholland 	 */
29950dbef1aSdholland 
30050dbef1aSdholland 	if (!(inqbuf->atap_config != WDC_CFG_CFA_MAGIC &&
30150dbef1aSdholland 	      (inqbuf->atap_config & WDC_CFG_ATAPI) &&
30250dbef1aSdholland 	      ((inqbuf->atap_model[0] == 'N' &&
30350dbef1aSdholland 	        inqbuf->atap_model[1] == 'E') ||
30450dbef1aSdholland 	       (inqbuf->atap_model[0] == 'F' &&
30550dbef1aSdholland 	        inqbuf->atap_model[1] == 'X')))) {
30650dbef1aSdholland 		needswap = 1;
30750dbef1aSdholland 	}
30850dbef1aSdholland #endif
30950dbef1aSdholland 
31050dbef1aSdholland 	ata_extract_string(model, sizeof(model),
31150dbef1aSdholland 	    inqbuf->atap_model, sizeof(inqbuf->atap_model), needswap);
31250dbef1aSdholland 	humanize_number(size, sizeof(size),
31350dbef1aSdholland 	    (uint64_t)dd->dd_secsize * (uint64_t)dd->dd_totsec,
31450dbef1aSdholland 	    "", HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL);
31550dbef1aSdholland 
31650dbef1aSdholland 	snprintf(dd->dd_descr, sizeof(dd->dd_descr), "%s (%s, %s)",
31750dbef1aSdholland 	    dd->dd_name, size, model);
31850dbef1aSdholland 
31950dbef1aSdholland 	return 1;
32050dbef1aSdholland }
32150dbef1aSdholland 
32250dbef1aSdholland static void
32350dbef1aSdholland get_descr(struct disk_desc *dd)
32450dbef1aSdholland {
32572ea5dbaSchristos 	char size[5];
32650dbef1aSdholland 	dd->dd_descr[0] = '\0';
32750dbef1aSdholland 
32850dbef1aSdholland 	/* try ATA */
32972ea5dbaSchristos 	if (get_descr_ata(dd))
33050dbef1aSdholland 		goto done;
33150dbef1aSdholland 	/* try SCSI */
33272ea5dbaSchristos 	if (get_descr_scsi(dd))
33350dbef1aSdholland 		goto done;
3344103857bSmartin 
3354103857bSmartin 	/* XXX: identify for ld @ NVME or microSD */
3364103857bSmartin 
3374b2364d9Smartin 	/* XXX: get description from raid, cgd, vnd... */
33872ea5dbaSchristos done:
3394103857bSmartin 	/* punt, just give some generic info */
3404103857bSmartin 	humanize_number(size, sizeof(size),
3414103857bSmartin 	    (uint64_t)dd->dd_secsize * (uint64_t)dd->dd_totsec,
3424103857bSmartin 	    "", HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL);
3434103857bSmartin 
3444103857bSmartin 	snprintf(dd->dd_descr, sizeof(dd->dd_descr),
3454103857bSmartin 	    "%s (%s)", dd->dd_name, size);
34650dbef1aSdholland }
34750dbef1aSdholland 
348a48ed55eSmartin /*
349a48ed55eSmartin  * State for helper callback for get_default_cdrom
350a48ed55eSmartin  */
351a48ed55eSmartin struct default_cdrom_data {
352a48ed55eSmartin 	char *device;
353a48ed55eSmartin 	size_t max_len;
354a48ed55eSmartin 	bool found;
355a48ed55eSmartin };
356a48ed55eSmartin 
357a48ed55eSmartin /*
358a48ed55eSmartin  * Helper function for get_default_cdrom, gets passed a device
359a48ed55eSmartin  * name and a void pointer to default_cdrom_data.
360a48ed55eSmartin  */
361a48ed55eSmartin static bool
362a48ed55eSmartin get_default_cdrom_helper(void *state, const char *dev)
363a48ed55eSmartin {
364a48ed55eSmartin 	struct default_cdrom_data *data = state;
365a48ed55eSmartin 
36657cf8237Smartin 	if (!is_cdrom_device(dev, false))
3671c2e5b02Smartin 		return true;
3681c2e5b02Smartin 
369a48ed55eSmartin 	strlcpy(data->device, dev, data->max_len);
3701c2e5b02Smartin 	strlcat(data->device, "a", data->max_len); /* default to partition a */
371a48ed55eSmartin 	data->found = true;
372a48ed55eSmartin 
373a48ed55eSmartin 	return false;	/* one is enough, stop iteration */
374a48ed55eSmartin }
375a48ed55eSmartin 
376a48ed55eSmartin /*
377a48ed55eSmartin  * Set the argument to the name of the first CD devices actually
378a48ed55eSmartin  * available, leave it unmodified otherwise.
379a48ed55eSmartin  * Return true if a device has been found.
38050dbef1aSdholland  */
3813b44a3d7Smartin bool
3823b44a3d7Smartin get_default_cdrom(char *cd, size_t max_len)
38350dbef1aSdholland {
384a48ed55eSmartin 	struct default_cdrom_data state;
38550dbef1aSdholland 
386a48ed55eSmartin 	state.device = cd;
387a48ed55eSmartin 	state.max_len = max_len;
388a48ed55eSmartin 	state.found = false;
38950dbef1aSdholland 
390a48ed55eSmartin 	if (enumerate_disks(&state, get_default_cdrom_helper))
391a48ed55eSmartin 		return state.found;
392a48ed55eSmartin 
393a48ed55eSmartin 	return false;
39450dbef1aSdholland }
39550dbef1aSdholland 
3964103857bSmartin static bool
3972575b4dcSmartin get_wedge_descr(struct disk_desc *dd)
3982575b4dcSmartin {
3992575b4dcSmartin 	struct dkwedge_info dkw;
4002575b4dcSmartin 
40172ea5dbaSchristos 	if (!get_wedge_info(dd->dd_name, &dkw))
4024103857bSmartin 		return false;
4032575b4dcSmartin 
40472ea5dbaSchristos 	snprintf(dd->dd_descr, sizeof(dd->dd_descr), "%s (%s@%s)",
4052575b4dcSmartin 	    dkw.dkw_wname, dkw.dkw_devname, dkw.dkw_parent);
40672ea5dbaSchristos 	return true;
4072575b4dcSmartin }
4082575b4dcSmartin 
4092575b4dcSmartin static bool
4102575b4dcSmartin get_name_and_parent(const char *dev, char *name, char *parent)
4112575b4dcSmartin {
4122575b4dcSmartin 	struct dkwedge_info dkw;
4132575b4dcSmartin 
41472ea5dbaSchristos 	if (!get_wedge_info(dev, &dkw))
4152575b4dcSmartin 		return false;
4162575b4dcSmartin 	strcpy(name, (const char *)dkw.dkw_wname);
4172575b4dcSmartin 	strcpy(parent, dkw.dkw_parent);
41872ea5dbaSchristos 	return true;
4192575b4dcSmartin }
4202575b4dcSmartin 
4212575b4dcSmartin static bool
4222575b4dcSmartin find_swap_part_on(const char *dev, char *swap_name)
4232575b4dcSmartin {
4242575b4dcSmartin 	struct dkwedge_list dkwl;
42572ea5dbaSchristos 	struct dkwedge_info *dkw;
4262575b4dcSmartin 	u_int i;
4272575b4dcSmartin 	bool res = false;
4282575b4dcSmartin 
42972ea5dbaSchristos 	if (!get_wedge_list(dev, &dkwl))
4302575b4dcSmartin 		return false;
4312575b4dcSmartin 
43272ea5dbaSchristos 	dkw = dkwl.dkwl_buf;
4332575b4dcSmartin 	for (i = 0; i < dkwl.dkwl_nwedges; i++) {
4342575b4dcSmartin 		res = strcmp(dkw[i].dkw_ptype, DKW_PTYPE_SWAP) == 0;
4352575b4dcSmartin 		if (res) {
4362575b4dcSmartin 			strcpy(swap_name, (const char*)dkw[i].dkw_wname);
4372575b4dcSmartin 			break;
4382575b4dcSmartin 		}
4392575b4dcSmartin 	}
44072ea5dbaSchristos 	free(dkwl.dkwl_buf);
4412575b4dcSmartin 
4422575b4dcSmartin 	return res;
4432575b4dcSmartin }
4442575b4dcSmartin 
4452575b4dcSmartin static bool
4462575b4dcSmartin is_ffs_wedge(const char *dev)
4472575b4dcSmartin {
4482575b4dcSmartin 	struct dkwedge_info dkw;
4492575b4dcSmartin 
45072ea5dbaSchristos 	if (!get_wedge_info(dev, &dkw))
4512575b4dcSmartin 		return false;
4522575b4dcSmartin 
45372ea5dbaSchristos 	return strcmp(dkw.dkw_ptype, DKW_PTYPE_FFS) == 0;
4542575b4dcSmartin }
4552575b4dcSmartin 
4563b44a3d7Smartin /*
4573b44a3d7Smartin  * Does this device match an entry in our default CDROM device list?
45857cf8237Smartin  * If looking for install targets, we also flag floopy devices.
4593b44a3d7Smartin  */
4601c2e5b02Smartin bool
46157cf8237Smartin is_cdrom_device(const char *dev, bool as_target)
4623b44a3d7Smartin {
46357cf8237Smartin 	static const char *target_devices[] = {
4648b5066c4Smartin #ifdef CD_NAMES
4658b5066c4Smartin 		CD_NAMES
4668b5066c4Smartin #endif
4678b5066c4Smartin #if defined(CD_NAMES) && defined(FLOPPY_NAMES)
4688b5066c4Smartin 		,
4698b5066c4Smartin #endif
4708b5066c4Smartin #ifdef FLOPPY_NAMES
4718b5066c4Smartin 		FLOPPY_NAMES
4728b5066c4Smartin #endif
4738b5066c4Smartin #if defined(CD_NAMES) || defined(FLOPPY_NAMES)
4748b5066c4Smartin 		,
4758b5066c4Smartin #endif
4768b5066c4Smartin 		0
4778b5066c4Smartin 	};
47857cf8237Smartin 	static const char *src_devices[] = {
47957cf8237Smartin #ifdef CD_NAMES
48057cf8237Smartin 		CD_NAMES ,
48157cf8237Smartin #endif
48257cf8237Smartin 		0
48357cf8237Smartin 	};
4843b44a3d7Smartin 
48557cf8237Smartin 	for (const char **dev_pat = as_target ? target_devices : src_devices;
48657cf8237Smartin 	     *dev_pat; dev_pat++)
4874bb5c537Smartin 		if (fnmatch(*dev_pat, dev, 0) == 0)
488e80b64deSmartin 			return true;
4893b44a3d7Smartin 
4903b44a3d7Smartin 	return false;
4913b44a3d7Smartin }
4923b44a3d7Smartin 
493c4cf3d8dSmartin /* does this device match any entry in the driver list? */
494c4cf3d8dSmartin static bool
495c4cf3d8dSmartin dev_in_list(const char *dev, const char **list)
496c4cf3d8dSmartin {
497c4cf3d8dSmartin 
498c4cf3d8dSmartin 	for ( ; *list; list++) {
499c4cf3d8dSmartin 
500c4cf3d8dSmartin 		size_t len = strlen(*list);
501c4cf3d8dSmartin 
502c4cf3d8dSmartin 		/* start of name matches? */
503c4cf3d8dSmartin 		if (strncmp(dev, *list, len) == 0) {
504c4cf3d8dSmartin 			char *endp;
505c4cf3d8dSmartin 			int e;
506c4cf3d8dSmartin 
507c4cf3d8dSmartin 			/* remainder of name is a decimal number? */
508c4cf3d8dSmartin 			strtou(dev+len, &endp, 10, 0, INT_MAX, &e);
509c4cf3d8dSmartin 			if (endp && *endp == 0 && e == 0)
510c4cf3d8dSmartin 				return true;
511c4cf3d8dSmartin 		}
512c4cf3d8dSmartin 	}
513c4cf3d8dSmartin 
514c4cf3d8dSmartin 	return false;
515c4cf3d8dSmartin }
516c4cf3d8dSmartin 
517c4cf3d8dSmartin bool
518c4cf3d8dSmartin is_bootable_device(const char *dev)
519c4cf3d8dSmartin {
520c4cf3d8dSmartin 	static const char *non_bootable_devs[] = {
521c4cf3d8dSmartin 		"raid",	/* bootcode lives outside of raid */
522c4cf3d8dSmartin 		"xbd",	/* xen virtual device, can not boot from that */
523c4cf3d8dSmartin 		NULL
524c4cf3d8dSmartin 	};
525c4cf3d8dSmartin 
526c4cf3d8dSmartin 	return !dev_in_list(dev, non_bootable_devs);
527c4cf3d8dSmartin }
528c4cf3d8dSmartin 
529c4cf3d8dSmartin bool
530c4cf3d8dSmartin is_partitionable_device(const char *dev)
531c4cf3d8dSmartin {
532c4cf3d8dSmartin 	static const char *non_partitionable_devs[] = {
533d4a37f7cSmsaitoh 		"dk",	/* this is already a partitioned slice */
534c4cf3d8dSmartin 		NULL
535c4cf3d8dSmartin 	};
536c4cf3d8dSmartin 
537c4cf3d8dSmartin 	return !dev_in_list(dev, non_partitionable_devs);
538c4cf3d8dSmartin }
539c4cf3d8dSmartin 
5403b44a3d7Smartin /*
5413b44a3d7Smartin  * Multi-purpose helper function:
542a48ed55eSmartin  * iterate all known disks, invoke a callback for each.
543a48ed55eSmartin  * Stop iteration when the callback returns false.
544a48ed55eSmartin  * Return true when iteration actually happend, false on error.
5453b44a3d7Smartin  */
5461c2e5b02Smartin bool
547a48ed55eSmartin enumerate_disks(void *state, bool (*func)(void *state, const char *dev))
54850dbef1aSdholland {
5497a391039Smartin 	static const int mib[] = { CTL_HW, HW_DISKNAMES };
5507a391039Smartin 	static const unsigned int miblen = __arraycount(mib);
5517a391039Smartin 	const char *xd;
5527a391039Smartin 	char *disk_names;
553a48ed55eSmartin 	size_t len;
55450dbef1aSdholland 
5557a391039Smartin 	if (sysctl(mib, miblen, NULL, &len, NULL, 0) == -1)
556a48ed55eSmartin 		return false;
557a48ed55eSmartin 
5587a391039Smartin 	disk_names = malloc(len);
5597a391039Smartin 	if (disk_names == NULL)
560a48ed55eSmartin 		return false;
5617a391039Smartin 
5627a391039Smartin 	if (sysctl(mib, miblen, disk_names, &len, NULL, 0) == -1) {
5637a391039Smartin 		free(disk_names);
564a48ed55eSmartin 		return false;
5657a391039Smartin 	}
5667a391039Smartin 
5677a391039Smartin 	for (xd = strtok(disk_names, " "); xd != NULL; xd = strtok(NULL, " ")) {
568a48ed55eSmartin 		if (!(*func)(state, xd))
569a48ed55eSmartin 			break;
570a48ed55eSmartin 	}
571a48ed55eSmartin 	free(disk_names);
572a48ed55eSmartin 
573a48ed55eSmartin 	return true;
574a48ed55eSmartin }
575a48ed55eSmartin 
576a48ed55eSmartin /*
577a48ed55eSmartin  * Helper state for get_disks
578a48ed55eSmartin  */
579a48ed55eSmartin struct get_disks_state {
580a48ed55eSmartin 	int numdisks;
581a48ed55eSmartin 	struct disk_desc *dd;
582a48ed55eSmartin 	bool with_non_partitionable;
583a48ed55eSmartin };
584a48ed55eSmartin 
585a48ed55eSmartin /*
586a48ed55eSmartin  * Helper function for get_disks enumartion
587a48ed55eSmartin  */
588a48ed55eSmartin static bool
589a48ed55eSmartin get_disks_helper(void *arg, const char *dev)
590a48ed55eSmartin {
591a48ed55eSmartin 	struct get_disks_state *state = arg;
5924103857bSmartin 	struct disk_geom geo;
593a48ed55eSmartin 
5943b44a3d7Smartin 	/* is this a CD device? */
59557cf8237Smartin 	if (is_cdrom_device(dev, true))
596a48ed55eSmartin 		return true;
5973b44a3d7Smartin 
598c4cf3d8dSmartin 	memset(state->dd, 0, sizeof(*state->dd));
599a48ed55eSmartin 	strlcpy(state->dd->dd_name, dev, sizeof state->dd->dd_name - 2);
600c4cf3d8dSmartin 	state->dd->dd_no_mbr = !is_bootable_device(dev);
601c4cf3d8dSmartin 	state->dd->dd_no_part = !is_partitionable_device(dev);
6027a391039Smartin 
603a48ed55eSmartin 	if (state->dd->dd_no_part && !state->with_non_partitionable)
604a48ed55eSmartin 		return true;
60550dbef1aSdholland 
6064103857bSmartin 	if (!get_disk_geom(state->dd->dd_name, &geo)) {
60750dbef1aSdholland 		if (errno == ENOENT)
608a48ed55eSmartin 			return true;
609a48ed55eSmartin 		if (errno != ENOTTY || !state->dd->dd_no_part)
6102575b4dcSmartin 			/*
6112575b4dcSmartin 			 * Allow plain partitions,
6122575b4dcSmartin 			 * like already existing wedges
6132575b4dcSmartin 			 * (like dk0) if marked as
6142575b4dcSmartin 			 * non-partitioning device.
6152575b4dcSmartin 			 * For all other cases, continue
6162575b4dcSmartin 			 * with the next disk.
6172575b4dcSmartin 			 */
618a48ed55eSmartin 			return true;
619a48ed55eSmartin 		if (!is_ffs_wedge(state->dd->dd_name))
620a48ed55eSmartin 			return true;
62150dbef1aSdholland 	}
62250dbef1aSdholland 
62350dbef1aSdholland 	/*
62450dbef1aSdholland 	 * Exclude a disk mounted as root partition,
62550dbef1aSdholland 	 * in case of install-image on a USB memstick.
62650dbef1aSdholland 	 */
6275864e121Smartin 	if (is_active_rootpart(state->dd->dd_name,
6285864e121Smartin 	    state->dd->dd_no_part ? -1 : 0))
629a48ed55eSmartin 		return true;
63050dbef1aSdholland 
6314103857bSmartin 	state->dd->dd_cyl = geo.dg_ncylinders;
6324103857bSmartin 	state->dd->dd_head = geo.dg_ntracks;
6334103857bSmartin 	state->dd->dd_sec = geo.dg_nsectors;
6344103857bSmartin 	state->dd->dd_secsize = geo.dg_secsize;
6354103857bSmartin 	state->dd->dd_totsec = geo.dg_secperunit;
6364103857bSmartin 
6374103857bSmartin 	if (!state->dd->dd_no_part || !get_wedge_descr(state->dd))
638a48ed55eSmartin 		get_descr(state->dd);
639a48ed55eSmartin 	state->dd++;
640a48ed55eSmartin 	state->numdisks++;
641a48ed55eSmartin 	if (state->numdisks == MAX_DISKS)
642a48ed55eSmartin 		return false;
643a48ed55eSmartin 
644a48ed55eSmartin 	return true;
64550dbef1aSdholland }
646a48ed55eSmartin 
647a48ed55eSmartin /*
648a48ed55eSmartin  * Get all disk devices that are not CDs.
649a48ed55eSmartin  * Optionally leave out those that can not be partitioned further.
650a48ed55eSmartin  */
651a48ed55eSmartin static int
652a48ed55eSmartin get_disks(struct disk_desc *dd, bool with_non_partitionable)
653a48ed55eSmartin {
654a48ed55eSmartin 	struct get_disks_state state;
655a48ed55eSmartin 
656a48ed55eSmartin 	/* initialize */
657a48ed55eSmartin 	state.numdisks = 0;
658a48ed55eSmartin 	state.dd = dd;
659a48ed55eSmartin 	state.with_non_partitionable = with_non_partitionable;
660a48ed55eSmartin 
661a48ed55eSmartin 	if (enumerate_disks(&state, get_disks_helper))
662a48ed55eSmartin 		return state.numdisks;
663a48ed55eSmartin 
664a48ed55eSmartin 	return 0;
66550dbef1aSdholland }
66650dbef1aSdholland 
6674103857bSmartin #ifdef DEBUG_VERBOSE
6684103857bSmartin static void
6694103857bSmartin dump_parts(const struct disk_partitions *parts)
6704103857bSmartin {
6714103857bSmartin 	fprintf(stderr, "%s partitions on %s:\n",
6724103857bSmartin 	    MSG_XLAT(parts->pscheme->short_name), parts->disk);
6734103857bSmartin 
6744103857bSmartin 	for (size_t p = 0; p < parts->num_part; p++) {
6754103857bSmartin 		struct disk_part_info info;
6764103857bSmartin 
6774103857bSmartin 		if (parts->pscheme->get_part_info(
6784103857bSmartin 		    parts, p, &info)) {
6794103857bSmartin 			fprintf(stderr, " #%zu: start: %" PRIu64 " "
6804103857bSmartin 			    "size: %" PRIu64 ", flags: %x\n",
6814103857bSmartin 			    p, info.start, info.size,
6824103857bSmartin 			    info.flags);
6834103857bSmartin 			if (info.nat_type)
6844103857bSmartin 				fprintf(stderr, "\ttype: %s\n",
6854103857bSmartin 				    info.nat_type->description);
6864103857bSmartin 		} else {
6874103857bSmartin 			fprintf(stderr, "failed to get info "
6884103857bSmartin 			    "for partition #%zu\n", p);
6894103857bSmartin 		}
6904103857bSmartin 	}
6914103857bSmartin 	fprintf(stderr, "%" PRIu64 " sectors free, disk size %" PRIu64
6924103857bSmartin 	    " sectors, %zu partitions used\n", parts->free_space,
6934103857bSmartin 	    parts->disk_size, parts->num_part);
6944103857bSmartin }
6954103857bSmartin #endif
6964103857bSmartin 
6974103857bSmartin static bool
6984103857bSmartin delete_scheme(struct pm_devs *p)
6994103857bSmartin {
7004103857bSmartin 
7014103857bSmartin 	if (!ask_noyes(MSG_removepartswarn))
7024103857bSmartin 		return false;
7034103857bSmartin 
7044103857bSmartin 	p->parts->pscheme->free(p->parts);
7054103857bSmartin 	p->parts = NULL;
7064103857bSmartin 	return true;
7074103857bSmartin }
7084103857bSmartin 
7094103857bSmartin 
7104103857bSmartin static void
7114103857bSmartin convert_copy(struct disk_partitions *old_parts,
7124103857bSmartin     struct disk_partitions *new_parts)
7134103857bSmartin {
7144103857bSmartin 	struct disk_part_info oinfo, ninfo;
7154103857bSmartin 	part_id i;
7164103857bSmartin 
7174103857bSmartin 	for (i = 0; i < old_parts->num_part; i++) {
7184103857bSmartin 		if (!old_parts->pscheme->get_part_info(old_parts, i, &oinfo))
7194103857bSmartin 			continue;
7204103857bSmartin 
7214103857bSmartin 		if (oinfo.flags & PTI_PSCHEME_INTERNAL)
7224103857bSmartin 			continue;
7234103857bSmartin 
7244103857bSmartin 		if (oinfo.flags & PTI_SEC_CONTAINER) {
7254103857bSmartin 		    	if (old_parts->pscheme->secondary_partitions) {
7264103857bSmartin 				struct disk_partitions *sec_part =
7274103857bSmartin 					old_parts->pscheme->
7284103857bSmartin 					    secondary_partitions(
72983478358Smartin 					    old_parts, oinfo.start, false);
7304103857bSmartin 				if (sec_part)
7314103857bSmartin 					convert_copy(sec_part, new_parts);
7324103857bSmartin 			}
7334103857bSmartin 			continue;
7344103857bSmartin 		}
7354103857bSmartin 
7364103857bSmartin 		if (!new_parts->pscheme->adapt_foreign_part_info(new_parts,
7374103857bSmartin 			    &oinfo, &ninfo))
7384103857bSmartin 			continue;
7394103857bSmartin 		new_parts->pscheme->add_partition(new_parts, &ninfo, NULL);
7404103857bSmartin 	}
7414103857bSmartin }
7424103857bSmartin 
7434103857bSmartin bool
7444103857bSmartin convert_scheme(struct pm_devs *p, bool is_boot_drive, const char **err_msg)
7454103857bSmartin {
7464103857bSmartin 	struct disk_partitions *old_parts, *new_parts;
7474103857bSmartin 	const struct disk_partitioning_scheme *new_scheme;
7484103857bSmartin 
7494103857bSmartin 	*err_msg = NULL;
7504103857bSmartin 
7514103857bSmartin 	old_parts = p->parts;
7524103857bSmartin 	new_scheme = select_part_scheme(p, old_parts->pscheme,
7534103857bSmartin 	    false, MSG_select_other_partscheme);
7544103857bSmartin 
7554103857bSmartin 	if (new_scheme == NULL)
7564103857bSmartin 		return false;
7574103857bSmartin 
7584103857bSmartin 	new_parts = new_scheme->create_new_for_disk(p->diskdev,
7594103857bSmartin 	    0, p->dlsize, p->dlsize, is_boot_drive);
7604103857bSmartin 	if (new_parts == NULL)
7614103857bSmartin 		return false;
7624103857bSmartin 
7634103857bSmartin 	convert_copy(old_parts, new_parts);
7644103857bSmartin 
7654103857bSmartin 	if (new_parts->num_part == 0) {
7664103857bSmartin 		/* need to cleanup */
7674103857bSmartin 		new_parts->pscheme->free(new_parts);
7684103857bSmartin 		return false;
7694103857bSmartin 	}
7704103857bSmartin 
7714103857bSmartin 	old_parts->pscheme->free(old_parts);
7724103857bSmartin 	p->parts = new_parts;
7734103857bSmartin 	return true;
7744103857bSmartin }
7754103857bSmartin 
776b1fa9754Smartin static struct pm_devs *
777b1fa9754Smartin dummy_whole_system_pm(void)
778b1fa9754Smartin {
779b1fa9754Smartin 	static struct pm_devs whole_system = {
780b1fa9754Smartin 		.diskdev = "/",
781b1fa9754Smartin 		.no_mbr = true,
782b1fa9754Smartin 		.no_part = true,
783b1fa9754Smartin 		.cur_system = true,
784b1fa9754Smartin 	};
785b1fa9754Smartin 	static bool init = false;
786b1fa9754Smartin 
787b1fa9754Smartin 	if (!init) {
788b1fa9754Smartin 		strlcpy(whole_system.diskdev_descr,
789b1fa9754Smartin 		    msg_string(MSG_running_system),
790b1fa9754Smartin 		    sizeof whole_system.diskdev_descr);
791b1fa9754Smartin 	}
792b1fa9754Smartin 
793b1fa9754Smartin 	return &whole_system;
794b1fa9754Smartin }
795b1fa9754Smartin 
79650dbef1aSdholland int
797b1fa9754Smartin find_disks(const char *doingwhat, bool allow_cur_system)
79850dbef1aSdholland {
79950dbef1aSdholland 	struct disk_desc disks[MAX_DISKS];
800b1fa9754Smartin 	/* need two more menu entries: current system + extended partitioning */
801b1fa9754Smartin 	menu_ent dsk_menu[__arraycount(disks) + 2];
80250dbef1aSdholland 	struct disk_desc *disk;
8032575b4dcSmartin 	int i = 0, skipped = 0;
8042575b4dcSmartin 	int already_found, numdisks, selected_disk = -1;
80550dbef1aSdholland 	int menu_no;
8064103857bSmartin 	struct pm_devs *pm_i, *pm_last = NULL;
8074103857bSmartin 
8084103857bSmartin 	memset(dsk_menu, 0, sizeof(dsk_menu));
80950dbef1aSdholland 
81050dbef1aSdholland 	/* Find disks. */
811a48ed55eSmartin 	numdisks = get_disks(disks, partman_go <= 0);
81250dbef1aSdholland 
81350dbef1aSdholland 	/* need a redraw here, kernel messages hose everything */
81450dbef1aSdholland 	touchwin(stdscr);
81550dbef1aSdholland 	refresh();
81650dbef1aSdholland 	/* Kill typeahead, it won't be what the user had in mind */
81750dbef1aSdholland 	fpurge(stdin);
81850dbef1aSdholland 
819bbeaff62Sisaki 	/*
820bbeaff62Sisaki 	 * partman_go: <0 - we want to see menu with extended partitioning
821bbeaff62Sisaki 	 *            ==0 - we want to see simple select disk menu
822bbeaff62Sisaki 	 *             >0 - we do not want to see any menus, just detect
823bbeaff62Sisaki 	 *                  all disks
824bbeaff62Sisaki 	 */
8254b2364d9Smartin 	if (partman_go <= 0) {
826b1fa9754Smartin 		if (numdisks == 0 && !allow_cur_system) {
82750dbef1aSdholland 			/* No disks found! */
8284103857bSmartin 			hit_enter_to_continue(MSG_nodisk, NULL);
82950dbef1aSdholland 			/*endwin();*/
83050dbef1aSdholland 			return -1;
83150dbef1aSdholland 		} else {
832b1fa9754Smartin 			/* One or more disks found or current system allowed */
833b1fa9754Smartin 			i = 0;
834b1fa9754Smartin 			if (allow_cur_system) {
835b1fa9754Smartin 				dsk_menu[i].opt_name = MSG_running_system;
836b1fa9754Smartin 				dsk_menu[i].opt_flags = OPT_EXIT;
837b1fa9754Smartin 				dsk_menu[i].opt_action = set_menu_select;
838b1fa9754Smartin 				i++;
839b1fa9754Smartin 			}
8407edc37a7Smartin 			for (; i < numdisks+allow_cur_system; i++) {
8412575b4dcSmartin 				dsk_menu[i].opt_name =
842b1fa9754Smartin 				    disks[i-allow_cur_system].dd_descr;
84350dbef1aSdholland 				dsk_menu[i].opt_flags = OPT_EXIT;
8444b2364d9Smartin 				dsk_menu[i].opt_action = set_menu_select;
8454b2364d9Smartin 			}
8464b2364d9Smartin 			if (partman_go < 0) {
8474b2364d9Smartin 				dsk_menu[i].opt_name = MSG_partman;
8484b2364d9Smartin 				dsk_menu[i].opt_flags = OPT_EXIT;
8494b2364d9Smartin 				dsk_menu[i].opt_action = set_menu_select;
850b1fa9754Smartin 				i++;
85150dbef1aSdholland 			}
85250dbef1aSdholland 			menu_no = new_menu(MSG_Available_disks,
853b1fa9754Smartin 				dsk_menu, i, -1,
8542575b4dcSmartin 				 4, 0, 0, MC_SCROLL,
85550dbef1aSdholland 				NULL, NULL, NULL, NULL, NULL);
85650dbef1aSdholland 			if (menu_no == -1)
85750dbef1aSdholland 				return -1;
85824ecf24eSchristos 			msg_fmt_display(MSG_ask_disk, "%s", doingwhat);
85950dbef1aSdholland 			process_menu(menu_no, &selected_disk);
86050dbef1aSdholland 			free_menu(menu_no);
861b1fa9754Smartin 			if (allow_cur_system) {
862b1fa9754Smartin 				if (selected_disk == 0) {
863b1fa9754Smartin 					pm = dummy_whole_system_pm();
864b1fa9754Smartin 					return 1;
865b1fa9754Smartin 				} else {
866b1fa9754Smartin 					selected_disk--;
867b1fa9754Smartin 				}
868b1fa9754Smartin 			}
86950dbef1aSdholland 		}
8704b2364d9Smartin 		if (partman_go < 0 && selected_disk == numdisks) {
8714b2364d9Smartin 			partman_go = 1;
8724b2364d9Smartin 			return -2;
8734b2364d9Smartin 		} else
8744b2364d9Smartin 			partman_go = 0;
8754b2364d9Smartin 		if (selected_disk < 0 || selected_disk >= numdisks)
8764b2364d9Smartin 			return -1;
8774b2364d9Smartin 	}
87850dbef1aSdholland 
8794b2364d9Smartin 	/* Fill pm struct with device(s) info */
8804b2364d9Smartin 	for (i = 0; i < numdisks; i++) {
8814b2364d9Smartin 		if (! partman_go)
88250dbef1aSdholland 			disk = disks + selected_disk;
8834b2364d9Smartin 		else {
8844b2364d9Smartin 			disk = disks + i;
8854b2364d9Smartin 			already_found = 0;
8864b2364d9Smartin 			SLIST_FOREACH(pm_i, &pm_head, l) {
8874b2364d9Smartin 				pm_last = pm_i;
888e32f4c09Smartin 				if (strcmp(pm_i->diskdev, disk->dd_name) == 0) {
889e32f4c09Smartin 					already_found = 1;
8904b2364d9Smartin 					break;
8914b2364d9Smartin 				}
8924b2364d9Smartin 			}
893e32f4c09Smartin 			if (pm_i != NULL && already_found) {
894e32f4c09Smartin 				/*
895e32f4c09Smartin 				 * We already added this device, but
896e32f4c09Smartin 				 * partitions might have changed
897e32f4c09Smartin 				 */
898e32f4c09Smartin 				if (!pm_i->found) {
899e32f4c09Smartin 					pm_i->found = true;
900e32f4c09Smartin 					if (pm_i->parts == NULL) {
901e32f4c09Smartin 						pm_i->parts =
902e32f4c09Smartin 						    partitions_read_disk(
903e32f4c09Smartin 						    pm_i->diskdev,
904e32f4c09Smartin 						    disk->dd_totsec);
905e32f4c09Smartin 					}
906e32f4c09Smartin 				}
9074b2364d9Smartin 				continue;
9084b2364d9Smartin 			}
909e32f4c09Smartin 		}
9104b2364d9Smartin 		pm = pm_new;
9114b2364d9Smartin 		pm->found = 1;
9124103857bSmartin 		pm->ptstart = 0;
9134103857bSmartin 		pm->ptsize = 0;
9144b2364d9Smartin 		pm->bootable = 0;
9154b2364d9Smartin 		strlcpy(pm->diskdev, disk->dd_name, sizeof pm->diskdev);
9164b2364d9Smartin 		strlcpy(pm->diskdev_descr, disk->dd_descr, sizeof pm->diskdev_descr);
91750dbef1aSdholland 		/* Use as a default disk if the user has the sets on a local disk */
91850dbef1aSdholland 		strlcpy(localfs_dev, disk->dd_name, sizeof localfs_dev);
91950dbef1aSdholland 
9204103857bSmartin 		/*
9214103857bSmartin 		 * Init disk size and geometry
9224103857bSmartin 		 */
9234103857bSmartin 		pm->sectorsize = disk->dd_secsize;
9244103857bSmartin 		pm->dlcyl = disk->dd_cyl;
9254103857bSmartin 		pm->dlhead = disk->dd_head;
9264103857bSmartin 		pm->dlsec = disk->dd_sec;
9274103857bSmartin 		pm->dlsize = disk->dd_totsec;
9284103857bSmartin 		if (pm->dlsize == 0)
9294103857bSmartin 			pm->dlsize = disk->dd_cyl * disk->dd_head
9304103857bSmartin 			    * disk->dd_sec;
9314103857bSmartin 
9324103857bSmartin 		pm->parts = partitions_read_disk(pm->diskdev, disk->dd_totsec);
9334103857bSmartin 
9344103857bSmartin again:
9354103857bSmartin 
9364103857bSmartin #ifdef DEBUG_VERBOSE
9374103857bSmartin 		if (pm->parts) {
9384103857bSmartin 			fputs("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n", stderr);
9394103857bSmartin 			dump_parts(pm->parts);
9404103857bSmartin 
9414103857bSmartin 			if (pm->parts->pscheme->secondary_partitions) {
9424103857bSmartin 				const struct disk_partitions *sparts =
9434103857bSmartin 				    pm->parts->pscheme->secondary_partitions(
94483478358Smartin 				    pm->parts, pm->ptstart, false);
9454103857bSmartin 				if (sparts != NULL)
9464103857bSmartin 					dump_parts(sparts);
9474103857bSmartin 			}
9484103857bSmartin 		}
9494103857bSmartin #endif
9504103857bSmartin 
9514103857bSmartin 		pm->no_mbr = disk->dd_no_mbr;
9522575b4dcSmartin 		pm->no_part = disk->dd_no_part;
9532575b4dcSmartin 		if (!pm->no_part) {
9544b2364d9Smartin 			pm->sectorsize = disk->dd_secsize;
9554b2364d9Smartin 			pm->dlcyl = disk->dd_cyl;
9564b2364d9Smartin 			pm->dlhead = disk->dd_head;
9574b2364d9Smartin 			pm->dlsec = disk->dd_sec;
9584b2364d9Smartin 			pm->dlsize = disk->dd_totsec;
9594b2364d9Smartin 			if (pm->dlsize == 0)
9604103857bSmartin 				pm->dlsize = disk->dd_cyl * disk->dd_head
9614103857bSmartin 				    * disk->dd_sec;
9624103857bSmartin 
9634103857bSmartin 			if (pm->parts && pm->parts->pscheme->size_limit != 0
9644103857bSmartin 			    && pm->dlsize > pm->parts->pscheme->size_limit
9654103857bSmartin 			    && ! partman_go) {
9664103857bSmartin 
9674103857bSmartin 				char size[5], limit[5];
9684103857bSmartin 
9694103857bSmartin 				humanize_number(size, sizeof(size),
9704103857bSmartin 				    (uint64_t)pm->dlsize * 512U,
9714103857bSmartin 				    "", HN_AUTOSCALE, HN_B | HN_NOSPACE
9724103857bSmartin 				    | HN_DECIMAL);
9734103857bSmartin 
9744103857bSmartin 				humanize_number(limit, sizeof(limit),
9754103857bSmartin 				    (uint64_t)pm->parts->pscheme->size_limit
9764103857bSmartin 					* 512U,
9774103857bSmartin 				    "", HN_AUTOSCALE, HN_B | HN_NOSPACE
9784103857bSmartin 				    | HN_DECIMAL);
9794103857bSmartin 
9804b2364d9Smartin 				if (logfp)
9814103857bSmartin 					fprintf(logfp,
9824103857bSmartin 					    "disk %s: is too big (%" PRIu64
9834103857bSmartin 					    " blocks, %s), will be truncated\n",
9844103857bSmartin 						pm->diskdev, pm->dlsize,
9854103857bSmartin 						size);
9864103857bSmartin 
9874103857bSmartin 				msg_display_subst(MSG_toobigdisklabel, 5,
9884103857bSmartin 				   pm->diskdev,
9894103857bSmartin 				   msg_string(pm->parts->pscheme->name),
9904103857bSmartin 				   msg_string(pm->parts->pscheme->short_name),
9914103857bSmartin 				   size, limit);
9924103857bSmartin 
9934103857bSmartin 				int sel = -1;
9944103857bSmartin 				const char *err = NULL;
9954103857bSmartin 				process_menu(MENU_convertscheme, &sel);
9964103857bSmartin 				if (sel == 1) {
9974103857bSmartin 					if (!delete_scheme(pm)) {
99850dbef1aSdholland 						return -1;
99950dbef1aSdholland 					}
10004103857bSmartin 					goto again;
10014103857bSmartin 				} else if (sel == 2) {
10024103857bSmartin 					if (!convert_scheme(pm,
10034103857bSmartin 					     partman_go < 0, &err)) {
10044103857bSmartin 						if (err != NULL)
10054103857bSmartin 							err_msg_win(err);
10064103857bSmartin 						return -1;
10074103857bSmartin 					}
10084103857bSmartin 					goto again;
10094103857bSmartin 				} else if (sel == 3) {
10104103857bSmartin 					return -1;
10114103857bSmartin 				}
10124103857bSmartin 				pm->dlsize = pm->parts->pscheme->size_limit;
10134103857bSmartin 			}
10142575b4dcSmartin 		} else {
10152575b4dcSmartin 			pm->sectorsize = 0;
10162575b4dcSmartin 			pm->dlcyl = 0;
10172575b4dcSmartin 			pm->dlhead = 0;
10182575b4dcSmartin 			pm->dlsec = 0;
10192575b4dcSmartin 			pm->dlsize = 0;
10202575b4dcSmartin 			pm->no_mbr = 1;
10212575b4dcSmartin 		}
10224b2364d9Smartin 		pm->dlcylsize = pm->dlhead * pm->dlsec;
102350dbef1aSdholland 
10244b2364d9Smartin 		if (partman_go) {
10254b2364d9Smartin 			pm_getrefdev(pm_new);
10264b2364d9Smartin 			if (SLIST_EMPTY(&pm_head) || pm_last == NULL)
10274b2364d9Smartin 				 SLIST_INSERT_HEAD(&pm_head, pm_new, l);
10284b2364d9Smartin 			else
10294b2364d9Smartin 				 SLIST_INSERT_AFTER(pm_last, pm_new, l);
10304103857bSmartin 			pm_new = malloc(sizeof (struct pm_devs));
10314b2364d9Smartin 			memset(pm_new, 0, sizeof *pm_new);
10324b2364d9Smartin 		} else
10334103857bSmartin 			/* We are not in partman and do not want to process
10344103857bSmartin 			 * all devices, exit */
10354b2364d9Smartin 			break;
10364b2364d9Smartin 	}
103750dbef1aSdholland 
10382575b4dcSmartin 	return numdisks-skipped;
103950dbef1aSdholland }
104050dbef1aSdholland 
104150dbef1aSdholland static int
10424103857bSmartin sort_part_usage_by_mount(const void *a, const void *b)
104350dbef1aSdholland {
10444103857bSmartin 	const struct part_usage_info *pa = a, *pb = b;
10454103857bSmartin 
10464103857bSmartin 	/* sort all real partitions by mount point */
10474103857bSmartin 	if ((pa->instflags & PUIINST_MOUNT) &&
10484103857bSmartin 	    (pb->instflags & PUIINST_MOUNT))
10494103857bSmartin 		return strcmp(pa->mount, pb->mount);
10504103857bSmartin 
10514103857bSmartin 	/* real partitions go first */
10524103857bSmartin 	if (pa->instflags & PUIINST_MOUNT)
10534103857bSmartin 		return -1;
10544103857bSmartin 	if (pb->instflags & PUIINST_MOUNT)
10554103857bSmartin 		return 1;
10564103857bSmartin 
10574103857bSmartin 	/* arbitrary order for all other partitions */
10584103857bSmartin 	if (pa->type == PT_swap)
10594103857bSmartin 		return -1;
10604103857bSmartin 	if (pb->type == PT_swap)
10614103857bSmartin 		return 1;
10624103857bSmartin 	if (pa->type < pb->type)
10634103857bSmartin 		return -1;
10644103857bSmartin 	if (pa->type > pb->type)
10654103857bSmartin 		return 1;
10664103857bSmartin 	if (pa->cur_part_id < pb->cur_part_id)
10674103857bSmartin 		return -1;
10684103857bSmartin 	if (pa->cur_part_id > pb->cur_part_id)
10694103857bSmartin 		return 1;
10704103857bSmartin 	return (uintptr_t)a < (uintptr_t)b ? -1 : 1;
107150dbef1aSdholland }
107250dbef1aSdholland 
107350dbef1aSdholland int
10744103857bSmartin make_filesystems(struct install_partition_desc *install)
107550dbef1aSdholland {
10764103857bSmartin 	int error = 0, partno = -1;
10774103857bSmartin 	char *newfs = NULL, devdev[PATH_MAX], rdev[PATH_MAX];
10784103857bSmartin 	size_t i;
10794103857bSmartin 	struct part_usage_info *ptn;
10804103857bSmartin 	struct disk_partitions *parts;
10814103857bSmartin 	const char *mnt_opts = NULL, *fsname = NULL;
108250dbef1aSdholland 
1083b1fa9754Smartin 	if (pm->cur_system)
1084b1fa9754Smartin 		return 1;
1085b1fa9754Smartin 
10862575b4dcSmartin 	if (pm->no_part) {
10872575b4dcSmartin 		/* check if this target device already has a ffs */
10884103857bSmartin 		snprintf(rdev, sizeof rdev, _PATH_DEV "/r%s", pm->diskdev);
10894103857bSmartin 		error = fsck_preen(rdev, "ffs", true);
10902575b4dcSmartin 		if (error) {
10912575b4dcSmartin 			if (!ask_noyes(MSG_No_filesystem_newfs))
10922575b4dcSmartin 				return EINVAL;
10932575b4dcSmartin 			error = run_program(RUN_DISPLAY | RUN_PROGRESS,
10944103857bSmartin 			    "/sbin/newfs -V2 -O2 %s", rdev);
10952575b4dcSmartin 		}
10962575b4dcSmartin 
10974f30cbf3Smartin 		md_pre_mount(install, 0);
10982575b4dcSmartin 
10992575b4dcSmartin 		make_target_dir("/");
11004103857bSmartin 
11014103857bSmartin 		snprintf(devdev, sizeof devdev, _PATH_DEV "%s", pm->diskdev);
11022575b4dcSmartin 		error = target_mount_do("-o async", devdev, "/");
11032575b4dcSmartin 		if (error) {
11044103857bSmartin 			msg_display_subst(MSG_mountfail, 2, devdev, "/");
11054103857bSmartin 			hit_enter_to_continue(NULL, NULL);
11062575b4dcSmartin 		}
11072575b4dcSmartin 
11084103857bSmartin 		return error;
11094103857bSmartin 	}
111050dbef1aSdholland 
111150dbef1aSdholland 	/* Making new file systems and mounting them */
111250dbef1aSdholland 
111350dbef1aSdholland 	/* sort to ensure /usr/local is mounted after /usr (etc) */
11144103857bSmartin 	qsort(install->infos, install->num, sizeof(*install->infos),
11154103857bSmartin 	    sort_part_usage_by_mount);
111650dbef1aSdholland 
11174103857bSmartin 	for (i = 0; i < install->num; i++) {
111850dbef1aSdholland 		/*
111987c16c7aSmartin 		 * Newfs all file systems mareked as needing this.
112087c16c7aSmartin 		 * Mount the ones that have a mountpoint in the target.
112150dbef1aSdholland 		 */
11224103857bSmartin 		ptn = &install->infos[i];
11234103857bSmartin 		parts = ptn->parts;
11240dfd6624Smartin 		newfs = NULL;
11250dfd6624Smartin 		fsname = NULL;
112650dbef1aSdholland 
1127a8e7688bSmartin 		if (ptn->size == 0 || parts == NULL|| ptn->type == PT_swap)
112850dbef1aSdholland 			continue;
112950dbef1aSdholland 
11304103857bSmartin 		if (parts->pscheme->get_part_device(parts, ptn->cur_part_id,
11314103857bSmartin 		    devdev, sizeof devdev, &partno, parent_device_only, false)
11324103857bSmartin 		    && is_active_rootpart(devdev, partno))
11334103857bSmartin 			continue;
11344103857bSmartin 
11354103857bSmartin 		parts->pscheme->get_part_device(parts, ptn->cur_part_id,
11364103857bSmartin 		    devdev, sizeof devdev, &partno, plain_name, true);
11374103857bSmartin 
11384103857bSmartin 		parts->pscheme->get_part_device(parts, ptn->cur_part_id,
11394103857bSmartin 		    rdev, sizeof rdev, &partno, raw_dev_name, true);
11404b2364d9Smartin 
11414103857bSmartin 		switch (ptn->fs_type) {
114250dbef1aSdholland 		case FS_APPLEUFS:
11434103857bSmartin 			asprintf(&newfs, "/sbin/newfs");
11444103857bSmartin 			mnt_opts = "-tffs -o async";
11454103857bSmartin 			fsname = "ffs";
114650dbef1aSdholland 			break;
114750dbef1aSdholland 		case FS_BSDFFS:
114850dbef1aSdholland 			asprintf(&newfs,
11494103857bSmartin 			    "/sbin/newfs -V2 -O %d",
11504103857bSmartin 			    ptn->fs_version == 2 ? 2 : 1);
11514103857bSmartin 			if (ptn->mountflags & PUIMNT_LOG)
11524103857bSmartin 				mnt_opts = "-tffs -o log";
115350dbef1aSdholland 			else
11544103857bSmartin 				mnt_opts = "-tffs -o async";
11554103857bSmartin 			fsname = "ffs";
115650dbef1aSdholland 			break;
115750dbef1aSdholland 		case FS_BSDLFS:
11584103857bSmartin 			asprintf(&newfs, "/sbin/newfs_lfs");
11594103857bSmartin 			mnt_opts = "-tlfs";
11604103857bSmartin 			fsname = "lfs";
116150dbef1aSdholland 			break;
116250dbef1aSdholland 		case FS_MSDOS:
116350dbef1aSdholland 			asprintf(&newfs, "/sbin/newfs_msdos");
11644103857bSmartin 			mnt_opts = "-tmsdos";
11654103857bSmartin 			fsname = "msdos";
116650dbef1aSdholland 			break;
116750dbef1aSdholland 		case FS_SYSVBFS:
116850dbef1aSdholland 			asprintf(&newfs, "/sbin/newfs_sysvbfs");
11694103857bSmartin 			mnt_opts = "-tsysvbfs";
11704103857bSmartin 			fsname = "sysvbfs";
117150dbef1aSdholland 			break;
11720dfd6624Smartin 		case FS_V7:
11730dfd6624Smartin 			asprintf(&newfs, "/sbin/newfs_v7fs");
11740dfd6624Smartin 			mnt_opts = "-tv7fs";
11750dfd6624Smartin 			fsname = "v7fs";
11760dfd6624Smartin 			break;
117750dbef1aSdholland 		case FS_EX2FS:
117850dbef1aSdholland 			asprintf(&newfs, "/sbin/newfs_ext2fs");
11794103857bSmartin 			mnt_opts = "-text2fs";
11804103857bSmartin 			fsname = "ext2fs";
118150dbef1aSdholland 			break;
118250dbef1aSdholland 		}
11834103857bSmartin 		if ((ptn->instflags & PUIINST_NEWFS) && newfs != NULL) {
11844103857bSmartin 			if (ptn->fs_type == FS_MSDOS) {
118550dbef1aSdholland 			        /* newfs only if mount fails */
118650dbef1aSdholland 			        if (run_program(RUN_SILENT | RUN_ERROR_OK,
11874103857bSmartin 				    "mount -rt msdos %s /mnt2", devdev) != 0)
118850dbef1aSdholland 					error = run_program(
118950dbef1aSdholland 					    RUN_DISPLAY | RUN_PROGRESS,
11904103857bSmartin 					    "%s %s",
11914103857bSmartin 					    newfs, rdev);
119250dbef1aSdholland 				else {
119350dbef1aSdholland 					run_program(RUN_SILENT | RUN_ERROR_OK,
119450dbef1aSdholland 					    "umount /mnt2");
119550dbef1aSdholland 					error = 0;
119650dbef1aSdholland 				}
11974103857bSmartin 			} else {
119850dbef1aSdholland 				error = run_program(RUN_DISPLAY | RUN_PROGRESS,
11994103857bSmartin 			    "%s %s", newfs, rdev);
12004103857bSmartin 			}
12010dfd6624Smartin 		} else if ((ptn->instflags & (PUIINST_MOUNT|PUIINST_BOOT))
12020dfd6624Smartin 		    && fsname != NULL) {
120350dbef1aSdholland 			/* We'd better check it isn't dirty */
12044103857bSmartin 			error = fsck_preen(devdev, fsname, false);
120550dbef1aSdholland 		}
120650dbef1aSdholland 		free(newfs);
12074103857bSmartin 		if (error != 0)
120850dbef1aSdholland 			return error;
120950dbef1aSdholland 
12104103857bSmartin 		ptn->instflags &= ~PUIINST_NEWFS;
12114f30cbf3Smartin 		md_pre_mount(install, i);
121250dbef1aSdholland 
12134103857bSmartin 		if (partman_go == 0 && (ptn->instflags & PUIINST_MOUNT) &&
12144103857bSmartin 				mnt_opts != NULL) {
12154103857bSmartin 			make_target_dir(ptn->mount);
12164103857bSmartin 			error = target_mount_do(mnt_opts, devdev,
12174103857bSmartin 			    ptn->mount);
121850dbef1aSdholland 			if (error) {
12194103857bSmartin 				msg_display_subst(MSG_mountfail, 2, devdev,
12204103857bSmartin 				    ptn->mount);
12214103857bSmartin 				hit_enter_to_continue(NULL, NULL);
122250dbef1aSdholland 				return error;
122350dbef1aSdholland 			}
122450dbef1aSdholland 		}
122550dbef1aSdholland 	}
122650dbef1aSdholland 	return 0;
122750dbef1aSdholland }
122850dbef1aSdholland 
122950dbef1aSdholland int
12304103857bSmartin make_fstab(struct install_partition_desc *install)
123150dbef1aSdholland {
123250dbef1aSdholland 	FILE *f;
12334103857bSmartin 	const char *dump_dev = NULL;
12344103857bSmartin 	const char *dev;
12354103857bSmartin 	char dev_buf[PATH_MAX], swap_dev[PATH_MAX];
12364103857bSmartin 
1237b1fa9754Smartin 	if (pm->cur_system)
1238b1fa9754Smartin 		return 1;
1239b1fa9754Smartin 
12404103857bSmartin 	swap_dev[0] = 0;
124150dbef1aSdholland 
124250dbef1aSdholland 	/* Create the fstab. */
124350dbef1aSdholland 	make_target_dir("/etc");
124450dbef1aSdholland 	f = target_fopen("/etc/fstab", "w");
124550dbef1aSdholland 	scripting_fprintf(NULL, "cat <<EOF >%s/etc/fstab\n", target_prefix());
124650dbef1aSdholland 
12474b2364d9Smartin 	if (logfp)
12484b2364d9Smartin 		(void)fprintf(logfp,
12494103857bSmartin 		    "Making %s/etc/fstab (%s).\n", target_prefix(),
12504103857bSmartin 		    pm->diskdev);
12514b2364d9Smartin 
125250dbef1aSdholland 	if (f == NULL) {
125350dbef1aSdholland 		msg_display(MSG_createfstab);
125450dbef1aSdholland 		if (logfp)
125550dbef1aSdholland 			(void)fprintf(logfp, "Failed to make /etc/fstab!\n");
12564103857bSmartin 		hit_enter_to_continue(NULL, NULL);
12574b2364d9Smartin #ifndef DEBUG
125850dbef1aSdholland 		return 1;
125950dbef1aSdholland #else
126050dbef1aSdholland 		f = stdout;
126150dbef1aSdholland #endif
126250dbef1aSdholland 	}
126350dbef1aSdholland 
1264c52e6b59Smartin 	scripting_fprintf(f, "# NetBSD /etc/fstab\n# See /usr/share/examples/"
1265c52e6b59Smartin 			"fstab/ for more examples.\n");
12662575b4dcSmartin 
12672575b4dcSmartin 	if (pm->no_part) {
12682575b4dcSmartin 		/* single dk? target */
12692575b4dcSmartin 		char buf[200], parent[200], swap[200], *prompt;
12702575b4dcSmartin 		int res;
12712575b4dcSmartin 
12722575b4dcSmartin 		if (!get_name_and_parent(pm->diskdev, buf, parent))
12732575b4dcSmartin 			goto done_with_disks;
1274a7267d53Smartin 		scripting_fprintf(f, NAME_PREFIX "%s\t/\tffs\trw\t\t1 1\n",
12752575b4dcSmartin 		    buf);
12762575b4dcSmartin 		if (!find_swap_part_on(parent, swap))
12772575b4dcSmartin 			goto done_with_disks;
12784103857bSmartin 		const char *args[] = { parent, swap };
12794103857bSmartin 		prompt = str_arg_subst(msg_string(MSG_Auto_add_swap_part),
12804103857bSmartin 		    __arraycount(args), args);
12812575b4dcSmartin 		res = ask_yesno(prompt);
12822575b4dcSmartin 		free(prompt);
12832575b4dcSmartin 		if (res)
1284a7267d53Smartin 			scripting_fprintf(f, NAME_PREFIX "%s\tnone"
12852575b4dcSmartin 			    "\tswap\tsw,dp\t\t0 0\n", swap);
12862575b4dcSmartin 		goto done_with_disks;
12872575b4dcSmartin 	}
12882575b4dcSmartin 
12894103857bSmartin 	for (size_t i = 0; i < install->num; i++) {
12904103857bSmartin 
12914103857bSmartin 		const struct part_usage_info *ptn = &install->infos[i];
12924103857bSmartin 
12934103857bSmartin 		if (ptn->type != PT_swap &&
12944103857bSmartin 		    (ptn->instflags & PUIINST_MOUNT) == 0)
12954103857bSmartin 			continue;
12964103857bSmartin 
129750dbef1aSdholland 		const char *s = "";
12984103857bSmartin 		const char *mp = ptn->mount;
129950dbef1aSdholland 		const char *fstype = "ffs";
130050dbef1aSdholland 		int fsck_pass = 0, dump_freq = 0;
130150dbef1aSdholland 
13024103857bSmartin 		if (ptn->parts->pscheme->get_part_device(ptn->parts,
13034103857bSmartin 			    ptn->cur_part_id, dev_buf, sizeof dev_buf, NULL,
13044103857bSmartin 			    logical_name, true))
13054103857bSmartin 			dev = dev_buf;
13064b2364d9Smartin 		else
13074103857bSmartin 			dev = NULL;
13084b2364d9Smartin 
130950dbef1aSdholland 		if (!*mp) {
131050dbef1aSdholland 			/*
131150dbef1aSdholland 			 * No mount point specified, comment out line and
131250dbef1aSdholland 			 * use /mnt as a placeholder for the mount point.
131350dbef1aSdholland 			 */
131450dbef1aSdholland 			s = "# ";
131550dbef1aSdholland 			mp = "/mnt";
131650dbef1aSdholland 		}
131750dbef1aSdholland 
13184103857bSmartin 		switch (ptn->fs_type) {
131950dbef1aSdholland 		case FS_UNUSED:
132050dbef1aSdholland 			continue;
132150dbef1aSdholland 		case FS_BSDLFS:
132250dbef1aSdholland 			/* If there is no LFS, just comment it out. */
132350dbef1aSdholland 			if (!check_lfs_progs())
132450dbef1aSdholland 				s = "# ";
132550dbef1aSdholland 			fstype = "lfs";
132650dbef1aSdholland 			/* FALLTHROUGH */
132750dbef1aSdholland 		case FS_BSDFFS:
132850dbef1aSdholland 			fsck_pass = (strcmp(mp, "/") == 0) ? 1 : 2;
132950dbef1aSdholland 			dump_freq = 1;
133050dbef1aSdholland 			break;
133150dbef1aSdholland 		case FS_MSDOS:
133250dbef1aSdholland 			fstype = "msdos";
133350dbef1aSdholland 			break;
133450dbef1aSdholland 		case FS_SWAP:
13354103857bSmartin 			if (swap_dev[0] == 0) {
13364103857bSmartin 				strncpy(swap_dev, dev, sizeof swap_dev);
133750dbef1aSdholland 				dump_dev = ",dp";
133850dbef1aSdholland 			} else {
133950dbef1aSdholland 				dump_dev = "";
134050dbef1aSdholland 			}
13414103857bSmartin 			scripting_fprintf(f, "%s\t\tnone\tswap\tsw%s\t\t 0 0\n",
13424b2364d9Smartin 				dev, dump_dev);
134350dbef1aSdholland 			continue;
134450dbef1aSdholland 		case FS_SYSVBFS:
134550dbef1aSdholland 			fstype = "sysvbfs";
134650dbef1aSdholland 			make_target_dir("/stand");
134750dbef1aSdholland 			break;
134850dbef1aSdholland 		default:
134950dbef1aSdholland 			fstype = "???";
135050dbef1aSdholland 			s = "# ";
135150dbef1aSdholland 			break;
135250dbef1aSdholland 		}
135350dbef1aSdholland 		/* The code that remounts root rw doesn't check the partition */
13544103857bSmartin 		if (strcmp(mp, "/") == 0 &&
13554103857bSmartin 		    (ptn->instflags & PUIINST_MOUNT) == 0)
135650dbef1aSdholland 			s = "# ";
135750dbef1aSdholland 
135850dbef1aSdholland  		scripting_fprintf(f,
13594103857bSmartin 		  "%s%s\t\t%s\t%s\trw%s%s%s%s%s%s%s%s\t\t %d %d\n",
13604b2364d9Smartin 		   s, dev, mp, fstype,
13614103857bSmartin 		   ptn->mountflags & PUIMNT_LOG ? ",log" : "",
1362b8a71b59Smartin 		   ptn->mountflags & PUIMNT_NOAUTO ? ",noauto" : "",
13634103857bSmartin 		   ptn->mountflags & PUIMNT_ASYNC ? ",async" : "",
13644103857bSmartin 		   ptn->mountflags & PUIMNT_NOATIME ? ",noatime" : "",
13654103857bSmartin 		   ptn->mountflags & PUIMNT_NODEV ? ",nodev" : "",
13664103857bSmartin 		   ptn->mountflags & PUIMNT_NODEVMTIME ? ",nodevmtime" : "",
13674103857bSmartin 		   ptn->mountflags & PUIMNT_NOEXEC ? ",noexec" : "",
13684103857bSmartin 		   ptn->mountflags & PUIMNT_NOSUID ? ",nosuid" : "",
136950dbef1aSdholland 		   dump_freq, fsck_pass);
137050dbef1aSdholland 	}
13714103857bSmartin 
13722575b4dcSmartin done_with_disks:
13734103857bSmartin 	if (tmp_ramdisk_size > 0) {
137450dbef1aSdholland #ifdef HAVE_TMPFS
137550dbef1aSdholland 		scripting_fprintf(f, "tmpfs\t\t/tmp\ttmpfs\trw,-m=1777,-s=%"
13764103857bSmartin 		    PRIu64 "\n",
137750dbef1aSdholland 		    tmp_ramdisk_size * 512);
137850dbef1aSdholland #else
13794103857bSmartin 		if (swap_dev[0] != 0)
13804103857bSmartin 			scripting_fprintf(f, "%s\t\t/tmp\tmfs\trw,-s=%"
13814103857bSmartin 			    PRIu64 "\n", swap_dev, tmp_ramdisk_size);
138250dbef1aSdholland 		else
138350dbef1aSdholland 			scripting_fprintf(f, "swap\t\t/tmp\tmfs\trw,-s=%"
13844103857bSmartin 			    PRIu64 "\n", tmp_ramdisk_size);
138550dbef1aSdholland #endif
138650dbef1aSdholland 	}
138750dbef1aSdholland 
13883b44a3d7Smartin 	if (cdrom_dev[0] == 0)
13893b44a3d7Smartin 		get_default_cdrom(cdrom_dev, sizeof(cdrom_dev));
13903b44a3d7Smartin 
139150dbef1aSdholland 	/* Add /kern, /proc and /dev/pts to fstab and make mountpoint. */
139250dbef1aSdholland 	scripting_fprintf(f, "kernfs\t\t/kern\tkernfs\trw\n");
139350dbef1aSdholland 	scripting_fprintf(f, "ptyfs\t\t/dev/pts\tptyfs\trw\n");
139450dbef1aSdholland 	scripting_fprintf(f, "procfs\t\t/proc\tprocfs\trw\n");
139550dbef1aSdholland 	scripting_fprintf(f, "/dev/%s\t\t/cdrom\tcd9660\tro,noauto\n",
13963b44a3d7Smartin 	    cdrom_dev);
139750dbef1aSdholland 	scripting_fprintf(f, "%stmpfs\t\t/var/shm\ttmpfs\trw,-m1777,-sram%%25\n",
139850dbef1aSdholland 	    tmpfs_on_var_shm() ? "" : "#");
139950dbef1aSdholland 	make_target_dir("/kern");
140050dbef1aSdholland 	make_target_dir("/proc");
140150dbef1aSdholland 	make_target_dir("/dev/pts");
140250dbef1aSdholland 	make_target_dir("/cdrom");
140350dbef1aSdholland 	make_target_dir("/var/shm");
140450dbef1aSdholland 
140550dbef1aSdholland 	scripting_fprintf(NULL, "EOF\n");
140650dbef1aSdholland 
140750dbef1aSdholland 	fclose(f);
140850dbef1aSdholland 	fflush(NULL);
140950dbef1aSdholland 	return 0;
141050dbef1aSdholland }
141150dbef1aSdholland 
1412a7267d53Smartin static bool
1413a7267d53Smartin find_part_by_name(const char *name, struct disk_partitions **parts,
1414a7267d53Smartin     part_id *pno)
141550dbef1aSdholland {
1416a7267d53Smartin 	struct pm_devs *i;
1417a7267d53Smartin 	struct disk_partitions *ps;
1418a7267d53Smartin 	part_id id;
1419a7267d53Smartin 	struct disk_desc disks[MAX_DISKS];
1420a7267d53Smartin 	int n, cnt;
142150dbef1aSdholland 
1422a7267d53Smartin 	if (SLIST_EMPTY(&pm_head)) {
1423a7267d53Smartin 		/*
1424a7267d53Smartin 		 * List has not been filled, only "pm" is valid - check
1425a7267d53Smartin 		 * that first.
1426a7267d53Smartin 		 */
1427a7267d53Smartin 		if (pm->parts->pscheme->find_by_name != NULL) {
1428a7267d53Smartin 			id = pm->parts->pscheme->find_by_name(pm->parts, name);
1429a7267d53Smartin 			if (id != NO_PART) {
1430a7267d53Smartin 				*pno = id;
1431a7267d53Smartin 				*parts = pm->parts;
1432a7267d53Smartin 				return true;
1433a7267d53Smartin 			}
1434a7267d53Smartin 		}
1435a7267d53Smartin 		/*
1436a7267d53Smartin 		 * Not that easy - check all other disks
1437a7267d53Smartin 		 */
1438a7267d53Smartin 		cnt = get_disks(disks, false);
1439a7267d53Smartin 		for (n = 0; n < cnt; n++) {
1440a7267d53Smartin 			if (strcmp(disks[n].dd_name, pm->diskdev) == 0)
1441a7267d53Smartin 				continue;
1442a7267d53Smartin 			ps = partitions_read_disk(disks[n].dd_name,
1443a7267d53Smartin 			    disks[n].dd_totsec);
1444a7267d53Smartin 			if (ps == NULL)
1445a7267d53Smartin 				continue;
1446a7267d53Smartin 			if (ps->pscheme->find_by_name == NULL)
1447a7267d53Smartin 				continue;
1448a7267d53Smartin 			id = ps->pscheme->find_by_name(ps, name);
1449a7267d53Smartin 			if (id != NO_PART) {
1450a7267d53Smartin 				*pno = id;
1451a7267d53Smartin 				*parts = ps;
1452a7267d53Smartin 				return true;	/* XXX this leaks memory */
1453a7267d53Smartin 			}
1454a7267d53Smartin 			ps->pscheme->free(ps);
1455a7267d53Smartin 		}
14566de47033Smartin 	} else {
1457a7267d53Smartin 		SLIST_FOREACH(i, &pm_head, l) {
1458a7267d53Smartin 			if (i->parts == NULL)
1459a7267d53Smartin 				continue;
1460a7267d53Smartin 			if (i->parts->pscheme->find_by_name == NULL)
1461a7267d53Smartin 				continue;
1462a7267d53Smartin 			id = i->parts->pscheme->find_by_name(i->parts, name);
1463a7267d53Smartin 			if (id == NO_PART)
1464a7267d53Smartin 				continue;
1465a7267d53Smartin 			*pno = id;
1466a7267d53Smartin 			*parts = i->parts;
1467a7267d53Smartin 			return true;
1468a7267d53Smartin 		}
14696de47033Smartin 	}
14706de47033Smartin 
1471a7267d53Smartin 	*pno = NO_PART;
1472a7267d53Smartin 	*parts = NULL;
1473a7267d53Smartin 	return false;
1474a7267d53Smartin }
1475a7267d53Smartin 
1476a7267d53Smartin static int
1477a7267d53Smartin /*ARGSUSED*/
1478a7267d53Smartin process_found_fs(struct data *list, size_t num, const struct lookfor *item,
1479a7267d53Smartin     bool with_fsck)
1480a7267d53Smartin {
1481a7267d53Smartin 	int error;
1482a7267d53Smartin 	char rdev[PATH_MAX], dev[PATH_MAX],
1483a7267d53Smartin 	    options[STRSIZE], tmp[STRSIZE], *op, *last;
1484a7267d53Smartin 	const char *fsname = (const char*)item->var;
1485a7267d53Smartin 	part_id pno;
1486a7267d53Smartin 	struct disk_partitions *parts;
1487*d7f55badSmartin 	size_t len;
1488*d7f55badSmartin 	bool first, is_root;
1489a7267d53Smartin 
1490a7267d53Smartin 	if (num < 2 || strstr(list[2].u.s_val, "noauto") != NULL)
1491a7267d53Smartin 		return 0;
1492a7267d53Smartin 
1493*d7f55badSmartin 	is_root = strcmp(list[1].u.s_val, "/") == 0;
1494*d7f55badSmartin 	if (is_root && target_mounted())
1495a7267d53Smartin 		return 0;
1496a7267d53Smartin 
1497a7267d53Smartin 	if (strcmp(item->head, name_prefix) == 0) {
1498a7267d53Smartin 		/* this fstab entry uses NAME= syntax */
1499a7267d53Smartin 		if (!find_part_by_name(list[0].u.s_val,
1500a7267d53Smartin 		    &parts, &pno) || parts == NULL || pno == NO_PART)
1501a7267d53Smartin 			return 0;
1502a7267d53Smartin 		parts->pscheme->get_part_device(parts, pno,
1503a7267d53Smartin 		    dev, sizeof(dev), NULL, plain_name, true);
1504a7267d53Smartin 		parts->pscheme->get_part_device(parts, pno,
1505a7267d53Smartin 		    rdev, sizeof(rdev), NULL, raw_dev_name, true);
1506a7267d53Smartin 	} else {
1507*d7f55badSmartin 		/* this fstab entry uses the plain device name */
1508*d7f55badSmartin 		if (is_root) {
1509*d7f55badSmartin 			/*
1510*d7f55badSmartin 			 * PR 54480: we can not use the current device name
1511*d7f55badSmartin 			 * as it might be different from the real environment.
1512*d7f55badSmartin 			 * This is an abuse of the functionality, but it used
1513*d7f55badSmartin 			 * to work before (and still does work if only a single
1514*d7f55badSmartin 			 * target disk is involved).
1515*d7f55badSmartin 			 * Use the device name from the current "pm" instead.
1516*d7f55badSmartin 			 */
1517*d7f55badSmartin 			strcpy(rdev, "/dev/r");
1518*d7f55badSmartin 			strlcat(rdev, pm->diskdev, sizeof(rdev));
1519*d7f55badSmartin 			strcpy(dev, "/dev/");
1520*d7f55badSmartin 			strlcat(dev, pm->diskdev, sizeof(dev));
1521*d7f55badSmartin 			/* copy over the partition letter, if any */
1522*d7f55badSmartin 			len = strlen(list[0].u.s_val);
1523*d7f55badSmartin 			if (list[0].u.s_val[len-1] >= 'a' &&
1524*d7f55badSmartin 			    list[0].u.s_val[len-1] <=
1525*d7f55badSmartin 			    ('a' + getmaxpartitions())) {
1526*d7f55badSmartin 				strlcat(rdev, &list[0].u.s_val[len-1],
1527*d7f55badSmartin 				    sizeof(rdev));
1528*d7f55badSmartin 				strlcat(dev, &list[0].u.s_val[len-1],
1529*d7f55badSmartin 				    sizeof(dev));
1530*d7f55badSmartin 			}
1531*d7f55badSmartin 		} else {
1532a7267d53Smartin 			strcpy(rdev, "/dev/r");
1533a7267d53Smartin 			strlcat(rdev, list[0].u.s_val, sizeof(rdev));
1534a7267d53Smartin 			strcpy(dev, "/dev/");
1535a7267d53Smartin 			strlcat(dev, list[0].u.s_val, sizeof(dev));
1536a7267d53Smartin 		}
1537*d7f55badSmartin 	}
1538a7267d53Smartin 
1539a7267d53Smartin 	if (with_fsck) {
1540a7267d53Smartin 		/* need the raw device for fsck_preen */
1541a7267d53Smartin 		error = fsck_preen(rdev, fsname, false);
154250dbef1aSdholland 		if (error != 0)
154350dbef1aSdholland 			return error;
1544a7267d53Smartin 	}
154550dbef1aSdholland 
1546a7267d53Smartin 	/* add mount option for fs type */
1547a7267d53Smartin 	strcpy(options, "-t ");
1548a7267d53Smartin 	strlcat(options, fsname, sizeof(options));
1549a7267d53Smartin 
1550a7267d53Smartin 	/* extract mount options from fstab */
1551a7267d53Smartin 	strlcpy(tmp, list[2].u.s_val, sizeof(tmp));
1552a7267d53Smartin 	for (first = true, op = strtok_r(tmp, ",", &last); op != NULL;
1553a7267d53Smartin 	    op = strtok_r(NULL, ",", &last)) {
1554a7267d53Smartin 		if (strcmp(op, FSTAB_RW) == 0 ||
1555a7267d53Smartin 		    strcmp(op, FSTAB_RQ) == 0 ||
1556a7267d53Smartin 		    strcmp(op, FSTAB_RO) == 0 ||
1557a7267d53Smartin 		    strcmp(op, FSTAB_SW) == 0 ||
1558a7267d53Smartin 		    strcmp(op, FSTAB_DP) == 0 ||
1559a7267d53Smartin 		    strcmp(op, FSTAB_XX) == 0)
1560a7267d53Smartin 			continue;
1561a7267d53Smartin 		if (first) {
1562a7267d53Smartin 			first = false;
1563a7267d53Smartin 			strlcat(options, " -o ", sizeof(options));
1564a7267d53Smartin 		} else {
1565a7267d53Smartin 			strlcat(options, ",", sizeof(options));
1566a7267d53Smartin 		}
1567a7267d53Smartin 		strlcat(options, op, sizeof(options));
1568a7267d53Smartin 	}
1569a7267d53Smartin 
1570a7267d53Smartin 	error = target_mount(options, dev, list[1].u.s_val);
157150dbef1aSdholland 	if (error != 0) {
157224ecf24eSchristos 		msg_fmt_display(MSG_mount_failed, "%s", list[0].u.s_val);
1573e21052b4Smartin 		if (!ask_noyes(NULL))
157450dbef1aSdholland 			return error;
157550dbef1aSdholland 	}
157650dbef1aSdholland 	return 0;
157750dbef1aSdholland }
157850dbef1aSdholland 
157950dbef1aSdholland static int
158050dbef1aSdholland /*ARGSUSED*/
1581a7267d53Smartin found_fs(struct data *list, size_t num, const struct lookfor *item)
158250dbef1aSdholland {
1583a7267d53Smartin 	return process_found_fs(list, num, item, true);
158450dbef1aSdholland }
1585a7267d53Smartin 
1586a7267d53Smartin static int
1587a7267d53Smartin /*ARGSUSED*/
1588a7267d53Smartin found_fs_nocheck(struct data *list, size_t num, const struct lookfor *item)
1589a7267d53Smartin {
1590a7267d53Smartin 	return process_found_fs(list, num, item, false);
1591a7267d53Smartin }
159250dbef1aSdholland 
159350dbef1aSdholland /*
159450dbef1aSdholland  * Do an fsck. On failure, inform the user by showing a warning
159550dbef1aSdholland  * message and doing menu_ok() before proceeding.
15964103857bSmartin  * The device passed should be the full qualified path to raw disk
15974103857bSmartin  * (e.g. /dev/rwd0a).
159850dbef1aSdholland  * Returns 0 on success, or nonzero return code from fsck() on failure.
159950dbef1aSdholland  */
160050dbef1aSdholland static int
16014103857bSmartin fsck_preen(const char *disk, const char *fsname, bool silent)
160250dbef1aSdholland {
16034103857bSmartin 	char *prog, err[12];
160450dbef1aSdholland 	int error;
160550dbef1aSdholland 
160650dbef1aSdholland 	if (fsname == NULL)
160750dbef1aSdholland 		return 0;
160850dbef1aSdholland 	/* first, check if fsck program exists, if not, assume ok */
160950dbef1aSdholland 	asprintf(&prog, "/sbin/fsck_%s", fsname);
161050dbef1aSdholland 	if (prog == NULL)
161150dbef1aSdholland 		return 0;
16124d3ac9f2Smartin 	if (access(prog, X_OK) != 0) {
16134d3ac9f2Smartin 		free(prog);
161450dbef1aSdholland 		return 0;
16154d3ac9f2Smartin 	}
161650dbef1aSdholland 	if (!strcmp(fsname,"ffs"))
16174103857bSmartin 		fixsb(prog, disk);
16184103857bSmartin 	error = run_program(silent? RUN_SILENT|RUN_ERROR_OK : 0, "%s -p -q %s", prog, disk);
161950dbef1aSdholland 	free(prog);
16202575b4dcSmartin 	if (error != 0 && !silent) {
16214103857bSmartin 		sprintf(err, "%d", error);
16224103857bSmartin 		msg_display_subst(msg_string(MSG_badfs), 3,
16234103857bSmartin 		    disk, fsname, err);
1624e21052b4Smartin 		if (ask_noyes(NULL))
162550dbef1aSdholland 			error = 0;
162650dbef1aSdholland 		/* XXX at this point maybe we should run a full fsck? */
162750dbef1aSdholland 	}
162850dbef1aSdholland 	return error;
162950dbef1aSdholland }
163050dbef1aSdholland 
163150dbef1aSdholland /* This performs the same function as the etc/rc.d/fixsb script
163250dbef1aSdholland  * which attempts to correct problems with ffs1 filesystems
163350dbef1aSdholland  * which may have been introduced by booting a netbsd-current kernel
163450dbef1aSdholland  * from between April of 2003 and January 2004. For more information
163550dbef1aSdholland  * This script was developed as a response to NetBSD pr install/25138
163650dbef1aSdholland  * Additional prs regarding the original issue include:
163750dbef1aSdholland  *  bin/17910 kern/21283 kern/21404 port-macppc/23925 port-macppc/23926
163850dbef1aSdholland  */
163950dbef1aSdholland static void
16404103857bSmartin fixsb(const char *prog, const char *disk)
164150dbef1aSdholland {
164250dbef1aSdholland 	int fd;
164350dbef1aSdholland 	int rval;
164450dbef1aSdholland 	union {
164550dbef1aSdholland 		struct fs fs;
164650dbef1aSdholland 		char buf[SBLOCKSIZE];
164750dbef1aSdholland 	} sblk;
164850dbef1aSdholland 	struct fs *fs = &sblk.fs;
164950dbef1aSdholland 
16504103857bSmartin 	fd = open(disk, O_RDONLY);
165150dbef1aSdholland 	if (fd == -1)
165250dbef1aSdholland 		return;
165350dbef1aSdholland 
165450dbef1aSdholland 	/* Read ffsv1 main superblock */
165550dbef1aSdholland 	rval = pread(fd, sblk.buf, sizeof sblk.buf, SBLOCK_UFS1);
165650dbef1aSdholland 	close(fd);
165750dbef1aSdholland 	if (rval != sizeof sblk.buf)
165850dbef1aSdholland 		return;
165950dbef1aSdholland 
166050dbef1aSdholland 	if (fs->fs_magic != FS_UFS1_MAGIC &&
166150dbef1aSdholland 	    fs->fs_magic != FS_UFS1_MAGIC_SWAPPED)
166250dbef1aSdholland 		/* Not FFSv1 */
166350dbef1aSdholland 		return;
166450dbef1aSdholland 	if (fs->fs_old_flags & FS_FLAGS_UPDATED)
166550dbef1aSdholland 		/* properly updated fslevel 4 */
166650dbef1aSdholland 		return;
166750dbef1aSdholland 	if (fs->fs_bsize != fs->fs_maxbsize)
166850dbef1aSdholland 		/* not messed up */
166950dbef1aSdholland 		return;
167050dbef1aSdholland 
167150dbef1aSdholland 	/*
167250dbef1aSdholland 	 * OK we have a munged fs, first 'upgrade' to fslevel 4,
167350dbef1aSdholland 	 * We specify -b16 in order to stop fsck bleating that the
167450dbef1aSdholland 	 * sb doesn't match the first alternate.
167550dbef1aSdholland 	 */
167650dbef1aSdholland 	run_program(RUN_DISPLAY | RUN_PROGRESS,
16774103857bSmartin 	    "%s -p -b 16 -c 4 %s", prog, disk);
167850dbef1aSdholland 	/* Then downgrade to fslevel 3 */
167950dbef1aSdholland 	run_program(RUN_DISPLAY | RUN_PROGRESS,
16804103857bSmartin 	    "%s -p -c 3 %s", prog, disk);
168150dbef1aSdholland }
168250dbef1aSdholland 
168350dbef1aSdholland /*
168450dbef1aSdholland  * fsck and mount the root partition.
16854103857bSmartin  * devdev is the fully qualified block device name.
168650dbef1aSdholland  */
168750dbef1aSdholland static int
1688a7267d53Smartin mount_root(const char *devdev, bool first, bool writeable,
1689a7267d53Smartin      struct install_partition_desc *install)
169050dbef1aSdholland {
169150dbef1aSdholland 	int	error;
169250dbef1aSdholland 
16934103857bSmartin 	error = fsck_preen(devdev, "ffs", false);
169450dbef1aSdholland 	if (error != 0)
169550dbef1aSdholland 		return error;
169650dbef1aSdholland 
1697a7267d53Smartin 	if (first)
16984f30cbf3Smartin 		md_pre_mount(install, 0);
169950dbef1aSdholland 
17004103857bSmartin 	/* Mount devdev on target's "".
170150dbef1aSdholland 	 * If we pass "" as mount-on, Prefixing will DTRT.
170250dbef1aSdholland 	 * for now, use no options.
170350dbef1aSdholland 	 * XXX consider -o remount in case target root is
170450dbef1aSdholland 	 * current root, still readonly from single-user?
170550dbef1aSdholland 	 */
1706a7267d53Smartin 	return target_mount(writeable? "" : "-r", devdev, "");
170750dbef1aSdholland }
170850dbef1aSdholland 
170950dbef1aSdholland /* Get information on the file systems mounted from the root filesystem.
171050dbef1aSdholland  * Offer to convert them into 4.4BSD inodes if they are not 4.4BSD
171150dbef1aSdholland  * inodes.  Fsck them.  Mount them.
171250dbef1aSdholland  */
171350dbef1aSdholland 
171450dbef1aSdholland int
17154103857bSmartin mount_disks(struct install_partition_desc *install)
171650dbef1aSdholland {
171750dbef1aSdholland 	char *fstab;
171850dbef1aSdholland 	int   fstabsize;
171950dbef1aSdholland 	int   error;
17204103857bSmartin 	char devdev[PATH_MAX];
1721a7267d53Smartin 	size_t i, num_fs_types, num_entries;
1722a7267d53Smartin 	struct lookfor *fstabbuf, *l;
172350dbef1aSdholland 
1724b1fa9754Smartin 	if (install->cur_system)
1725b1fa9754Smartin 		return 0;
1726b1fa9754Smartin 
1727a7267d53Smartin 	/*
1728a7267d53Smartin 	 * Check what file system tools are available and create parsers
1729a7267d53Smartin 	 * for the corresponding fstab(5) entries - all others will be
1730a7267d53Smartin 	 * ignored.
1731a7267d53Smartin 	 */
1732a7267d53Smartin 	num_fs_types = 1;	/* ffs is implicit */
1733a7267d53Smartin 	for (i = 0; i < __arraycount(extern_fs_with_chk); i++) {
1734a7267d53Smartin 		sprintf(devdev, "/sbin/newfs_%s", extern_fs_with_chk[i]);
1735a7267d53Smartin 		if (file_exists_p(devdev))
1736a7267d53Smartin 			num_fs_types++;
1737a7267d53Smartin 	}
1738a7267d53Smartin 	for (i = 0; i < __arraycount(extern_fs_newfs_only); i++) {
1739a7267d53Smartin 		sprintf(devdev, "/sbin/newfs_%s", extern_fs_newfs_only[i]);
1740a7267d53Smartin 		if (file_exists_p(devdev))
1741a7267d53Smartin 			num_fs_types++;
1742a7267d53Smartin 	}
1743a7267d53Smartin 	num_entries = 2 *  num_fs_types + 1;	/* +1 for "ufs" special case */
1744a7267d53Smartin 	fstabbuf = calloc(num_entries, sizeof(*fstabbuf));
1745a7267d53Smartin 	if (fstabbuf == NULL)
1746a7267d53Smartin 		return -1;
1747a7267d53Smartin 	l = fstabbuf;
1748a7267d53Smartin 	l->head = "/dev/";
1749a7267d53Smartin 	l->fmt = strdup("/dev/%s %s ffs %s");
1750a7267d53Smartin 	l->todo = "c";
1751a7267d53Smartin 	l->var = __UNCONST("ffs");
1752a7267d53Smartin 	l->func = found_fs;
1753a7267d53Smartin 	l++;
1754a7267d53Smartin 	l->head = "/dev/";
1755a7267d53Smartin 	l->fmt = strdup("/dev/%s %s ufs %s");
1756a7267d53Smartin 	l->todo = "c";
1757a7267d53Smartin 	l->var = __UNCONST("ffs");
1758a7267d53Smartin 	l->func = found_fs;
1759a7267d53Smartin 	l++;
1760a7267d53Smartin 	l->head = NAME_PREFIX;
1761a7267d53Smartin 	l->fmt = strdup(NAME_PREFIX "%s %s ffs %s");
1762a7267d53Smartin 	l->todo = "c";
1763a7267d53Smartin 	l->var = __UNCONST("ffs");
1764a7267d53Smartin 	l->func = found_fs;
1765a7267d53Smartin 	l++;
1766a7267d53Smartin 	for (i = 0; i < __arraycount(extern_fs_with_chk); i++) {
1767a7267d53Smartin 		sprintf(devdev, "/sbin/newfs_%s", extern_fs_with_chk[i]);
1768a7267d53Smartin 		if (!file_exists_p(devdev))
1769a7267d53Smartin 			continue;
1770a7267d53Smartin 		sprintf(devdev, "/dev/%%s %%s %s %%s", extern_fs_with_chk[i]);
1771a7267d53Smartin 		l->head = "/dev/";
1772a7267d53Smartin 		l->fmt = strdup(devdev);
1773a7267d53Smartin 		l->todo = "c";
1774a7267d53Smartin 		l->var = __UNCONST(extern_fs_with_chk[i]);
1775a7267d53Smartin 		l->func = found_fs;
1776a7267d53Smartin 		l++;
1777a7267d53Smartin 		sprintf(devdev, NAME_PREFIX "%%s %%s %s %%s",
1778a7267d53Smartin 		    extern_fs_with_chk[i]);
1779a7267d53Smartin 		l->head = NAME_PREFIX;
1780a7267d53Smartin 		l->fmt = strdup(devdev);
1781a7267d53Smartin 		l->todo = "c";
1782a7267d53Smartin 		l->var = __UNCONST(extern_fs_with_chk[i]);
1783a7267d53Smartin 		l->func = found_fs;
1784a7267d53Smartin 		l++;
1785a7267d53Smartin 	}
1786a7267d53Smartin 	for (i = 0; i < __arraycount(extern_fs_newfs_only); i++) {
1787a7267d53Smartin 		sprintf(devdev, "/sbin/newfs_%s", extern_fs_newfs_only[i]);
1788a7267d53Smartin 		if (!file_exists_p(devdev))
1789a7267d53Smartin 			continue;
1790a7267d53Smartin 		sprintf(devdev, "/dev/%%s %%s %s %%s", extern_fs_newfs_only[i]);
1791a7267d53Smartin 		l->head = "/dev/";
1792a7267d53Smartin 		l->fmt = strdup(devdev);
1793a7267d53Smartin 		l->todo = "c";
1794a7267d53Smartin 		l->var = __UNCONST(extern_fs_newfs_only[i]);
1795a7267d53Smartin 		l->func = found_fs_nocheck;
1796a7267d53Smartin 		l++;
1797a7267d53Smartin 		sprintf(devdev, NAME_PREFIX "%%s %%s %s %%s",
1798a7267d53Smartin 		    extern_fs_newfs_only[i]);
1799a7267d53Smartin 		l->head = NAME_PREFIX;
1800a7267d53Smartin 		l->fmt = strdup(devdev);
1801a7267d53Smartin 		l->todo = "c";
1802a7267d53Smartin 		l->var = __UNCONST(extern_fs_newfs_only[i]);
1803a7267d53Smartin 		l->func = found_fs_nocheck;
1804a7267d53Smartin 		l++;
1805a7267d53Smartin 	}
1806a7267d53Smartin 	assert((size_t)(l - fstabbuf) == num_entries);
180750dbef1aSdholland 
180850dbef1aSdholland 	/* First the root device. */
180950dbef1aSdholland 	if (target_already_root())
181050dbef1aSdholland 		/* avoid needing to call target_already_root() again */
181150dbef1aSdholland 		targetroot_mnt[0] = 0;
181250dbef1aSdholland 	else {
1813c2ed2005Smartin 		for (i = 0; i < install->num; i++) {
1814c2ed2005Smartin 			if (is_root_part_mount(install->infos[i].mount))
1815c2ed2005Smartin 				break;
1816c2ed2005Smartin 		}
1817c2ed2005Smartin 
1818c2ed2005Smartin 		if (i >= install->num) {
1819c2ed2005Smartin 			hit_enter_to_continue(MSG_noroot, NULL);
1820c2ed2005Smartin 			return -1;
1821c2ed2005Smartin 		}
1822c2ed2005Smartin 
1823c2ed2005Smartin 		if (!install->infos[i].parts->pscheme->get_part_device(
1824c2ed2005Smartin 		    install->infos[i].parts, install->infos[i].cur_part_id,
18254103857bSmartin 		    devdev, sizeof devdev, NULL, plain_name, true))
18264103857bSmartin 			return -1;
1827a7267d53Smartin 		error = mount_root(devdev, true, false, install);
182850dbef1aSdholland 		if (error != 0 && error != EBUSY)
182950dbef1aSdholland 			return -1;
183050dbef1aSdholland 	}
183150dbef1aSdholland 
183250dbef1aSdholland 	/* Check the target /etc/fstab exists before trying to parse it. */
183350dbef1aSdholland 	if (target_dir_exists_p("/etc") == 0 ||
183450dbef1aSdholland 	    target_file_exists_p("/etc/fstab") == 0) {
183524ecf24eSchristos 		msg_fmt_display(MSG_noetcfstab, "%s", pm->diskdev);
18364103857bSmartin 		hit_enter_to_continue(NULL, NULL);
183750dbef1aSdholland 		return -1;
183850dbef1aSdholland 	}
183950dbef1aSdholland 
184050dbef1aSdholland 
184150dbef1aSdholland 	/* Get fstab entries from the target-root /etc/fstab. */
184250dbef1aSdholland 	fstabsize = target_collect_file(T_FILE, &fstab, "/etc/fstab");
184350dbef1aSdholland 	if (fstabsize < 0) {
184450dbef1aSdholland 		/* error ! */
184524ecf24eSchristos 		msg_fmt_display(MSG_badetcfstab, "%s", pm->diskdev);
18464103857bSmartin 		hit_enter_to_continue(NULL, NULL);
1847a7267d53Smartin 		umount_root();
18484b2364d9Smartin 		return -2;
184950dbef1aSdholland 	}
1850a7267d53Smartin 	/*
1851a7267d53Smartin 	 * We unmount the read-only root again, so we can mount it
1852a7267d53Smartin 	 * with proper options from /etc/fstab
1853a7267d53Smartin 	 */
1854a7267d53Smartin 	umount_root();
1855a7267d53Smartin 
1856a7267d53Smartin 	/*
1857a7267d53Smartin 	 * Now do all entries in /etc/fstab and mount them if required
1858a7267d53Smartin 	 */
1859a7267d53Smartin 	error = walk(fstab, (size_t)fstabsize, fstabbuf, num_entries);
186050dbef1aSdholland 	free(fstab);
1861a7267d53Smartin 	for (i = 0; i < num_entries; i++)
1862a7267d53Smartin 		free(__UNCONST(fstabbuf[i].fmt));
1863a7267d53Smartin 	free(fstabbuf);
186450dbef1aSdholland 
186550dbef1aSdholland 	return error;
186650dbef1aSdholland }
186750dbef1aSdholland 
186850dbef1aSdholland int
18694103857bSmartin set_swap_if_low_ram(struct install_partition_desc *install)
1870bbeaff62Sisaki {
187140a37f0dSabs 	if (get_ramsize() <= 32)
18724103857bSmartin 		return set_swap(install);
187340a37f0dSabs 	return 0;
187440a37f0dSabs }
187540a37f0dSabs 
187640a37f0dSabs int
18774103857bSmartin set_swap(struct install_partition_desc *install)
187850dbef1aSdholland {
18794103857bSmartin 	size_t i;
18804103857bSmartin 	char dev_buf[PATH_MAX];
188150dbef1aSdholland 	int rval;
188250dbef1aSdholland 
18834103857bSmartin 	for (i = 0; i < install->num; i++) {
18844103857bSmartin 		if (install->infos[i].type == PT_swap)
18854103857bSmartin 			break;
18864103857bSmartin 	}
18874103857bSmartin 	if (i >= install->num)
18884103857bSmartin 		return 0;
188950dbef1aSdholland 
18904103857bSmartin 	if (!install->infos[i].parts->pscheme->get_part_device(
18914103857bSmartin 	    install->infos[i].parts, install->infos[i].cur_part_id, dev_buf,
18924103857bSmartin 	    sizeof dev_buf, NULL, plain_name, true))
18934103857bSmartin 		return -1;
18944103857bSmartin 
18954103857bSmartin 	rval = swapctl(SWAP_ON, dev_buf, 0);
189650dbef1aSdholland 	if (rval != 0)
189750dbef1aSdholland 		return -1;
189850dbef1aSdholland 
189950dbef1aSdholland 	return 0;
190050dbef1aSdholland }
190150dbef1aSdholland 
190250dbef1aSdholland int
190350dbef1aSdholland check_swap(const char *disk, int remove_swap)
190450dbef1aSdholland {
190550dbef1aSdholland 	struct swapent *swap;
190650dbef1aSdholland 	char *cp;
190750dbef1aSdholland 	int nswap;
190850dbef1aSdholland 	int l;
190950dbef1aSdholland 	int rval = 0;
191050dbef1aSdholland 
191150dbef1aSdholland 	nswap = swapctl(SWAP_NSWAP, 0, 0);
191250dbef1aSdholland 	if (nswap <= 0)
191350dbef1aSdholland 		return 0;
191450dbef1aSdholland 
191550dbef1aSdholland 	swap = malloc(nswap * sizeof *swap);
191650dbef1aSdholland 	if (swap == NULL)
191750dbef1aSdholland 		return -1;
191850dbef1aSdholland 
191950dbef1aSdholland 	nswap = swapctl(SWAP_STATS, swap, nswap);
192050dbef1aSdholland 	if (nswap < 0)
192150dbef1aSdholland 		goto bad_swap;
192250dbef1aSdholland 
192350dbef1aSdholland 	l = strlen(disk);
192450dbef1aSdholland 	while (--nswap >= 0) {
192550dbef1aSdholland 		/* Should we check the se_dev or se_path? */
192650dbef1aSdholland 		cp = swap[nswap].se_path;
192750dbef1aSdholland 		if (memcmp(cp, "/dev/", 5) != 0)
192850dbef1aSdholland 			continue;
192950dbef1aSdholland 		if (memcmp(cp + 5, disk, l) != 0)
193050dbef1aSdholland 			continue;
193150dbef1aSdholland 		if (!isalpha(*(unsigned char *)(cp + 5 + l)))
193250dbef1aSdholland 			continue;
193350dbef1aSdholland 		if (cp[5 + l + 1] != 0)
193450dbef1aSdholland 			continue;
193550dbef1aSdholland 		/* ok path looks like it is for this device */
193650dbef1aSdholland 		if (!remove_swap) {
193750dbef1aSdholland 			/* count active swap areas */
193850dbef1aSdholland 			rval++;
193950dbef1aSdholland 			continue;
194050dbef1aSdholland 		}
194150dbef1aSdholland 		if (swapctl(SWAP_OFF, cp, 0) == -1)
194250dbef1aSdholland 			rval = -1;
194350dbef1aSdholland 	}
194450dbef1aSdholland 
194550dbef1aSdholland     done:
194650dbef1aSdholland 	free(swap);
194750dbef1aSdholland 	return rval;
194850dbef1aSdholland 
194950dbef1aSdholland     bad_swap:
195050dbef1aSdholland 	rval = -1;
195150dbef1aSdholland 	goto done;
195250dbef1aSdholland }
195350dbef1aSdholland 
195450dbef1aSdholland #ifdef HAVE_BOOTXX_xFS
195550dbef1aSdholland char *
19564103857bSmartin bootxx_name(struct install_partition_desc *install)
195750dbef1aSdholland {
195850dbef1aSdholland 	int fstype;
195950dbef1aSdholland 	const char *bootxxname;
196050dbef1aSdholland 	char *bootxx;
196150dbef1aSdholland 
196250dbef1aSdholland 	/* check we have boot code for the root partition type */
19634103857bSmartin 	fstype = install->infos[0].fs_type;
196450dbef1aSdholland 	switch (fstype) {
196550dbef1aSdholland #if defined(BOOTXX_FFSV1) || defined(BOOTXX_FFSV2)
196650dbef1aSdholland 	case FS_BSDFFS:
19674103857bSmartin 		if (install->infos[0].fs_version == 2) {
196850dbef1aSdholland #ifdef BOOTXX_FFSV2
196950dbef1aSdholland 			bootxxname = BOOTXX_FFSV2;
197050dbef1aSdholland #else
197150dbef1aSdholland 			bootxxname = NULL;
197250dbef1aSdholland #endif
197350dbef1aSdholland 		} else {
197450dbef1aSdholland #ifdef BOOTXX_FFSV1
197550dbef1aSdholland 			bootxxname = BOOTXX_FFSV1;
197650dbef1aSdholland #else
197750dbef1aSdholland 			bootxxname = NULL;
197850dbef1aSdholland #endif
197950dbef1aSdholland 		}
198050dbef1aSdholland 		break;
198150dbef1aSdholland #endif
19827935b6fcSpgoyette #ifdef BOOTXX_LFSV2
198350dbef1aSdholland 	case FS_BSDLFS:
19847935b6fcSpgoyette 		bootxxname = BOOTXX_LFSV2;
198550dbef1aSdholland 		break;
198650dbef1aSdholland #endif
198750dbef1aSdholland 	default:
198850dbef1aSdholland 		bootxxname = NULL;
198950dbef1aSdholland 		break;
199050dbef1aSdholland 	}
199150dbef1aSdholland 
199250dbef1aSdholland 	if (bootxxname == NULL)
199350dbef1aSdholland 		return NULL;
199450dbef1aSdholland 
199550dbef1aSdholland 	asprintf(&bootxx, "%s/%s", BOOTXXDIR, bootxxname);
199650dbef1aSdholland 	return bootxx;
199750dbef1aSdholland }
199850dbef1aSdholland #endif
19994b2364d9Smartin 
20004b2364d9Smartin /* from dkctl.c */
20014b2364d9Smartin static int
20024b2364d9Smartin get_dkwedges_sort(const void *a, const void *b)
20034b2364d9Smartin {
20044b2364d9Smartin 	const struct dkwedge_info *dkwa = a, *dkwb = b;
20054b2364d9Smartin 	const daddr_t oa = dkwa->dkw_offset, ob = dkwb->dkw_offset;
20064b2364d9Smartin 	return (oa < ob) ? -1 : (oa > ob) ? 1 : 0;
20074b2364d9Smartin }
20084b2364d9Smartin 
20094b2364d9Smartin int
20104b2364d9Smartin get_dkwedges(struct dkwedge_info **dkw, const char *diskdev)
20114b2364d9Smartin {
20124b2364d9Smartin 	struct dkwedge_list dkwl;
20134b2364d9Smartin 
20144b2364d9Smartin 	*dkw = NULL;
201572ea5dbaSchristos 	if (!get_wedge_list(diskdev, &dkwl))
20164b2364d9Smartin 		return -1;
20174b2364d9Smartin 
201872ea5dbaSchristos 	if (dkwl.dkwl_nwedges > 0 && *dkw != NULL) {
201972ea5dbaSchristos 		qsort(*dkw, dkwl.dkwl_nwedges, sizeof(**dkw),
202072ea5dbaSchristos 		    get_dkwedges_sort);
20214b2364d9Smartin 	}
20224b2364d9Smartin 
20234b2364d9Smartin 	return dkwl.dkwl_nwedges;
20244b2364d9Smartin }
2025