]> git.proxmox.com Git - grub2.git/blob - grub-core/partmap/bsdlabel.c
Import grub2_2.02+dfsg1.orig.tar.xz
[grub2.git] / grub-core / partmap / bsdlabel.c
1 /* bsdlabel.c - Read BSD style partition tables. */
2 /*
3 * GRUB -- GRand Unified Bootloader
4 * Copyright (C) 2002,2004,2005,2006,2007,2008,2009 Free Software Foundation, Inc.
5 *
6 * GRUB is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * GRUB is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include <grub/partition.h>
21 #include <grub/bsdlabel.h>
22 #include <grub/disk.h>
23 #include <grub/mm.h>
24 #include <grub/misc.h>
25 #include <grub/dl.h>
26 #include <grub/msdos_partition.h>
27 #include <grub/i18n.h>
28
29 GRUB_MOD_LICENSE ("GPLv3+");
30
31 #ifdef GRUB_UTIL
32 #include <grub/emu/misc.h>
33 #endif
34
35 static struct grub_partition_map grub_bsdlabel_partition_map;
36 static struct grub_partition_map grub_netbsdlabel_partition_map;
37 static struct grub_partition_map grub_openbsdlabel_partition_map;
38
39 \f
40
41 static grub_err_t
42 iterate_real (grub_disk_t disk, grub_disk_addr_t sector, int freebsd,
43 struct grub_partition_map *pmap,
44 grub_partition_iterate_hook_t hook, void *hook_data)
45 {
46 struct grub_partition_bsd_disk_label label;
47 struct grub_partition p;
48 grub_disk_addr_t delta = 0;
49 grub_disk_addr_t pos;
50
51 /* Read the BSD label. */
52 if (grub_disk_read (disk, sector, 0, sizeof (label), &label))
53 return grub_errno;
54
55 /* Check if it is valid. */
56 if (label.magic != grub_cpu_to_le32_compile_time (GRUB_PC_PARTITION_BSD_LABEL_MAGIC))
57 return grub_error (GRUB_ERR_BAD_PART_TABLE, "no signature");
58
59 /* A kludge to determine a base of be.offset. */
60 if (GRUB_PC_PARTITION_BSD_LABEL_WHOLE_DISK_PARTITION
61 < grub_cpu_to_le16 (label.num_partitions) && freebsd)
62 {
63 struct grub_partition_bsd_entry whole_disk_be;
64
65 pos = sizeof (label) + sector * GRUB_DISK_SECTOR_SIZE
66 + sizeof (struct grub_partition_bsd_entry)
67 * GRUB_PC_PARTITION_BSD_LABEL_WHOLE_DISK_PARTITION;
68
69 if (grub_disk_read (disk, pos / GRUB_DISK_SECTOR_SIZE,
70 pos % GRUB_DISK_SECTOR_SIZE, sizeof (whole_disk_be),
71 &whole_disk_be))
72 return grub_errno;
73
74 delta = grub_le_to_cpu32 (whole_disk_be.offset);
75 }
76
77 pos = sizeof (label) + sector * GRUB_DISK_SECTOR_SIZE;
78
79 for (p.number = 0;
80 p.number < grub_cpu_to_le16 (label.num_partitions);
81 p.number++, pos += sizeof (struct grub_partition_bsd_entry))
82 {
83 struct grub_partition_bsd_entry be;
84
85 if (p.number == GRUB_PC_PARTITION_BSD_LABEL_WHOLE_DISK_PARTITION)
86 continue;
87
88 p.offset = pos / GRUB_DISK_SECTOR_SIZE;
89 p.index = pos % GRUB_DISK_SECTOR_SIZE;
90
91 if (grub_disk_read (disk, p.offset, p.index, sizeof (be), &be))
92 return grub_errno;
93
94 p.start = grub_le_to_cpu32 (be.offset);
95 p.len = grub_le_to_cpu32 (be.size);
96 p.partmap = pmap;
97
98 if (p.len == 0)
99 continue;
100
101 if (p.start < delta)
102 {
103 #ifdef GRUB_UTIL
104 char *partname;
105 /* disk->partition != NULL as 0 < delta */
106 partname = disk->partition ? grub_partition_get_name (disk->partition)
107 : 0;
108 grub_util_warn (_("Discarding improperly nested partition (%s,%s,%s%d)"),
109 disk->name, partname ? : "", p.partmap->name,
110 p.number + 1);
111 grub_free (partname);
112 #endif
113 continue;
114 }
115
116 p.start -= delta;
117
118 if (hook (disk, &p, hook_data))
119 return grub_errno;
120 }
121 return GRUB_ERR_NONE;
122 }
123
124 static grub_err_t
125 bsdlabel_partition_map_iterate (grub_disk_t disk,
126 grub_partition_iterate_hook_t hook,
127 void *hook_data)
128 {
129
130 if (disk->partition && grub_strcmp (disk->partition->partmap->name, "msdos")
131 == 0 && disk->partition->msdostype == GRUB_PC_PARTITION_TYPE_FREEBSD)
132 return iterate_real (disk, GRUB_PC_PARTITION_BSD_LABEL_SECTOR, 1,
133 &grub_bsdlabel_partition_map, hook, hook_data);
134
135 if (disk->partition
136 && (grub_strcmp (disk->partition->partmap->name, "msdos") == 0
137 || disk->partition->partmap == &grub_bsdlabel_partition_map
138 || disk->partition->partmap == &grub_netbsdlabel_partition_map
139 || disk->partition->partmap == &grub_openbsdlabel_partition_map))
140 return grub_error (GRUB_ERR_BAD_PART_TABLE, "no embedding supported");
141
142 return iterate_real (disk, GRUB_PC_PARTITION_BSD_LABEL_SECTOR, 0,
143 &grub_bsdlabel_partition_map, hook, hook_data);
144 }
145
146 /* Context for netopenbsdlabel_partition_map_iterate. */
147 struct netopenbsdlabel_ctx
148 {
149 grub_uint8_t type;
150 struct grub_partition_map *pmap;
151 grub_partition_iterate_hook_t hook;
152 void *hook_data;
153 int count;
154 };
155
156 /* Helper for netopenbsdlabel_partition_map_iterate. */
157 static int
158 check_msdos (grub_disk_t dsk, const grub_partition_t partition, void *data)
159 {
160 struct netopenbsdlabel_ctx *ctx = data;
161 grub_err_t err;
162
163 if (partition->msdostype != ctx->type)
164 return 0;
165
166 err = iterate_real (dsk, partition->start
167 + GRUB_PC_PARTITION_BSD_LABEL_SECTOR, 0, ctx->pmap,
168 ctx->hook, ctx->hook_data);
169 if (err == GRUB_ERR_NONE)
170 {
171 ctx->count++;
172 return 1;
173 }
174 if (err == GRUB_ERR_BAD_PART_TABLE)
175 {
176 grub_errno = GRUB_ERR_NONE;
177 return 0;
178 }
179 grub_print_error ();
180 return 0;
181 }
182
183 /* This is a total breakage. Even when net-/openbsd label is inside partition
184 it actually describes the whole disk.
185 */
186 static grub_err_t
187 netopenbsdlabel_partition_map_iterate (grub_disk_t disk, grub_uint8_t type,
188 struct grub_partition_map *pmap,
189 grub_partition_iterate_hook_t hook,
190 void *hook_data)
191 {
192 if (disk->partition && grub_strcmp (disk->partition->partmap->name, "msdos")
193 == 0)
194 return grub_error (GRUB_ERR_BAD_PART_TABLE, "no embedding supported");
195
196 {
197 struct netopenbsdlabel_ctx ctx = {
198 .type = type,
199 .pmap = pmap,
200 .hook = hook,
201 .hook_data = hook_data,
202 .count = 0
203 };
204 grub_err_t err;
205
206 err = grub_partition_msdos_iterate (disk, check_msdos, &ctx);
207
208 if (err)
209 return err;
210 if (!ctx.count)
211 return grub_error (GRUB_ERR_BAD_PART_TABLE, "no bsdlabel found");
212 }
213 return GRUB_ERR_NONE;
214 }
215
216 static grub_err_t
217 netbsdlabel_partition_map_iterate (grub_disk_t disk,
218 grub_partition_iterate_hook_t hook,
219 void *hook_data)
220 {
221 return netopenbsdlabel_partition_map_iterate (disk,
222 GRUB_PC_PARTITION_TYPE_NETBSD,
223 &grub_netbsdlabel_partition_map,
224 hook, hook_data);
225 }
226
227 static grub_err_t
228 openbsdlabel_partition_map_iterate (grub_disk_t disk,
229 grub_partition_iterate_hook_t hook,
230 void *hook_data)
231 {
232 return netopenbsdlabel_partition_map_iterate (disk,
233 GRUB_PC_PARTITION_TYPE_OPENBSD,
234 &grub_openbsdlabel_partition_map,
235 hook, hook_data);
236 }
237
238
239 static struct grub_partition_map grub_bsdlabel_partition_map =
240 {
241 .name = "bsd",
242 .iterate = bsdlabel_partition_map_iterate,
243 };
244
245 static struct grub_partition_map grub_openbsdlabel_partition_map =
246 {
247 .name = "openbsd",
248 .iterate = openbsdlabel_partition_map_iterate,
249 };
250
251 static struct grub_partition_map grub_netbsdlabel_partition_map =
252 {
253 .name = "netbsd",
254 .iterate = netbsdlabel_partition_map_iterate,
255 };
256
257 \f
258
259 GRUB_MOD_INIT(part_bsd)
260 {
261 grub_partition_map_register (&grub_bsdlabel_partition_map);
262 grub_partition_map_register (&grub_netbsdlabel_partition_map);
263 grub_partition_map_register (&grub_openbsdlabel_partition_map);
264 }
265
266 GRUB_MOD_FINI(part_bsd)
267 {
268 grub_partition_map_unregister (&grub_bsdlabel_partition_map);
269 grub_partition_map_unregister (&grub_netbsdlabel_partition_map);
270 grub_partition_map_unregister (&grub_openbsdlabel_partition_map);
271 }