xref: /netbsd-src/usr.sbin/sysinst/partitions.c (revision 207defd0369f03b80f291e7c291be1f3b7ab3397)
1*207defd0Sandvar /*	$NetBSD: partitions.c,v 1.13 2021/09/11 20:28:06 andvar Exp $	*/
24103857bSmartin 
34103857bSmartin /*
46948e0f3Smartin  * Copyright (c) 2020 The NetBSD Foundation, Inc.
54103857bSmartin  * All rights reserved.
64103857bSmartin  *
74103857bSmartin  * Redistribution and use in source and binary forms, with or without
84103857bSmartin  * modification, are permitted provided that the following conditions
94103857bSmartin  * are met:
104103857bSmartin  * 1. Redistributions of source code must retain the above copyright
114103857bSmartin  *    notice, this list of conditions and the following disclaimer.
124103857bSmartin  * 2. Redistributions in binary form must reproduce the above copyright
134103857bSmartin  *    notice, this list of conditions and the following disclaimer in the
144103857bSmartin  *    documentation and/or other materials provided with the distribution.
154103857bSmartin  *
166948e0f3Smartin  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
176948e0f3Smartin  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
186948e0f3Smartin  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
196948e0f3Smartin  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
206948e0f3Smartin  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
214103857bSmartin  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
224103857bSmartin  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
234103857bSmartin  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
244103857bSmartin  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
256948e0f3Smartin  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
266948e0f3Smartin  * POSSIBILITY OF SUCH DAMAGE.
274103857bSmartin  */
284103857bSmartin 
294103857bSmartin #include "defs.h"
304103857bSmartin #include "mbr.h"
314103857bSmartin #include <assert.h>
324103857bSmartin 
334103857bSmartin /*
344103857bSmartin  * A list of partitioning schemes, so we can iterate over everything
354103857bSmartin  * supported (e.g. when partitioning a new disk). NULL terminated.
364103857bSmartin  */
374103857bSmartin const struct disk_partitioning_scheme **available_part_schemes;
384103857bSmartin /*
394103857bSmartin  * The number of valid entries on above list
404103857bSmartin  */
414103857bSmartin size_t num_available_part_schemes;
424103857bSmartin 
4313c212dcSmartin extern const struct disk_partitioning_scheme disklabel_parts;
4413c212dcSmartin 
454103857bSmartin /*
4686906049Smartin  * Generic reader - query a disk device and read all partitions from it.
4786906049Smartin  * disk_size is in units of physical sector size, which is passe as
4886906049Smartin  * bytes_per_sec.
494103857bSmartin  */
504103857bSmartin struct disk_partitions *
partitions_read_disk(const char * dev,daddr_t disk_size,size_t bytes_per_sec,bool no_mbr)5186906049Smartin partitions_read_disk(const char *dev, daddr_t disk_size, size_t bytes_per_sec,
5286906049Smartin     bool no_mbr)
534103857bSmartin {
544103857bSmartin 	const struct disk_partitioning_scheme **ps;
5513c212dcSmartin #ifdef HAVE_MBR
5613c212dcSmartin 	bool mbr_done = false, disklabel_done = false;
5713c212dcSmartin #endif
584103857bSmartin 
594103857bSmartin 	if (!available_part_schemes)
604103857bSmartin 		return NULL;
614103857bSmartin 
624103857bSmartin 	for (ps = available_part_schemes; *ps; ps++) {
634327f8a5Smartin #ifdef HAVE_MBR
6413c212dcSmartin 		if (!no_mbr && (*ps) == &disklabel_parts && !mbr_done)
6513c212dcSmartin 			continue;
66f96c1808Smartin 		if (no_mbr && (*ps)->name == MSG_parttype_mbr)
67f96c1808Smartin 			continue;
6813c212dcSmartin 		if ((*ps)->name == MSG_parttype_mbr)
6913c212dcSmartin 			mbr_done = true;
7013c212dcSmartin 		if ((*ps)->read_from_disk == disklabel_parts.read_from_disk)
7113c212dcSmartin 			disklabel_done = true;
724327f8a5Smartin #endif
734103857bSmartin 		struct disk_partitions *parts =
7486906049Smartin 		    (*ps)->read_from_disk(dev, 0, disk_size, bytes_per_sec,
7586906049Smartin 		        *ps);
764103857bSmartin 		if (parts)
774103857bSmartin 			return parts;
784103857bSmartin 	}
7913c212dcSmartin #ifdef HAVE_MBR
8013c212dcSmartin 	if (!disklabel_done)
8113c212dcSmartin 		return disklabel_parts.read_from_disk(dev, 0, disk_size,
8213c212dcSmartin 		    bytes_per_sec, &disklabel_parts);
8313c212dcSmartin #endif
844103857bSmartin 	return NULL;
854103857bSmartin }
864103857bSmartin 
87f77b58b1Smartin bool
generic_adapt_foreign_part_info(const struct disk_partitions * myself,struct disk_part_info * dest,const struct disk_partitioning_scheme * src_scheme,const struct disk_part_info * src)88f77b58b1Smartin generic_adapt_foreign_part_info(const struct disk_partitions *myself,
89f77b58b1Smartin     struct disk_part_info *dest,
90f77b58b1Smartin     const struct disk_partitioning_scheme *src_scheme,
91f77b58b1Smartin     const struct disk_part_info *src)
92f77b58b1Smartin {
93f77b58b1Smartin 	*dest = *src;
94f77b58b1Smartin 	if (myself->pscheme == src_scheme)
95f77b58b1Smartin 		return true;	/* no conversion needed */
96f77b58b1Smartin 
97f77b58b1Smartin 	if (src->nat_type == NULL)
98f77b58b1Smartin 		return false;
99f77b58b1Smartin 
100f77b58b1Smartin 	/* slightly simplistic, enhance when needed */
101194b0d85Smartin 	dest->nat_type = myself->pscheme->get_fs_part_type(
102194b0d85Smartin 	    dest->nat_type ? dest->nat_type->generic_ptype : PT_root,
103194b0d85Smartin 	    dest->fs_type,
104f77b58b1Smartin 	    dest->fs_sub_type);
105f77b58b1Smartin 	if (dest->nat_type == NULL)
106f77b58b1Smartin 		dest->nat_type = myself->pscheme->get_generic_part_type(
107f77b58b1Smartin 		    src->nat_type->generic_ptype);
108f77b58b1Smartin 	if (dest->nat_type == NULL)
109f77b58b1Smartin 		dest->nat_type = myself->pscheme->create_unknown_part_type();
110f77b58b1Smartin 	if (dest->nat_type == NULL)
111f77b58b1Smartin 		dest->nat_type = myself->pscheme->get_generic_part_type(
112f77b58b1Smartin 		    PT_unknown);
113f77b58b1Smartin 
114f77b58b1Smartin 	return true;
115f77b58b1Smartin }
116f77b58b1Smartin 
1174103857bSmartin /*************** global init ****************************************/
1184103857bSmartin /*
1194103857bSmartin  * Helper structure to fill our global list of available partitioning
1204103857bSmartin  * schemes.
1214103857bSmartin  */
1224103857bSmartin struct part_scheme_desc {
1234103857bSmartin 	bool (*is_available)(void);
1244103857bSmartin 	const struct disk_partitioning_scheme *ps;
1254103857bSmartin };
1264103857bSmartin 
1274103857bSmartin #ifdef HAVE_GPT
1284103857bSmartin bool gpt_parts_check(void);
1294103857bSmartin extern const struct disk_partitioning_scheme gpt_parts;
1304103857bSmartin #endif
1314103857bSmartin #ifdef HAVE_MBR
1324103857bSmartin extern const struct disk_partitioning_scheme mbr_parts;
1334103857bSmartin #endif
134b04f4d62Smartin 
13507c7ef65Smartin #if RAW_PART == 3
136b04f4d62Smartin static struct disk_partitioning_scheme only_disklabel_parts;
137b04f4d62Smartin 
138b04f4d62Smartin /*
139*207defd0Sandvar  * If not overridden by MD code, we can not boot from plain
140b04f4d62Smartin  * disklabel disks (w/o MBR).
141b04f4d62Smartin  */
have_only_disklabel_boot_support(const char * disk)142b04f4d62Smartin static bool have_only_disklabel_boot_support(const char *disk)
143b04f4d62Smartin {
144b04f4d62Smartin #ifdef HAVE_PLAIN_DISKLABEL_BOOT
145b04f4d62Smartin 	return HAVE_PLAIN_DISKLABEL_BOOT(disk);
146b04f4d62Smartin #else
147b04f4d62Smartin 	return false;
148b04f4d62Smartin #endif
149b04f4d62Smartin }
1504103857bSmartin #endif
1514103857bSmartin 
1524103857bSmartin /*
1534103857bSmartin  * One time initialization
1544103857bSmartin  */
1554103857bSmartin void
partitions_init(void)1564103857bSmartin partitions_init(void)
1574103857bSmartin {
1584103857bSmartin 	/*
1594103857bSmartin 	 * List of partitioning schemes.
1604103857bSmartin 	 * Order is important, the selection menu is created from start
1614103857bSmartin 	 * to end. Keep good defaults early. Most architectures will
1624103857bSmartin 	 * only offer very few entries.
1634103857bSmartin 	 */
1644103857bSmartin static const struct part_scheme_desc all_descs[] = {
16507c7ef65Smartin #if RAW_PART != 3	/* only available as primary on some architectures */
1664103857bSmartin 		{ NULL, &disklabel_parts },
1674103857bSmartin #endif
1684103857bSmartin #ifdef HAVE_GPT
1694103857bSmartin 		{ gpt_parts_check, &gpt_parts },
1704103857bSmartin #endif
1714103857bSmartin #ifdef HAVE_MBR
1724103857bSmartin 		{ NULL, &mbr_parts },
1734103857bSmartin #endif
17407c7ef65Smartin #if RAW_PART == 3	/* "whole disk NetBSD" disklabel variant */
175b04f4d62Smartin 		{ NULL, &only_disklabel_parts },
176b04f4d62Smartin #endif
1774103857bSmartin 	};
1784103857bSmartin 
1794103857bSmartin 	size_t i, avail;
1804103857bSmartin 	const struct disk_partitioning_scheme **out;
1814103857bSmartin 	bool *is_available;
1824103857bSmartin 	static const size_t all_cnt = __arraycount(all_descs);
1834103857bSmartin 
1844103857bSmartin 	check_available_binaries();
1854103857bSmartin 
18607c7ef65Smartin #if RAW_PART == 3
187b04f4d62Smartin 	/* generate a variant of disklabel w/o parent scheme */
188b04f4d62Smartin 	only_disklabel_parts = disklabel_parts;
189b04f4d62Smartin 	only_disklabel_parts.name = MSG_parttype_only_disklabel;
190b04f4d62Smartin 	only_disklabel_parts.have_boot_support =
191b04f4d62Smartin 	    have_only_disklabel_boot_support;
192b04f4d62Smartin #endif
193b04f4d62Smartin 
194b04f4d62Smartin 
1954103857bSmartin 	is_available = malloc(all_cnt);
1964103857bSmartin 
1974103857bSmartin 	for (avail = i = 0; i < all_cnt; i++) {
1984103857bSmartin 		is_available[i] = all_descs[i].is_available == NULL
1994103857bSmartin 				|| all_descs[i].is_available();
2004103857bSmartin 		if (is_available[i])
2014103857bSmartin 			avail++;
2024103857bSmartin 	}
2034103857bSmartin 
2044103857bSmartin 	if (avail == 0)
2054103857bSmartin 		return;
2064103857bSmartin 
2074103857bSmartin 	num_available_part_schemes = avail;
2084103857bSmartin 	available_part_schemes = malloc(sizeof(*available_part_schemes)
2094103857bSmartin 	    * (avail+1));
2104103857bSmartin 	if (available_part_schemes == NULL)
2114103857bSmartin 		return;
2124103857bSmartin 
2134103857bSmartin 	for (out = available_part_schemes, i = 0; i < all_cnt; i++) {
2144103857bSmartin 		if (!is_available[i])
2154103857bSmartin 			continue;
2164103857bSmartin 		*out++ = all_descs[i].ps;
2174103857bSmartin 	}
2184103857bSmartin 	*out = NULL;
2194103857bSmartin 
2204103857bSmartin 	free(is_available);
2214103857bSmartin }
222f77b58b1Smartin 
223f77b58b1Smartin /*
224f77b58b1Smartin  * Final cleanup
225f77b58b1Smartin  */
226f77b58b1Smartin void
partitions_cleanup(void)227f77b58b1Smartin partitions_cleanup(void)
228f77b58b1Smartin {
229f77b58b1Smartin 	for (size_t i = 0; i < num_available_part_schemes; i++)
230f77b58b1Smartin 		if (available_part_schemes[i]->cleanup != NULL)
231f77b58b1Smartin 			available_part_schemes[i]->cleanup();
232f77b58b1Smartin 	free(available_part_schemes);
233f77b58b1Smartin }
234