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