1*37a23ecfSmsaitoh /* $NetBSD: disks.c,v 1.95 2023/06/24 05:25:04 msaitoh 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
64429eff31Sjmcneill #include <sys/drvctlio.h>
65429eff31Sjmcneill
6650dbef1aSdholland #include "defs.h"
6750dbef1aSdholland #include "md.h"
6850dbef1aSdholland #include "msg_defs.h"
6950dbef1aSdholland #include "menu_defs.h"
7050dbef1aSdholland #include "txtwalk.h"
7150dbef1aSdholland
72d396d9d8Smartin /* #define DEBUG_VERBOSE 1 */
734103857bSmartin
7450dbef1aSdholland /* Disk descriptions */
7550dbef1aSdholland struct disk_desc {
7650dbef1aSdholland char dd_name[SSTRSIZE];
7737649e40Smrg char dd_descr[256];
782575b4dcSmartin bool dd_no_mbr, dd_no_part;
7950dbef1aSdholland uint dd_cyl;
8050dbef1aSdholland uint dd_head;
8150dbef1aSdholland uint dd_sec;
8250dbef1aSdholland uint dd_secsize;
834103857bSmartin daddr_t dd_totsec;
844b2364d9Smartin };
854b2364d9Smartin
86a7267d53Smartin #define NAME_PREFIX "NAME="
87a7267d53Smartin static const char name_prefix[] = NAME_PREFIX;
88a7267d53Smartin
89a7267d53Smartin /* things we could have as /sbin/newfs_* and /sbin/fsck_* */
90a7267d53Smartin static const char *extern_fs_with_chk[] = {
91bbe55e4fSreinoud "ext2fs", "lfs", "msdos", "udf", "v7fs"
92a7267d53Smartin };
93a7267d53Smartin
94a7267d53Smartin /* things we could have as /sbin/newfs_* but not /sbin/fsck_* */
95a7267d53Smartin static const char *extern_fs_newfs_only[] = {
96bbe55e4fSreinoud "sysvbfs"
97a7267d53Smartin };
986de47033Smartin
9950dbef1aSdholland /* Local prototypes */
100a7267d53Smartin static int found_fs(struct data *, size_t, const struct lookfor*);
101a7267d53Smartin static int found_fs_nocheck(struct data *, size_t, const struct lookfor*);
1024103857bSmartin static int fsck_preen(const char *, const char *, bool silent);
1034103857bSmartin static void fixsb(const char *, const char *);
10450dbef1aSdholland
10550dbef1aSdholland
10650dbef1aSdholland static bool tmpfs_on_var_shm(void);
10750dbef1aSdholland
10850dbef1aSdholland const char *
getfslabelname(uint f,uint f_version)1094103857bSmartin getfslabelname(uint f, uint f_version)
11050dbef1aSdholland {
1114103857bSmartin if (f == FS_TMPFS)
1124103857bSmartin return "tmpfs";
1134103857bSmartin else if (f == FS_MFS)
1144103857bSmartin return "mfs";
1159ba59248Smartin else if (f == FS_EFI_SP)
1169ba59248Smartin return msg_string(MSG_fs_type_efi_sp);
117dacc867eSmartin else if (f == FS_BSDFFS) {
118c6fbd201Smartin switch (f_version) {
119c6fbd201Smartin default:
120c6fbd201Smartin case 1: return msg_string(MSG_fs_type_ffs);
121c6fbd201Smartin case 2: return msg_string(MSG_fs_type_ffsv2);
122c6fbd201Smartin case 3: return msg_string(MSG_fs_type_ffsv2ea);
123c6fbd201Smartin }
124c6fbd201Smartin } else if (f == FS_EX2FS && f_version == 1)
125675f7bf6Smartin return msg_string(MSG_fs_type_ext2old);
1264103857bSmartin else if (f >= __arraycount(fstypenames) || fstypenames[f] == NULL)
12750dbef1aSdholland return "invalid";
12850dbef1aSdholland return fstypenames[f];
12950dbef1aSdholland }
13050dbef1aSdholland
13150dbef1aSdholland /*
132*37a23ecfSmsaitoh * Decide whether we want to mount a tmpfs on /var/shm: we do this always
13350dbef1aSdholland * when the machine has more than 16 MB of user memory. On smaller machines,
13450dbef1aSdholland * shm_open() and friends will not perform well anyway.
13550dbef1aSdholland */
13650dbef1aSdholland static bool
tmpfs_on_var_shm(void)13770b74d30Stsutsui tmpfs_on_var_shm(void)
13850dbef1aSdholland {
13950dbef1aSdholland uint64_t ram;
14050dbef1aSdholland size_t len;
14150dbef1aSdholland
14250dbef1aSdholland len = sizeof(ram);
14350dbef1aSdholland if (sysctlbyname("hw.usermem64", &ram, &len, NULL, 0))
14450dbef1aSdholland return false;
14550dbef1aSdholland
14672cf5c53Smartin return ram > 16 * MEG;
14750dbef1aSdholland }
14850dbef1aSdholland
14978432c80Smartin /*
1503a0698b0Smartin * Find length of string but ignore trailing whitespace
15178432c80Smartin */
1523a0698b0Smartin static int
trimmed_len(const char * s)1533a0698b0Smartin trimmed_len(const char *s)
15478432c80Smartin {
1553a0698b0Smartin size_t len = strlen(s);
15678432c80Smartin
1573a0698b0Smartin while (len > 0 && isspace((unsigned char)s[len - 1]))
1583a0698b0Smartin len--;
1593a0698b0Smartin return len;
16078432c80Smartin }
16178432c80Smartin
16250dbef1aSdholland /* from src/sbin/atactl/atactl.c
16350dbef1aSdholland * extract_string: copy a block of bytes out of ataparams and make
16450dbef1aSdholland * a proper string out of it, truncating trailing spaces and preserving
16550dbef1aSdholland * strict typing. And also, not doing unaligned accesses.
16650dbef1aSdholland */
16750dbef1aSdholland static void
ata_extract_string(char * buf,size_t bufmax,uint8_t * bytes,unsigned numbytes,int needswap)16850dbef1aSdholland ata_extract_string(char *buf, size_t bufmax,
16950dbef1aSdholland uint8_t *bytes, unsigned numbytes,
17050dbef1aSdholland int needswap)
17150dbef1aSdholland {
17250dbef1aSdholland unsigned i;
17350dbef1aSdholland size_t j;
17450dbef1aSdholland unsigned char ch1, ch2;
17550dbef1aSdholland
17650dbef1aSdholland for (i = 0, j = 0; i < numbytes; i += 2) {
17750dbef1aSdholland ch1 = bytes[i];
17850dbef1aSdholland ch2 = bytes[i+1];
17950dbef1aSdholland if (needswap && j < bufmax-1) {
18050dbef1aSdholland buf[j++] = ch2;
18150dbef1aSdholland }
18250dbef1aSdholland if (j < bufmax-1) {
18350dbef1aSdholland buf[j++] = ch1;
18450dbef1aSdholland }
18550dbef1aSdholland if (!needswap && j < bufmax-1) {
18650dbef1aSdholland buf[j++] = ch2;
18750dbef1aSdholland }
18850dbef1aSdholland }
18950dbef1aSdholland while (j > 0 && buf[j-1] == ' ') {
19050dbef1aSdholland j--;
19150dbef1aSdholland }
19250dbef1aSdholland buf[j] = '\0';
19350dbef1aSdholland }
19450dbef1aSdholland
19550dbef1aSdholland /*
19650dbef1aSdholland * from src/sbin/scsictl/scsi_subr.c
19750dbef1aSdholland */
19850dbef1aSdholland #define STRVIS_ISWHITE(x) ((x) == ' ' || (x) == '\0' || (x) == (u_char)'\377')
19950dbef1aSdholland
20050dbef1aSdholland static void
scsi_strvis(char * sdst,size_t dlen,const char * ssrc,size_t slen)20150dbef1aSdholland scsi_strvis(char *sdst, size_t dlen, const char *ssrc, size_t slen)
20250dbef1aSdholland {
20350dbef1aSdholland u_char *dst = (u_char *)sdst;
20450dbef1aSdholland const u_char *src = (const u_char *)ssrc;
20550dbef1aSdholland
20650dbef1aSdholland /* Trim leading and trailing blanks and NULs. */
20750dbef1aSdholland while (slen > 0 && STRVIS_ISWHITE(src[0]))
20850dbef1aSdholland ++src, --slen;
20950dbef1aSdholland while (slen > 0 && STRVIS_ISWHITE(src[slen - 1]))
21050dbef1aSdholland --slen;
21150dbef1aSdholland
21250dbef1aSdholland while (slen > 0) {
21350dbef1aSdholland if (*src < 0x20 || *src >= 0x80) {
21450dbef1aSdholland /* non-printable characters */
21550dbef1aSdholland dlen -= 4;
21650dbef1aSdholland if (dlen < 1)
21750dbef1aSdholland break;
21850dbef1aSdholland *dst++ = '\\';
21950dbef1aSdholland *dst++ = ((*src & 0300) >> 6) + '0';
22050dbef1aSdholland *dst++ = ((*src & 0070) >> 3) + '0';
22150dbef1aSdholland *dst++ = ((*src & 0007) >> 0) + '0';
22250dbef1aSdholland } else if (*src == '\\') {
22350dbef1aSdholland /* quote characters */
22450dbef1aSdholland dlen -= 2;
22550dbef1aSdholland if (dlen < 1)
22650dbef1aSdholland break;
22750dbef1aSdholland *dst++ = '\\';
22850dbef1aSdholland *dst++ = '\\';
22950dbef1aSdholland } else {
23050dbef1aSdholland /* normal characters */
23150dbef1aSdholland if (--dlen < 1)
23250dbef1aSdholland break;
23350dbef1aSdholland *dst++ = *src;
23450dbef1aSdholland }
23550dbef1aSdholland ++src, --slen;
23650dbef1aSdholland }
23750dbef1aSdholland
23850dbef1aSdholland *dst++ = 0;
23950dbef1aSdholland }
24050dbef1aSdholland
24150dbef1aSdholland
24250dbef1aSdholland static int
get_descr_scsi(struct disk_desc * dd)24372ea5dbaSchristos get_descr_scsi(struct disk_desc *dd)
24450dbef1aSdholland {
24550dbef1aSdholland struct scsipi_inquiry_data inqbuf;
24650dbef1aSdholland struct scsipi_inquiry cmd;
24750dbef1aSdholland scsireq_t req;
24850dbef1aSdholland /* x4 in case every character is escaped, +1 for NUL. */
24950dbef1aSdholland char vendor[(sizeof(inqbuf.vendor) * 4) + 1],
25050dbef1aSdholland product[(sizeof(inqbuf.product) * 4) + 1],
25150dbef1aSdholland revision[(sizeof(inqbuf.revision) * 4) + 1];
25250dbef1aSdholland char size[5];
25350dbef1aSdholland
25450dbef1aSdholland memset(&inqbuf, 0, sizeof(inqbuf));
25550dbef1aSdholland memset(&cmd, 0, sizeof(cmd));
25650dbef1aSdholland memset(&req, 0, sizeof(req));
25750dbef1aSdholland
25850dbef1aSdholland cmd.opcode = INQUIRY;
25950dbef1aSdholland cmd.length = sizeof(inqbuf);
26050dbef1aSdholland memcpy(req.cmd, &cmd, sizeof(cmd));
26150dbef1aSdholland req.cmdlen = sizeof(cmd);
26250dbef1aSdholland req.databuf = &inqbuf;
26350dbef1aSdholland req.datalen = sizeof(inqbuf);
26450dbef1aSdholland req.timeout = 10000;
26550dbef1aSdholland req.flags = SCCMD_READ;
26650dbef1aSdholland req.senselen = SENSEBUFLEN;
26750dbef1aSdholland
26872ea5dbaSchristos if (!disk_ioctl(dd->dd_name, SCIOCCOMMAND, &req)
26972ea5dbaSchristos || req.retsts != SCCMD_OK)
27050dbef1aSdholland return 0;
27150dbef1aSdholland
27250dbef1aSdholland scsi_strvis(vendor, sizeof(vendor), inqbuf.vendor,
27350dbef1aSdholland sizeof(inqbuf.vendor));
27450dbef1aSdholland scsi_strvis(product, sizeof(product), inqbuf.product,
27550dbef1aSdholland sizeof(inqbuf.product));
27650dbef1aSdholland scsi_strvis(revision, sizeof(revision), inqbuf.revision,
27750dbef1aSdholland sizeof(inqbuf.revision));
27850dbef1aSdholland
27950dbef1aSdholland humanize_number(size, sizeof(size),
28050dbef1aSdholland (uint64_t)dd->dd_secsize * (uint64_t)dd->dd_totsec,
28150dbef1aSdholland "", HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL);
28250dbef1aSdholland
28350dbef1aSdholland snprintf(dd->dd_descr, sizeof(dd->dd_descr),
28450dbef1aSdholland "%s (%s, %s %s)",
28550dbef1aSdholland dd->dd_name, size, vendor, product);
28650dbef1aSdholland
28750dbef1aSdholland return 1;
28850dbef1aSdholland }
28950dbef1aSdholland
29050dbef1aSdholland static int
get_descr_ata(struct disk_desc * dd)29172ea5dbaSchristos get_descr_ata(struct disk_desc *dd)
29250dbef1aSdholland {
29350dbef1aSdholland struct atareq req;
29450dbef1aSdholland static union {
29550dbef1aSdholland unsigned char inbuf[DEV_BSIZE];
29650dbef1aSdholland struct ataparams inqbuf;
29750dbef1aSdholland } inbuf;
29850dbef1aSdholland struct ataparams *inqbuf = &inbuf.inqbuf;
29950dbef1aSdholland char model[sizeof(inqbuf->atap_model)+1];
30050dbef1aSdholland char size[5];
30172ea5dbaSchristos int needswap = 0;
30250dbef1aSdholland
30350dbef1aSdholland memset(&inbuf, 0, sizeof(inbuf));
30450dbef1aSdholland memset(&req, 0, sizeof(req));
30550dbef1aSdholland
30650dbef1aSdholland req.flags = ATACMD_READ;
30750dbef1aSdholland req.command = WDCC_IDENTIFY;
30850dbef1aSdholland req.databuf = (void *)&inbuf;
30950dbef1aSdholland req.datalen = sizeof(inbuf);
31050dbef1aSdholland req.timeout = 1000;
31150dbef1aSdholland
31272ea5dbaSchristos if (!disk_ioctl(dd->dd_name, ATAIOCCOMMAND, &req)
31372ea5dbaSchristos || req.retsts != ATACMD_OK)
31450dbef1aSdholland return 0;
31550dbef1aSdholland
31650dbef1aSdholland #if BYTE_ORDER == LITTLE_ENDIAN
31750dbef1aSdholland /*
31850dbef1aSdholland * On little endian machines, we need to shuffle the string
31950dbef1aSdholland * byte order. However, we don't have to do this for NEC or
32050dbef1aSdholland * Mitsumi ATAPI devices
32150dbef1aSdholland */
32250dbef1aSdholland
32350dbef1aSdholland if (!(inqbuf->atap_config != WDC_CFG_CFA_MAGIC &&
32450dbef1aSdholland (inqbuf->atap_config & WDC_CFG_ATAPI) &&
32550dbef1aSdholland ((inqbuf->atap_model[0] == 'N' &&
32650dbef1aSdholland inqbuf->atap_model[1] == 'E') ||
32750dbef1aSdholland (inqbuf->atap_model[0] == 'F' &&
32850dbef1aSdholland inqbuf->atap_model[1] == 'X')))) {
32950dbef1aSdholland needswap = 1;
33050dbef1aSdholland }
33150dbef1aSdholland #endif
33250dbef1aSdholland
33350dbef1aSdholland ata_extract_string(model, sizeof(model),
33450dbef1aSdholland inqbuf->atap_model, sizeof(inqbuf->atap_model), needswap);
33550dbef1aSdholland humanize_number(size, sizeof(size),
33650dbef1aSdholland (uint64_t)dd->dd_secsize * (uint64_t)dd->dd_totsec,
33750dbef1aSdholland "", HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL);
33850dbef1aSdholland
33950dbef1aSdholland snprintf(dd->dd_descr, sizeof(dd->dd_descr), "%s (%s, %s)",
34050dbef1aSdholland dd->dd_name, size, model);
34150dbef1aSdholland
34250dbef1aSdholland return 1;
34350dbef1aSdholland }
34450dbef1aSdholland
345429eff31Sjmcneill static int
get_descr_drvctl(struct disk_desc * dd)346429eff31Sjmcneill get_descr_drvctl(struct disk_desc *dd)
347429eff31Sjmcneill {
348429eff31Sjmcneill prop_dictionary_t command_dict;
349429eff31Sjmcneill prop_dictionary_t args_dict;
350429eff31Sjmcneill prop_dictionary_t results_dict;
351429eff31Sjmcneill prop_dictionary_t props;
352429eff31Sjmcneill int8_t perr;
353429eff31Sjmcneill int error, fd;
354429eff31Sjmcneill bool rv;
3553a0698b0Smartin char size[5];
356429eff31Sjmcneill const char *model;
357429eff31Sjmcneill
358429eff31Sjmcneill fd = open("/dev/drvctl", O_RDONLY);
359429eff31Sjmcneill if (fd == -1)
360429eff31Sjmcneill return 0;
361429eff31Sjmcneill
362429eff31Sjmcneill command_dict = prop_dictionary_create();
363429eff31Sjmcneill args_dict = prop_dictionary_create();
364429eff31Sjmcneill
3655126c2f9Sjmcneill prop_dictionary_set_string_nocopy(command_dict, "drvctl-command",
366429eff31Sjmcneill "get-properties");
3675126c2f9Sjmcneill prop_dictionary_set_string_nocopy(args_dict, "device-name",
368429eff31Sjmcneill dd->dd_name);
369429eff31Sjmcneill prop_dictionary_set(command_dict, "drvctl-arguments", args_dict);
370429eff31Sjmcneill prop_object_release(args_dict);
371429eff31Sjmcneill
372429eff31Sjmcneill error = prop_dictionary_sendrecv_ioctl(command_dict, fd,
373429eff31Sjmcneill DRVCTLCOMMAND, &results_dict);
374429eff31Sjmcneill prop_object_release(command_dict);
375429eff31Sjmcneill close(fd);
376429eff31Sjmcneill if (error)
377429eff31Sjmcneill return 0;
378429eff31Sjmcneill
379429eff31Sjmcneill rv = prop_dictionary_get_int8(results_dict, "drvctl-error", &perr);
380429eff31Sjmcneill if (rv == false || perr != 0) {
381429eff31Sjmcneill prop_object_release(results_dict);
382429eff31Sjmcneill return 0;
383429eff31Sjmcneill }
384429eff31Sjmcneill
385429eff31Sjmcneill props = prop_dictionary_get(results_dict,
386429eff31Sjmcneill "drvctl-result-data");
387429eff31Sjmcneill if (props == NULL) {
388429eff31Sjmcneill prop_object_release(results_dict);
389429eff31Sjmcneill return 0;
390429eff31Sjmcneill }
391429eff31Sjmcneill props = prop_dictionary_get(props, "disk-info");
392429eff31Sjmcneill if (props == NULL ||
393429eff31Sjmcneill !prop_dictionary_get_string(props, "type", &model)) {
394429eff31Sjmcneill prop_object_release(results_dict);
395429eff31Sjmcneill return 0;
396429eff31Sjmcneill }
397429eff31Sjmcneill
398429eff31Sjmcneill humanize_number(size, sizeof(size),
399429eff31Sjmcneill (uint64_t)dd->dd_secsize * (uint64_t)dd->dd_totsec,
400429eff31Sjmcneill "", HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL);
401429eff31Sjmcneill
4023a0698b0Smartin snprintf(dd->dd_descr, sizeof(dd->dd_descr), "%s (%s, %.*s)",
4033a0698b0Smartin dd->dd_name, size, trimmed_len(model), model);
404429eff31Sjmcneill
405429eff31Sjmcneill prop_object_release(results_dict);
406429eff31Sjmcneill
407429eff31Sjmcneill return 1;
408429eff31Sjmcneill }
409429eff31Sjmcneill
41050dbef1aSdholland static void
get_descr(struct disk_desc * dd)41150dbef1aSdholland get_descr(struct disk_desc *dd)
41250dbef1aSdholland {
41372ea5dbaSchristos char size[5];
41450dbef1aSdholland dd->dd_descr[0] = '\0';
41550dbef1aSdholland
416429eff31Sjmcneill /* try drvctl first, fallback to direct probing */
417429eff31Sjmcneill if (get_descr_drvctl(dd))
418429eff31Sjmcneill return;
41950dbef1aSdholland /* try ATA */
42072ea5dbaSchristos if (get_descr_ata(dd))
4219005fea0Sjmcneill return;
42250dbef1aSdholland /* try SCSI */
42372ea5dbaSchristos if (get_descr_scsi(dd))
4249005fea0Sjmcneill return;
4254103857bSmartin
4264b2364d9Smartin /* XXX: get description from raid, cgd, vnd... */
4279005fea0Sjmcneill
4284103857bSmartin /* punt, just give some generic info */
4294103857bSmartin humanize_number(size, sizeof(size),
4304103857bSmartin (uint64_t)dd->dd_secsize * (uint64_t)dd->dd_totsec,
4314103857bSmartin "", HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL);
4324103857bSmartin
4334103857bSmartin snprintf(dd->dd_descr, sizeof(dd->dd_descr),
4344103857bSmartin "%s (%s)", dd->dd_name, size);
43550dbef1aSdholland }
43650dbef1aSdholland
437a48ed55eSmartin /*
438a48ed55eSmartin * State for helper callback for get_default_cdrom
439a48ed55eSmartin */
440a48ed55eSmartin struct default_cdrom_data {
441a48ed55eSmartin char *device;
442a48ed55eSmartin size_t max_len;
443a48ed55eSmartin bool found;
444a48ed55eSmartin };
445a48ed55eSmartin
446a48ed55eSmartin /*
447a48ed55eSmartin * Helper function for get_default_cdrom, gets passed a device
448a48ed55eSmartin * name and a void pointer to default_cdrom_data.
449a48ed55eSmartin */
450a48ed55eSmartin static bool
get_default_cdrom_helper(void * state,const char * dev)451a48ed55eSmartin get_default_cdrom_helper(void *state, const char *dev)
452a48ed55eSmartin {
453a48ed55eSmartin struct default_cdrom_data *data = state;
454a48ed55eSmartin
45557cf8237Smartin if (!is_cdrom_device(dev, false))
4561c2e5b02Smartin return true;
4571c2e5b02Smartin
458a48ed55eSmartin strlcpy(data->device, dev, data->max_len);
4591c2e5b02Smartin strlcat(data->device, "a", data->max_len); /* default to partition a */
460a48ed55eSmartin data->found = true;
461a48ed55eSmartin
462a48ed55eSmartin return false; /* one is enough, stop iteration */
463a48ed55eSmartin }
464a48ed55eSmartin
465a48ed55eSmartin /*
466a48ed55eSmartin * Set the argument to the name of the first CD devices actually
467a48ed55eSmartin * available, leave it unmodified otherwise.
468a48ed55eSmartin * Return true if a device has been found.
46950dbef1aSdholland */
4703b44a3d7Smartin bool
get_default_cdrom(char * cd,size_t max_len)4713b44a3d7Smartin get_default_cdrom(char *cd, size_t max_len)
47250dbef1aSdholland {
473a48ed55eSmartin struct default_cdrom_data state;
47450dbef1aSdholland
475a48ed55eSmartin state.device = cd;
476a48ed55eSmartin state.max_len = max_len;
477a48ed55eSmartin state.found = false;
47850dbef1aSdholland
479a48ed55eSmartin if (enumerate_disks(&state, get_default_cdrom_helper))
480a48ed55eSmartin return state.found;
481a48ed55eSmartin
482a48ed55eSmartin return false;
48350dbef1aSdholland }
48450dbef1aSdholland
4854103857bSmartin static bool
get_wedge_descr(struct disk_desc * dd)4862575b4dcSmartin get_wedge_descr(struct disk_desc *dd)
4872575b4dcSmartin {
4882575b4dcSmartin struct dkwedge_info dkw;
4892575b4dcSmartin
49072ea5dbaSchristos if (!get_wedge_info(dd->dd_name, &dkw))
4914103857bSmartin return false;
4922575b4dcSmartin
49372ea5dbaSchristos snprintf(dd->dd_descr, sizeof(dd->dd_descr), "%s (%s@%s)",
4942575b4dcSmartin dkw.dkw_wname, dkw.dkw_devname, dkw.dkw_parent);
49572ea5dbaSchristos return true;
4962575b4dcSmartin }
4972575b4dcSmartin
4982575b4dcSmartin static bool
get_name_and_parent(const char * dev,char * name,char * parent)4992575b4dcSmartin get_name_and_parent(const char *dev, char *name, char *parent)
5002575b4dcSmartin {
5012575b4dcSmartin struct dkwedge_info dkw;
5022575b4dcSmartin
50372ea5dbaSchristos if (!get_wedge_info(dev, &dkw))
5042575b4dcSmartin return false;
5052575b4dcSmartin strcpy(name, (const char *)dkw.dkw_wname);
5062575b4dcSmartin strcpy(parent, dkw.dkw_parent);
50772ea5dbaSchristos return true;
5082575b4dcSmartin }
5092575b4dcSmartin
5102575b4dcSmartin static bool
find_swap_part_on(const char * dev,char * swap_name)5112575b4dcSmartin find_swap_part_on(const char *dev, char *swap_name)
5122575b4dcSmartin {
5132575b4dcSmartin struct dkwedge_list dkwl;
51472ea5dbaSchristos struct dkwedge_info *dkw;
5152575b4dcSmartin u_int i;
5162575b4dcSmartin bool res = false;
5172575b4dcSmartin
51872ea5dbaSchristos if (!get_wedge_list(dev, &dkwl))
5192575b4dcSmartin return false;
5202575b4dcSmartin
52172ea5dbaSchristos dkw = dkwl.dkwl_buf;
5222575b4dcSmartin for (i = 0; i < dkwl.dkwl_nwedges; i++) {
5232575b4dcSmartin res = strcmp(dkw[i].dkw_ptype, DKW_PTYPE_SWAP) == 0;
5242575b4dcSmartin if (res) {
5252575b4dcSmartin strcpy(swap_name, (const char*)dkw[i].dkw_wname);
5262575b4dcSmartin break;
5272575b4dcSmartin }
5282575b4dcSmartin }
52972ea5dbaSchristos free(dkwl.dkwl_buf);
5302575b4dcSmartin
5312575b4dcSmartin return res;
5322575b4dcSmartin }
5332575b4dcSmartin
5342575b4dcSmartin static bool
is_ffs_wedge(const char * dev)5352575b4dcSmartin is_ffs_wedge(const char *dev)
5362575b4dcSmartin {
5372575b4dcSmartin struct dkwedge_info dkw;
5382575b4dcSmartin
53972ea5dbaSchristos if (!get_wedge_info(dev, &dkw))
5402575b4dcSmartin return false;
5412575b4dcSmartin
54272ea5dbaSchristos return strcmp(dkw.dkw_ptype, DKW_PTYPE_FFS) == 0;
5432575b4dcSmartin }
5442575b4dcSmartin
5453b44a3d7Smartin /*
5463b44a3d7Smartin * Does this device match an entry in our default CDROM device list?
54757cf8237Smartin * If looking for install targets, we also flag floopy devices.
5483b44a3d7Smartin */
5491c2e5b02Smartin bool
is_cdrom_device(const char * dev,bool as_target)55057cf8237Smartin is_cdrom_device(const char *dev, bool as_target)
5513b44a3d7Smartin {
55257cf8237Smartin static const char *target_devices[] = {
5538b5066c4Smartin #ifdef CD_NAMES
5548b5066c4Smartin CD_NAMES
5558b5066c4Smartin #endif
5568b5066c4Smartin #if defined(CD_NAMES) && defined(FLOPPY_NAMES)
5578b5066c4Smartin ,
5588b5066c4Smartin #endif
5598b5066c4Smartin #ifdef FLOPPY_NAMES
5608b5066c4Smartin FLOPPY_NAMES
5618b5066c4Smartin #endif
5628b5066c4Smartin #if defined(CD_NAMES) || defined(FLOPPY_NAMES)
5638b5066c4Smartin ,
5648b5066c4Smartin #endif
5658b5066c4Smartin 0
5668b5066c4Smartin };
56757cf8237Smartin static const char *src_devices[] = {
56857cf8237Smartin #ifdef CD_NAMES
56957cf8237Smartin CD_NAMES ,
57057cf8237Smartin #endif
57157cf8237Smartin 0
57257cf8237Smartin };
5733b44a3d7Smartin
57457cf8237Smartin for (const char **dev_pat = as_target ? target_devices : src_devices;
57557cf8237Smartin *dev_pat; dev_pat++)
5764bb5c537Smartin if (fnmatch(*dev_pat, dev, 0) == 0)
577e80b64deSmartin return true;
5783b44a3d7Smartin
5793b44a3d7Smartin return false;
5803b44a3d7Smartin }
5813b44a3d7Smartin
582c4cf3d8dSmartin /* does this device match any entry in the driver list? */
583c4cf3d8dSmartin static bool
dev_in_list(const char * dev,const char ** list)584c4cf3d8dSmartin dev_in_list(const char *dev, const char **list)
585c4cf3d8dSmartin {
586c4cf3d8dSmartin
587c4cf3d8dSmartin for ( ; *list; list++) {
588c4cf3d8dSmartin
589c4cf3d8dSmartin size_t len = strlen(*list);
590c4cf3d8dSmartin
591c4cf3d8dSmartin /* start of name matches? */
592c4cf3d8dSmartin if (strncmp(dev, *list, len) == 0) {
593c4cf3d8dSmartin char *endp;
594c4cf3d8dSmartin int e;
595c4cf3d8dSmartin
596c4cf3d8dSmartin /* remainder of name is a decimal number? */
597c4cf3d8dSmartin strtou(dev+len, &endp, 10, 0, INT_MAX, &e);
598c4cf3d8dSmartin if (endp && *endp == 0 && e == 0)
599c4cf3d8dSmartin return true;
600c4cf3d8dSmartin }
601c4cf3d8dSmartin }
602c4cf3d8dSmartin
603c4cf3d8dSmartin return false;
604c4cf3d8dSmartin }
605c4cf3d8dSmartin
606c4cf3d8dSmartin bool
is_bootable_device(const char * dev)607c4cf3d8dSmartin is_bootable_device(const char *dev)
608c4cf3d8dSmartin {
609c4cf3d8dSmartin static const char *non_bootable_devs[] = {
610c4cf3d8dSmartin "raid", /* bootcode lives outside of raid */
611c4cf3d8dSmartin "xbd", /* xen virtual device, can not boot from that */
612c4cf3d8dSmartin NULL
613c4cf3d8dSmartin };
614c4cf3d8dSmartin
615c4cf3d8dSmartin return !dev_in_list(dev, non_bootable_devs);
616c4cf3d8dSmartin }
617c4cf3d8dSmartin
618c4cf3d8dSmartin bool
is_partitionable_device(const char * dev)619c4cf3d8dSmartin is_partitionable_device(const char *dev)
620c4cf3d8dSmartin {
621c4cf3d8dSmartin static const char *non_partitionable_devs[] = {
622d4a37f7cSmsaitoh "dk", /* this is already a partitioned slice */
623c4cf3d8dSmartin NULL
624c4cf3d8dSmartin };
625c4cf3d8dSmartin
626c4cf3d8dSmartin return !dev_in_list(dev, non_partitionable_devs);
627c4cf3d8dSmartin }
628c4cf3d8dSmartin
6293b44a3d7Smartin /*
6303b44a3d7Smartin * Multi-purpose helper function:
631a48ed55eSmartin * iterate all known disks, invoke a callback for each.
632a48ed55eSmartin * Stop iteration when the callback returns false.
6338324be4cSandvar * Return true when iteration actually happened, false on error.
6343b44a3d7Smartin */
6351c2e5b02Smartin bool
enumerate_disks(void * state,bool (* func)(void * state,const char * dev))636a48ed55eSmartin enumerate_disks(void *state, bool (*func)(void *state, const char *dev))
63750dbef1aSdholland {
6387a391039Smartin static const int mib[] = { CTL_HW, HW_DISKNAMES };
6397a391039Smartin static const unsigned int miblen = __arraycount(mib);
6407a391039Smartin const char *xd;
6417a391039Smartin char *disk_names;
642a48ed55eSmartin size_t len;
64350dbef1aSdholland
6447a391039Smartin if (sysctl(mib, miblen, NULL, &len, NULL, 0) == -1)
645a48ed55eSmartin return false;
646a48ed55eSmartin
6477a391039Smartin disk_names = malloc(len);
6487a391039Smartin if (disk_names == NULL)
649a48ed55eSmartin return false;
6507a391039Smartin
6517a391039Smartin if (sysctl(mib, miblen, disk_names, &len, NULL, 0) == -1) {
6527a391039Smartin free(disk_names);
653a48ed55eSmartin return false;
6547a391039Smartin }
6557a391039Smartin
6567a391039Smartin for (xd = strtok(disk_names, " "); xd != NULL; xd = strtok(NULL, " ")) {
657a48ed55eSmartin if (!(*func)(state, xd))
658a48ed55eSmartin break;
659a48ed55eSmartin }
660a48ed55eSmartin free(disk_names);
661a48ed55eSmartin
662a48ed55eSmartin return true;
663a48ed55eSmartin }
664a48ed55eSmartin
665a48ed55eSmartin /*
666a48ed55eSmartin * Helper state for get_disks
667a48ed55eSmartin */
668a48ed55eSmartin struct get_disks_state {
669a48ed55eSmartin int numdisks;
670a48ed55eSmartin struct disk_desc *dd;
671a48ed55eSmartin bool with_non_partitionable;
672a48ed55eSmartin };
673a48ed55eSmartin
674a48ed55eSmartin /*
675a48ed55eSmartin * Helper function for get_disks enumartion
676a48ed55eSmartin */
677a48ed55eSmartin static bool
get_disks_helper(void * arg,const char * dev)678a48ed55eSmartin get_disks_helper(void *arg, const char *dev)
679a48ed55eSmartin {
680a48ed55eSmartin struct get_disks_state *state = arg;
6814103857bSmartin struct disk_geom geo;
682a48ed55eSmartin
6833b44a3d7Smartin /* is this a CD device? */
68457cf8237Smartin if (is_cdrom_device(dev, true))
685a48ed55eSmartin return true;
6863b44a3d7Smartin
687c4cf3d8dSmartin memset(state->dd, 0, sizeof(*state->dd));
688a48ed55eSmartin strlcpy(state->dd->dd_name, dev, sizeof state->dd->dd_name - 2);
689c4cf3d8dSmartin state->dd->dd_no_mbr = !is_bootable_device(dev);
690c4cf3d8dSmartin state->dd->dd_no_part = !is_partitionable_device(dev);
6917a391039Smartin
692a48ed55eSmartin if (state->dd->dd_no_part && !state->with_non_partitionable)
693a48ed55eSmartin return true;
69450dbef1aSdholland
6954103857bSmartin if (!get_disk_geom(state->dd->dd_name, &geo)) {
69650dbef1aSdholland if (errno == ENOENT)
697a48ed55eSmartin return true;
698a48ed55eSmartin if (errno != ENOTTY || !state->dd->dd_no_part)
6992575b4dcSmartin /*
7002575b4dcSmartin * Allow plain partitions,
7012575b4dcSmartin * like already existing wedges
7022575b4dcSmartin * (like dk0) if marked as
7032575b4dcSmartin * non-partitioning device.
7042575b4dcSmartin * For all other cases, continue
7052575b4dcSmartin * with the next disk.
7062575b4dcSmartin */
707a48ed55eSmartin return true;
708a48ed55eSmartin if (!is_ffs_wedge(state->dd->dd_name))
709a48ed55eSmartin return true;
71050dbef1aSdholland }
71150dbef1aSdholland
71250dbef1aSdholland /*
71350dbef1aSdholland * Exclude a disk mounted as root partition,
71450dbef1aSdholland * in case of install-image on a USB memstick.
71550dbef1aSdholland */
7165864e121Smartin if (is_active_rootpart(state->dd->dd_name,
7175864e121Smartin state->dd->dd_no_part ? -1 : 0))
718a48ed55eSmartin return true;
71950dbef1aSdholland
7204103857bSmartin state->dd->dd_cyl = geo.dg_ncylinders;
7214103857bSmartin state->dd->dd_head = geo.dg_ntracks;
7224103857bSmartin state->dd->dd_sec = geo.dg_nsectors;
7234103857bSmartin state->dd->dd_secsize = geo.dg_secsize;
7244103857bSmartin state->dd->dd_totsec = geo.dg_secperunit;
7254103857bSmartin
7264103857bSmartin if (!state->dd->dd_no_part || !get_wedge_descr(state->dd))
727a48ed55eSmartin get_descr(state->dd);
728a48ed55eSmartin state->dd++;
729a48ed55eSmartin state->numdisks++;
730a48ed55eSmartin if (state->numdisks == MAX_DISKS)
731a48ed55eSmartin return false;
732a48ed55eSmartin
733a48ed55eSmartin return true;
73450dbef1aSdholland }
735a48ed55eSmartin
736a48ed55eSmartin /*
737a48ed55eSmartin * Get all disk devices that are not CDs.
738a48ed55eSmartin * Optionally leave out those that can not be partitioned further.
739a48ed55eSmartin */
740a48ed55eSmartin static int
get_disks(struct disk_desc * dd,bool with_non_partitionable)741a48ed55eSmartin get_disks(struct disk_desc *dd, bool with_non_partitionable)
742a48ed55eSmartin {
743a48ed55eSmartin struct get_disks_state state;
744a48ed55eSmartin
745a48ed55eSmartin /* initialize */
746a48ed55eSmartin state.numdisks = 0;
747a48ed55eSmartin state.dd = dd;
748a48ed55eSmartin state.with_non_partitionable = with_non_partitionable;
749a48ed55eSmartin
750a48ed55eSmartin if (enumerate_disks(&state, get_disks_helper))
751a48ed55eSmartin return state.numdisks;
752a48ed55eSmartin
753a48ed55eSmartin return 0;
75450dbef1aSdholland }
75550dbef1aSdholland
7564103857bSmartin #ifdef DEBUG_VERBOSE
7574103857bSmartin static void
dump_parts(const struct disk_partitions * parts)7584103857bSmartin dump_parts(const struct disk_partitions *parts)
7594103857bSmartin {
7604103857bSmartin fprintf(stderr, "%s partitions on %s:\n",
7614103857bSmartin MSG_XLAT(parts->pscheme->short_name), parts->disk);
7624103857bSmartin
7634103857bSmartin for (size_t p = 0; p < parts->num_part; p++) {
7644103857bSmartin struct disk_part_info info;
7654103857bSmartin
7664103857bSmartin if (parts->pscheme->get_part_info(
7674103857bSmartin parts, p, &info)) {
7684103857bSmartin fprintf(stderr, " #%zu: start: %" PRIu64 " "
7694103857bSmartin "size: %" PRIu64 ", flags: %x\n",
7704103857bSmartin p, info.start, info.size,
7714103857bSmartin info.flags);
7724103857bSmartin if (info.nat_type)
7734103857bSmartin fprintf(stderr, "\ttype: %s\n",
7744103857bSmartin info.nat_type->description);
7754103857bSmartin } else {
7764103857bSmartin fprintf(stderr, "failed to get info "
7774103857bSmartin "for partition #%zu\n", p);
7784103857bSmartin }
7794103857bSmartin }
7804103857bSmartin fprintf(stderr, "%" PRIu64 " sectors free, disk size %" PRIu64
7814103857bSmartin " sectors, %zu partitions used\n", parts->free_space,
7824103857bSmartin parts->disk_size, parts->num_part);
7834103857bSmartin }
7844103857bSmartin #endif
7854103857bSmartin
7864103857bSmartin static bool
delete_scheme(struct pm_devs * p)7874103857bSmartin delete_scheme(struct pm_devs *p)
7884103857bSmartin {
7894103857bSmartin
7904103857bSmartin if (!ask_noyes(MSG_removepartswarn))
7914103857bSmartin return false;
7924103857bSmartin
7934103857bSmartin p->parts->pscheme->free(p->parts);
7944103857bSmartin p->parts = NULL;
7954103857bSmartin return true;
7964103857bSmartin }
7974103857bSmartin
7984103857bSmartin
79974e9a67aSmartin static bool
convert_copy(struct disk_partitions * old_parts,struct disk_partitions * new_parts)8004103857bSmartin convert_copy(struct disk_partitions *old_parts,
8014103857bSmartin struct disk_partitions *new_parts)
8024103857bSmartin {
8034103857bSmartin struct disk_part_info oinfo, ninfo;
8044103857bSmartin part_id i;
80574e9a67aSmartin bool err = false;
8064103857bSmartin
8074103857bSmartin for (i = 0; i < old_parts->num_part; i++) {
8084103857bSmartin if (!old_parts->pscheme->get_part_info(old_parts, i, &oinfo))
8094103857bSmartin continue;
8104103857bSmartin
8114103857bSmartin if (oinfo.flags & PTI_PSCHEME_INTERNAL)
8124103857bSmartin continue;
8134103857bSmartin
8144103857bSmartin if (oinfo.flags & PTI_SEC_CONTAINER) {
8154103857bSmartin if (old_parts->pscheme->secondary_partitions) {
8164103857bSmartin struct disk_partitions *sec_part =
8174103857bSmartin old_parts->pscheme->
8184103857bSmartin secondary_partitions(
81983478358Smartin old_parts, oinfo.start, false);
82074e9a67aSmartin if (sec_part && !convert_copy(sec_part,
82174e9a67aSmartin new_parts))
82274e9a67aSmartin err = true;
8234103857bSmartin }
8244103857bSmartin continue;
8254103857bSmartin }
8264103857bSmartin
8274103857bSmartin if (!new_parts->pscheme->adapt_foreign_part_info(new_parts,
82874e9a67aSmartin &ninfo, old_parts->pscheme, &oinfo)) {
82974e9a67aSmartin err = true;
8304103857bSmartin continue;
8314103857bSmartin }
83274e9a67aSmartin if (!new_parts->pscheme->add_partition(new_parts, &ninfo,
83374e9a67aSmartin NULL))
83474e9a67aSmartin err = true;
83574e9a67aSmartin }
83674e9a67aSmartin return !err;
8374103857bSmartin }
8384103857bSmartin
8394103857bSmartin bool
convert_scheme(struct pm_devs * p,bool is_boot_drive,const char ** err_msg)8404103857bSmartin convert_scheme(struct pm_devs *p, bool is_boot_drive, const char **err_msg)
8414103857bSmartin {
8424103857bSmartin struct disk_partitions *old_parts, *new_parts;
8434103857bSmartin const struct disk_partitioning_scheme *new_scheme;
8444103857bSmartin
8454103857bSmartin *err_msg = NULL;
8464103857bSmartin
8474103857bSmartin old_parts = p->parts;
8484103857bSmartin new_scheme = select_part_scheme(p, old_parts->pscheme,
8494103857bSmartin false, MSG_select_other_partscheme);
8504103857bSmartin
8510c74f0eeSmartin if (new_scheme == NULL) {
8520c74f0eeSmartin if (err_msg)
8530c74f0eeSmartin *err_msg = INTERNAL_ERROR;
8544103857bSmartin return false;
8550c74f0eeSmartin }
8564103857bSmartin
8574103857bSmartin new_parts = new_scheme->create_new_for_disk(p->diskdev,
85886906049Smartin 0, p->dlsize, is_boot_drive, NULL);
8590c74f0eeSmartin if (new_parts == NULL) {
8600c74f0eeSmartin if (err_msg)
8610c74f0eeSmartin *err_msg = MSG_out_of_memory;
8624103857bSmartin return false;
8630c74f0eeSmartin }
8644103857bSmartin
86574e9a67aSmartin if (!convert_copy(old_parts, new_parts)) {
8664103857bSmartin /* need to cleanup */
86774e9a67aSmartin if (err_msg)
86874e9a67aSmartin *err_msg = MSG_cvtscheme_error;
8694103857bSmartin new_parts->pscheme->free(new_parts);
8704103857bSmartin return false;
8714103857bSmartin }
8724103857bSmartin
8734103857bSmartin old_parts->pscheme->free(old_parts);
8744103857bSmartin p->parts = new_parts;
8754103857bSmartin return true;
8764103857bSmartin }
8774103857bSmartin
878b1fa9754Smartin static struct pm_devs *
dummy_whole_system_pm(void)879b1fa9754Smartin dummy_whole_system_pm(void)
880b1fa9754Smartin {
881b1fa9754Smartin static struct pm_devs whole_system = {
882b1fa9754Smartin .diskdev = "/",
883b1fa9754Smartin .no_mbr = true,
884b1fa9754Smartin .no_part = true,
885b1fa9754Smartin .cur_system = true,
886b1fa9754Smartin };
887b1fa9754Smartin static bool init = false;
888b1fa9754Smartin
889b1fa9754Smartin if (!init) {
890b1fa9754Smartin strlcpy(whole_system.diskdev_descr,
891b1fa9754Smartin msg_string(MSG_running_system),
892b1fa9754Smartin sizeof whole_system.diskdev_descr);
893b1fa9754Smartin }
894b1fa9754Smartin
895b1fa9754Smartin return &whole_system;
896b1fa9754Smartin }
897b1fa9754Smartin
89850dbef1aSdholland int
find_disks(const char * doingwhat,bool allow_cur_system)899b1fa9754Smartin find_disks(const char *doingwhat, bool allow_cur_system)
90050dbef1aSdholland {
90150dbef1aSdholland struct disk_desc disks[MAX_DISKS];
902b1fa9754Smartin /* need two more menu entries: current system + extended partitioning */
90332928aa7Smartin menu_ent dsk_menu[__arraycount(disks) + 2],
90432928aa7Smartin wedge_menu[__arraycount(dsk_menu)];
90532928aa7Smartin int disk_no[__arraycount(dsk_menu)], wedge_no[__arraycount(dsk_menu)];
90650dbef1aSdholland struct disk_desc *disk;
90732928aa7Smartin int i = 0, dno, wno, skipped = 0;
9082575b4dcSmartin int already_found, numdisks, selected_disk = -1;
90932928aa7Smartin int menu_no, w_menu_no;
9106ce58267Smartin size_t max_desc_len;
9114103857bSmartin struct pm_devs *pm_i, *pm_last = NULL;
91232928aa7Smartin bool any_wedges = false;
9134103857bSmartin
9144103857bSmartin memset(dsk_menu, 0, sizeof(dsk_menu));
91532928aa7Smartin memset(wedge_menu, 0, sizeof(wedge_menu));
91650dbef1aSdholland
91750dbef1aSdholland /* Find disks. */
918a48ed55eSmartin numdisks = get_disks(disks, partman_go <= 0);
91950dbef1aSdholland
92050dbef1aSdholland /* need a redraw here, kernel messages hose everything */
92150dbef1aSdholland touchwin(stdscr);
92250dbef1aSdholland refresh();
92350dbef1aSdholland /* Kill typeahead, it won't be what the user had in mind */
92450dbef1aSdholland fpurge(stdin);
9256ce58267Smartin /*
9266ce58267Smartin * we need space for the menu box and the row label,
9276ce58267Smartin * this sums up to 7 characters.
9286ce58267Smartin */
9296ce58267Smartin max_desc_len = getmaxx(stdscr) - 8;
9306ce58267Smartin if (max_desc_len >= __arraycount(disks[0].dd_descr))
9316ce58267Smartin max_desc_len = __arraycount(disks[0].dd_descr) - 1;
93250dbef1aSdholland
933bbeaff62Sisaki /*
934bbeaff62Sisaki * partman_go: <0 - we want to see menu with extended partitioning
935bbeaff62Sisaki * ==0 - we want to see simple select disk menu
936bbeaff62Sisaki * >0 - we do not want to see any menus, just detect
937bbeaff62Sisaki * all disks
938bbeaff62Sisaki */
9394b2364d9Smartin if (partman_go <= 0) {
940b1fa9754Smartin if (numdisks == 0 && !allow_cur_system) {
94150dbef1aSdholland /* No disks found! */
9424103857bSmartin hit_enter_to_continue(MSG_nodisk, NULL);
94350dbef1aSdholland /*endwin();*/
94450dbef1aSdholland return -1;
94550dbef1aSdholland } else {
946b1fa9754Smartin /* One or more disks found or current system allowed */
94732928aa7Smartin dno = wno = 0;
948b1fa9754Smartin if (allow_cur_system) {
94932928aa7Smartin dsk_menu[dno].opt_name = MSG_running_system;
95032928aa7Smartin dsk_menu[dno].opt_flags = OPT_EXIT;
95132928aa7Smartin dsk_menu[dno].opt_action = set_menu_select;
95232928aa7Smartin disk_no[dno] = -1;
95332928aa7Smartin i++; dno++;
954b1fa9754Smartin }
95532928aa7Smartin for (i = 0; i < numdisks; i++) {
95632928aa7Smartin if (disks[i].dd_no_part) {
95732928aa7Smartin any_wedges = true;
95832928aa7Smartin wedge_menu[wno].opt_name =
95932928aa7Smartin disks[i].dd_descr;
9606ce58267Smartin disks[i].dd_descr[max_desc_len] = 0;
96132928aa7Smartin wedge_menu[wno].opt_flags = OPT_EXIT;
96232928aa7Smartin wedge_menu[wno].opt_action =
96332928aa7Smartin set_menu_select;
96432928aa7Smartin wedge_no[wno] = i;
96532928aa7Smartin wno++;
96632928aa7Smartin } else {
96732928aa7Smartin dsk_menu[dno].opt_name =
96832928aa7Smartin disks[i].dd_descr;
9696ce58267Smartin disks[i].dd_descr[max_desc_len] = 0;
97032928aa7Smartin dsk_menu[dno].opt_flags = OPT_EXIT;
97132928aa7Smartin dsk_menu[dno].opt_action =
97232928aa7Smartin set_menu_select;
97332928aa7Smartin disk_no[dno] = i;
97432928aa7Smartin dno++;
97532928aa7Smartin }
97632928aa7Smartin }
97732928aa7Smartin if (any_wedges) {
97832928aa7Smartin dsk_menu[dno].opt_name = MSG_selectwedge;
97932928aa7Smartin dsk_menu[dno].opt_flags = OPT_EXIT;
98032928aa7Smartin dsk_menu[dno].opt_action = set_menu_select;
98132928aa7Smartin disk_no[dno] = -2;
98232928aa7Smartin dno++;
9834b2364d9Smartin }
9844b2364d9Smartin if (partman_go < 0) {
98532928aa7Smartin dsk_menu[dno].opt_name = MSG_partman;
98632928aa7Smartin dsk_menu[dno].opt_flags = OPT_EXIT;
98732928aa7Smartin dsk_menu[dno].opt_action = set_menu_select;
98832928aa7Smartin disk_no[dno] = -3;
98932928aa7Smartin dno++;
99050dbef1aSdholland }
99132928aa7Smartin w_menu_no = -1;
99250dbef1aSdholland menu_no = new_menu(MSG_Available_disks,
99332928aa7Smartin dsk_menu, dno, -1,
9942575b4dcSmartin 4, 0, 0, MC_SCROLL,
9957ca7eecaSmartin NULL, NULL, NULL, NULL, MSG_exit_menu_generic);
99650dbef1aSdholland if (menu_no == -1)
99750dbef1aSdholland return -1;
99832928aa7Smartin for (;;) {
99924ecf24eSchristos msg_fmt_display(MSG_ask_disk, "%s", doingwhat);
100032928aa7Smartin i = -1;
100132928aa7Smartin process_menu(menu_no, &i);
10027e86db2eSmartin if (i == -1)
10037e86db2eSmartin return -1;
100432928aa7Smartin if (disk_no[i] == -2) {
100532928aa7Smartin /* do wedges menu */
100632928aa7Smartin if (w_menu_no == -1) {
100732928aa7Smartin w_menu_no = new_menu(
100832928aa7Smartin MSG_Available_wedges,
100932928aa7Smartin wedge_menu, wno, -1,
101032928aa7Smartin 4, 0, 0, MC_SCROLL,
101132928aa7Smartin NULL, NULL, NULL, NULL,
101232928aa7Smartin MSG_exit_menu_generic);
101332928aa7Smartin if (w_menu_no == -1) {
101432928aa7Smartin selected_disk = -1;
101532928aa7Smartin break;
101632928aa7Smartin }
101732928aa7Smartin }
101832928aa7Smartin i = -1;
101932928aa7Smartin process_menu(w_menu_no, &i);
102032928aa7Smartin if (i == -1)
102132928aa7Smartin continue;
102232928aa7Smartin selected_disk = wedge_no[i];
102332928aa7Smartin break;
102432928aa7Smartin }
102532928aa7Smartin selected_disk = disk_no[i];
102632928aa7Smartin break;
102732928aa7Smartin }
102832928aa7Smartin if (w_menu_no >= 0)
102932928aa7Smartin free_menu(w_menu_no);
103050dbef1aSdholland free_menu(menu_no);
103132928aa7Smartin if (allow_cur_system && selected_disk == -1) {
1032b1fa9754Smartin pm = dummy_whole_system_pm();
1033b1fa9754Smartin return 1;
1034b1fa9754Smartin }
1035b1fa9754Smartin }
103632928aa7Smartin if (partman_go < 0 && selected_disk == -3) {
10374b2364d9Smartin partman_go = 1;
10384b2364d9Smartin return -2;
10394b2364d9Smartin } else
10404b2364d9Smartin partman_go = 0;
104132928aa7Smartin if (selected_disk < 0 || selected_disk < 0
104232928aa7Smartin || selected_disk >= numdisks)
10434b2364d9Smartin return -1;
10444b2364d9Smartin }
104550dbef1aSdholland
10464b2364d9Smartin /* Fill pm struct with device(s) info */
10474b2364d9Smartin for (i = 0; i < numdisks; i++) {
10484b2364d9Smartin if (! partman_go)
104950dbef1aSdholland disk = disks + selected_disk;
10504b2364d9Smartin else {
10514b2364d9Smartin disk = disks + i;
10524b2364d9Smartin already_found = 0;
10534b2364d9Smartin SLIST_FOREACH(pm_i, &pm_head, l) {
10544b2364d9Smartin pm_last = pm_i;
1055e32f4c09Smartin if (strcmp(pm_i->diskdev, disk->dd_name) == 0) {
1056e32f4c09Smartin already_found = 1;
10574b2364d9Smartin break;
10584b2364d9Smartin }
10594b2364d9Smartin }
1060e32f4c09Smartin if (pm_i != NULL && already_found) {
1061e32f4c09Smartin /*
1062e32f4c09Smartin * We already added this device, but
1063e32f4c09Smartin * partitions might have changed
1064e32f4c09Smartin */
1065e32f4c09Smartin if (!pm_i->found) {
1066e32f4c09Smartin pm_i->found = true;
1067e32f4c09Smartin if (pm_i->parts == NULL) {
1068e32f4c09Smartin pm_i->parts =
1069e32f4c09Smartin partitions_read_disk(
1070e32f4c09Smartin pm_i->diskdev,
1071f96c1808Smartin disk->dd_totsec,
107286906049Smartin disk->dd_secsize,
1073f96c1808Smartin disk->dd_no_mbr);
1074e32f4c09Smartin }
1075e32f4c09Smartin }
10764b2364d9Smartin continue;
10774b2364d9Smartin }
1078e32f4c09Smartin }
10794b2364d9Smartin pm = pm_new;
10804b2364d9Smartin pm->found = 1;
10814103857bSmartin pm->ptstart = 0;
10824103857bSmartin pm->ptsize = 0;
10834b2364d9Smartin strlcpy(pm->diskdev, disk->dd_name, sizeof pm->diskdev);
10844b2364d9Smartin strlcpy(pm->diskdev_descr, disk->dd_descr, sizeof pm->diskdev_descr);
108550dbef1aSdholland /* Use as a default disk if the user has the sets on a local disk */
108650dbef1aSdholland strlcpy(localfs_dev, disk->dd_name, sizeof localfs_dev);
108750dbef1aSdholland
10884103857bSmartin /*
10894103857bSmartin * Init disk size and geometry
10904103857bSmartin */
10914103857bSmartin pm->sectorsize = disk->dd_secsize;
10924103857bSmartin pm->dlcyl = disk->dd_cyl;
10934103857bSmartin pm->dlhead = disk->dd_head;
10944103857bSmartin pm->dlsec = disk->dd_sec;
10954103857bSmartin pm->dlsize = disk->dd_totsec;
10964103857bSmartin if (pm->dlsize == 0)
109786906049Smartin pm->dlsize =
109886906049Smartin disk->dd_cyl * disk->dd_head * disk->dd_sec;
10994103857bSmartin
1100f96c1808Smartin pm->parts = partitions_read_disk(pm->diskdev,
110186906049Smartin pm->dlsize, disk->dd_secsize, disk->dd_no_mbr);
11024103857bSmartin
11034103857bSmartin again:
11044103857bSmartin
11054103857bSmartin #ifdef DEBUG_VERBOSE
11064103857bSmartin if (pm->parts) {
11074103857bSmartin fputs("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n", stderr);
11084103857bSmartin dump_parts(pm->parts);
11094103857bSmartin
11104103857bSmartin if (pm->parts->pscheme->secondary_partitions) {
11114103857bSmartin const struct disk_partitions *sparts =
11124103857bSmartin pm->parts->pscheme->secondary_partitions(
111383478358Smartin pm->parts, pm->ptstart, false);
11144103857bSmartin if (sparts != NULL)
11154103857bSmartin dump_parts(sparts);
11164103857bSmartin }
11174103857bSmartin }
11184103857bSmartin #endif
11194103857bSmartin
11204103857bSmartin pm->no_mbr = disk->dd_no_mbr;
11212575b4dcSmartin pm->no_part = disk->dd_no_part;
11222575b4dcSmartin if (!pm->no_part) {
11234b2364d9Smartin pm->sectorsize = disk->dd_secsize;
11244b2364d9Smartin pm->dlcyl = disk->dd_cyl;
11254b2364d9Smartin pm->dlhead = disk->dd_head;
11264b2364d9Smartin pm->dlsec = disk->dd_sec;
11274b2364d9Smartin pm->dlsize = disk->dd_totsec;
11284b2364d9Smartin if (pm->dlsize == 0)
112986906049Smartin pm->dlsize =
113086906049Smartin disk->dd_cyl * disk->dd_head * disk->dd_sec;
11314103857bSmartin
11324103857bSmartin if (pm->parts && pm->parts->pscheme->size_limit != 0
11334103857bSmartin && pm->dlsize > pm->parts->pscheme->size_limit
11344103857bSmartin && ! partman_go) {
11354103857bSmartin
11364103857bSmartin char size[5], limit[5];
11374103857bSmartin
11384103857bSmartin humanize_number(size, sizeof(size),
113986906049Smartin (uint64_t)pm->dlsize * pm->sectorsize,
11404103857bSmartin "", HN_AUTOSCALE, HN_B | HN_NOSPACE
11414103857bSmartin | HN_DECIMAL);
11424103857bSmartin
11434103857bSmartin humanize_number(limit, sizeof(limit),
11444103857bSmartin (uint64_t)pm->parts->pscheme->size_limit
11454103857bSmartin * 512U,
11464103857bSmartin "", HN_AUTOSCALE, HN_B | HN_NOSPACE
11474103857bSmartin | HN_DECIMAL);
11484103857bSmartin
11494b2364d9Smartin if (logfp)
11504103857bSmartin fprintf(logfp,
11514103857bSmartin "disk %s: is too big (%" PRIu64
11524103857bSmartin " blocks, %s), will be truncated\n",
11534103857bSmartin pm->diskdev, pm->dlsize,
11544103857bSmartin size);
11554103857bSmartin
11564103857bSmartin msg_display_subst(MSG_toobigdisklabel, 5,
11574103857bSmartin pm->diskdev,
11584103857bSmartin msg_string(pm->parts->pscheme->name),
11594103857bSmartin msg_string(pm->parts->pscheme->short_name),
11604103857bSmartin size, limit);
11614103857bSmartin
11624103857bSmartin int sel = -1;
11634103857bSmartin const char *err = NULL;
11644103857bSmartin process_menu(MENU_convertscheme, &sel);
11654103857bSmartin if (sel == 1) {
11664103857bSmartin if (!delete_scheme(pm)) {
116750dbef1aSdholland return -1;
116850dbef1aSdholland }
11694103857bSmartin goto again;
11704103857bSmartin } else if (sel == 2) {
11714103857bSmartin if (!convert_scheme(pm,
11724103857bSmartin partman_go < 0, &err)) {
11734103857bSmartin if (err != NULL)
11744103857bSmartin err_msg_win(err);
11754103857bSmartin return -1;
11764103857bSmartin }
11774103857bSmartin goto again;
11784103857bSmartin } else if (sel == 3) {
11794103857bSmartin return -1;
11804103857bSmartin }
11814103857bSmartin pm->dlsize = pm->parts->pscheme->size_limit;
11824103857bSmartin }
11832575b4dcSmartin } else {
11842575b4dcSmartin pm->sectorsize = 0;
11852575b4dcSmartin pm->dlcyl = 0;
11862575b4dcSmartin pm->dlhead = 0;
11872575b4dcSmartin pm->dlsec = 0;
11882575b4dcSmartin pm->dlsize = 0;
11892575b4dcSmartin pm->no_mbr = 1;
11902575b4dcSmartin }
11914b2364d9Smartin pm->dlcylsize = pm->dlhead * pm->dlsec;
119250dbef1aSdholland
11934b2364d9Smartin if (partman_go) {
11944b2364d9Smartin pm_getrefdev(pm_new);
11954b2364d9Smartin if (SLIST_EMPTY(&pm_head) || pm_last == NULL)
11964b2364d9Smartin SLIST_INSERT_HEAD(&pm_head, pm_new, l);
11974b2364d9Smartin else
11984b2364d9Smartin SLIST_INSERT_AFTER(pm_last, pm_new, l);
11994103857bSmartin pm_new = malloc(sizeof (struct pm_devs));
12004b2364d9Smartin memset(pm_new, 0, sizeof *pm_new);
12014b2364d9Smartin } else
12024103857bSmartin /* We are not in partman and do not want to process
12034103857bSmartin * all devices, exit */
12044b2364d9Smartin break;
12054b2364d9Smartin }
120650dbef1aSdholland
12072575b4dcSmartin return numdisks-skipped;
120850dbef1aSdholland }
120950dbef1aSdholland
121050dbef1aSdholland static int
sort_part_usage_by_mount(const void * a,const void * b)12114103857bSmartin sort_part_usage_by_mount(const void *a, const void *b)
121250dbef1aSdholland {
12134103857bSmartin const struct part_usage_info *pa = a, *pb = b;
12144103857bSmartin
12154103857bSmartin /* sort all real partitions by mount point */
12164103857bSmartin if ((pa->instflags & PUIINST_MOUNT) &&
12174103857bSmartin (pb->instflags & PUIINST_MOUNT))
12184103857bSmartin return strcmp(pa->mount, pb->mount);
12194103857bSmartin
12204103857bSmartin /* real partitions go first */
12214103857bSmartin if (pa->instflags & PUIINST_MOUNT)
12224103857bSmartin return -1;
12234103857bSmartin if (pb->instflags & PUIINST_MOUNT)
12244103857bSmartin return 1;
12254103857bSmartin
12264103857bSmartin /* arbitrary order for all other partitions */
12274103857bSmartin if (pa->type == PT_swap)
12284103857bSmartin return -1;
12294103857bSmartin if (pb->type == PT_swap)
12304103857bSmartin return 1;
12314103857bSmartin if (pa->type < pb->type)
12324103857bSmartin return -1;
12334103857bSmartin if (pa->type > pb->type)
12344103857bSmartin return 1;
12354103857bSmartin if (pa->cur_part_id < pb->cur_part_id)
12364103857bSmartin return -1;
12374103857bSmartin if (pa->cur_part_id > pb->cur_part_id)
12384103857bSmartin return 1;
12394103857bSmartin return (uintptr_t)a < (uintptr_t)b ? -1 : 1;
124050dbef1aSdholland }
124150dbef1aSdholland
12420998f09fSmartin /*
12430998f09fSmartin * Are we able to newfs this type of file system?
12440998f09fSmartin * Keep in sync with switch labels below!
12450998f09fSmartin */
12460998f09fSmartin bool
can_newfs_fstype(unsigned int t)12470998f09fSmartin can_newfs_fstype(unsigned int t)
12480998f09fSmartin {
12490998f09fSmartin switch (t) {
12500998f09fSmartin case FS_APPLEUFS:
12510998f09fSmartin case FS_BSDFFS:
12520998f09fSmartin case FS_BSDLFS:
12530998f09fSmartin case FS_MSDOS:
12540998f09fSmartin case FS_EFI_SP:
12550998f09fSmartin case FS_SYSVBFS:
12560998f09fSmartin case FS_V7:
12570998f09fSmartin case FS_EX2FS:
12580998f09fSmartin return true;
12590998f09fSmartin }
12600998f09fSmartin return false;
12610998f09fSmartin }
12620998f09fSmartin
126350dbef1aSdholland int
make_filesystems(struct install_partition_desc * install)12644103857bSmartin make_filesystems(struct install_partition_desc *install)
126550dbef1aSdholland {
12664103857bSmartin int error = 0, partno = -1;
1267cb429b90Smartin char *newfs = NULL, devdev[PATH_MAX], rdev[PATH_MAX],
1268cb429b90Smartin opts[200], opt[30];
12694103857bSmartin size_t i;
12704103857bSmartin struct part_usage_info *ptn;
12714103857bSmartin struct disk_partitions *parts;
12724103857bSmartin const char *mnt_opts = NULL, *fsname = NULL;
127350dbef1aSdholland
1274b1fa9754Smartin if (pm->cur_system)
1275b1fa9754Smartin return 1;
1276b1fa9754Smartin
12772575b4dcSmartin if (pm->no_part) {
12782575b4dcSmartin /* check if this target device already has a ffs */
12794103857bSmartin snprintf(rdev, sizeof rdev, _PATH_DEV "/r%s", pm->diskdev);
12804103857bSmartin error = fsck_preen(rdev, "ffs", true);
12812575b4dcSmartin if (error) {
12822575b4dcSmartin if (!ask_noyes(MSG_No_filesystem_newfs))
12832575b4dcSmartin return EINVAL;
12842575b4dcSmartin error = run_program(RUN_DISPLAY | RUN_PROGRESS,
1285c6fbd201Smartin "/sbin/newfs -V2 -O2ea %s", rdev);
12862575b4dcSmartin }
12872575b4dcSmartin
12884f30cbf3Smartin md_pre_mount(install, 0);
12892575b4dcSmartin
12902575b4dcSmartin make_target_dir("/");
12914103857bSmartin
12924103857bSmartin snprintf(devdev, sizeof devdev, _PATH_DEV "%s", pm->diskdev);
12932575b4dcSmartin error = target_mount_do("-o async", devdev, "/");
12942575b4dcSmartin if (error) {
12954103857bSmartin msg_display_subst(MSG_mountfail, 2, devdev, "/");
12964103857bSmartin hit_enter_to_continue(NULL, NULL);
12972575b4dcSmartin }
12982575b4dcSmartin
12994103857bSmartin return error;
13004103857bSmartin }
130150dbef1aSdholland
130250dbef1aSdholland /* Making new file systems and mounting them */
130350dbef1aSdholland
130450dbef1aSdholland /* sort to ensure /usr/local is mounted after /usr (etc) */
13054103857bSmartin qsort(install->infos, install->num, sizeof(*install->infos),
13064103857bSmartin sort_part_usage_by_mount);
130750dbef1aSdholland
13084103857bSmartin for (i = 0; i < install->num; i++) {
130950dbef1aSdholland /*
1310d6ad8858Smartin * Newfs all file systems marked as needing this.
131187c16c7aSmartin * Mount the ones that have a mountpoint in the target.
131250dbef1aSdholland */
13134103857bSmartin ptn = &install->infos[i];
13144103857bSmartin parts = ptn->parts;
13150dfd6624Smartin newfs = NULL;
13160dfd6624Smartin fsname = NULL;
131750dbef1aSdholland
1318a8e7688bSmartin if (ptn->size == 0 || parts == NULL|| ptn->type == PT_swap)
131950dbef1aSdholland continue;
132050dbef1aSdholland
13214103857bSmartin if (parts->pscheme->get_part_device(parts, ptn->cur_part_id,
1322abce8cb3Smartin devdev, sizeof devdev, &partno, parent_device_only, false,
1323abce8cb3Smartin false) && is_active_rootpart(devdev, partno))
13244103857bSmartin continue;
13254103857bSmartin
13264103857bSmartin parts->pscheme->get_part_device(parts, ptn->cur_part_id,
1327abce8cb3Smartin devdev, sizeof devdev, &partno, plain_name, true, true);
13284103857bSmartin
13294103857bSmartin parts->pscheme->get_part_device(parts, ptn->cur_part_id,
1330abce8cb3Smartin rdev, sizeof rdev, &partno, raw_dev_name, true, true);
13314b2364d9Smartin
1332cb429b90Smartin opts[0] = 0;
13334103857bSmartin switch (ptn->fs_type) {
133450dbef1aSdholland case FS_APPLEUFS:
1335cb429b90Smartin if (ptn->fs_opt3 != 0)
1336cb429b90Smartin snprintf(opts, sizeof opts, "-i %u",
1337cb429b90Smartin ptn->fs_opt3);
1338cb429b90Smartin asprintf(&newfs, "/sbin/newfs %s", opts);
13394103857bSmartin mnt_opts = "-tffs -o async";
13404103857bSmartin fsname = "ffs";
134150dbef1aSdholland break;
134250dbef1aSdholland case FS_BSDFFS:
1343cb429b90Smartin if (ptn->fs_opt3 != 0)
1344cb429b90Smartin snprintf(opts, sizeof opts, "-i %u ",
1345cb429b90Smartin ptn->fs_opt3);
1346cb429b90Smartin if (ptn->fs_opt1 != 0) {
1347cb429b90Smartin snprintf(opt, sizeof opt, "-b %u ",
1348cb429b90Smartin ptn->fs_opt1);
1349cb429b90Smartin strcat(opts, opt);
1350cb429b90Smartin }
1351cb429b90Smartin if (ptn->fs_opt2 != 0) {
1352cb429b90Smartin snprintf(opt, sizeof opt, "-f %u ",
1353cb429b90Smartin ptn->fs_opt2);
1354cb429b90Smartin strcat(opts, opt);
1355cb429b90Smartin }
1356c6fbd201Smartin const char *ffs_fmt;
1357c6fbd201Smartin switch (ptn->fs_version) {
1358c6fbd201Smartin case 3: ffs_fmt = "2ea"; break;
1359c6fbd201Smartin case 2: ffs_fmt = "2"; break;
1360c6fbd201Smartin case 1:
1361c6fbd201Smartin default: ffs_fmt = "1"; break;
1362c6fbd201Smartin }
136350dbef1aSdholland asprintf(&newfs,
1364c6fbd201Smartin "/sbin/newfs -V2 -O %s %s",
1365c6fbd201Smartin ffs_fmt, opts);
13664103857bSmartin if (ptn->mountflags & PUIMNT_LOG)
13674103857bSmartin mnt_opts = "-tffs -o log";
136850dbef1aSdholland else
13694103857bSmartin mnt_opts = "-tffs -o async";
13704103857bSmartin fsname = "ffs";
137150dbef1aSdholland break;
137250dbef1aSdholland case FS_BSDLFS:
1373cb429b90Smartin if (ptn->fs_opt1 != 0 && ptn->fs_opt2 != 0)
1374cb429b90Smartin snprintf(opts, sizeof opts, "-b %u",
1375cb429b90Smartin ptn->fs_opt1 * ptn->fs_opt2);
1376cb429b90Smartin asprintf(&newfs, "/sbin/newfs_lfs %s", opts);
13774103857bSmartin mnt_opts = "-tlfs";
13784103857bSmartin fsname = "lfs";
137950dbef1aSdholland break;
138050dbef1aSdholland case FS_MSDOS:
13810998f09fSmartin case FS_EFI_SP:
138250dbef1aSdholland asprintf(&newfs, "/sbin/newfs_msdos");
13834103857bSmartin mnt_opts = "-tmsdos";
13844103857bSmartin fsname = "msdos";
138550dbef1aSdholland break;
138650dbef1aSdholland case FS_SYSVBFS:
138750dbef1aSdholland asprintf(&newfs, "/sbin/newfs_sysvbfs");
13884103857bSmartin mnt_opts = "-tsysvbfs";
13894103857bSmartin fsname = "sysvbfs";
139050dbef1aSdholland break;
13910dfd6624Smartin case FS_V7:
13920dfd6624Smartin asprintf(&newfs, "/sbin/newfs_v7fs");
13930dfd6624Smartin mnt_opts = "-tv7fs";
13940dfd6624Smartin fsname = "v7fs";
13950dfd6624Smartin break;
139650dbef1aSdholland case FS_EX2FS:
1397675f7bf6Smartin asprintf(&newfs,
1398675f7bf6Smartin ptn->fs_version == 1 ?
1399675f7bf6Smartin "/sbin/newfs_ext2fs -O 0" :
1400675f7bf6Smartin "/sbin/newfs_ext2fs");
14014103857bSmartin mnt_opts = "-text2fs";
14024103857bSmartin fsname = "ext2fs";
140350dbef1aSdholland break;
140450dbef1aSdholland }
14054103857bSmartin if ((ptn->instflags & PUIINST_NEWFS) && newfs != NULL) {
140650dbef1aSdholland error = run_program(RUN_DISPLAY | RUN_PROGRESS,
14074103857bSmartin "%s %s", newfs, rdev);
14080dfd6624Smartin } else if ((ptn->instflags & (PUIINST_MOUNT|PUIINST_BOOT))
14090dfd6624Smartin && fsname != NULL) {
141050dbef1aSdholland /* We'd better check it isn't dirty */
14114103857bSmartin error = fsck_preen(devdev, fsname, false);
141250dbef1aSdholland }
141350dbef1aSdholland free(newfs);
14144103857bSmartin if (error != 0)
141550dbef1aSdholland return error;
141650dbef1aSdholland
14174103857bSmartin ptn->instflags &= ~PUIINST_NEWFS;
14184f30cbf3Smartin md_pre_mount(install, i);
141950dbef1aSdholland
14204103857bSmartin if (partman_go == 0 && (ptn->instflags & PUIINST_MOUNT) &&
14214103857bSmartin mnt_opts != NULL) {
14224103857bSmartin make_target_dir(ptn->mount);
14234103857bSmartin error = target_mount_do(mnt_opts, devdev,
14244103857bSmartin ptn->mount);
142550dbef1aSdholland if (error) {
14264103857bSmartin msg_display_subst(MSG_mountfail, 2, devdev,
14274103857bSmartin ptn->mount);
14284103857bSmartin hit_enter_to_continue(NULL, NULL);
142950dbef1aSdholland return error;
143050dbef1aSdholland }
143150dbef1aSdholland }
143250dbef1aSdholland }
143350dbef1aSdholland return 0;
143450dbef1aSdholland }
143550dbef1aSdholland
143650dbef1aSdholland int
make_fstab(struct install_partition_desc * install)14374103857bSmartin make_fstab(struct install_partition_desc *install)
143850dbef1aSdholland {
143950dbef1aSdholland FILE *f;
14404103857bSmartin const char *dump_dev = NULL;
14414103857bSmartin const char *dev;
14424103857bSmartin char dev_buf[PATH_MAX], swap_dev[PATH_MAX];
14434103857bSmartin
1444b1fa9754Smartin if (pm->cur_system)
1445b1fa9754Smartin return 1;
1446b1fa9754Smartin
14474103857bSmartin swap_dev[0] = 0;
144850dbef1aSdholland
144950dbef1aSdholland /* Create the fstab. */
145050dbef1aSdholland make_target_dir("/etc");
145150dbef1aSdholland f = target_fopen("/etc/fstab", "w");
145250dbef1aSdholland scripting_fprintf(NULL, "cat <<EOF >%s/etc/fstab\n", target_prefix());
145350dbef1aSdholland
14544b2364d9Smartin if (logfp)
14554b2364d9Smartin (void)fprintf(logfp,
14564103857bSmartin "Making %s/etc/fstab (%s).\n", target_prefix(),
14574103857bSmartin pm->diskdev);
14584b2364d9Smartin
145950dbef1aSdholland if (f == NULL) {
146050dbef1aSdholland msg_display(MSG_createfstab);
146150dbef1aSdholland if (logfp)
146250dbef1aSdholland (void)fprintf(logfp, "Failed to make /etc/fstab!\n");
14634103857bSmartin hit_enter_to_continue(NULL, NULL);
14644b2364d9Smartin #ifndef DEBUG
146550dbef1aSdholland return 1;
146650dbef1aSdholland #else
146750dbef1aSdholland f = stdout;
146850dbef1aSdholland #endif
146950dbef1aSdholland }
147050dbef1aSdholland
1471c52e6b59Smartin scripting_fprintf(f, "# NetBSD /etc/fstab\n# See /usr/share/examples/"
1472c52e6b59Smartin "fstab/ for more examples.\n");
14732575b4dcSmartin
14742575b4dcSmartin if (pm->no_part) {
14752575b4dcSmartin /* single dk? target */
14762575b4dcSmartin char buf[200], parent[200], swap[200], *prompt;
14772575b4dcSmartin int res;
14782575b4dcSmartin
14792575b4dcSmartin if (!get_name_and_parent(pm->diskdev, buf, parent))
14802575b4dcSmartin goto done_with_disks;
1481a7267d53Smartin scripting_fprintf(f, NAME_PREFIX "%s\t/\tffs\trw\t\t1 1\n",
14822575b4dcSmartin buf);
14832575b4dcSmartin if (!find_swap_part_on(parent, swap))
14842575b4dcSmartin goto done_with_disks;
14854103857bSmartin const char *args[] = { parent, swap };
14864103857bSmartin prompt = str_arg_subst(msg_string(MSG_Auto_add_swap_part),
14874103857bSmartin __arraycount(args), args);
14882575b4dcSmartin res = ask_yesno(prompt);
14892575b4dcSmartin free(prompt);
14902575b4dcSmartin if (res)
1491a7267d53Smartin scripting_fprintf(f, NAME_PREFIX "%s\tnone"
14922575b4dcSmartin "\tswap\tsw,dp\t\t0 0\n", swap);
14932575b4dcSmartin goto done_with_disks;
14942575b4dcSmartin }
14952575b4dcSmartin
14964103857bSmartin for (size_t i = 0; i < install->num; i++) {
14974103857bSmartin
14984103857bSmartin const struct part_usage_info *ptn = &install->infos[i];
14994103857bSmartin
1500e1c38267Smartin if (ptn->size == 0)
1501e1c38267Smartin continue;
1502e1c38267Smartin
15030e7fb040Smartin bool is_tmpfs = ptn->type == PT_root &&
15040e7fb040Smartin ptn->fs_type == FS_TMPFS &&
15050e7fb040Smartin (ptn->flags & PUIFLG_JUST_MOUNTPOINT);
15060e7fb040Smartin
15070e7fb040Smartin if (!is_tmpfs && ptn->type != PT_swap &&
15084103857bSmartin (ptn->instflags & PUIINST_MOUNT) == 0)
15094103857bSmartin continue;
15104103857bSmartin
151150dbef1aSdholland const char *s = "";
15124103857bSmartin const char *mp = ptn->mount;
151350dbef1aSdholland const char *fstype = "ffs";
151450dbef1aSdholland int fsck_pass = 0, dump_freq = 0;
151550dbef1aSdholland
15164103857bSmartin if (ptn->parts->pscheme->get_part_device(ptn->parts,
15174103857bSmartin ptn->cur_part_id, dev_buf, sizeof dev_buf, NULL,
1518abce8cb3Smartin logical_name, true, false))
15194103857bSmartin dev = dev_buf;
15204b2364d9Smartin else
15214103857bSmartin dev = NULL;
15224b2364d9Smartin
152350dbef1aSdholland if (!*mp) {
152450dbef1aSdholland /*
152550dbef1aSdholland * No mount point specified, comment out line and
152650dbef1aSdholland * use /mnt as a placeholder for the mount point.
152750dbef1aSdholland */
152850dbef1aSdholland s = "# ";
152950dbef1aSdholland mp = "/mnt";
153050dbef1aSdholland }
153150dbef1aSdholland
15324103857bSmartin switch (ptn->fs_type) {
153350dbef1aSdholland case FS_UNUSED:
153450dbef1aSdholland continue;
153550dbef1aSdholland case FS_BSDLFS:
153650dbef1aSdholland /* If there is no LFS, just comment it out. */
153750dbef1aSdholland if (!check_lfs_progs())
153850dbef1aSdholland s = "# ";
153950dbef1aSdholland fstype = "lfs";
154050dbef1aSdholland /* FALLTHROUGH */
154150dbef1aSdholland case FS_BSDFFS:
154250dbef1aSdholland fsck_pass = (strcmp(mp, "/") == 0) ? 1 : 2;
154350dbef1aSdholland dump_freq = 1;
154450dbef1aSdholland break;
154550dbef1aSdholland case FS_MSDOS:
154650dbef1aSdholland fstype = "msdos";
154750dbef1aSdholland break;
154850dbef1aSdholland case FS_SWAP:
15494103857bSmartin if (swap_dev[0] == 0) {
1550f16eda65Smartin strlcpy(swap_dev, dev, sizeof swap_dev);
155150dbef1aSdholland dump_dev = ",dp";
155250dbef1aSdholland } else {
155350dbef1aSdholland dump_dev = "";
155450dbef1aSdholland }
15554103857bSmartin scripting_fprintf(f, "%s\t\tnone\tswap\tsw%s\t\t 0 0\n",
15564b2364d9Smartin dev, dump_dev);
155750dbef1aSdholland continue;
15580e7fb040Smartin #ifdef HAVE_TMPFS
15590e7fb040Smartin case FS_TMPFS:
15600e7fb040Smartin if (ptn->size < 0)
15610e7fb040Smartin scripting_fprintf(f,
15620e7fb040Smartin "tmpfs\t\t/tmp\ttmpfs\trw,-m=1777,"
15630e7fb040Smartin "-s=ram%%%" PRIu64 "\n", -ptn->size);
15640e7fb040Smartin else
15650e7fb040Smartin scripting_fprintf(f,
15660e7fb040Smartin "tmpfs\t\t/tmp\ttmpfs\trw,-m=1777,"
15670e7fb040Smartin "-s=%" PRIu64 "M\n", ptn->size);
15680e7fb040Smartin continue;
15690e7fb040Smartin #else
15700e7fb040Smartin case FS_MFS:
15710e7fb040Smartin if (swap_dev[0] != 0)
15720e7fb040Smartin scripting_fprintf(f,
15730e7fb040Smartin "%s\t\t/tmp\tmfs\trw,-s=%"
15740e7fb040Smartin PRIu64 "\n", swap_dev, ptn->size);
15750e7fb040Smartin else
15760e7fb040Smartin scripting_fprintf(f,
15770e7fb040Smartin "swap\t\t/tmp\tmfs\trw,-s=%"
15780e7fb040Smartin PRIu64 "\n", ptn->size);
15790e7fb040Smartin continue;
15800e7fb040Smartin #endif
158150dbef1aSdholland case FS_SYSVBFS:
158250dbef1aSdholland fstype = "sysvbfs";
158350dbef1aSdholland make_target_dir("/stand");
158450dbef1aSdholland break;
158550dbef1aSdholland default:
158650dbef1aSdholland fstype = "???";
158750dbef1aSdholland s = "# ";
158850dbef1aSdholland break;
158950dbef1aSdholland }
159050dbef1aSdholland /* The code that remounts root rw doesn't check the partition */
15914103857bSmartin if (strcmp(mp, "/") == 0 &&
15924103857bSmartin (ptn->instflags & PUIINST_MOUNT) == 0)
159350dbef1aSdholland s = "# ";
159450dbef1aSdholland
159550dbef1aSdholland scripting_fprintf(f,
15964103857bSmartin "%s%s\t\t%s\t%s\trw%s%s%s%s%s%s%s%s\t\t %d %d\n",
15974b2364d9Smartin s, dev, mp, fstype,
15984103857bSmartin ptn->mountflags & PUIMNT_LOG ? ",log" : "",
1599b8a71b59Smartin ptn->mountflags & PUIMNT_NOAUTO ? ",noauto" : "",
16004103857bSmartin ptn->mountflags & PUIMNT_ASYNC ? ",async" : "",
16014103857bSmartin ptn->mountflags & PUIMNT_NOATIME ? ",noatime" : "",
16024103857bSmartin ptn->mountflags & PUIMNT_NODEV ? ",nodev" : "",
16034103857bSmartin ptn->mountflags & PUIMNT_NODEVMTIME ? ",nodevmtime" : "",
16044103857bSmartin ptn->mountflags & PUIMNT_NOEXEC ? ",noexec" : "",
16054103857bSmartin ptn->mountflags & PUIMNT_NOSUID ? ",nosuid" : "",
160650dbef1aSdholland dump_freq, fsck_pass);
160750dbef1aSdholland }
16084103857bSmartin
16092575b4dcSmartin done_with_disks:
16103b44a3d7Smartin if (cdrom_dev[0] == 0)
16113b44a3d7Smartin get_default_cdrom(cdrom_dev, sizeof(cdrom_dev));
16123b44a3d7Smartin
161350dbef1aSdholland /* Add /kern, /proc and /dev/pts to fstab and make mountpoint. */
161450dbef1aSdholland scripting_fprintf(f, "kernfs\t\t/kern\tkernfs\trw\n");
161550dbef1aSdholland scripting_fprintf(f, "ptyfs\t\t/dev/pts\tptyfs\trw\n");
161650dbef1aSdholland scripting_fprintf(f, "procfs\t\t/proc\tprocfs\trw\n");
16176b2c2692Smartin if (cdrom_dev[0] != 0)
161850dbef1aSdholland scripting_fprintf(f, "/dev/%s\t\t/cdrom\tcd9660\tro,noauto\n",
16193b44a3d7Smartin cdrom_dev);
162050dbef1aSdholland scripting_fprintf(f, "%stmpfs\t\t/var/shm\ttmpfs\trw,-m1777,-sram%%25\n",
162150dbef1aSdholland tmpfs_on_var_shm() ? "" : "#");
162250dbef1aSdholland make_target_dir("/kern");
162350dbef1aSdholland make_target_dir("/proc");
162450dbef1aSdholland make_target_dir("/dev/pts");
16256b2c2692Smartin if (cdrom_dev[0] != 0)
162650dbef1aSdholland make_target_dir("/cdrom");
162750dbef1aSdholland make_target_dir("/var/shm");
162850dbef1aSdholland
162950dbef1aSdholland scripting_fprintf(NULL, "EOF\n");
163050dbef1aSdholland
163150dbef1aSdholland fclose(f);
163250dbef1aSdholland fflush(NULL);
163350dbef1aSdholland return 0;
163450dbef1aSdholland }
163550dbef1aSdholland
1636a7267d53Smartin static bool
find_part_by_name(const char * name,struct disk_partitions ** parts,part_id * pno)1637a7267d53Smartin find_part_by_name(const char *name, struct disk_partitions **parts,
1638a7267d53Smartin part_id *pno)
163950dbef1aSdholland {
1640a7267d53Smartin struct pm_devs *i;
1641a7267d53Smartin struct disk_partitions *ps;
1642a7267d53Smartin part_id id;
1643a7267d53Smartin struct disk_desc disks[MAX_DISKS];
1644a7267d53Smartin int n, cnt;
164550dbef1aSdholland
1646a7267d53Smartin if (SLIST_EMPTY(&pm_head)) {
1647a7267d53Smartin /*
1648a7267d53Smartin * List has not been filled, only "pm" is valid - check
1649a7267d53Smartin * that first.
1650a7267d53Smartin */
165138baaacfSmartin if (pm->parts != NULL &&
165238baaacfSmartin pm->parts->pscheme->find_by_name != NULL) {
1653a7267d53Smartin id = pm->parts->pscheme->find_by_name(pm->parts, name);
1654a7267d53Smartin if (id != NO_PART) {
1655a7267d53Smartin *pno = id;
1656a7267d53Smartin *parts = pm->parts;
1657a7267d53Smartin return true;
1658a7267d53Smartin }
1659a7267d53Smartin }
1660a7267d53Smartin /*
1661a7267d53Smartin * Not that easy - check all other disks
1662a7267d53Smartin */
1663a7267d53Smartin cnt = get_disks(disks, false);
1664a7267d53Smartin for (n = 0; n < cnt; n++) {
1665a7267d53Smartin if (strcmp(disks[n].dd_name, pm->diskdev) == 0)
1666a7267d53Smartin continue;
1667a7267d53Smartin ps = partitions_read_disk(disks[n].dd_name,
166886906049Smartin disks[n].dd_totsec,
166986906049Smartin disks[n].dd_secsize,
167086906049Smartin disks[n].dd_no_mbr);
1671a7267d53Smartin if (ps == NULL)
1672a7267d53Smartin continue;
1673a7267d53Smartin if (ps->pscheme->find_by_name == NULL)
1674a7267d53Smartin continue;
1675a7267d53Smartin id = ps->pscheme->find_by_name(ps, name);
1676a7267d53Smartin if (id != NO_PART) {
1677a7267d53Smartin *pno = id;
1678a7267d53Smartin *parts = ps;
1679a7267d53Smartin return true; /* XXX this leaks memory */
1680a7267d53Smartin }
1681a7267d53Smartin ps->pscheme->free(ps);
1682a7267d53Smartin }
16836de47033Smartin } else {
1684a7267d53Smartin SLIST_FOREACH(i, &pm_head, l) {
1685a7267d53Smartin if (i->parts == NULL)
1686a7267d53Smartin continue;
1687a7267d53Smartin if (i->parts->pscheme->find_by_name == NULL)
1688a7267d53Smartin continue;
1689a7267d53Smartin id = i->parts->pscheme->find_by_name(i->parts, name);
1690a7267d53Smartin if (id == NO_PART)
1691a7267d53Smartin continue;
1692a7267d53Smartin *pno = id;
1693a7267d53Smartin *parts = i->parts;
1694a7267d53Smartin return true;
1695a7267d53Smartin }
16966de47033Smartin }
16976de47033Smartin
1698a7267d53Smartin *pno = NO_PART;
1699a7267d53Smartin *parts = NULL;
1700a7267d53Smartin return false;
1701a7267d53Smartin }
1702a7267d53Smartin
1703a7267d53Smartin static int
1704a7267d53Smartin /*ARGSUSED*/
process_found_fs(struct data * list,size_t num,const struct lookfor * item,bool with_fsck)1705a7267d53Smartin process_found_fs(struct data *list, size_t num, const struct lookfor *item,
1706a7267d53Smartin bool with_fsck)
1707a7267d53Smartin {
1708a7267d53Smartin int error;
1709a7267d53Smartin char rdev[PATH_MAX], dev[PATH_MAX],
1710a7267d53Smartin options[STRSIZE], tmp[STRSIZE], *op, *last;
1711a7267d53Smartin const char *fsname = (const char*)item->var;
1712a7267d53Smartin part_id pno;
1713a7267d53Smartin struct disk_partitions *parts;
1714d7f55badSmartin size_t len;
1715d7f55badSmartin bool first, is_root;
1716a7267d53Smartin
1717a7267d53Smartin if (num < 2 || strstr(list[2].u.s_val, "noauto") != NULL)
1718a7267d53Smartin return 0;
1719a7267d53Smartin
1720d7f55badSmartin is_root = strcmp(list[1].u.s_val, "/") == 0;
1721d7f55badSmartin if (is_root && target_mounted())
1722a7267d53Smartin return 0;
1723a7267d53Smartin
1724a7267d53Smartin if (strcmp(item->head, name_prefix) == 0) {
1725a7267d53Smartin /* this fstab entry uses NAME= syntax */
17267cc1a7bbSmartin
17277cc1a7bbSmartin /* unescape */
17287cc1a7bbSmartin char *src, *dst;
17297cc1a7bbSmartin for (src = list[0].u.s_val, dst =src; src[0] != 0; ) {
17307cc1a7bbSmartin if (src[0] == '\\' && src[1] != 0)
17317cc1a7bbSmartin src++;
17327cc1a7bbSmartin *dst++ = *src++;
17337cc1a7bbSmartin }
17347cc1a7bbSmartin *dst = 0;
17357cc1a7bbSmartin
1736a7267d53Smartin if (!find_part_by_name(list[0].u.s_val,
1737a7267d53Smartin &parts, &pno) || parts == NULL || pno == NO_PART)
1738a7267d53Smartin return 0;
1739a7267d53Smartin parts->pscheme->get_part_device(parts, pno,
1740abce8cb3Smartin dev, sizeof(dev), NULL, plain_name, true, true);
1741a7267d53Smartin parts->pscheme->get_part_device(parts, pno,
1742abce8cb3Smartin rdev, sizeof(rdev), NULL, raw_dev_name, true, true);
1743a7267d53Smartin } else {
1744d7f55badSmartin /* this fstab entry uses the plain device name */
1745d7f55badSmartin if (is_root) {
1746d7f55badSmartin /*
1747d7f55badSmartin * PR 54480: we can not use the current device name
1748d7f55badSmartin * as it might be different from the real environment.
1749d7f55badSmartin * This is an abuse of the functionality, but it used
1750d7f55badSmartin * to work before (and still does work if only a single
1751d7f55badSmartin * target disk is involved).
1752d7f55badSmartin * Use the device name from the current "pm" instead.
1753d7f55badSmartin */
1754d7f55badSmartin strcpy(rdev, "/dev/r");
1755d7f55badSmartin strlcat(rdev, pm->diskdev, sizeof(rdev));
1756d7f55badSmartin strcpy(dev, "/dev/");
1757d7f55badSmartin strlcat(dev, pm->diskdev, sizeof(dev));
1758d7f55badSmartin /* copy over the partition letter, if any */
1759d7f55badSmartin len = strlen(list[0].u.s_val);
1760d7f55badSmartin if (list[0].u.s_val[len-1] >= 'a' &&
1761d7f55badSmartin list[0].u.s_val[len-1] <=
1762d7f55badSmartin ('a' + getmaxpartitions())) {
1763d7f55badSmartin strlcat(rdev, &list[0].u.s_val[len-1],
1764d7f55badSmartin sizeof(rdev));
1765d7f55badSmartin strlcat(dev, &list[0].u.s_val[len-1],
1766d7f55badSmartin sizeof(dev));
1767d7f55badSmartin }
1768d7f55badSmartin } else {
1769a7267d53Smartin strcpy(rdev, "/dev/r");
1770a7267d53Smartin strlcat(rdev, list[0].u.s_val, sizeof(rdev));
1771a7267d53Smartin strcpy(dev, "/dev/");
1772a7267d53Smartin strlcat(dev, list[0].u.s_val, sizeof(dev));
1773a7267d53Smartin }
1774d7f55badSmartin }
1775a7267d53Smartin
1776a7267d53Smartin if (with_fsck) {
1777a7267d53Smartin /* need the raw device for fsck_preen */
1778a7267d53Smartin error = fsck_preen(rdev, fsname, false);
177950dbef1aSdholland if (error != 0)
178050dbef1aSdholland return error;
1781a7267d53Smartin }
178250dbef1aSdholland
1783a7267d53Smartin /* add mount option for fs type */
1784a7267d53Smartin strcpy(options, "-t ");
1785a7267d53Smartin strlcat(options, fsname, sizeof(options));
1786a7267d53Smartin
1787a7267d53Smartin /* extract mount options from fstab */
1788a7267d53Smartin strlcpy(tmp, list[2].u.s_val, sizeof(tmp));
1789a7267d53Smartin for (first = true, op = strtok_r(tmp, ",", &last); op != NULL;
1790a7267d53Smartin op = strtok_r(NULL, ",", &last)) {
1791a7267d53Smartin if (strcmp(op, FSTAB_RW) == 0 ||
1792a7267d53Smartin strcmp(op, FSTAB_RQ) == 0 ||
1793a7267d53Smartin strcmp(op, FSTAB_RO) == 0 ||
1794a7267d53Smartin strcmp(op, FSTAB_SW) == 0 ||
1795a7267d53Smartin strcmp(op, FSTAB_DP) == 0 ||
1796a7267d53Smartin strcmp(op, FSTAB_XX) == 0)
1797a7267d53Smartin continue;
1798a7267d53Smartin if (first) {
1799a7267d53Smartin first = false;
1800a7267d53Smartin strlcat(options, " -o ", sizeof(options));
1801a7267d53Smartin } else {
1802a7267d53Smartin strlcat(options, ",", sizeof(options));
1803a7267d53Smartin }
1804a7267d53Smartin strlcat(options, op, sizeof(options));
1805a7267d53Smartin }
1806a7267d53Smartin
1807a7267d53Smartin error = target_mount(options, dev, list[1].u.s_val);
180850dbef1aSdholland if (error != 0) {
180924ecf24eSchristos msg_fmt_display(MSG_mount_failed, "%s", list[0].u.s_val);
1810e21052b4Smartin if (!ask_noyes(NULL))
181150dbef1aSdholland return error;
181250dbef1aSdholland }
181350dbef1aSdholland return 0;
181450dbef1aSdholland }
181550dbef1aSdholland
181650dbef1aSdholland static int
181750dbef1aSdholland /*ARGSUSED*/
found_fs(struct data * list,size_t num,const struct lookfor * item)1818a7267d53Smartin found_fs(struct data *list, size_t num, const struct lookfor *item)
181950dbef1aSdholland {
1820a7267d53Smartin return process_found_fs(list, num, item, true);
182150dbef1aSdholland }
1822a7267d53Smartin
1823a7267d53Smartin static int
1824a7267d53Smartin /*ARGSUSED*/
found_fs_nocheck(struct data * list,size_t num,const struct lookfor * item)1825a7267d53Smartin found_fs_nocheck(struct data *list, size_t num, const struct lookfor *item)
1826a7267d53Smartin {
1827a7267d53Smartin return process_found_fs(list, num, item, false);
1828a7267d53Smartin }
182950dbef1aSdholland
183050dbef1aSdholland /*
183150dbef1aSdholland * Do an fsck. On failure, inform the user by showing a warning
183250dbef1aSdholland * message and doing menu_ok() before proceeding.
18334103857bSmartin * The device passed should be the full qualified path to raw disk
18344103857bSmartin * (e.g. /dev/rwd0a).
183550dbef1aSdholland * Returns 0 on success, or nonzero return code from fsck() on failure.
183650dbef1aSdholland */
183750dbef1aSdholland static int
fsck_preen(const char * disk,const char * fsname,bool silent)18384103857bSmartin fsck_preen(const char *disk, const char *fsname, bool silent)
183950dbef1aSdholland {
18404103857bSmartin char *prog, err[12];
184150dbef1aSdholland int error;
184250dbef1aSdholland
184350dbef1aSdholland if (fsname == NULL)
184450dbef1aSdholland return 0;
184550dbef1aSdholland /* first, check if fsck program exists, if not, assume ok */
184650dbef1aSdholland asprintf(&prog, "/sbin/fsck_%s", fsname);
184750dbef1aSdholland if (prog == NULL)
184850dbef1aSdholland return 0;
18494d3ac9f2Smartin if (access(prog, X_OK) != 0) {
18504d3ac9f2Smartin free(prog);
185150dbef1aSdholland return 0;
18524d3ac9f2Smartin }
185350dbef1aSdholland if (!strcmp(fsname,"ffs"))
18544103857bSmartin fixsb(prog, disk);
18554103857bSmartin error = run_program(silent? RUN_SILENT|RUN_ERROR_OK : 0, "%s -p -q %s", prog, disk);
185650dbef1aSdholland free(prog);
18572575b4dcSmartin if (error != 0 && !silent) {
18584103857bSmartin sprintf(err, "%d", error);
18594103857bSmartin msg_display_subst(msg_string(MSG_badfs), 3,
18604103857bSmartin disk, fsname, err);
1861e21052b4Smartin if (ask_noyes(NULL))
186250dbef1aSdholland error = 0;
186350dbef1aSdholland /* XXX at this point maybe we should run a full fsck? */
186450dbef1aSdholland }
186550dbef1aSdholland return error;
186650dbef1aSdholland }
186750dbef1aSdholland
186850dbef1aSdholland /* This performs the same function as the etc/rc.d/fixsb script
186950dbef1aSdholland * which attempts to correct problems with ffs1 filesystems
187050dbef1aSdholland * which may have been introduced by booting a netbsd-current kernel
187150dbef1aSdholland * from between April of 2003 and January 2004. For more information
187250dbef1aSdholland * This script was developed as a response to NetBSD pr install/25138
187350dbef1aSdholland * Additional prs regarding the original issue include:
187450dbef1aSdholland * bin/17910 kern/21283 kern/21404 port-macppc/23925 port-macppc/23926
187550dbef1aSdholland */
187650dbef1aSdholland static void
fixsb(const char * prog,const char * disk)18774103857bSmartin fixsb(const char *prog, const char *disk)
187850dbef1aSdholland {
187950dbef1aSdholland int fd;
188050dbef1aSdholland int rval;
188150dbef1aSdholland union {
188250dbef1aSdholland struct fs fs;
188350dbef1aSdholland char buf[SBLOCKSIZE];
188450dbef1aSdholland } sblk;
188550dbef1aSdholland struct fs *fs = &sblk.fs;
188650dbef1aSdholland
18874103857bSmartin fd = open(disk, O_RDONLY);
188850dbef1aSdholland if (fd == -1)
188950dbef1aSdholland return;
189050dbef1aSdholland
189150dbef1aSdholland /* Read ffsv1 main superblock */
189250dbef1aSdholland rval = pread(fd, sblk.buf, sizeof sblk.buf, SBLOCK_UFS1);
189350dbef1aSdholland close(fd);
189450dbef1aSdholland if (rval != sizeof sblk.buf)
189550dbef1aSdholland return;
189650dbef1aSdholland
189750dbef1aSdholland if (fs->fs_magic != FS_UFS1_MAGIC &&
189850dbef1aSdholland fs->fs_magic != FS_UFS1_MAGIC_SWAPPED)
189950dbef1aSdholland /* Not FFSv1 */
190050dbef1aSdholland return;
190150dbef1aSdholland if (fs->fs_old_flags & FS_FLAGS_UPDATED)
190250dbef1aSdholland /* properly updated fslevel 4 */
190350dbef1aSdholland return;
190450dbef1aSdholland if (fs->fs_bsize != fs->fs_maxbsize)
190550dbef1aSdholland /* not messed up */
190650dbef1aSdholland return;
190750dbef1aSdholland
190850dbef1aSdholland /*
190950dbef1aSdholland * OK we have a munged fs, first 'upgrade' to fslevel 4,
191050dbef1aSdholland * We specify -b16 in order to stop fsck bleating that the
191150dbef1aSdholland * sb doesn't match the first alternate.
191250dbef1aSdholland */
191350dbef1aSdholland run_program(RUN_DISPLAY | RUN_PROGRESS,
19144103857bSmartin "%s -p -b 16 -c 4 %s", prog, disk);
191550dbef1aSdholland /* Then downgrade to fslevel 3 */
191650dbef1aSdholland run_program(RUN_DISPLAY | RUN_PROGRESS,
19174103857bSmartin "%s -p -c 3 %s", prog, disk);
191850dbef1aSdholland }
191950dbef1aSdholland
192050dbef1aSdholland /*
192150dbef1aSdholland * fsck and mount the root partition.
19224103857bSmartin * devdev is the fully qualified block device name.
192350dbef1aSdholland */
192450dbef1aSdholland static int
mount_root(const char * devdev,bool first,bool writeable,struct install_partition_desc * install)1925a7267d53Smartin mount_root(const char *devdev, bool first, bool writeable,
1926a7267d53Smartin struct install_partition_desc *install)
192750dbef1aSdholland {
192850dbef1aSdholland int error;
192950dbef1aSdholland
19304103857bSmartin error = fsck_preen(devdev, "ffs", false);
193150dbef1aSdholland if (error != 0)
193250dbef1aSdholland return error;
193350dbef1aSdholland
1934a7267d53Smartin if (first)
19354f30cbf3Smartin md_pre_mount(install, 0);
193650dbef1aSdholland
19374103857bSmartin /* Mount devdev on target's "".
193850dbef1aSdholland * If we pass "" as mount-on, Prefixing will DTRT.
193950dbef1aSdholland * for now, use no options.
194050dbef1aSdholland * XXX consider -o remount in case target root is
194150dbef1aSdholland * current root, still readonly from single-user?
194250dbef1aSdholland */
1943a7267d53Smartin return target_mount(writeable? "" : "-r", devdev, "");
194450dbef1aSdholland }
194550dbef1aSdholland
194650dbef1aSdholland /* Get information on the file systems mounted from the root filesystem.
194750dbef1aSdholland * Offer to convert them into 4.4BSD inodes if they are not 4.4BSD
194850dbef1aSdholland * inodes. Fsck them. Mount them.
194950dbef1aSdholland */
195050dbef1aSdholland
195150dbef1aSdholland int
mount_disks(struct install_partition_desc * install)19524103857bSmartin mount_disks(struct install_partition_desc *install)
195350dbef1aSdholland {
195450dbef1aSdholland char *fstab;
195550dbef1aSdholland int fstabsize;
195650dbef1aSdholland int error;
19574103857bSmartin char devdev[PATH_MAX];
1958a7267d53Smartin size_t i, num_fs_types, num_entries;
1959a7267d53Smartin struct lookfor *fstabbuf, *l;
196050dbef1aSdholland
1961b1fa9754Smartin if (install->cur_system)
1962b1fa9754Smartin return 0;
1963b1fa9754Smartin
1964a7267d53Smartin /*
1965a7267d53Smartin * Check what file system tools are available and create parsers
1966a7267d53Smartin * for the corresponding fstab(5) entries - all others will be
1967a7267d53Smartin * ignored.
1968a7267d53Smartin */
1969a7267d53Smartin num_fs_types = 1; /* ffs is implicit */
1970a7267d53Smartin for (i = 0; i < __arraycount(extern_fs_with_chk); i++) {
1971a7267d53Smartin sprintf(devdev, "/sbin/newfs_%s", extern_fs_with_chk[i]);
1972a7267d53Smartin if (file_exists_p(devdev))
1973a7267d53Smartin num_fs_types++;
1974a7267d53Smartin }
1975a7267d53Smartin for (i = 0; i < __arraycount(extern_fs_newfs_only); i++) {
1976a7267d53Smartin sprintf(devdev, "/sbin/newfs_%s", extern_fs_newfs_only[i]);
1977a7267d53Smartin if (file_exists_p(devdev))
1978a7267d53Smartin num_fs_types++;
1979a7267d53Smartin }
1980a7267d53Smartin num_entries = 2 * num_fs_types + 1; /* +1 for "ufs" special case */
1981a7267d53Smartin fstabbuf = calloc(num_entries, sizeof(*fstabbuf));
1982a7267d53Smartin if (fstabbuf == NULL)
1983a7267d53Smartin return -1;
1984a7267d53Smartin l = fstabbuf;
1985a7267d53Smartin l->head = "/dev/";
1986a7267d53Smartin l->fmt = strdup("/dev/%s %s ffs %s");
1987a7267d53Smartin l->todo = "c";
1988a7267d53Smartin l->var = __UNCONST("ffs");
1989a7267d53Smartin l->func = found_fs;
1990a7267d53Smartin l++;
1991a7267d53Smartin l->head = "/dev/";
1992a7267d53Smartin l->fmt = strdup("/dev/%s %s ufs %s");
1993a7267d53Smartin l->todo = "c";
1994a7267d53Smartin l->var = __UNCONST("ffs");
1995a7267d53Smartin l->func = found_fs;
1996a7267d53Smartin l++;
1997a7267d53Smartin l->head = NAME_PREFIX;
1998a7267d53Smartin l->fmt = strdup(NAME_PREFIX "%s %s ffs %s");
1999a7267d53Smartin l->todo = "c";
2000a7267d53Smartin l->var = __UNCONST("ffs");
2001a7267d53Smartin l->func = found_fs;
2002a7267d53Smartin l++;
2003a7267d53Smartin for (i = 0; i < __arraycount(extern_fs_with_chk); i++) {
2004a7267d53Smartin sprintf(devdev, "/sbin/newfs_%s", extern_fs_with_chk[i]);
2005a7267d53Smartin if (!file_exists_p(devdev))
2006a7267d53Smartin continue;
2007a7267d53Smartin sprintf(devdev, "/dev/%%s %%s %s %%s", extern_fs_with_chk[i]);
2008a7267d53Smartin l->head = "/dev/";
2009a7267d53Smartin l->fmt = strdup(devdev);
2010a7267d53Smartin l->todo = "c";
2011a7267d53Smartin l->var = __UNCONST(extern_fs_with_chk[i]);
2012a7267d53Smartin l->func = found_fs;
2013a7267d53Smartin l++;
2014a7267d53Smartin sprintf(devdev, NAME_PREFIX "%%s %%s %s %%s",
2015a7267d53Smartin extern_fs_with_chk[i]);
2016a7267d53Smartin l->head = NAME_PREFIX;
2017a7267d53Smartin l->fmt = strdup(devdev);
2018a7267d53Smartin l->todo = "c";
2019a7267d53Smartin l->var = __UNCONST(extern_fs_with_chk[i]);
2020a7267d53Smartin l->func = found_fs;
2021a7267d53Smartin l++;
2022a7267d53Smartin }
2023a7267d53Smartin for (i = 0; i < __arraycount(extern_fs_newfs_only); i++) {
2024a7267d53Smartin sprintf(devdev, "/sbin/newfs_%s", extern_fs_newfs_only[i]);
2025a7267d53Smartin if (!file_exists_p(devdev))
2026a7267d53Smartin continue;
2027a7267d53Smartin sprintf(devdev, "/dev/%%s %%s %s %%s", extern_fs_newfs_only[i]);
2028a7267d53Smartin l->head = "/dev/";
2029a7267d53Smartin l->fmt = strdup(devdev);
2030a7267d53Smartin l->todo = "c";
2031a7267d53Smartin l->var = __UNCONST(extern_fs_newfs_only[i]);
2032a7267d53Smartin l->func = found_fs_nocheck;
2033a7267d53Smartin l++;
2034a7267d53Smartin sprintf(devdev, NAME_PREFIX "%%s %%s %s %%s",
2035a7267d53Smartin extern_fs_newfs_only[i]);
2036a7267d53Smartin l->head = NAME_PREFIX;
2037a7267d53Smartin l->fmt = strdup(devdev);
2038a7267d53Smartin l->todo = "c";
2039a7267d53Smartin l->var = __UNCONST(extern_fs_newfs_only[i]);
2040a7267d53Smartin l->func = found_fs_nocheck;
2041a7267d53Smartin l++;
2042a7267d53Smartin }
2043a7267d53Smartin assert((size_t)(l - fstabbuf) == num_entries);
204450dbef1aSdholland
204550dbef1aSdholland /* First the root device. */
204638baaacfSmartin if (target_already_root()) {
204750dbef1aSdholland /* avoid needing to call target_already_root() again */
204850dbef1aSdholland targetroot_mnt[0] = 0;
204938baaacfSmartin } else if (pm->no_part) {
205038baaacfSmartin snprintf(devdev, sizeof devdev, _PATH_DEV "%s", pm->diskdev);
205138baaacfSmartin error = mount_root(devdev, true, false, install);
205238baaacfSmartin if (error != 0 && error != EBUSY)
205338baaacfSmartin return -1;
205438baaacfSmartin } else {
2055c2ed2005Smartin for (i = 0; i < install->num; i++) {
2056c2ed2005Smartin if (is_root_part_mount(install->infos[i].mount))
2057c2ed2005Smartin break;
2058c2ed2005Smartin }
2059c2ed2005Smartin
2060c2ed2005Smartin if (i >= install->num) {
2061c2ed2005Smartin hit_enter_to_continue(MSG_noroot, NULL);
2062c2ed2005Smartin return -1;
2063c2ed2005Smartin }
2064c2ed2005Smartin
2065c2ed2005Smartin if (!install->infos[i].parts->pscheme->get_part_device(
2066c2ed2005Smartin install->infos[i].parts, install->infos[i].cur_part_id,
2067abce8cb3Smartin devdev, sizeof devdev, NULL, plain_name, true, true))
20684103857bSmartin return -1;
2069a7267d53Smartin error = mount_root(devdev, true, false, install);
207050dbef1aSdholland if (error != 0 && error != EBUSY)
207150dbef1aSdholland return -1;
207250dbef1aSdholland }
207350dbef1aSdholland
207450dbef1aSdholland /* Check the target /etc/fstab exists before trying to parse it. */
207550dbef1aSdholland if (target_dir_exists_p("/etc") == 0 ||
207650dbef1aSdholland target_file_exists_p("/etc/fstab") == 0) {
207724ecf24eSchristos msg_fmt_display(MSG_noetcfstab, "%s", pm->diskdev);
20784103857bSmartin hit_enter_to_continue(NULL, NULL);
207950dbef1aSdholland return -1;
208050dbef1aSdholland }
208150dbef1aSdholland
208250dbef1aSdholland
208350dbef1aSdholland /* Get fstab entries from the target-root /etc/fstab. */
208450dbef1aSdholland fstabsize = target_collect_file(T_FILE, &fstab, "/etc/fstab");
208550dbef1aSdholland if (fstabsize < 0) {
208650dbef1aSdholland /* error ! */
208724ecf24eSchristos msg_fmt_display(MSG_badetcfstab, "%s", pm->diskdev);
20884103857bSmartin hit_enter_to_continue(NULL, NULL);
2089a7267d53Smartin umount_root();
20904b2364d9Smartin return -2;
209150dbef1aSdholland }
2092a7267d53Smartin /*
2093a7267d53Smartin * We unmount the read-only root again, so we can mount it
2094a7267d53Smartin * with proper options from /etc/fstab
2095a7267d53Smartin */
2096a7267d53Smartin umount_root();
2097a7267d53Smartin
2098a7267d53Smartin /*
2099a7267d53Smartin * Now do all entries in /etc/fstab and mount them if required
2100a7267d53Smartin */
2101a7267d53Smartin error = walk(fstab, (size_t)fstabsize, fstabbuf, num_entries);
210250dbef1aSdholland free(fstab);
2103a7267d53Smartin for (i = 0; i < num_entries; i++)
2104a7267d53Smartin free(__UNCONST(fstabbuf[i].fmt));
2105a7267d53Smartin free(fstabbuf);
210650dbef1aSdholland
210750dbef1aSdholland return error;
210850dbef1aSdholland }
210950dbef1aSdholland
211098c332e3Smartin static char swap_dev[PATH_MAX];
211198c332e3Smartin
211238248942Smartin void
set_swap_if_low_ram(struct install_partition_desc * install)21134103857bSmartin set_swap_if_low_ram(struct install_partition_desc *install)
2114bbeaff62Sisaki {
211598c332e3Smartin swap_dev[0] = 0;
21167fd225f6Smartin if (get_ramsize() <= TINY_RAM_SIZE)
211738248942Smartin set_swap(install);
211840a37f0dSabs }
211940a37f0dSabs
212038248942Smartin void
set_swap(struct install_partition_desc * install)21214103857bSmartin set_swap(struct install_partition_desc *install)
212250dbef1aSdholland {
21234103857bSmartin size_t i;
212450dbef1aSdholland int rval;
212550dbef1aSdholland
212698c332e3Smartin swap_dev[0] = 0;
21274103857bSmartin for (i = 0; i < install->num; i++) {
21284103857bSmartin if (install->infos[i].type == PT_swap)
21294103857bSmartin break;
21304103857bSmartin }
21314103857bSmartin if (i >= install->num)
213238248942Smartin return;
213350dbef1aSdholland
21344103857bSmartin if (!install->infos[i].parts->pscheme->get_part_device(
213598c332e3Smartin install->infos[i].parts, install->infos[i].cur_part_id, swap_dev,
213698c332e3Smartin sizeof swap_dev, NULL, plain_name, true, true))
213738248942Smartin return;
21384103857bSmartin
213998c332e3Smartin rval = swapctl(SWAP_ON, swap_dev, 0);
214038248942Smartin if (rval != 0)
214198c332e3Smartin swap_dev[0] = 0;
214298c332e3Smartin }
214398c332e3Smartin
214498c332e3Smartin void
clear_swap(void)214598c332e3Smartin clear_swap(void)
214698c332e3Smartin {
214798c332e3Smartin
214898c332e3Smartin if (swap_dev[0] == 0)
214998c332e3Smartin return;
215098c332e3Smartin swapctl(SWAP_OFF, swap_dev, 0);
215198c332e3Smartin swap_dev[0] = 0;
215250dbef1aSdholland }
215350dbef1aSdholland
215450dbef1aSdholland int
check_swap(const char * disk,int remove_swap)215550dbef1aSdholland check_swap(const char *disk, int remove_swap)
215650dbef1aSdholland {
215750dbef1aSdholland struct swapent *swap;
215850dbef1aSdholland char *cp;
215950dbef1aSdholland int nswap;
216050dbef1aSdholland int l;
216150dbef1aSdholland int rval = 0;
216250dbef1aSdholland
216350dbef1aSdholland nswap = swapctl(SWAP_NSWAP, 0, 0);
216450dbef1aSdholland if (nswap <= 0)
216550dbef1aSdholland return 0;
216650dbef1aSdholland
216750dbef1aSdholland swap = malloc(nswap * sizeof *swap);
216850dbef1aSdholland if (swap == NULL)
216950dbef1aSdholland return -1;
217050dbef1aSdholland
217150dbef1aSdholland nswap = swapctl(SWAP_STATS, swap, nswap);
217250dbef1aSdholland if (nswap < 0)
217350dbef1aSdholland goto bad_swap;
217450dbef1aSdholland
217550dbef1aSdholland l = strlen(disk);
217650dbef1aSdholland while (--nswap >= 0) {
217750dbef1aSdholland /* Should we check the se_dev or se_path? */
217850dbef1aSdholland cp = swap[nswap].se_path;
217950dbef1aSdholland if (memcmp(cp, "/dev/", 5) != 0)
218050dbef1aSdholland continue;
218150dbef1aSdholland if (memcmp(cp + 5, disk, l) != 0)
218250dbef1aSdholland continue;
218350dbef1aSdholland if (!isalpha(*(unsigned char *)(cp + 5 + l)))
218450dbef1aSdholland continue;
218550dbef1aSdholland if (cp[5 + l + 1] != 0)
218650dbef1aSdholland continue;
218750dbef1aSdholland /* ok path looks like it is for this device */
218850dbef1aSdholland if (!remove_swap) {
218950dbef1aSdholland /* count active swap areas */
219050dbef1aSdholland rval++;
219150dbef1aSdholland continue;
219250dbef1aSdholland }
219350dbef1aSdholland if (swapctl(SWAP_OFF, cp, 0) == -1)
219450dbef1aSdholland rval = -1;
219550dbef1aSdholland }
219650dbef1aSdholland
219750dbef1aSdholland done:
219850dbef1aSdholland free(swap);
219950dbef1aSdholland return rval;
220050dbef1aSdholland
220150dbef1aSdholland bad_swap:
220250dbef1aSdholland rval = -1;
220350dbef1aSdholland goto done;
220450dbef1aSdholland }
220550dbef1aSdholland
220650dbef1aSdholland #ifdef HAVE_BOOTXX_xFS
220750dbef1aSdholland char *
bootxx_name(struct install_partition_desc * install)22084103857bSmartin bootxx_name(struct install_partition_desc *install)
220950dbef1aSdholland {
2210df91044bSmartin size_t i;
2211df91044bSmartin int fstype = -1;
221250dbef1aSdholland const char *bootxxname;
221350dbef1aSdholland char *bootxx;
221450dbef1aSdholland
2215df91044bSmartin /* find a partition to be mounted as / */
2216df91044bSmartin for (i = 0; i < install->num; i++) {
2217df91044bSmartin if ((install->infos[i].instflags & PUIINST_MOUNT)
2218df91044bSmartin && strcmp(install->infos[i].mount, "/") == 0) {
2219df91044bSmartin fstype = install->infos[i].fs_type;
2220df91044bSmartin break;
2221df91044bSmartin }
2222df91044bSmartin }
2223df91044bSmartin if (fstype < 0) {
2224df91044bSmartin /* not found? take first root type partition instead */
2225df91044bSmartin for (i = 0; i < install->num; i++) {
2226df91044bSmartin if (install->infos[i].type == PT_root) {
2227df91044bSmartin fstype = install->infos[i].fs_type;
2228df91044bSmartin break;
2229df91044bSmartin }
2230df91044bSmartin }
2231df91044bSmartin }
2232df91044bSmartin
223350dbef1aSdholland /* check we have boot code for the root partition type */
223450dbef1aSdholland switch (fstype) {
223550dbef1aSdholland #if defined(BOOTXX_FFSV1) || defined(BOOTXX_FFSV2)
223650dbef1aSdholland case FS_BSDFFS:
2237cda02d64Smartin if (install->infos[i].fs_version >= 2) {
223850dbef1aSdholland #ifdef BOOTXX_FFSV2
223950dbef1aSdholland bootxxname = BOOTXX_FFSV2;
224050dbef1aSdholland #else
224150dbef1aSdholland bootxxname = NULL;
224250dbef1aSdholland #endif
224350dbef1aSdholland } else {
224450dbef1aSdholland #ifdef BOOTXX_FFSV1
224550dbef1aSdholland bootxxname = BOOTXX_FFSV1;
224650dbef1aSdholland #else
224750dbef1aSdholland bootxxname = NULL;
224850dbef1aSdholland #endif
224950dbef1aSdholland }
225050dbef1aSdholland break;
225150dbef1aSdholland #endif
22527935b6fcSpgoyette #ifdef BOOTXX_LFSV2
225350dbef1aSdholland case FS_BSDLFS:
22547935b6fcSpgoyette bootxxname = BOOTXX_LFSV2;
225550dbef1aSdholland break;
225650dbef1aSdholland #endif
225750dbef1aSdholland default:
225850dbef1aSdholland bootxxname = NULL;
225950dbef1aSdholland break;
226050dbef1aSdholland }
226150dbef1aSdholland
226250dbef1aSdholland if (bootxxname == NULL)
226350dbef1aSdholland return NULL;
226450dbef1aSdholland
226550dbef1aSdholland asprintf(&bootxx, "%s/%s", BOOTXXDIR, bootxxname);
226650dbef1aSdholland return bootxx;
226750dbef1aSdholland }
226850dbef1aSdholland #endif
22694b2364d9Smartin
22704b2364d9Smartin /* from dkctl.c */
22714b2364d9Smartin static int
get_dkwedges_sort(const void * a,const void * b)22724b2364d9Smartin get_dkwedges_sort(const void *a, const void *b)
22734b2364d9Smartin {
22744b2364d9Smartin const struct dkwedge_info *dkwa = a, *dkwb = b;
22754b2364d9Smartin const daddr_t oa = dkwa->dkw_offset, ob = dkwb->dkw_offset;
22764b2364d9Smartin return (oa < ob) ? -1 : (oa > ob) ? 1 : 0;
22774b2364d9Smartin }
22784b2364d9Smartin
22794b2364d9Smartin int
get_dkwedges(struct dkwedge_info ** dkw,const char * diskdev)22804b2364d9Smartin get_dkwedges(struct dkwedge_info **dkw, const char *diskdev)
22814b2364d9Smartin {
22824b2364d9Smartin struct dkwedge_list dkwl;
22834b2364d9Smartin
22844b2364d9Smartin *dkw = NULL;
228572ea5dbaSchristos if (!get_wedge_list(diskdev, &dkwl))
22864b2364d9Smartin return -1;
22874b2364d9Smartin
228872ea5dbaSchristos if (dkwl.dkwl_nwedges > 0 && *dkw != NULL) {
228972ea5dbaSchristos qsort(*dkw, dkwl.dkwl_nwedges, sizeof(**dkw),
229072ea5dbaSchristos get_dkwedges_sort);
22914b2364d9Smartin }
22924b2364d9Smartin
22934b2364d9Smartin return dkwl.dkwl_nwedges;
22944b2364d9Smartin }
2295f77b58b1Smartin
2296485d5309Smartin #ifndef NO_CLONES
2297f77b58b1Smartin /*
2298f77b58b1Smartin * Helper structures used in the partition select menu
2299f77b58b1Smartin */
2300f77b58b1Smartin struct single_partition {
2301f77b58b1Smartin struct disk_partitions *parts;
2302f77b58b1Smartin part_id id;
2303f77b58b1Smartin };
2304f77b58b1Smartin
2305f77b58b1Smartin struct sel_menu_data {
2306f77b58b1Smartin struct single_partition *partitions;
2307f77b58b1Smartin struct selected_partition result;
2308f77b58b1Smartin };
2309f77b58b1Smartin
2310f77b58b1Smartin static int
select_single_part(menudesc * m,void * arg)2311f77b58b1Smartin select_single_part(menudesc *m, void *arg)
2312f77b58b1Smartin {
2313f77b58b1Smartin struct sel_menu_data *data = arg;
2314f77b58b1Smartin
2315f77b58b1Smartin data->result.parts = data->partitions[m->cursel].parts;
2316f77b58b1Smartin data->result.id = data->partitions[m->cursel].id;
2317f77b58b1Smartin
2318f77b58b1Smartin return 1;
2319f77b58b1Smartin }
2320f77b58b1Smartin
2321f77b58b1Smartin static void
display_single_part(menudesc * m,int opt,void * arg)2322f77b58b1Smartin display_single_part(menudesc *m, int opt, void *arg)
2323f77b58b1Smartin {
2324f77b58b1Smartin const struct sel_menu_data *data = arg;
2325f77b58b1Smartin struct disk_part_info info;
2326f77b58b1Smartin struct disk_partitions *parts = data->partitions[opt].parts;
2327f77b58b1Smartin part_id id = data->partitions[opt].id;
2328f77b58b1Smartin int l;
2329f77b58b1Smartin const char *desc = NULL;
2330f77b58b1Smartin char line[MENUSTRSIZE*2];
2331f77b58b1Smartin
2332f77b58b1Smartin if (!parts->pscheme->get_part_info(parts, id, &info))
2333f77b58b1Smartin return;
2334f77b58b1Smartin
2335f77b58b1Smartin if (parts->pscheme->other_partition_identifier != NULL)
2336f77b58b1Smartin desc = parts->pscheme->other_partition_identifier(
2337f77b58b1Smartin parts, id);
2338f77b58b1Smartin
2339f77b58b1Smartin daddr_t start = info.start / sizemult;
2340f77b58b1Smartin daddr_t size = info.size / sizemult;
2341f77b58b1Smartin snprintf(line, sizeof line, "%s [%" PRIu64 " @ %" PRIu64 "]",
2342f77b58b1Smartin parts->disk, size, start);
2343f77b58b1Smartin
2344f77b58b1Smartin if (info.nat_type != NULL) {
2345f77b58b1Smartin strlcat(line, " ", sizeof line);
2346f77b58b1Smartin strlcat(line, info.nat_type->description, sizeof line);
2347f77b58b1Smartin }
2348f77b58b1Smartin
2349f77b58b1Smartin if (desc != NULL) {
2350f77b58b1Smartin strlcat(line, ": ", sizeof line);
2351f77b58b1Smartin strlcat(line, desc, sizeof line);
2352f77b58b1Smartin }
2353f77b58b1Smartin
2354f77b58b1Smartin l = strlen(line);
2355f77b58b1Smartin if (l >= (m->w))
2356f77b58b1Smartin strcpy(line + (m->w-3), "...");
2357f77b58b1Smartin wprintw(m->mw, "%s", line);
2358f77b58b1Smartin }
2359f77b58b1Smartin
2360f77b58b1Smartin /*
2361f77b58b1Smartin * is the given "test" partitions set used in the selected set?
2362f77b58b1Smartin */
2363f77b58b1Smartin static bool
selection_has_parts(struct selected_partitions * sel,const struct disk_partitions * test)2364f77b58b1Smartin selection_has_parts(struct selected_partitions *sel,
2365f77b58b1Smartin const struct disk_partitions *test)
2366f77b58b1Smartin {
2367f77b58b1Smartin size_t i;
2368f77b58b1Smartin
2369f77b58b1Smartin for (i = 0; i < sel->num_sel; i++) {
2370f77b58b1Smartin if (sel->selection[i].parts == test)
2371f77b58b1Smartin return true;
2372f77b58b1Smartin }
2373f77b58b1Smartin return false;
2374f77b58b1Smartin }
2375f77b58b1Smartin
2376f77b58b1Smartin /*
2377f77b58b1Smartin * is the given "test" partition in the selected set?
2378f77b58b1Smartin */
2379f77b58b1Smartin static bool
selection_has_partition(struct selected_partitions * sel,const struct disk_partitions * test,part_id test_id)2380f77b58b1Smartin selection_has_partition(struct selected_partitions *sel,
2381f77b58b1Smartin const struct disk_partitions *test, part_id test_id)
2382f77b58b1Smartin {
2383f77b58b1Smartin size_t i;
2384f77b58b1Smartin
2385f77b58b1Smartin for (i = 0; i < sel->num_sel; i++) {
2386f77b58b1Smartin if (sel->selection[i].parts == test &&
2387f77b58b1Smartin sel->selection[i].id == test_id)
2388f77b58b1Smartin return true;
2389f77b58b1Smartin }
2390f77b58b1Smartin return false;
2391f77b58b1Smartin }
2392f77b58b1Smartin
2393f77b58b1Smartin /*
2394f77b58b1Smartin * let the user select a partition, optionally skipping all partitions
2395f77b58b1Smartin * on the "ignore" device
2396f77b58b1Smartin */
2397f77b58b1Smartin static bool
add_select_partition(struct selected_partitions * res,struct disk_partitions ** all_parts,size_t all_cnt)2398f77b58b1Smartin add_select_partition(struct selected_partitions *res,
2399f77b58b1Smartin struct disk_partitions **all_parts, size_t all_cnt)
2400f77b58b1Smartin {
2401f77b58b1Smartin struct disk_partitions *ps;
2402f77b58b1Smartin struct disk_part_info info;
2403f77b58b1Smartin part_id id;
2404f77b58b1Smartin struct single_partition *partitions, *pp;
2405f77b58b1Smartin struct menu_ent *part_menu_opts, *menup;
2406f77b58b1Smartin size_t n, part_cnt;
2407f77b58b1Smartin int sel_menu;
2408f77b58b1Smartin
2409f77b58b1Smartin /*
2410f77b58b1Smartin * count how many items our menu will have
2411f77b58b1Smartin */
2412f77b58b1Smartin part_cnt = 0;
2413f77b58b1Smartin for (n = 0; n < all_cnt; n++) {
2414f77b58b1Smartin ps = all_parts[n];
2415f77b58b1Smartin for (id = 0; id < ps->num_part; id++) {
2416f77b58b1Smartin if (selection_has_partition(res, ps, id))
2417f77b58b1Smartin continue;
2418f77b58b1Smartin if (!ps->pscheme->get_part_info(ps, id, &info))
2419f77b58b1Smartin continue;
2420f77b58b1Smartin if (info.flags & (PTI_SEC_CONTAINER|PTI_WHOLE_DISK|
2421f77b58b1Smartin PTI_PSCHEME_INTERNAL|PTI_RAW_PART))
2422f77b58b1Smartin continue;
2423f77b58b1Smartin part_cnt++;
2424f77b58b1Smartin }
2425f77b58b1Smartin }
2426f77b58b1Smartin
2427f77b58b1Smartin /*
2428f77b58b1Smartin * create a menu from this and let the user
2429f77b58b1Smartin * select one partition
2430f77b58b1Smartin */
2431f77b58b1Smartin part_menu_opts = NULL;
2432f77b58b1Smartin partitions = calloc(part_cnt, sizeof *partitions);
2433f77b58b1Smartin if (partitions == NULL)
2434f77b58b1Smartin goto done;
2435f77b58b1Smartin part_menu_opts = calloc(part_cnt, sizeof *part_menu_opts);
2436f77b58b1Smartin if (part_menu_opts == NULL)
2437f77b58b1Smartin goto done;
2438f77b58b1Smartin pp = partitions;
2439f77b58b1Smartin menup = part_menu_opts;
2440f77b58b1Smartin for (n = 0; n < all_cnt; n++) {
2441f77b58b1Smartin ps = all_parts[n];
2442f77b58b1Smartin for (id = 0; id < ps->num_part; id++) {
2443f77b58b1Smartin if (selection_has_partition(res, ps, id))
2444f77b58b1Smartin continue;
2445f77b58b1Smartin if (!ps->pscheme->get_part_info(ps, id, &info))
2446f77b58b1Smartin continue;
2447f77b58b1Smartin if (info.flags & (PTI_SEC_CONTAINER|PTI_WHOLE_DISK|
2448f77b58b1Smartin PTI_PSCHEME_INTERNAL|PTI_RAW_PART))
2449f77b58b1Smartin continue;
2450f77b58b1Smartin pp->parts = ps;
2451f77b58b1Smartin pp->id = id;
2452f77b58b1Smartin pp++;
2453f77b58b1Smartin menup->opt_action = select_single_part;
2454f77b58b1Smartin menup++;
2455f77b58b1Smartin }
2456f77b58b1Smartin }
2457f77b58b1Smartin sel_menu = new_menu(MSG_select_foreign_part, part_menu_opts, part_cnt,
2458f77b58b1Smartin 3, 3, 0, 60,
2459f77b58b1Smartin MC_SUBMENU | MC_SCROLL | MC_NOCLEAR,
2460f77b58b1Smartin NULL, display_single_part, NULL,
24617ca7eecaSmartin NULL, MSG_exit_menu_generic);
2462f77b58b1Smartin if (sel_menu != -1) {
2463f77b58b1Smartin struct selected_partition *newsels;
2464f77b58b1Smartin struct sel_menu_data data;
2465f77b58b1Smartin
2466f77b58b1Smartin memset(&data, 0, sizeof data);
2467f77b58b1Smartin data.partitions = partitions;
2468f77b58b1Smartin process_menu(sel_menu, &data);
2469f77b58b1Smartin free_menu(sel_menu);
2470f77b58b1Smartin
2471f77b58b1Smartin if (data.result.parts != NULL) {
2472f77b58b1Smartin newsels = realloc(res->selection,
2473f77b58b1Smartin sizeof(*res->selection)*(res->num_sel+1));
2474f77b58b1Smartin if (newsels != NULL) {
2475f77b58b1Smartin res->selection = newsels;
2476f77b58b1Smartin newsels += res->num_sel++;
2477f77b58b1Smartin newsels->parts = data.result.parts;
2478f77b58b1Smartin newsels->id = data.result.id;
2479f77b58b1Smartin }
2480f77b58b1Smartin }
2481f77b58b1Smartin }
2482f77b58b1Smartin
2483f77b58b1Smartin /*
2484f77b58b1Smartin * Final cleanup
2485f77b58b1Smartin */
2486f77b58b1Smartin done:
2487f77b58b1Smartin free(part_menu_opts);
2488f77b58b1Smartin free(partitions);
2489f77b58b1Smartin
2490f77b58b1Smartin return res->num_sel > 0;
2491f77b58b1Smartin }
2492f77b58b1Smartin
2493f77b58b1Smartin struct part_selection_and_all_parts {
2494f77b58b1Smartin struct selected_partitions *selection;
2495f77b58b1Smartin struct disk_partitions **all_parts;
2496f77b58b1Smartin size_t all_cnt;
2497f77b58b1Smartin char *title;
2498f77b58b1Smartin bool cancelled;
2499f77b58b1Smartin };
2500f77b58b1Smartin
2501f77b58b1Smartin static int
toggle_clone_data(struct menudesc * m,void * arg)2502f77b58b1Smartin toggle_clone_data(struct menudesc *m, void *arg)
2503f77b58b1Smartin {
2504f77b58b1Smartin struct part_selection_and_all_parts *sel = arg;
2505f77b58b1Smartin
2506f77b58b1Smartin sel->selection->with_data = !sel->selection->with_data;
2507f77b58b1Smartin return 0;
2508f77b58b1Smartin }
2509f77b58b1Smartin
2510f77b58b1Smartin static int
add_another(struct menudesc * m,void * arg)2511f77b58b1Smartin add_another(struct menudesc *m, void *arg)
2512f77b58b1Smartin {
2513f77b58b1Smartin struct part_selection_and_all_parts *sel = arg;
2514f77b58b1Smartin
2515f77b58b1Smartin add_select_partition(sel->selection, sel->all_parts, sel->all_cnt);
2516f77b58b1Smartin return 0;
2517f77b58b1Smartin }
2518f77b58b1Smartin
2519f77b58b1Smartin static int
cancel_clone(struct menudesc * m,void * arg)2520f77b58b1Smartin cancel_clone(struct menudesc *m, void *arg)
2521f77b58b1Smartin {
2522f77b58b1Smartin struct part_selection_and_all_parts *sel = arg;
2523f77b58b1Smartin
2524f77b58b1Smartin sel->cancelled = true;
2525f77b58b1Smartin return 1;
2526f77b58b1Smartin }
2527f77b58b1Smartin
2528f77b58b1Smartin static void
update_sel_part_title(struct part_selection_and_all_parts * sel)2529f77b58b1Smartin update_sel_part_title(struct part_selection_and_all_parts *sel)
2530f77b58b1Smartin {
2531f77b58b1Smartin struct disk_part_info info;
2532f77b58b1Smartin char *buf, line[MENUSTRSIZE];
2533f77b58b1Smartin size_t buf_len, i;
2534f77b58b1Smartin
2535f77b58b1Smartin buf_len = MENUSTRSIZE * (1+sel->selection->num_sel);
2536f77b58b1Smartin buf = malloc(buf_len);
2537f77b58b1Smartin if (buf == NULL)
2538f77b58b1Smartin return;
2539f77b58b1Smartin
2540f77b58b1Smartin strcpy(buf, msg_string(MSG_select_source_hdr));
2541f77b58b1Smartin for (i = 0; i < sel->selection->num_sel; i++) {
2542f77b58b1Smartin struct selected_partition *s =
2543f77b58b1Smartin &sel->selection->selection[i];
2544f77b58b1Smartin if (!s->parts->pscheme->get_part_info(s->parts, s->id, &info))
2545f77b58b1Smartin continue;
2546f77b58b1Smartin daddr_t start = info.start / sizemult;
2547f77b58b1Smartin daddr_t size = info.size / sizemult;
2548f77b58b1Smartin sprintf(line, "\n %s [%" PRIu64 " @ %" PRIu64 "] ",
2549f77b58b1Smartin s->parts->disk, size, start);
2550f77b58b1Smartin if (info.nat_type != NULL)
2551f77b58b1Smartin strlcat(line, info.nat_type->description, sizeof(line));
2552f77b58b1Smartin strlcat(buf, line, buf_len);
2553f77b58b1Smartin }
2554f77b58b1Smartin free(sel->title);
2555f77b58b1Smartin sel->title = buf;
2556f77b58b1Smartin }
2557f77b58b1Smartin
2558f77b58b1Smartin static void
post_sel_part(struct menudesc * m,void * arg)2559f77b58b1Smartin post_sel_part(struct menudesc *m, void *arg)
2560f77b58b1Smartin {
2561f77b58b1Smartin struct part_selection_and_all_parts *sel = arg;
2562f77b58b1Smartin
2563f77b58b1Smartin if (m->mw == NULL)
2564f77b58b1Smartin return;
2565f77b58b1Smartin update_sel_part_title(sel);
2566f77b58b1Smartin m->title = sel->title;
2567f77b58b1Smartin m->h = 0;
2568f77b58b1Smartin resize_menu_height(m);
2569f77b58b1Smartin }
2570f77b58b1Smartin
2571f77b58b1Smartin static void
fmt_sel_part_line(struct menudesc * m,int i,void * arg)2572f77b58b1Smartin fmt_sel_part_line(struct menudesc *m, int i, void *arg)
2573f77b58b1Smartin {
2574f77b58b1Smartin struct part_selection_and_all_parts *sel = arg;
2575f77b58b1Smartin
2576f77b58b1Smartin wprintw(m->mw, "%s: %s", msg_string(MSG_clone_with_data),
2577f77b58b1Smartin sel->selection->with_data ?
2578f77b58b1Smartin msg_string(MSG_Yes) :
2579f77b58b1Smartin msg_string(MSG_No));
2580f77b58b1Smartin }
2581f77b58b1Smartin
2582f77b58b1Smartin bool
select_partitions(struct selected_partitions * res,const struct disk_partitions * ignore)2583f77b58b1Smartin select_partitions(struct selected_partitions *res,
2584f77b58b1Smartin const struct disk_partitions *ignore)
2585f77b58b1Smartin {
2586f77b58b1Smartin struct disk_desc disks[MAX_DISKS];
2587f77b58b1Smartin struct disk_partitions *ps;
2588f77b58b1Smartin struct part_selection_and_all_parts data;
2589f77b58b1Smartin struct pm_devs *i;
2590f77b58b1Smartin size_t j;
2591f77b58b1Smartin int cnt, n, m;
2592f77b58b1Smartin static menu_ent men[] = {
2593f77b58b1Smartin { .opt_name = MSG_select_source_add,
2594f77b58b1Smartin .opt_action = add_another },
2595f77b58b1Smartin { .opt_action = toggle_clone_data },
2596f77b58b1Smartin { .opt_name = MSG_cancel, .opt_action = cancel_clone },
2597f77b58b1Smartin };
2598f77b58b1Smartin
2599f77b58b1Smartin memset(res, 0, sizeof *res);
2600f77b58b1Smartin memset(&data, 0, sizeof data);
2601f77b58b1Smartin data.selection = res;
2602f77b58b1Smartin
2603f77b58b1Smartin /*
2604f77b58b1Smartin * collect all available partition sets
2605f77b58b1Smartin */
2606f77b58b1Smartin data.all_cnt = 0;
2607f77b58b1Smartin if (SLIST_EMPTY(&pm_head)) {
2608f77b58b1Smartin cnt = get_disks(disks, false);
2609f77b58b1Smartin if (cnt <= 0)
2610f77b58b1Smartin return false;
2611f77b58b1Smartin
2612f77b58b1Smartin /*
2613f77b58b1Smartin * allocate two slots for each disk (primary/secondary)
2614f77b58b1Smartin */
2615f77b58b1Smartin data.all_parts = calloc(2*cnt, sizeof *data.all_parts);
2616f77b58b1Smartin if (data.all_parts == NULL)
2617f77b58b1Smartin return false;
2618f77b58b1Smartin
2619f77b58b1Smartin for (n = 0; n < cnt; n++) {
2620f77b58b1Smartin if (ignore != NULL &&
2621f77b58b1Smartin strcmp(disks[n].dd_name, ignore->disk) == 0)
2622f77b58b1Smartin continue;
2623f77b58b1Smartin
2624f77b58b1Smartin ps = partitions_read_disk(disks[n].dd_name,
262586906049Smartin disks[n].dd_totsec,
262686906049Smartin disks[n].dd_secsize,
262786906049Smartin disks[n].dd_no_mbr);
2628f77b58b1Smartin if (ps == NULL)
2629f77b58b1Smartin continue;
2630f77b58b1Smartin data.all_parts[data.all_cnt++] = ps;
2631f77b58b1Smartin ps = get_inner_parts(ps);
2632f77b58b1Smartin if (ps == NULL)
2633f77b58b1Smartin continue;
2634f77b58b1Smartin data.all_parts[data.all_cnt++] = ps;
2635f77b58b1Smartin }
2636f77b58b1Smartin if (data.all_cnt > 0)
2637f77b58b1Smartin res->free_parts = true;
2638f77b58b1Smartin } else {
2639f77b58b1Smartin cnt = 0;
2640f77b58b1Smartin SLIST_FOREACH(i, &pm_head, l)
2641f77b58b1Smartin cnt++;
2642f77b58b1Smartin
2643f77b58b1Smartin data.all_parts = calloc(cnt, sizeof *data.all_parts);
2644f77b58b1Smartin if (data.all_parts == NULL)
2645f77b58b1Smartin return false;
2646f77b58b1Smartin
2647f77b58b1Smartin SLIST_FOREACH(i, &pm_head, l) {
2648f77b58b1Smartin if (i->parts == NULL)
2649f77b58b1Smartin continue;
2650f77b58b1Smartin if (i->parts == ignore)
2651f77b58b1Smartin continue;
2652f77b58b1Smartin data.all_parts[data.all_cnt++] = i->parts;
2653f77b58b1Smartin }
2654f77b58b1Smartin }
2655f77b58b1Smartin
2656f77b58b1Smartin if (!add_select_partition(res, data.all_parts, data.all_cnt))
2657f77b58b1Smartin goto fail;
2658f77b58b1Smartin
2659f77b58b1Smartin /* loop with menu */
2660f77b58b1Smartin update_sel_part_title(&data);
2661f77b58b1Smartin m = new_menu(data.title, men, __arraycount(men), 3, 2, 0, 65, MC_SCROLL,
26627ca7eecaSmartin post_sel_part, fmt_sel_part_line, NULL, NULL, MSG_clone_src_done);
2663f77b58b1Smartin process_menu(m, &data);
2664f77b58b1Smartin free(data.title);
2665f77b58b1Smartin if (res->num_sel == 0)
2666f77b58b1Smartin goto fail;
2667f77b58b1Smartin
2668f77b58b1Smartin /* cleanup */
2669f77b58b1Smartin if (res->free_parts) {
2670f77b58b1Smartin for (j = 0; j < data.all_cnt; j++) {
2671f77b58b1Smartin if (selection_has_parts(res, data.all_parts[j]))
2672f77b58b1Smartin continue;
2673f77b58b1Smartin if (data.all_parts[j]->parent != NULL)
2674f77b58b1Smartin continue;
2675f77b58b1Smartin data.all_parts[j]->pscheme->free(data.all_parts[j]);
2676f77b58b1Smartin }
2677f77b58b1Smartin }
2678f77b58b1Smartin free(data.all_parts);
2679f77b58b1Smartin return true;
2680f77b58b1Smartin
2681f77b58b1Smartin fail:
2682f77b58b1Smartin if (res->free_parts) {
2683f77b58b1Smartin for (j = 0; j < data.all_cnt; j++) {
2684f77b58b1Smartin if (data.all_parts[j]->parent != NULL)
2685f77b58b1Smartin continue;
2686f77b58b1Smartin data.all_parts[j]->pscheme->free(data.all_parts[j]);
2687f77b58b1Smartin }
2688f77b58b1Smartin }
2689f77b58b1Smartin free(data.all_parts);
2690f77b58b1Smartin return false;
2691f77b58b1Smartin }
2692f77b58b1Smartin
2693f77b58b1Smartin void
free_selected_partitions(struct selected_partitions * selected)2694f77b58b1Smartin free_selected_partitions(struct selected_partitions *selected)
2695f77b58b1Smartin {
2696f77b58b1Smartin size_t i;
2697f77b58b1Smartin struct disk_partitions *parts;
2698f77b58b1Smartin
2699f77b58b1Smartin if (!selected->free_parts)
2700f77b58b1Smartin return;
2701f77b58b1Smartin
2702f77b58b1Smartin for (i = 0; i < selected->num_sel; i++) {
2703f77b58b1Smartin parts = selected->selection[i].parts;
2704f77b58b1Smartin
2705f77b58b1Smartin /* remove from list before testing for other instances */
2706f77b58b1Smartin selected->selection[i].parts = NULL;
2707f77b58b1Smartin
2708db383f47Sandvar /* if this is the secondary partition set, the parent owns it */
2709f77b58b1Smartin if (parts->parent != NULL)
2710f77b58b1Smartin continue;
2711f77b58b1Smartin
2712f77b58b1Smartin /* only free once (we use the last one) */
2713f77b58b1Smartin if (selection_has_parts(selected, parts))
2714f77b58b1Smartin continue;
2715f77b58b1Smartin parts->pscheme->free(parts);
2716f77b58b1Smartin }
2717f77b58b1Smartin free(selected->selection);
2718f77b58b1Smartin }
2719f77b58b1Smartin
2720f77b58b1Smartin daddr_t
selected_parts_size(struct selected_partitions * selected)2721f77b58b1Smartin selected_parts_size(struct selected_partitions *selected)
2722f77b58b1Smartin {
2723f77b58b1Smartin struct disk_part_info info;
2724f77b58b1Smartin size_t i;
2725f77b58b1Smartin daddr_t s = 0;
2726f77b58b1Smartin
2727f77b58b1Smartin for (i = 0; i < selected->num_sel; i++) {
2728f77b58b1Smartin if (!selected->selection[i].parts->pscheme->get_part_info(
2729f77b58b1Smartin selected->selection[i].parts,
2730f77b58b1Smartin selected->selection[i].id, &info))
2731f77b58b1Smartin continue;
2732f77b58b1Smartin s += info.size;
2733f77b58b1Smartin }
2734f77b58b1Smartin
2735f77b58b1Smartin return s;
2736f77b58b1Smartin }
2737f77b58b1Smartin
2738f77b58b1Smartin int
clone_target_select(menudesc * m,void * arg)2739f77b58b1Smartin clone_target_select(menudesc *m, void *arg)
2740f77b58b1Smartin {
2741f77b58b1Smartin struct clone_target_menu_data *data = arg;
2742f77b58b1Smartin
2743f77b58b1Smartin data->res = m->cursel;
2744f77b58b1Smartin return 1;
2745f77b58b1Smartin }
2746f77b58b1Smartin
2747f77b58b1Smartin bool
clone_partition_data(struct disk_partitions * dest_parts,part_id did,struct disk_partitions * src_parts,part_id sid)2748f77b58b1Smartin clone_partition_data(struct disk_partitions *dest_parts, part_id did,
2749f77b58b1Smartin struct disk_partitions *src_parts, part_id sid)
2750f77b58b1Smartin {
2751f77b58b1Smartin char src_dev[MAXPATHLEN], target_dev[MAXPATHLEN];
2752f77b58b1Smartin
2753f77b58b1Smartin if (!src_parts->pscheme->get_part_device(
2754f77b58b1Smartin src_parts, sid, src_dev, sizeof src_dev, NULL,
2755abce8cb3Smartin raw_dev_name, true, true))
2756f77b58b1Smartin return false;
2757f77b58b1Smartin if (!dest_parts->pscheme->get_part_device(
2758f77b58b1Smartin dest_parts, did, target_dev, sizeof target_dev, NULL,
2759abce8cb3Smartin raw_dev_name, true, true))
2760f77b58b1Smartin return false;
2761f77b58b1Smartin
2762f77b58b1Smartin return run_program(RUN_DISPLAY | RUN_PROGRESS,
2763f77b58b1Smartin "progress -f %s -b 1m dd bs=1m of=%s",
2764f77b58b1Smartin src_dev, target_dev) == 0;
2765f77b58b1Smartin }
2766485d5309Smartin #endif
2767485d5309Smartin
2768