1 /* pc.c - Read PC style partition tables. */
3 * GRUB -- GRand Unified Bootloader
4 * Copyright (C) 2002,2004,2005,2006,2007 Free Software Foundation, Inc.
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.
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.
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/>.
20 #include <grub/partition.h>
21 #include <grub/pc_partition.h>
22 #include <grub/disk.h>
24 #include <grub/misc.h>
27 /* RDB partition tables for AROS */
28 struct grub_partition_map
*grub_rdb_partition_map
= NULL
;
30 static struct grub_partition_map grub_pc_partition_map
;
33 static grub_dl_t my_mod
;
37 /* Parse the partition representation in STR and return a partition. */
38 static grub_partition_t
39 grub_partition_parse (const char *str
)
42 struct grub_pc_partition
*pcdata
;
44 char *s
= (char *) str
;
46 p
= (grub_partition_t
) grub_malloc (sizeof (*p
));
50 pcdata
= (struct grub_pc_partition
*) grub_malloc (sizeof (*pcdata
));
55 p
->partmap
= &grub_pc_partition_map
;
57 /* Initialize some of the fields with invalid values. */
58 pcdata
->bsd_part
= pcdata
->dos_type
= pcdata
->bsd_type
= p
->index
= -1;
60 /* Get the DOS partition number. The number is counted from one for
61 the user interface, and from zero internally. */
62 pcdata
->dos_part
= grub_strtoul (s
, &s
, 0) - 1;
66 /* Not found. Maybe only a BSD label is specified. */
67 pcdata
->dos_part
= -1;
68 grub_errno
= GRUB_ERR_NONE
;
75 if (*s
>= 'a' && *s
<= 'h')
77 pcdata
->bsd_part
= *s
- 'a';
85 if (pcdata
->dos_part
== -1 && pcdata
->bsd_part
== -1)
93 grub_error (GRUB_ERR_BAD_FILENAME
, "invalid partition");
98 pc_partition_map_iterate (grub_disk_t disk
,
99 int (*hook
) (grub_disk_t disk
,
100 const grub_partition_t partition
))
102 struct grub_partition p
;
103 struct grub_pc_partition pcdata
;
104 struct grub_pc_partition_mbr mbr
;
105 struct grub_pc_partition_disk_label label
;
106 struct grub_disk raw
;
108 /* Enforce raw disk access. */
113 pcdata
.ext_offset
= 0;
114 pcdata
.dos_part
= -1;
116 p
.partmap
= &grub_pc_partition_map
;
121 struct grub_pc_partition_entry
*e
;
124 if (grub_disk_read (&raw
, p
.offset
, 0, sizeof (mbr
), (char *) &mbr
))
127 /* Check if it is valid. */
128 if (mbr
.signature
!= grub_cpu_to_le16 (GRUB_PC_PARTITION_SIGNATURE
))
129 return grub_error (GRUB_ERR_BAD_PART_TABLE
, "no signature");
131 /* Analyze DOS partitions. */
132 for (p
.index
= 0; p
.index
< 4; p
.index
++)
134 e
= mbr
.entries
+ p
.index
;
136 p
.start
= p
.offset
+ grub_le_to_cpu32 (e
->start
);
137 p
.len
= grub_le_to_cpu32 (e
->length
);
138 pcdata
.bsd_part
= -1;
139 pcdata
.dos_type
= e
->type
;
140 pcdata
.bsd_type
= -1;
142 grub_dprintf ("partition",
143 "partition %d: flag 0x%x, type 0x%x, start 0x%llx, len 0x%llx\n",
144 p
.index
, e
->flag
, pcdata
.dos_type
,
145 (unsigned long long) p
.start
,
146 (unsigned long long) p
.len
);
148 /* If this is a GPT partition, this MBR is just a dummy. */
149 if (e
->type
== GRUB_PC_PARTITION_TYPE_GPT_DISK
&& p
.index
== 0)
150 return grub_error (GRUB_ERR_BAD_PART_TABLE
, "dummy mbr");
152 /* If this partition is a normal one, call the hook. */
153 if (! grub_pc_partition_is_empty (e
->type
)
154 && ! grub_pc_partition_is_extended (e
->type
))
160 /* Check if this is a RDB partition table. */
161 if (grub_rdb_partition_map
&& grub_pc_partition_is_rdb(e
->type
))
163 struct grub_partition p2
;
164 struct grub_disk raw2
;
167 auto int rdb_hook(grub_disk_t disk
, const grub_partition_t p
);
169 int rdb_hook(grub_disk_t disk
__attribute__((unused
)),
170 const grub_partition_t part
)
173 pcdata
.bsd_part
= part
->index
;
176 p2
.offset
+= p
.offset
;
178 p2
.partmap
= &grub_pc_partition_map
;
180 grub_dprintf("partition", "RDB part %c start=%ld\n",
181 (char)('a' + part
->index
), (long)p2
.start
);
183 ok
= hook(disk
, &p2
);
190 grub_rdb_partition_map
->iterate(&raw2
, rdb_hook
);
198 /* Check if this is a BSD partition. */
199 if (grub_pc_partition_is_bsd (e
->type
))
201 /* Check if the BSD label is within the DOS partition. */
202 if (p
.len
<= GRUB_PC_PARTITION_BSD_LABEL_SECTOR
)
203 return grub_error (GRUB_ERR_BAD_PART_TABLE
,
204 "no space for disk label");
206 /* Read the BSD label. */
207 if (grub_disk_read (&raw
,
209 + GRUB_PC_PARTITION_BSD_LABEL_SECTOR
),
215 /* Check if it is valid. */
217 != grub_cpu_to_le32 (GRUB_PC_PARTITION_BSD_LABEL_MAGIC
))
218 return grub_error (GRUB_ERR_BAD_PART_TABLE
,
219 "invalid disk label magic 0x%x",
222 for (pcdata
.bsd_part
= 0;
223 pcdata
.bsd_part
< grub_cpu_to_le16 (label
.num_partitions
);
226 struct grub_pc_partition_bsd_entry
*be
227 = label
.entries
+ pcdata
.bsd_part
;
229 p
.start
= grub_le_to_cpu32 (be
->offset
);
230 p
.len
= grub_le_to_cpu32 (be
->size
);
231 pcdata
.bsd_type
= be
->fs_type
;
233 if (be
->fs_type
!= GRUB_PC_PARTITION_BSD_TYPE_UNUSED
)
239 else if (pcdata
.dos_part
< 4)
240 /* If this partition is a logical one, shouldn't increase the
245 /* Find an extended partition. */
246 for (i
= 0; i
< 4; i
++)
250 if (grub_pc_partition_is_extended (e
->type
))
252 p
.offset
= pcdata
.ext_offset
+ grub_le_to_cpu32 (e
->start
);
253 if (! pcdata
.ext_offset
)
254 pcdata
.ext_offset
= p
.offset
;
260 /* If no extended partition, the end. */
270 static grub_partition_t
271 pc_partition_map_probe (grub_disk_t disk
, const char *str
)
274 struct grub_pc_partition
*pcdata
;
276 auto int find_func (grub_disk_t d
, const grub_partition_t partition
);
278 int find_func (grub_disk_t d
__attribute__ ((unused
)),
279 const grub_partition_t partition
)
281 struct grub_pc_partition
*partdata
= partition
->data
;
283 if ((pcdata
->dos_part
== partdata
->dos_part
|| pcdata
->dos_part
== -1)
284 && pcdata
->bsd_part
== partdata
->bsd_part
)
286 grub_memcpy (p
, partition
, sizeof (*p
));
288 grub_memcpy (pcdata
, partdata
, sizeof (*pcdata
));
295 p
= grub_partition_parse (str
);
300 pc_partition_map_iterate (disk
, find_func
);
306 grub_error (GRUB_ERR_BAD_DEVICE
, "no such partition");
320 pc_partition_map_get_name (const grub_partition_t p
)
323 struct grub_pc_partition
*pcdata
= p
->data
;
325 name
= grub_malloc (13);
329 if (pcdata
->bsd_part
< 0)
330 grub_sprintf (name
, "%d", pcdata
->dos_part
+ 1);
331 else if (pcdata
->dos_part
< 0)
332 grub_sprintf (name
, "%c", pcdata
->bsd_part
+ 'a');
334 grub_sprintf (name
, "%d,%c", pcdata
->dos_part
+ 1, pcdata
->bsd_part
+ 'a');
340 /* Partition map type. */
341 static struct grub_partition_map grub_pc_partition_map
=
343 .name
= "pc_partition_map",
344 .iterate
= pc_partition_map_iterate
,
345 .probe
= pc_partition_map_probe
,
346 .get_name
= pc_partition_map_get_name
349 GRUB_MOD_INIT(pc_partition_map
)
351 grub_partition_map_register (&grub_pc_partition_map
);
357 GRUB_MOD_FINI(pc_partition_map
)
359 grub_partition_map_unregister (&grub_pc_partition_map
);