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 static struct grub_partition_map grub_pc_partition_map
;
30 static grub_dl_t my_mod
;
34 /* Parse the partition representation in STR and return a partition. */
35 static grub_partition_t
36 grub_partition_parse (const char *str
)
39 struct grub_pc_partition
*pcdata
;
41 char *s
= (char *) str
;
43 p
= (grub_partition_t
) grub_malloc (sizeof (*p
));
47 pcdata
= (struct grub_pc_partition
*) grub_malloc (sizeof (*pcdata
));
52 p
->partmap
= &grub_pc_partition_map
;
54 /* Initialize some of the fields with invalid values. */
55 pcdata
->bsd_part
= pcdata
->dos_type
= pcdata
->bsd_type
= p
->index
= -1;
57 /* Get the DOS partition number. The number is counted from one for
58 the user interface, and from zero internally. */
59 pcdata
->dos_part
= grub_strtoul (s
, &s
, 0) - 1;
63 /* Not found. Maybe only a BSD label is specified. */
64 pcdata
->dos_part
= -1;
65 grub_errno
= GRUB_ERR_NONE
;
72 if (*s
>= 'a' && *s
<= 'h')
74 pcdata
->bsd_part
= *s
- 'a';
82 if (pcdata
->dos_part
== -1 && pcdata
->bsd_part
== -1)
90 grub_error (GRUB_ERR_BAD_FILENAME
, "invalid partition");
95 pc_partition_map_iterate (grub_disk_t disk
,
96 int (*hook
) (grub_disk_t disk
,
97 const grub_partition_t partition
))
99 struct grub_partition p
;
100 struct grub_pc_partition pcdata
;
101 struct grub_pc_partition_mbr mbr
;
102 struct grub_pc_partition_disk_label label
;
103 struct grub_disk raw
;
105 /* Enforce raw disk access. */
110 pcdata
.ext_offset
= 0;
111 pcdata
.dos_part
= -1;
113 p
.partmap
= &grub_pc_partition_map
;
118 struct grub_pc_partition_entry
*e
;
121 if (grub_disk_read (&raw
, p
.offset
, 0, sizeof (mbr
), (char *) &mbr
))
124 /* Check if it is valid. */
125 if (mbr
.signature
!= grub_cpu_to_le16 (GRUB_PC_PARTITION_SIGNATURE
))
126 return grub_error (GRUB_ERR_BAD_PART_TABLE
, "no signature");
128 /* Analyze DOS partitions. */
129 for (p
.index
= 0; p
.index
< 4; p
.index
++)
131 e
= mbr
.entries
+ p
.index
;
133 p
.start
= p
.offset
+ grub_le_to_cpu32 (e
->start
);
134 p
.len
= grub_le_to_cpu32 (e
->length
);
135 pcdata
.bsd_part
= -1;
136 pcdata
.dos_type
= e
->type
;
137 pcdata
.bsd_type
= -1;
139 grub_dprintf ("partition",
140 "partition %d: flag 0x%x, type 0x%x, start 0x%llx, len 0x%llx\n",
141 p
.index
, e
->flag
, pcdata
.dos_type
, p
.start
, p
.len
);
143 /* If this is a GPT partition, this MBR is just a dummy. */
144 if (e
->type
== GRUB_PC_PARTITION_TYPE_GPT_DISK
&& p
.index
== 0)
145 return grub_error (GRUB_ERR_BAD_PART_TABLE
, "dummy mbr");
147 /* If this partition is a normal one, call the hook. */
148 if (! grub_pc_partition_is_empty (e
->type
)
149 && ! grub_pc_partition_is_extended (e
->type
))
156 /* Check if this is a BSD partition. */
157 if (grub_pc_partition_is_bsd (e
->type
))
159 /* Check if the BSD label is within the DOS partition. */
160 if (p
.len
<= GRUB_PC_PARTITION_BSD_LABEL_SECTOR
)
161 return grub_error (GRUB_ERR_BAD_PART_TABLE
,
162 "no space for disk label");
164 /* Read the BSD label. */
165 if (grub_disk_read (&raw
,
167 + GRUB_PC_PARTITION_BSD_LABEL_SECTOR
),
173 /* Check if it is valid. */
175 != grub_cpu_to_le32 (GRUB_PC_PARTITION_BSD_LABEL_MAGIC
))
176 return grub_error (GRUB_ERR_BAD_PART_TABLE
,
177 "invalid disk label magic 0x%x",
180 for (pcdata
.bsd_part
= 0;
181 pcdata
.bsd_part
< grub_cpu_to_le16 (label
.num_partitions
);
184 struct grub_pc_partition_bsd_entry
*be
185 = label
.entries
+ pcdata
.bsd_part
;
187 p
.start
= grub_le_to_cpu32 (be
->offset
);
188 p
.len
= grub_le_to_cpu32 (be
->size
);
189 pcdata
.bsd_type
= be
->fs_type
;
191 if (be
->fs_type
!= GRUB_PC_PARTITION_BSD_TYPE_UNUSED
)
197 else if (pcdata
.dos_part
< 4)
198 /* If this partition is a logical one, shouldn't increase the
203 /* Find an extended partition. */
204 for (i
= 0; i
< 4; i
++)
208 if (grub_pc_partition_is_extended (e
->type
))
210 p
.offset
= pcdata
.ext_offset
+ grub_le_to_cpu32 (e
->start
);
211 if (! pcdata
.ext_offset
)
212 pcdata
.ext_offset
= p
.offset
;
218 /* If no extended partition, the end. */
228 static grub_partition_t
229 pc_partition_map_probe (grub_disk_t disk
, const char *str
)
232 struct grub_pc_partition
*pcdata
;
234 auto int find_func (grub_disk_t d
, const grub_partition_t partition
);
236 int find_func (grub_disk_t d
__attribute__ ((unused
)),
237 const grub_partition_t partition
)
239 struct grub_pc_partition
*partdata
= partition
->data
;
241 if ((pcdata
->dos_part
== partdata
->dos_part
|| pcdata
->dos_part
== -1)
242 && pcdata
->bsd_part
== partdata
->bsd_part
)
244 grub_memcpy (p
, partition
, sizeof (*p
));
246 grub_memcpy (pcdata
, partdata
, sizeof (*pcdata
));
253 p
= grub_partition_parse (str
);
258 if (pc_partition_map_iterate (disk
, find_func
))
263 grub_error (GRUB_ERR_BAD_DEVICE
, "no such partition");
277 pc_partition_map_get_name (const grub_partition_t p
)
280 struct grub_pc_partition
*pcdata
= p
->data
;
282 name
= grub_malloc (13);
286 if (pcdata
->bsd_part
< 0)
287 grub_sprintf (name
, "%d", pcdata
->dos_part
+ 1);
288 else if (pcdata
->dos_part
< 0)
289 grub_sprintf (name
, "%c", pcdata
->bsd_part
+ 'a');
291 grub_sprintf (name
, "%d,%c", pcdata
->dos_part
+ 1, pcdata
->bsd_part
+ 'a');
297 /* Partition map type. */
298 static struct grub_partition_map grub_pc_partition_map
=
300 .name
= "pc_partition_map",
301 .iterate
= pc_partition_map_iterate
,
302 .probe
= pc_partition_map_probe
,
303 .get_name
= pc_partition_map_get_name
306 GRUB_MOD_INIT(pc_partition_map
)
308 grub_partition_map_register (&grub_pc_partition_map
);
314 GRUB_MOD_FINI(pc_partition_map
)
316 grub_partition_map_unregister (&grub_pc_partition_map
);