xref: /netbsd-src/usr.sbin/sysinst/partitions.c (revision 7330f729ccf0bd976a06f95fad452fe774fc7fd1)
1 /*	$NetBSD: partitions.c,v 1.4 2019/10/26 07:32:52 martin Exp $	*/
2 
3 /*
4  * Copyright 2018 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY PIERMONT INFORMATION SYSTEMS INC. ``AS IS''
17  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED. IN NO EVENT SHALL PIERMONT INFORMATION SYSTEMS INC. BE
20  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26  * THE POSSIBILITY OF SUCH DAMAGE.
27  *
28  */
29 
30 #include "defs.h"
31 #include "mbr.h"
32 #include <assert.h>
33 
34 /*
35  * A list of partitioning schemes, so we can iterate over everything
36  * supported (e.g. when partitioning a new disk). NULL terminated.
37  */
38 const struct disk_partitioning_scheme **available_part_schemes;
39 /*
40  * The number of valid entries on above list
41  */
42 size_t num_available_part_schemes;
43 
44 /*
45  * Generic reader - query a disk device and read all partitions from it
46  */
47 struct disk_partitions *
48 partitions_read_disk(const char *dev, daddr_t disk_size, bool no_mbr)
49 {
50 	const struct disk_partitioning_scheme **ps;
51 
52 	if (!available_part_schemes)
53 		return NULL;
54 
55 	for (ps = available_part_schemes; *ps; ps++) {
56 #ifdef HAVE_MBR
57 		if (no_mbr && (*ps)->name == MSG_parttype_mbr)
58 			continue;
59 #endif
60 		struct disk_partitions *parts =
61 		    (*ps)->read_from_disk(dev, 0, disk_size, *ps);
62 		if (parts)
63 			return parts;
64 	}
65 	return NULL;
66 }
67 
68 /*************** global init ****************************************/
69 /*
70  * Helper structure to fill our global list of available partitioning
71  * schemes.
72  */
73 struct part_scheme_desc {
74 	bool (*is_available)(void);
75 	const struct disk_partitioning_scheme *ps;
76 };
77 
78 #ifdef HAVE_GPT
79 bool gpt_parts_check(void);
80 extern const struct disk_partitioning_scheme gpt_parts;
81 #endif
82 #ifdef HAVE_MBR
83 extern const struct disk_partitioning_scheme mbr_parts;
84 #endif
85 
86 extern const struct disk_partitioning_scheme disklabel_parts;
87 #if RAW_PART != 2
88 static struct disk_partitioning_scheme only_disklabel_parts;
89 
90 /*
91  * If not overriden by MD code, we can not boot from plain
92  * disklabel disks (w/o MBR).
93  */
94 static bool have_only_disklabel_boot_support(const char *disk)
95 {
96 #ifdef HAVE_PLAIN_DISKLABEL_BOOT
97 	return HAVE_PLAIN_DISKLABEL_BOOT(disk);
98 #else
99 	return false;
100 #endif
101 }
102 #endif
103 
104 /*
105  * One time initialization
106  */
107 void
108 partitions_init(void)
109 {
110 	/*
111 	 * List of partitioning schemes.
112 	 * Order is important, the selection menu is created from start
113 	 * to end. Keep good defaults early. Most architectures will
114 	 * only offer very few entries.
115 	 */
116 static const struct part_scheme_desc all_descs[] = {
117 #if RAW_PART == 2	/* only available as primary on some architectures */
118 		{ NULL, &disklabel_parts },
119 #endif
120 #ifdef HAVE_GPT
121 		{ gpt_parts_check, &gpt_parts },
122 #endif
123 #ifdef HAVE_MBR
124 		{ NULL, &mbr_parts },
125 #endif
126 #if RAW_PART != 2	/* "whole disk NetBSD" disklabel variant */
127 		{ NULL, &only_disklabel_parts },
128 #endif
129 	};
130 
131 	size_t i, avail;
132 	const struct disk_partitioning_scheme **out;
133 	bool *is_available;
134 	static const size_t all_cnt = __arraycount(all_descs);
135 
136 	check_available_binaries();
137 
138 #if RAW_PART != 2
139 	/* generate a variant of disklabel w/o parent scheme */
140 	only_disklabel_parts = disklabel_parts;
141 	only_disklabel_parts.name = MSG_parttype_only_disklabel;
142 	only_disklabel_parts.have_boot_support =
143 	    have_only_disklabel_boot_support;
144 #endif
145 
146 
147 	is_available = malloc(all_cnt);
148 
149 	for (avail = i = 0; i < all_cnt; i++) {
150 		is_available[i] = all_descs[i].is_available == NULL
151 				|| all_descs[i].is_available();
152 		if (is_available[i])
153 			avail++;
154 	}
155 
156 	if (avail == 0)
157 		return;
158 
159 	num_available_part_schemes = avail;
160 	available_part_schemes = malloc(sizeof(*available_part_schemes)
161 	    * (avail+1));
162 	if (available_part_schemes == NULL)
163 		return;
164 
165 	for (out = available_part_schemes, i = 0; i < all_cnt; i++) {
166 		if (!is_available[i])
167 			continue;
168 		*out++ = all_descs[i].ps;
169 	}
170 	*out = NULL;
171 
172 	free(is_available);
173 }
174