/src/util-linux/libblkid/src/partitions/bsd.c
Line | Count | Source |
1 | | /* |
2 | | * BSD/OSF partition 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 | | * Inspired by fdisk, partx, Linux kernel, libparted and openbsd header files. |
10 | | */ |
11 | | #include <stdio.h> |
12 | | #include <string.h> |
13 | | #include <stdlib.h> |
14 | | #include <stdint.h> |
15 | | |
16 | | #include "partitions.h" |
17 | | #include "pt-bsd.h" |
18 | | |
19 | | /* Returns 'blkid_idmag' in 512-sectors */ |
20 | 0 | #define BLKID_MAG_SECTOR(_mag) (((_mag)->kboff / 2) + ((_mag)->sboff >> 9)) |
21 | | |
22 | | /* Returns 'blkid_idmag' in bytes */ |
23 | 0 | #define BLKID_MAG_OFFSET(_mag) ((_mag)->kboff << 10) + ((_mag)->sboff) |
24 | | |
25 | | /* Returns 'blkid_idmag' offset in bytes within the last sector */ |
26 | | #define BLKID_MAG_LASTOFFSET(_mag) \ |
27 | 0 | (BLKID_MAG_OFFSET(_mag) - (BLKID_MAG_SECTOR(_mag) << 9)) |
28 | | |
29 | | static uint16_t bsd_checksum(const struct bsd_disklabel *l) |
30 | 0 | { |
31 | 0 | uint16_t v, csum = 0; |
32 | 0 | const char *end = (const char *) (l + 1); |
33 | |
|
34 | 0 | for (const char *c = (const char *) l; c < end; c += sizeof(uint16_t)) { |
35 | 0 | memcpy(&v, c, sizeof(v)); |
36 | 0 | csum ^= v; |
37 | 0 | } |
38 | 0 | return csum ^ le16_to_cpu(l->d_checksum); |
39 | 0 | } |
40 | | |
41 | | static int probe_bsd_pt(blkid_probe pr, const struct blkid_idmag *mag) |
42 | 313 | { |
43 | 313 | struct bsd_disklabel *l; |
44 | 313 | struct bsd_partition *p; |
45 | 313 | const char *name = "bsd" ; |
46 | 313 | blkid_parttable tab = NULL; |
47 | 313 | blkid_partition parent; |
48 | 313 | blkid_partlist ls; |
49 | 313 | int i, nparts = BSD_MAXPARTITIONS; |
50 | 313 | const unsigned char *data; |
51 | 313 | int rc = BLKID_PROBE_NONE; |
52 | 313 | uint32_t abs_offset = 0; |
53 | | |
54 | 313 | if (blkid_partitions_need_typeonly(pr)) |
55 | | /* caller does not ask for details about partitions */ |
56 | 313 | return rc; |
57 | | |
58 | 0 | data = blkid_probe_get_sector(pr, BLKID_MAG_SECTOR(mag)); |
59 | 0 | if (!data) { |
60 | 0 | if (errno) |
61 | 0 | rc = -errno; |
62 | 0 | goto nothing; |
63 | 0 | } |
64 | | |
65 | 0 | l = (struct bsd_disklabel *) (data + BLKID_MAG_LASTOFFSET(mag)); |
66 | |
|
67 | 0 | if (!blkid_probe_verify_csum(pr, bsd_checksum(l), le16_to_cpu(l->d_checksum))) { |
68 | 0 | rc = BLKID_PROBE_NONE; |
69 | 0 | goto nothing; |
70 | 0 | } |
71 | | |
72 | 0 | ls = blkid_probe_get_partlist(pr); |
73 | 0 | if (!ls) |
74 | 0 | goto nothing; |
75 | | |
76 | | /* try to determine the real type of BSD system according to |
77 | | * (parental) primary partition */ |
78 | 0 | parent = blkid_partlist_get_parent(ls); |
79 | 0 | if (parent) { |
80 | 0 | switch(blkid_partition_get_type(parent)) { |
81 | 0 | case MBR_FREEBSD_PARTITION: |
82 | 0 | name = "freebsd"; |
83 | 0 | abs_offset = blkid_partition_get_start(parent); |
84 | 0 | break; |
85 | 0 | case MBR_NETBSD_PARTITION: |
86 | 0 | name = "netbsd"; |
87 | 0 | break; |
88 | 0 | case MBR_OPENBSD_PARTITION: |
89 | 0 | name = "openbsd"; |
90 | 0 | break; |
91 | 0 | default: |
92 | 0 | DBG(LOWPROBE, ul_debug( |
93 | 0 | "WARNING: BSD label detected on unknown (0x%x) " |
94 | 0 | "primary partition", |
95 | 0 | blkid_partition_get_type(parent))); |
96 | 0 | break; |
97 | 0 | } |
98 | 0 | } |
99 | | |
100 | 0 | tab = blkid_partlist_new_parttable(ls, name, BLKID_MAG_OFFSET(mag)); |
101 | 0 | if (!tab) { |
102 | 0 | rc = -ENOMEM; |
103 | 0 | goto nothing; |
104 | 0 | } |
105 | | |
106 | 0 | if (le16_to_cpu(l->d_npartitions) < BSD_MAXPARTITIONS) |
107 | 0 | nparts = le16_to_cpu(l->d_npartitions); |
108 | | |
109 | 0 | else if (le16_to_cpu(l->d_npartitions) > BSD_MAXPARTITIONS) |
110 | 0 | DBG(LOWPROBE, ul_debug( |
111 | 0 | "WARNING: ignore %d more BSD partitions", |
112 | 0 | le16_to_cpu(l->d_npartitions) - BSD_MAXPARTITIONS)); |
113 | |
|
114 | 0 | for (i = 0, p = l->d_partitions; i < nparts; i++, p++) { |
115 | 0 | blkid_partition par; |
116 | 0 | uint32_t start, size; |
117 | |
|
118 | 0 | if (p->p_fstype == BSD_FS_UNUSED) |
119 | 0 | continue; |
120 | | |
121 | 0 | start = le32_to_cpu(p->p_offset); |
122 | 0 | size = le32_to_cpu(p->p_size); |
123 | | |
124 | | /* FreeBSD since version 10 uses relative offsets. We can use |
125 | | * 3rd partition (special wholedisk partition) to detect this |
126 | | * situation. |
127 | | */ |
128 | 0 | if (abs_offset && nparts >= 3 |
129 | 0 | && le32_to_cpu(l->d_partitions[2].p_offset) == 0) |
130 | 0 | start += abs_offset; |
131 | |
|
132 | 0 | if (parent && blkid_partition_get_start(parent) == start |
133 | 0 | && blkid_partition_get_size(parent) == size) { |
134 | 0 | DBG(LOWPROBE, ul_debug( |
135 | 0 | "WARNING: BSD partition (%d) same like parent, " |
136 | 0 | "ignore", i)); |
137 | 0 | continue; |
138 | 0 | } |
139 | 0 | if (parent && !blkid_is_nested_dimension(parent, start, size)) { |
140 | 0 | DBG(LOWPROBE, ul_debug( |
141 | 0 | "WARNING: BSD partition (%d) overflow " |
142 | 0 | "detected, ignore", i)); |
143 | 0 | continue; |
144 | 0 | } |
145 | | |
146 | 0 | par = blkid_partlist_add_partition(ls, tab, start, size); |
147 | 0 | if (!par) { |
148 | 0 | rc = -ENOMEM; |
149 | 0 | goto nothing; |
150 | 0 | } |
151 | | |
152 | 0 | blkid_partition_set_type(par, p->p_fstype); |
153 | 0 | } |
154 | | |
155 | 0 | return BLKID_PROBE_OK; |
156 | | |
157 | 0 | nothing: |
158 | 0 | return rc; |
159 | 0 | } |
160 | | |
161 | | |
162 | | /* |
163 | | * All BSD variants use the same magic string (little-endian), |
164 | | * and the same disklabel. |
165 | | * |
166 | | * The difference between {Free,Open,...}BSD is in the (parental) |
167 | | * primary partition type. |
168 | | * |
169 | | * See also: http://en.wikipedia.org/wiki/BSD_disklabel |
170 | | * |
171 | | * The location of BSD disk label is architecture specific and in defined by |
172 | | * LABELSECTOR and LABELOFFSET macros in the disklabel.h file. The location |
173 | | * also depends on BSD variant, FreeBSD uses only one location, NetBSD and |
174 | | * OpenBSD are more creative... |
175 | | * |
176 | | * The basic overview: |
177 | | * |
178 | | * arch | LABELSECTOR | LABELOFFSET |
179 | | * ------------------------+-------------+------------ |
180 | | * amd64 arm hppa hppa64 | | |
181 | | * i386, macppc, mvmeppc | 1 | 0 |
182 | | * sgi, aviion, sh, socppc | | |
183 | | * ------------------------+-------------+------------ |
184 | | * alpha luna88k mac68k | 0 | 64 |
185 | | * sparc(OpenBSD) vax | | |
186 | | * ------------------------+-------------+------------ |
187 | | * sparc64 sparc(NetBSD) | 0 | 128 |
188 | | * ------------------------+-------------+------------ |
189 | | * |
190 | | * ...and more (see http://fxr.watson.org/fxr/ident?v=NETBSD;i=LABELSECTOR) |
191 | | * |
192 | | */ |
193 | | const struct blkid_idinfo bsd_pt_idinfo = |
194 | | { |
195 | | .name = "bsd", |
196 | | .probefunc = probe_bsd_pt, |
197 | | .magics = |
198 | | { |
199 | | { .magic = "\x57\x45\x56\x82", .len = 4, .sboff = 512 }, |
200 | | { .magic = "\x57\x45\x56\x82", .len = 4, .sboff = 64 }, |
201 | | { .magic = "\x57\x45\x56\x82", .len = 4, .sboff = 128 }, |
202 | | { NULL } |
203 | | } |
204 | | }; |
205 | | |