1 /*
2 * mac partitions parsing code
3 *
4 * Copyright (C) 2009 Karel Zak <kzak@redhat.com>
5 *
6 * This file may be redistributed under the terms of the
7 * GNU Lesser General Public License.
8 *
9 */
10 #include <stdio.h>
11 #include <string.h>
12 #include <stdlib.h>
13 #include <stdint.h>
14
15 #include "partitions.h"
16
17 #define MAC_PARTITION_MAGIC 0x504d
18 #define MAC_PARTITION_MAGIC_OLD 0x5453
19
20 /*
21 * Mac partition entry
22 * http://developer.apple.com/legacy/mac/library/documentation/mac/Devices/Devices-126.html
23 */
24 struct mac_partition {
25 uint16_t signature; /* expected to be MAC_PARTITION_MAGIC */
26 uint16_t reserved; /* reserved */
27 uint32_t map_count; /* # blocks in partition map */
28 uint32_t start_block; /* absolute starting block # of partition */
29 uint32_t block_count; /* number of blocks in partition */
30 char name[32]; /* partition name */
31 char type[32]; /* string type description */
32 uint32_t data_start; /* rel block # of first data block */
33 uint32_t data_count; /* number of data blocks */
34 uint32_t status; /* partition status bits */
35 uint32_t boot_start; /* first logical block of boot code */
36 uint32_t boot_size; /* size of boot code, in bytes */
37 uint32_t boot_load; /* boot code load address */
38 uint32_t boot_load2; /* reserved */
39 uint32_t boot_entry; /* boot code entry point */
40 uint32_t boot_entry2; /* reserved */
41 uint32_t boot_cksum; /* boot code checksum */
42 char processor[16]; /* identifies ISA of boot */
43
44 /* there is more stuff after this that we don't need */
45 } __attribute__((packed));
46
47 /*
48 * Driver descriptor structure, in block 0
49 * http://developer.apple.com/legacy/mac/library/documentation/mac/Devices/Devices-121.html
50 */
51 struct mac_driver_desc {
52 uint16_t signature; /* expected to be MAC_DRIVER_MAGIC */
53 uint16_t block_size; /* block size of the device */
54 uint32_t block_count; /* number of blocks on the device */
55
56 /* there is more stuff after this that we don't need */
57 } __attribute__((packed));
58
59 static inline unsigned char *get_mac_block(
60 blkid_probe pr,
61 uint16_t block_size,
62 uint32_t num)
63 {
64 return blkid_probe_get_buffer(pr, (uint64_t) num * block_size, block_size);
65 }
66
67 static inline int has_part_signature(struct mac_partition *p)
68 {
69 return be16_to_cpu(p->signature) == MAC_PARTITION_MAGIC ||
70 be16_to_cpu(p->signature) == MAC_PARTITION_MAGIC_OLD;
71 }
72
73 static int probe_mac_pt(blkid_probe pr,
74 const struct blkid_idmag *mag __attribute__((__unused__)))
75 {
76 struct mac_driver_desc *md;
77 struct mac_partition *p;
78 blkid_parttable tab = NULL;
79 blkid_partlist ls;
80 uint16_t block_size;
81 uint16_t ssf; /* sector size fragment */
82 uint32_t nblks, nprts, i;
83
84
85 /* The driver descriptor record is always located at physical block 0,
86 * the first block on the disk.
87 */
88 md = (struct mac_driver_desc *) blkid_probe_get_sector(pr, 0);
89 if (!md) {
90 if (errno)
91 return -errno;
92 goto nothing;
93 }
94
95 block_size = be16_to_cpu(md->block_size);
96 if (block_size < sizeof(struct mac_partition))
97 goto nothing;
98
99 /* The partition map always begins at physical block 1,
100 * the second block on the disk.
101 */
102 p = (struct mac_partition *) get_mac_block(pr, block_size, 1);
103 if (!p) {
104 if (errno)
105 return -errno;
106 goto nothing;
107 }
108
109 /* check the first partition signature */
110 if (!has_part_signature(p))
111 goto nothing;
112
113 if (blkid_partitions_need_typeonly(pr))
114 /* caller does not ask for details about partitions */
115 return 0;
116
117 ls = blkid_probe_get_partlist(pr);
118 if (!ls)
119 goto nothing;
120
121 tab = blkid_partlist_new_parttable(ls, "mac", 0);
122 if (!tab)
123 goto err;
124
125 ssf = block_size / 512;
126 nblks = be32_to_cpu(p->map_count);
127 if (nblks > 256) {
128 nprts = 256;
129 DBG(LOWPROBE, ul_debug(
130 "mac: map_count too large, entry[0]: %u, "
131 "enforcing limit of %u", nblks, nprts));
132 } else
133 nprts = nblks;
134
135 for (i = 0; i < nprts; ++i) {
136 blkid_partition par;
137 uint32_t start;
138 uint32_t size;
139
140 p = (struct mac_partition *) get_mac_block(pr, block_size, i + 1);
141 if (!p) {
142 if (errno)
143 return -errno;
144 goto nothing;
145 }
146 if (!has_part_signature(p))
147 goto nothing;
148
149 if (be32_to_cpu(p->map_count) != nblks) {
150 DBG(LOWPROBE, ul_debug(
151 "mac: inconsistent map_count in partition map, "
152 "entry[0]: %u, entry[%u]: %u",
153 nblks, i,
154 be32_to_cpu(p->map_count)));
155 }
156
157 /*
158 * note that libparted ignores some mac partitions according to
159 * the partition name (e.g. "Apple_Free" or "Apple_Void"). We
160 * follows Linux kernel and all partitions are visible
161 */
162
163 start = be32_to_cpu(p->start_block) * ssf;
164 size = be32_to_cpu(p->block_count) * ssf;
165
166 par = blkid_partlist_add_partition(ls, tab, start, size);
167 if (!par)
168 goto err;
169
170 blkid_partition_set_name(par, (unsigned char *) p->name,
171 sizeof(p->name));
172
173 blkid_partition_set_type_string(par, (unsigned char *) p->type,
174 sizeof(p->type));
175 }
176
177 return BLKID_PROBE_OK;
178
179 nothing:
180 return BLKID_PROBE_NONE;
181 err:
182 return -ENOMEM;
183 }
184
185 /*
186 * Mac disk always begin with "Driver Descriptor Record"
187 * (struct mac_driver_desc) and magic 0x4552.
188 */
189 const struct blkid_idinfo mac_pt_idinfo =
190 {
191 .name = "mac",
192 .probefunc = probe_mac_pt,
193 .magics =
194 {
195 /* big-endian magic string */
196 { .magic = "\x45\x52", .len = 2 },
197 { NULL }
198 }
199 };
200