1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * fs/partitions/msdos.c
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Code extracted from drivers/block/genhd.c
6*4882a593Smuzhiyun * Copyright (C) 1991-1998 Linus Torvalds
7*4882a593Smuzhiyun *
8*4882a593Smuzhiyun * Thanks to Branko Lankester, lankeste@fwi.uva.nl, who found a bug
9*4882a593Smuzhiyun * in the early extended-partition checks and added DM partitions
10*4882a593Smuzhiyun *
11*4882a593Smuzhiyun * Support for DiskManager v6.0x added by Mark Lord,
12*4882a593Smuzhiyun * with information provided by OnTrack. This now works for linux fdisk
13*4882a593Smuzhiyun * and LILO, as well as loadlin and bootln. Note that disks other than
14*4882a593Smuzhiyun * /dev/hda *must* have a "DOS" type 0x51 partition in the first slot (hda1).
15*4882a593Smuzhiyun *
16*4882a593Smuzhiyun * More flexible handling of extended partitions - aeb, 950831
17*4882a593Smuzhiyun *
18*4882a593Smuzhiyun * Check partition table on IDE disks for common CHS translations
19*4882a593Smuzhiyun *
20*4882a593Smuzhiyun * Re-organised Feb 1998 Russell King
21*4882a593Smuzhiyun *
22*4882a593Smuzhiyun * BSD disklabel support by Yossi Gottlieb <yogo@math.tau.ac.il>
23*4882a593Smuzhiyun * updated by Marc Espie <Marc.Espie@openbsd.org>
24*4882a593Smuzhiyun *
25*4882a593Smuzhiyun * Unixware slices support by Andrzej Krzysztofowicz <ankry@mif.pg.gda.pl>
26*4882a593Smuzhiyun * and Krzysztof G. Baranowski <kgb@knm.org.pl>
27*4882a593Smuzhiyun */
28*4882a593Smuzhiyun #include <linux/msdos_fs.h>
29*4882a593Smuzhiyun #include <linux/msdos_partition.h>
30*4882a593Smuzhiyun
31*4882a593Smuzhiyun #include "check.h"
32*4882a593Smuzhiyun #include "efi.h"
33*4882a593Smuzhiyun
34*4882a593Smuzhiyun /*
35*4882a593Smuzhiyun * Many architectures don't like unaligned accesses, while
36*4882a593Smuzhiyun * the nr_sects and start_sect partition table entries are
37*4882a593Smuzhiyun * at a 2 (mod 4) address.
38*4882a593Smuzhiyun */
39*4882a593Smuzhiyun #include <asm/unaligned.h>
40*4882a593Smuzhiyun
nr_sects(struct msdos_partition * p)41*4882a593Smuzhiyun static inline sector_t nr_sects(struct msdos_partition *p)
42*4882a593Smuzhiyun {
43*4882a593Smuzhiyun return (sector_t)get_unaligned_le32(&p->nr_sects);
44*4882a593Smuzhiyun }
45*4882a593Smuzhiyun
start_sect(struct msdos_partition * p)46*4882a593Smuzhiyun static inline sector_t start_sect(struct msdos_partition *p)
47*4882a593Smuzhiyun {
48*4882a593Smuzhiyun return (sector_t)get_unaligned_le32(&p->start_sect);
49*4882a593Smuzhiyun }
50*4882a593Smuzhiyun
is_extended_partition(struct msdos_partition * p)51*4882a593Smuzhiyun static inline int is_extended_partition(struct msdos_partition *p)
52*4882a593Smuzhiyun {
53*4882a593Smuzhiyun return (p->sys_ind == DOS_EXTENDED_PARTITION ||
54*4882a593Smuzhiyun p->sys_ind == WIN98_EXTENDED_PARTITION ||
55*4882a593Smuzhiyun p->sys_ind == LINUX_EXTENDED_PARTITION);
56*4882a593Smuzhiyun }
57*4882a593Smuzhiyun
58*4882a593Smuzhiyun #define MSDOS_LABEL_MAGIC1 0x55
59*4882a593Smuzhiyun #define MSDOS_LABEL_MAGIC2 0xAA
60*4882a593Smuzhiyun
61*4882a593Smuzhiyun static inline int
msdos_magic_present(unsigned char * p)62*4882a593Smuzhiyun msdos_magic_present(unsigned char *p)
63*4882a593Smuzhiyun {
64*4882a593Smuzhiyun return (p[0] == MSDOS_LABEL_MAGIC1 && p[1] == MSDOS_LABEL_MAGIC2);
65*4882a593Smuzhiyun }
66*4882a593Smuzhiyun
67*4882a593Smuzhiyun /* Value is EBCDIC 'IBMA' */
68*4882a593Smuzhiyun #define AIX_LABEL_MAGIC1 0xC9
69*4882a593Smuzhiyun #define AIX_LABEL_MAGIC2 0xC2
70*4882a593Smuzhiyun #define AIX_LABEL_MAGIC3 0xD4
71*4882a593Smuzhiyun #define AIX_LABEL_MAGIC4 0xC1
aix_magic_present(struct parsed_partitions * state,unsigned char * p)72*4882a593Smuzhiyun static int aix_magic_present(struct parsed_partitions *state, unsigned char *p)
73*4882a593Smuzhiyun {
74*4882a593Smuzhiyun struct msdos_partition *pt = (struct msdos_partition *) (p + 0x1be);
75*4882a593Smuzhiyun Sector sect;
76*4882a593Smuzhiyun unsigned char *d;
77*4882a593Smuzhiyun int slot, ret = 0;
78*4882a593Smuzhiyun
79*4882a593Smuzhiyun if (!(p[0] == AIX_LABEL_MAGIC1 &&
80*4882a593Smuzhiyun p[1] == AIX_LABEL_MAGIC2 &&
81*4882a593Smuzhiyun p[2] == AIX_LABEL_MAGIC3 &&
82*4882a593Smuzhiyun p[3] == AIX_LABEL_MAGIC4))
83*4882a593Smuzhiyun return 0;
84*4882a593Smuzhiyun
85*4882a593Smuzhiyun /*
86*4882a593Smuzhiyun * Assume the partition table is valid if Linux partitions exists.
87*4882a593Smuzhiyun * Note that old Solaris/x86 partitions use the same indicator as
88*4882a593Smuzhiyun * Linux swap partitions, so we consider that a Linux partition as
89*4882a593Smuzhiyun * well.
90*4882a593Smuzhiyun */
91*4882a593Smuzhiyun for (slot = 1; slot <= 4; slot++, pt++) {
92*4882a593Smuzhiyun if (pt->sys_ind == SOLARIS_X86_PARTITION ||
93*4882a593Smuzhiyun pt->sys_ind == LINUX_RAID_PARTITION ||
94*4882a593Smuzhiyun pt->sys_ind == LINUX_DATA_PARTITION ||
95*4882a593Smuzhiyun pt->sys_ind == LINUX_LVM_PARTITION ||
96*4882a593Smuzhiyun is_extended_partition(pt))
97*4882a593Smuzhiyun return 0;
98*4882a593Smuzhiyun }
99*4882a593Smuzhiyun d = read_part_sector(state, 7, §);
100*4882a593Smuzhiyun if (d) {
101*4882a593Smuzhiyun if (d[0] == '_' && d[1] == 'L' && d[2] == 'V' && d[3] == 'M')
102*4882a593Smuzhiyun ret = 1;
103*4882a593Smuzhiyun put_dev_sector(sect);
104*4882a593Smuzhiyun }
105*4882a593Smuzhiyun return ret;
106*4882a593Smuzhiyun }
107*4882a593Smuzhiyun
set_info(struct parsed_partitions * state,int slot,u32 disksig)108*4882a593Smuzhiyun static void set_info(struct parsed_partitions *state, int slot,
109*4882a593Smuzhiyun u32 disksig)
110*4882a593Smuzhiyun {
111*4882a593Smuzhiyun struct partition_meta_info *info = &state->parts[slot].info;
112*4882a593Smuzhiyun
113*4882a593Smuzhiyun snprintf(info->uuid, sizeof(info->uuid), "%08x-%02x", disksig,
114*4882a593Smuzhiyun slot);
115*4882a593Smuzhiyun info->volname[0] = 0;
116*4882a593Smuzhiyun state->parts[slot].has_info = true;
117*4882a593Smuzhiyun }
118*4882a593Smuzhiyun
119*4882a593Smuzhiyun /*
120*4882a593Smuzhiyun * Create devices for each logical partition in an extended partition.
121*4882a593Smuzhiyun * The logical partitions form a linked list, with each entry being
122*4882a593Smuzhiyun * a partition table with two entries. The first entry
123*4882a593Smuzhiyun * is the real data partition (with a start relative to the partition
124*4882a593Smuzhiyun * table start). The second is a pointer to the next logical partition
125*4882a593Smuzhiyun * (with a start relative to the entire extended partition).
126*4882a593Smuzhiyun * We do not create a Linux partition for the partition tables, but
127*4882a593Smuzhiyun * only for the actual data partitions.
128*4882a593Smuzhiyun */
129*4882a593Smuzhiyun
parse_extended(struct parsed_partitions * state,sector_t first_sector,sector_t first_size,u32 disksig)130*4882a593Smuzhiyun static void parse_extended(struct parsed_partitions *state,
131*4882a593Smuzhiyun sector_t first_sector, sector_t first_size,
132*4882a593Smuzhiyun u32 disksig)
133*4882a593Smuzhiyun {
134*4882a593Smuzhiyun struct msdos_partition *p;
135*4882a593Smuzhiyun Sector sect;
136*4882a593Smuzhiyun unsigned char *data;
137*4882a593Smuzhiyun sector_t this_sector, this_size;
138*4882a593Smuzhiyun sector_t sector_size = bdev_logical_block_size(state->bdev) / 512;
139*4882a593Smuzhiyun int loopct = 0; /* number of links followed
140*4882a593Smuzhiyun without finding a data partition */
141*4882a593Smuzhiyun int i;
142*4882a593Smuzhiyun
143*4882a593Smuzhiyun this_sector = first_sector;
144*4882a593Smuzhiyun this_size = first_size;
145*4882a593Smuzhiyun
146*4882a593Smuzhiyun while (1) {
147*4882a593Smuzhiyun if (++loopct > 100)
148*4882a593Smuzhiyun return;
149*4882a593Smuzhiyun if (state->next == state->limit)
150*4882a593Smuzhiyun return;
151*4882a593Smuzhiyun data = read_part_sector(state, this_sector, §);
152*4882a593Smuzhiyun if (!data)
153*4882a593Smuzhiyun return;
154*4882a593Smuzhiyun
155*4882a593Smuzhiyun if (!msdos_magic_present(data + 510))
156*4882a593Smuzhiyun goto done;
157*4882a593Smuzhiyun
158*4882a593Smuzhiyun p = (struct msdos_partition *) (data + 0x1be);
159*4882a593Smuzhiyun
160*4882a593Smuzhiyun /*
161*4882a593Smuzhiyun * Usually, the first entry is the real data partition,
162*4882a593Smuzhiyun * the 2nd entry is the next extended partition, or empty,
163*4882a593Smuzhiyun * and the 3rd and 4th entries are unused.
164*4882a593Smuzhiyun * However, DRDOS sometimes has the extended partition as
165*4882a593Smuzhiyun * the first entry (when the data partition is empty),
166*4882a593Smuzhiyun * and OS/2 seems to use all four entries.
167*4882a593Smuzhiyun */
168*4882a593Smuzhiyun
169*4882a593Smuzhiyun /*
170*4882a593Smuzhiyun * First process the data partition(s)
171*4882a593Smuzhiyun */
172*4882a593Smuzhiyun for (i = 0; i < 4; i++, p++) {
173*4882a593Smuzhiyun sector_t offs, size, next;
174*4882a593Smuzhiyun
175*4882a593Smuzhiyun if (!nr_sects(p) || is_extended_partition(p))
176*4882a593Smuzhiyun continue;
177*4882a593Smuzhiyun
178*4882a593Smuzhiyun /* Check the 3rd and 4th entries -
179*4882a593Smuzhiyun these sometimes contain random garbage */
180*4882a593Smuzhiyun offs = start_sect(p)*sector_size;
181*4882a593Smuzhiyun size = nr_sects(p)*sector_size;
182*4882a593Smuzhiyun next = this_sector + offs;
183*4882a593Smuzhiyun if (i >= 2) {
184*4882a593Smuzhiyun if (offs + size > this_size)
185*4882a593Smuzhiyun continue;
186*4882a593Smuzhiyun if (next < first_sector)
187*4882a593Smuzhiyun continue;
188*4882a593Smuzhiyun if (next + size > first_sector + first_size)
189*4882a593Smuzhiyun continue;
190*4882a593Smuzhiyun }
191*4882a593Smuzhiyun
192*4882a593Smuzhiyun put_partition(state, state->next, next, size);
193*4882a593Smuzhiyun set_info(state, state->next, disksig);
194*4882a593Smuzhiyun if (p->sys_ind == LINUX_RAID_PARTITION)
195*4882a593Smuzhiyun state->parts[state->next].flags = ADDPART_FLAG_RAID;
196*4882a593Smuzhiyun loopct = 0;
197*4882a593Smuzhiyun if (++state->next == state->limit)
198*4882a593Smuzhiyun goto done;
199*4882a593Smuzhiyun }
200*4882a593Smuzhiyun /*
201*4882a593Smuzhiyun * Next, process the (first) extended partition, if present.
202*4882a593Smuzhiyun * (So far, there seems to be no reason to make
203*4882a593Smuzhiyun * parse_extended() recursive and allow a tree
204*4882a593Smuzhiyun * of extended partitions.)
205*4882a593Smuzhiyun * It should be a link to the next logical partition.
206*4882a593Smuzhiyun */
207*4882a593Smuzhiyun p -= 4;
208*4882a593Smuzhiyun for (i = 0; i < 4; i++, p++)
209*4882a593Smuzhiyun if (nr_sects(p) && is_extended_partition(p))
210*4882a593Smuzhiyun break;
211*4882a593Smuzhiyun if (i == 4)
212*4882a593Smuzhiyun goto done; /* nothing left to do */
213*4882a593Smuzhiyun
214*4882a593Smuzhiyun this_sector = first_sector + start_sect(p) * sector_size;
215*4882a593Smuzhiyun this_size = nr_sects(p) * sector_size;
216*4882a593Smuzhiyun put_dev_sector(sect);
217*4882a593Smuzhiyun }
218*4882a593Smuzhiyun done:
219*4882a593Smuzhiyun put_dev_sector(sect);
220*4882a593Smuzhiyun }
221*4882a593Smuzhiyun
222*4882a593Smuzhiyun #define SOLARIS_X86_NUMSLICE 16
223*4882a593Smuzhiyun #define SOLARIS_X86_VTOC_SANE (0x600DDEEEUL)
224*4882a593Smuzhiyun
225*4882a593Smuzhiyun struct solaris_x86_slice {
226*4882a593Smuzhiyun __le16 s_tag; /* ID tag of partition */
227*4882a593Smuzhiyun __le16 s_flag; /* permission flags */
228*4882a593Smuzhiyun __le32 s_start; /* start sector no of partition */
229*4882a593Smuzhiyun __le32 s_size; /* # of blocks in partition */
230*4882a593Smuzhiyun };
231*4882a593Smuzhiyun
232*4882a593Smuzhiyun struct solaris_x86_vtoc {
233*4882a593Smuzhiyun unsigned int v_bootinfo[3]; /* info needed by mboot */
234*4882a593Smuzhiyun __le32 v_sanity; /* to verify vtoc sanity */
235*4882a593Smuzhiyun __le32 v_version; /* layout version */
236*4882a593Smuzhiyun char v_volume[8]; /* volume name */
237*4882a593Smuzhiyun __le16 v_sectorsz; /* sector size in bytes */
238*4882a593Smuzhiyun __le16 v_nparts; /* number of partitions */
239*4882a593Smuzhiyun unsigned int v_reserved[10]; /* free space */
240*4882a593Smuzhiyun struct solaris_x86_slice
241*4882a593Smuzhiyun v_slice[SOLARIS_X86_NUMSLICE]; /* slice headers */
242*4882a593Smuzhiyun unsigned int timestamp[SOLARIS_X86_NUMSLICE]; /* timestamp */
243*4882a593Smuzhiyun char v_asciilabel[128]; /* for compatibility */
244*4882a593Smuzhiyun };
245*4882a593Smuzhiyun
246*4882a593Smuzhiyun /* james@bpgc.com: Solaris has a nasty indicator: 0x82 which also
247*4882a593Smuzhiyun indicates linux swap. Be careful before believing this is Solaris. */
248*4882a593Smuzhiyun
parse_solaris_x86(struct parsed_partitions * state,sector_t offset,sector_t size,int origin)249*4882a593Smuzhiyun static void parse_solaris_x86(struct parsed_partitions *state,
250*4882a593Smuzhiyun sector_t offset, sector_t size, int origin)
251*4882a593Smuzhiyun {
252*4882a593Smuzhiyun #ifdef CONFIG_SOLARIS_X86_PARTITION
253*4882a593Smuzhiyun Sector sect;
254*4882a593Smuzhiyun struct solaris_x86_vtoc *v;
255*4882a593Smuzhiyun int i;
256*4882a593Smuzhiyun short max_nparts;
257*4882a593Smuzhiyun
258*4882a593Smuzhiyun v = read_part_sector(state, offset + 1, §);
259*4882a593Smuzhiyun if (!v)
260*4882a593Smuzhiyun return;
261*4882a593Smuzhiyun if (le32_to_cpu(v->v_sanity) != SOLARIS_X86_VTOC_SANE) {
262*4882a593Smuzhiyun put_dev_sector(sect);
263*4882a593Smuzhiyun return;
264*4882a593Smuzhiyun }
265*4882a593Smuzhiyun {
266*4882a593Smuzhiyun char tmp[1 + BDEVNAME_SIZE + 10 + 11 + 1];
267*4882a593Smuzhiyun
268*4882a593Smuzhiyun snprintf(tmp, sizeof(tmp), " %s%d: <solaris:", state->name, origin);
269*4882a593Smuzhiyun strlcat(state->pp_buf, tmp, PAGE_SIZE);
270*4882a593Smuzhiyun }
271*4882a593Smuzhiyun if (le32_to_cpu(v->v_version) != 1) {
272*4882a593Smuzhiyun char tmp[64];
273*4882a593Smuzhiyun
274*4882a593Smuzhiyun snprintf(tmp, sizeof(tmp), " cannot handle version %d vtoc>\n",
275*4882a593Smuzhiyun le32_to_cpu(v->v_version));
276*4882a593Smuzhiyun strlcat(state->pp_buf, tmp, PAGE_SIZE);
277*4882a593Smuzhiyun put_dev_sector(sect);
278*4882a593Smuzhiyun return;
279*4882a593Smuzhiyun }
280*4882a593Smuzhiyun /* Ensure we can handle previous case of VTOC with 8 entries gracefully */
281*4882a593Smuzhiyun max_nparts = le16_to_cpu(v->v_nparts) > 8 ? SOLARIS_X86_NUMSLICE : 8;
282*4882a593Smuzhiyun for (i = 0; i < max_nparts && state->next < state->limit; i++) {
283*4882a593Smuzhiyun struct solaris_x86_slice *s = &v->v_slice[i];
284*4882a593Smuzhiyun char tmp[3 + 10 + 1 + 1];
285*4882a593Smuzhiyun
286*4882a593Smuzhiyun if (s->s_size == 0)
287*4882a593Smuzhiyun continue;
288*4882a593Smuzhiyun snprintf(tmp, sizeof(tmp), " [s%d]", i);
289*4882a593Smuzhiyun strlcat(state->pp_buf, tmp, PAGE_SIZE);
290*4882a593Smuzhiyun /* solaris partitions are relative to current MS-DOS
291*4882a593Smuzhiyun * one; must add the offset of the current partition */
292*4882a593Smuzhiyun put_partition(state, state->next++,
293*4882a593Smuzhiyun le32_to_cpu(s->s_start)+offset,
294*4882a593Smuzhiyun le32_to_cpu(s->s_size));
295*4882a593Smuzhiyun }
296*4882a593Smuzhiyun put_dev_sector(sect);
297*4882a593Smuzhiyun strlcat(state->pp_buf, " >\n", PAGE_SIZE);
298*4882a593Smuzhiyun #endif
299*4882a593Smuzhiyun }
300*4882a593Smuzhiyun
301*4882a593Smuzhiyun /* check against BSD src/sys/sys/disklabel.h for consistency */
302*4882a593Smuzhiyun #define BSD_DISKMAGIC (0x82564557UL) /* The disk magic number */
303*4882a593Smuzhiyun #define BSD_MAXPARTITIONS 16
304*4882a593Smuzhiyun #define OPENBSD_MAXPARTITIONS 16
305*4882a593Smuzhiyun #define BSD_FS_UNUSED 0 /* disklabel unused partition entry ID */
306*4882a593Smuzhiyun struct bsd_disklabel {
307*4882a593Smuzhiyun __le32 d_magic; /* the magic number */
308*4882a593Smuzhiyun __s16 d_type; /* drive type */
309*4882a593Smuzhiyun __s16 d_subtype; /* controller/d_type specific */
310*4882a593Smuzhiyun char d_typename[16]; /* type name, e.g. "eagle" */
311*4882a593Smuzhiyun char d_packname[16]; /* pack identifier */
312*4882a593Smuzhiyun __u32 d_secsize; /* # of bytes per sector */
313*4882a593Smuzhiyun __u32 d_nsectors; /* # of data sectors per track */
314*4882a593Smuzhiyun __u32 d_ntracks; /* # of tracks per cylinder */
315*4882a593Smuzhiyun __u32 d_ncylinders; /* # of data cylinders per unit */
316*4882a593Smuzhiyun __u32 d_secpercyl; /* # of data sectors per cylinder */
317*4882a593Smuzhiyun __u32 d_secperunit; /* # of data sectors per unit */
318*4882a593Smuzhiyun __u16 d_sparespertrack; /* # of spare sectors per track */
319*4882a593Smuzhiyun __u16 d_sparespercyl; /* # of spare sectors per cylinder */
320*4882a593Smuzhiyun __u32 d_acylinders; /* # of alt. cylinders per unit */
321*4882a593Smuzhiyun __u16 d_rpm; /* rotational speed */
322*4882a593Smuzhiyun __u16 d_interleave; /* hardware sector interleave */
323*4882a593Smuzhiyun __u16 d_trackskew; /* sector 0 skew, per track */
324*4882a593Smuzhiyun __u16 d_cylskew; /* sector 0 skew, per cylinder */
325*4882a593Smuzhiyun __u32 d_headswitch; /* head switch time, usec */
326*4882a593Smuzhiyun __u32 d_trkseek; /* track-to-track seek, usec */
327*4882a593Smuzhiyun __u32 d_flags; /* generic flags */
328*4882a593Smuzhiyun #define NDDATA 5
329*4882a593Smuzhiyun __u32 d_drivedata[NDDATA]; /* drive-type specific information */
330*4882a593Smuzhiyun #define NSPARE 5
331*4882a593Smuzhiyun __u32 d_spare[NSPARE]; /* reserved for future use */
332*4882a593Smuzhiyun __le32 d_magic2; /* the magic number (again) */
333*4882a593Smuzhiyun __le16 d_checksum; /* xor of data incl. partitions */
334*4882a593Smuzhiyun
335*4882a593Smuzhiyun /* filesystem and partition information: */
336*4882a593Smuzhiyun __le16 d_npartitions; /* number of partitions in following */
337*4882a593Smuzhiyun __le32 d_bbsize; /* size of boot area at sn0, bytes */
338*4882a593Smuzhiyun __le32 d_sbsize; /* max size of fs superblock, bytes */
339*4882a593Smuzhiyun struct bsd_partition { /* the partition table */
340*4882a593Smuzhiyun __le32 p_size; /* number of sectors in partition */
341*4882a593Smuzhiyun __le32 p_offset; /* starting sector */
342*4882a593Smuzhiyun __le32 p_fsize; /* filesystem basic fragment size */
343*4882a593Smuzhiyun __u8 p_fstype; /* filesystem type, see below */
344*4882a593Smuzhiyun __u8 p_frag; /* filesystem fragments per block */
345*4882a593Smuzhiyun __le16 p_cpg; /* filesystem cylinders per group */
346*4882a593Smuzhiyun } d_partitions[BSD_MAXPARTITIONS]; /* actually may be more */
347*4882a593Smuzhiyun };
348*4882a593Smuzhiyun
349*4882a593Smuzhiyun #if defined(CONFIG_BSD_DISKLABEL)
350*4882a593Smuzhiyun /*
351*4882a593Smuzhiyun * Create devices for BSD partitions listed in a disklabel, under a
352*4882a593Smuzhiyun * dos-like partition. See parse_extended() for more information.
353*4882a593Smuzhiyun */
parse_bsd(struct parsed_partitions * state,sector_t offset,sector_t size,int origin,char * flavour,int max_partitions)354*4882a593Smuzhiyun static void parse_bsd(struct parsed_partitions *state,
355*4882a593Smuzhiyun sector_t offset, sector_t size, int origin, char *flavour,
356*4882a593Smuzhiyun int max_partitions)
357*4882a593Smuzhiyun {
358*4882a593Smuzhiyun Sector sect;
359*4882a593Smuzhiyun struct bsd_disklabel *l;
360*4882a593Smuzhiyun struct bsd_partition *p;
361*4882a593Smuzhiyun char tmp[64];
362*4882a593Smuzhiyun
363*4882a593Smuzhiyun l = read_part_sector(state, offset + 1, §);
364*4882a593Smuzhiyun if (!l)
365*4882a593Smuzhiyun return;
366*4882a593Smuzhiyun if (le32_to_cpu(l->d_magic) != BSD_DISKMAGIC) {
367*4882a593Smuzhiyun put_dev_sector(sect);
368*4882a593Smuzhiyun return;
369*4882a593Smuzhiyun }
370*4882a593Smuzhiyun
371*4882a593Smuzhiyun snprintf(tmp, sizeof(tmp), " %s%d: <%s:", state->name, origin, flavour);
372*4882a593Smuzhiyun strlcat(state->pp_buf, tmp, PAGE_SIZE);
373*4882a593Smuzhiyun
374*4882a593Smuzhiyun if (le16_to_cpu(l->d_npartitions) < max_partitions)
375*4882a593Smuzhiyun max_partitions = le16_to_cpu(l->d_npartitions);
376*4882a593Smuzhiyun for (p = l->d_partitions; p - l->d_partitions < max_partitions; p++) {
377*4882a593Smuzhiyun sector_t bsd_start, bsd_size;
378*4882a593Smuzhiyun
379*4882a593Smuzhiyun if (state->next == state->limit)
380*4882a593Smuzhiyun break;
381*4882a593Smuzhiyun if (p->p_fstype == BSD_FS_UNUSED)
382*4882a593Smuzhiyun continue;
383*4882a593Smuzhiyun bsd_start = le32_to_cpu(p->p_offset);
384*4882a593Smuzhiyun bsd_size = le32_to_cpu(p->p_size);
385*4882a593Smuzhiyun /* FreeBSD has relative offset if C partition offset is zero */
386*4882a593Smuzhiyun if (memcmp(flavour, "bsd\0", 4) == 0 &&
387*4882a593Smuzhiyun le32_to_cpu(l->d_partitions[2].p_offset) == 0)
388*4882a593Smuzhiyun bsd_start += offset;
389*4882a593Smuzhiyun if (offset == bsd_start && size == bsd_size)
390*4882a593Smuzhiyun /* full parent partition, we have it already */
391*4882a593Smuzhiyun continue;
392*4882a593Smuzhiyun if (offset > bsd_start || offset+size < bsd_start+bsd_size) {
393*4882a593Smuzhiyun strlcat(state->pp_buf, "bad subpartition - ignored\n", PAGE_SIZE);
394*4882a593Smuzhiyun continue;
395*4882a593Smuzhiyun }
396*4882a593Smuzhiyun put_partition(state, state->next++, bsd_start, bsd_size);
397*4882a593Smuzhiyun }
398*4882a593Smuzhiyun put_dev_sector(sect);
399*4882a593Smuzhiyun if (le16_to_cpu(l->d_npartitions) > max_partitions) {
400*4882a593Smuzhiyun snprintf(tmp, sizeof(tmp), " (ignored %d more)",
401*4882a593Smuzhiyun le16_to_cpu(l->d_npartitions) - max_partitions);
402*4882a593Smuzhiyun strlcat(state->pp_buf, tmp, PAGE_SIZE);
403*4882a593Smuzhiyun }
404*4882a593Smuzhiyun strlcat(state->pp_buf, " >\n", PAGE_SIZE);
405*4882a593Smuzhiyun }
406*4882a593Smuzhiyun #endif
407*4882a593Smuzhiyun
parse_freebsd(struct parsed_partitions * state,sector_t offset,sector_t size,int origin)408*4882a593Smuzhiyun static void parse_freebsd(struct parsed_partitions *state,
409*4882a593Smuzhiyun sector_t offset, sector_t size, int origin)
410*4882a593Smuzhiyun {
411*4882a593Smuzhiyun #ifdef CONFIG_BSD_DISKLABEL
412*4882a593Smuzhiyun parse_bsd(state, offset, size, origin, "bsd", BSD_MAXPARTITIONS);
413*4882a593Smuzhiyun #endif
414*4882a593Smuzhiyun }
415*4882a593Smuzhiyun
parse_netbsd(struct parsed_partitions * state,sector_t offset,sector_t size,int origin)416*4882a593Smuzhiyun static void parse_netbsd(struct parsed_partitions *state,
417*4882a593Smuzhiyun sector_t offset, sector_t size, int origin)
418*4882a593Smuzhiyun {
419*4882a593Smuzhiyun #ifdef CONFIG_BSD_DISKLABEL
420*4882a593Smuzhiyun parse_bsd(state, offset, size, origin, "netbsd", BSD_MAXPARTITIONS);
421*4882a593Smuzhiyun #endif
422*4882a593Smuzhiyun }
423*4882a593Smuzhiyun
parse_openbsd(struct parsed_partitions * state,sector_t offset,sector_t size,int origin)424*4882a593Smuzhiyun static void parse_openbsd(struct parsed_partitions *state,
425*4882a593Smuzhiyun sector_t offset, sector_t size, int origin)
426*4882a593Smuzhiyun {
427*4882a593Smuzhiyun #ifdef CONFIG_BSD_DISKLABEL
428*4882a593Smuzhiyun parse_bsd(state, offset, size, origin, "openbsd",
429*4882a593Smuzhiyun OPENBSD_MAXPARTITIONS);
430*4882a593Smuzhiyun #endif
431*4882a593Smuzhiyun }
432*4882a593Smuzhiyun
433*4882a593Smuzhiyun #define UNIXWARE_DISKMAGIC (0xCA5E600DUL) /* The disk magic number */
434*4882a593Smuzhiyun #define UNIXWARE_DISKMAGIC2 (0x600DDEEEUL) /* The slice table magic nr */
435*4882a593Smuzhiyun #define UNIXWARE_NUMSLICE 16
436*4882a593Smuzhiyun #define UNIXWARE_FS_UNUSED 0 /* Unused slice entry ID */
437*4882a593Smuzhiyun
438*4882a593Smuzhiyun struct unixware_slice {
439*4882a593Smuzhiyun __le16 s_label; /* label */
440*4882a593Smuzhiyun __le16 s_flags; /* permission flags */
441*4882a593Smuzhiyun __le32 start_sect; /* starting sector */
442*4882a593Smuzhiyun __le32 nr_sects; /* number of sectors in slice */
443*4882a593Smuzhiyun };
444*4882a593Smuzhiyun
445*4882a593Smuzhiyun struct unixware_disklabel {
446*4882a593Smuzhiyun __le32 d_type; /* drive type */
447*4882a593Smuzhiyun __le32 d_magic; /* the magic number */
448*4882a593Smuzhiyun __le32 d_version; /* version number */
449*4882a593Smuzhiyun char d_serial[12]; /* serial number of the device */
450*4882a593Smuzhiyun __le32 d_ncylinders; /* # of data cylinders per device */
451*4882a593Smuzhiyun __le32 d_ntracks; /* # of tracks per cylinder */
452*4882a593Smuzhiyun __le32 d_nsectors; /* # of data sectors per track */
453*4882a593Smuzhiyun __le32 d_secsize; /* # of bytes per sector */
454*4882a593Smuzhiyun __le32 d_part_start; /* # of first sector of this partition*/
455*4882a593Smuzhiyun __le32 d_unknown1[12]; /* ? */
456*4882a593Smuzhiyun __le32 d_alt_tbl; /* byte offset of alternate table */
457*4882a593Smuzhiyun __le32 d_alt_len; /* byte length of alternate table */
458*4882a593Smuzhiyun __le32 d_phys_cyl; /* # of physical cylinders per device */
459*4882a593Smuzhiyun __le32 d_phys_trk; /* # of physical tracks per cylinder */
460*4882a593Smuzhiyun __le32 d_phys_sec; /* # of physical sectors per track */
461*4882a593Smuzhiyun __le32 d_phys_bytes; /* # of physical bytes per sector */
462*4882a593Smuzhiyun __le32 d_unknown2; /* ? */
463*4882a593Smuzhiyun __le32 d_unknown3; /* ? */
464*4882a593Smuzhiyun __le32 d_pad[8]; /* pad */
465*4882a593Smuzhiyun
466*4882a593Smuzhiyun struct unixware_vtoc {
467*4882a593Smuzhiyun __le32 v_magic; /* the magic number */
468*4882a593Smuzhiyun __le32 v_version; /* version number */
469*4882a593Smuzhiyun char v_name[8]; /* volume name */
470*4882a593Smuzhiyun __le16 v_nslices; /* # of slices */
471*4882a593Smuzhiyun __le16 v_unknown1; /* ? */
472*4882a593Smuzhiyun __le32 v_reserved[10]; /* reserved */
473*4882a593Smuzhiyun struct unixware_slice
474*4882a593Smuzhiyun v_slice[UNIXWARE_NUMSLICE]; /* slice headers */
475*4882a593Smuzhiyun } vtoc;
476*4882a593Smuzhiyun }; /* 408 */
477*4882a593Smuzhiyun
478*4882a593Smuzhiyun /*
479*4882a593Smuzhiyun * Create devices for Unixware partitions listed in a disklabel, under a
480*4882a593Smuzhiyun * dos-like partition. See parse_extended() for more information.
481*4882a593Smuzhiyun */
parse_unixware(struct parsed_partitions * state,sector_t offset,sector_t size,int origin)482*4882a593Smuzhiyun static void parse_unixware(struct parsed_partitions *state,
483*4882a593Smuzhiyun sector_t offset, sector_t size, int origin)
484*4882a593Smuzhiyun {
485*4882a593Smuzhiyun #ifdef CONFIG_UNIXWARE_DISKLABEL
486*4882a593Smuzhiyun Sector sect;
487*4882a593Smuzhiyun struct unixware_disklabel *l;
488*4882a593Smuzhiyun struct unixware_slice *p;
489*4882a593Smuzhiyun
490*4882a593Smuzhiyun l = read_part_sector(state, offset + 29, §);
491*4882a593Smuzhiyun if (!l)
492*4882a593Smuzhiyun return;
493*4882a593Smuzhiyun if (le32_to_cpu(l->d_magic) != UNIXWARE_DISKMAGIC ||
494*4882a593Smuzhiyun le32_to_cpu(l->vtoc.v_magic) != UNIXWARE_DISKMAGIC2) {
495*4882a593Smuzhiyun put_dev_sector(sect);
496*4882a593Smuzhiyun return;
497*4882a593Smuzhiyun }
498*4882a593Smuzhiyun {
499*4882a593Smuzhiyun char tmp[1 + BDEVNAME_SIZE + 10 + 12 + 1];
500*4882a593Smuzhiyun
501*4882a593Smuzhiyun snprintf(tmp, sizeof(tmp), " %s%d: <unixware:", state->name, origin);
502*4882a593Smuzhiyun strlcat(state->pp_buf, tmp, PAGE_SIZE);
503*4882a593Smuzhiyun }
504*4882a593Smuzhiyun p = &l->vtoc.v_slice[1];
505*4882a593Smuzhiyun /* I omit the 0th slice as it is the same as whole disk. */
506*4882a593Smuzhiyun while (p - &l->vtoc.v_slice[0] < UNIXWARE_NUMSLICE) {
507*4882a593Smuzhiyun if (state->next == state->limit)
508*4882a593Smuzhiyun break;
509*4882a593Smuzhiyun
510*4882a593Smuzhiyun if (p->s_label != UNIXWARE_FS_UNUSED)
511*4882a593Smuzhiyun put_partition(state, state->next++,
512*4882a593Smuzhiyun le32_to_cpu(p->start_sect),
513*4882a593Smuzhiyun le32_to_cpu(p->nr_sects));
514*4882a593Smuzhiyun p++;
515*4882a593Smuzhiyun }
516*4882a593Smuzhiyun put_dev_sector(sect);
517*4882a593Smuzhiyun strlcat(state->pp_buf, " >\n", PAGE_SIZE);
518*4882a593Smuzhiyun #endif
519*4882a593Smuzhiyun }
520*4882a593Smuzhiyun
521*4882a593Smuzhiyun #define MINIX_NR_SUBPARTITIONS 4
522*4882a593Smuzhiyun
523*4882a593Smuzhiyun /*
524*4882a593Smuzhiyun * Minix 2.0.0/2.0.2 subpartition support.
525*4882a593Smuzhiyun * Anand Krishnamurthy <anandk@wiproge.med.ge.com>
526*4882a593Smuzhiyun * Rajeev V. Pillai <rajeevvp@yahoo.com>
527*4882a593Smuzhiyun */
parse_minix(struct parsed_partitions * state,sector_t offset,sector_t size,int origin)528*4882a593Smuzhiyun static void parse_minix(struct parsed_partitions *state,
529*4882a593Smuzhiyun sector_t offset, sector_t size, int origin)
530*4882a593Smuzhiyun {
531*4882a593Smuzhiyun #ifdef CONFIG_MINIX_SUBPARTITION
532*4882a593Smuzhiyun Sector sect;
533*4882a593Smuzhiyun unsigned char *data;
534*4882a593Smuzhiyun struct msdos_partition *p;
535*4882a593Smuzhiyun int i;
536*4882a593Smuzhiyun
537*4882a593Smuzhiyun data = read_part_sector(state, offset, §);
538*4882a593Smuzhiyun if (!data)
539*4882a593Smuzhiyun return;
540*4882a593Smuzhiyun
541*4882a593Smuzhiyun p = (struct msdos_partition *)(data + 0x1be);
542*4882a593Smuzhiyun
543*4882a593Smuzhiyun /* The first sector of a Minix partition can have either
544*4882a593Smuzhiyun * a secondary MBR describing its subpartitions, or
545*4882a593Smuzhiyun * the normal boot sector. */
546*4882a593Smuzhiyun if (msdos_magic_present(data + 510) &&
547*4882a593Smuzhiyun p->sys_ind == MINIX_PARTITION) { /* subpartition table present */
548*4882a593Smuzhiyun char tmp[1 + BDEVNAME_SIZE + 10 + 9 + 1];
549*4882a593Smuzhiyun
550*4882a593Smuzhiyun snprintf(tmp, sizeof(tmp), " %s%d: <minix:", state->name, origin);
551*4882a593Smuzhiyun strlcat(state->pp_buf, tmp, PAGE_SIZE);
552*4882a593Smuzhiyun for (i = 0; i < MINIX_NR_SUBPARTITIONS; i++, p++) {
553*4882a593Smuzhiyun if (state->next == state->limit)
554*4882a593Smuzhiyun break;
555*4882a593Smuzhiyun /* add each partition in use */
556*4882a593Smuzhiyun if (p->sys_ind == MINIX_PARTITION)
557*4882a593Smuzhiyun put_partition(state, state->next++,
558*4882a593Smuzhiyun start_sect(p), nr_sects(p));
559*4882a593Smuzhiyun }
560*4882a593Smuzhiyun strlcat(state->pp_buf, " >\n", PAGE_SIZE);
561*4882a593Smuzhiyun }
562*4882a593Smuzhiyun put_dev_sector(sect);
563*4882a593Smuzhiyun #endif /* CONFIG_MINIX_SUBPARTITION */
564*4882a593Smuzhiyun }
565*4882a593Smuzhiyun
566*4882a593Smuzhiyun static struct {
567*4882a593Smuzhiyun unsigned char id;
568*4882a593Smuzhiyun void (*parse)(struct parsed_partitions *, sector_t, sector_t, int);
569*4882a593Smuzhiyun } subtypes[] = {
570*4882a593Smuzhiyun {FREEBSD_PARTITION, parse_freebsd},
571*4882a593Smuzhiyun {NETBSD_PARTITION, parse_netbsd},
572*4882a593Smuzhiyun {OPENBSD_PARTITION, parse_openbsd},
573*4882a593Smuzhiyun {MINIX_PARTITION, parse_minix},
574*4882a593Smuzhiyun {UNIXWARE_PARTITION, parse_unixware},
575*4882a593Smuzhiyun {SOLARIS_X86_PARTITION, parse_solaris_x86},
576*4882a593Smuzhiyun {NEW_SOLARIS_X86_PARTITION, parse_solaris_x86},
577*4882a593Smuzhiyun {0, NULL},
578*4882a593Smuzhiyun };
579*4882a593Smuzhiyun
msdos_partition(struct parsed_partitions * state)580*4882a593Smuzhiyun int msdos_partition(struct parsed_partitions *state)
581*4882a593Smuzhiyun {
582*4882a593Smuzhiyun sector_t sector_size = bdev_logical_block_size(state->bdev) / 512;
583*4882a593Smuzhiyun Sector sect;
584*4882a593Smuzhiyun unsigned char *data;
585*4882a593Smuzhiyun struct msdos_partition *p;
586*4882a593Smuzhiyun struct fat_boot_sector *fb;
587*4882a593Smuzhiyun int slot;
588*4882a593Smuzhiyun u32 disksig;
589*4882a593Smuzhiyun
590*4882a593Smuzhiyun data = read_part_sector(state, 0, §);
591*4882a593Smuzhiyun if (!data)
592*4882a593Smuzhiyun return -1;
593*4882a593Smuzhiyun
594*4882a593Smuzhiyun /*
595*4882a593Smuzhiyun * Note order! (some AIX disks, e.g. unbootable kind,
596*4882a593Smuzhiyun * have no MSDOS 55aa)
597*4882a593Smuzhiyun */
598*4882a593Smuzhiyun if (aix_magic_present(state, data)) {
599*4882a593Smuzhiyun put_dev_sector(sect);
600*4882a593Smuzhiyun #ifdef CONFIG_AIX_PARTITION
601*4882a593Smuzhiyun return aix_partition(state);
602*4882a593Smuzhiyun #else
603*4882a593Smuzhiyun strlcat(state->pp_buf, " [AIX]", PAGE_SIZE);
604*4882a593Smuzhiyun return 0;
605*4882a593Smuzhiyun #endif
606*4882a593Smuzhiyun }
607*4882a593Smuzhiyun
608*4882a593Smuzhiyun if (!msdos_magic_present(data + 510)) {
609*4882a593Smuzhiyun put_dev_sector(sect);
610*4882a593Smuzhiyun return 0;
611*4882a593Smuzhiyun }
612*4882a593Smuzhiyun
613*4882a593Smuzhiyun /*
614*4882a593Smuzhiyun * Now that the 55aa signature is present, this is probably
615*4882a593Smuzhiyun * either the boot sector of a FAT filesystem or a DOS-type
616*4882a593Smuzhiyun * partition table. Reject this in case the boot indicator
617*4882a593Smuzhiyun * is not 0 or 0x80.
618*4882a593Smuzhiyun */
619*4882a593Smuzhiyun p = (struct msdos_partition *) (data + 0x1be);
620*4882a593Smuzhiyun for (slot = 1; slot <= 4; slot++, p++) {
621*4882a593Smuzhiyun if (p->boot_ind != 0 && p->boot_ind != 0x80) {
622*4882a593Smuzhiyun /*
623*4882a593Smuzhiyun * Even without a valid boot inidicator value
624*4882a593Smuzhiyun * its still possible this is valid FAT filesystem
625*4882a593Smuzhiyun * without a partition table.
626*4882a593Smuzhiyun */
627*4882a593Smuzhiyun fb = (struct fat_boot_sector *) data;
628*4882a593Smuzhiyun if (slot == 1 && fb->reserved && fb->fats
629*4882a593Smuzhiyun && fat_valid_media(fb->media)) {
630*4882a593Smuzhiyun strlcat(state->pp_buf, "\n", PAGE_SIZE);
631*4882a593Smuzhiyun put_dev_sector(sect);
632*4882a593Smuzhiyun return 1;
633*4882a593Smuzhiyun } else {
634*4882a593Smuzhiyun put_dev_sector(sect);
635*4882a593Smuzhiyun return 0;
636*4882a593Smuzhiyun }
637*4882a593Smuzhiyun }
638*4882a593Smuzhiyun }
639*4882a593Smuzhiyun
640*4882a593Smuzhiyun #ifdef CONFIG_EFI_PARTITION
641*4882a593Smuzhiyun p = (struct msdos_partition *) (data + 0x1be);
642*4882a593Smuzhiyun for (slot = 1 ; slot <= 4 ; slot++, p++) {
643*4882a593Smuzhiyun /* If this is an EFI GPT disk, msdos should ignore it. */
644*4882a593Smuzhiyun if (p->sys_ind == EFI_PMBR_OSTYPE_EFI_GPT) {
645*4882a593Smuzhiyun put_dev_sector(sect);
646*4882a593Smuzhiyun return 0;
647*4882a593Smuzhiyun }
648*4882a593Smuzhiyun }
649*4882a593Smuzhiyun #endif
650*4882a593Smuzhiyun p = (struct msdos_partition *) (data + 0x1be);
651*4882a593Smuzhiyun
652*4882a593Smuzhiyun disksig = le32_to_cpup((__le32 *)(data + 0x1b8));
653*4882a593Smuzhiyun
654*4882a593Smuzhiyun /*
655*4882a593Smuzhiyun * Look for partitions in two passes:
656*4882a593Smuzhiyun * First find the primary and DOS-type extended partitions.
657*4882a593Smuzhiyun * On the second pass look inside *BSD, Unixware and Solaris partitions.
658*4882a593Smuzhiyun */
659*4882a593Smuzhiyun
660*4882a593Smuzhiyun state->next = 5;
661*4882a593Smuzhiyun for (slot = 1 ; slot <= 4 ; slot++, p++) {
662*4882a593Smuzhiyun sector_t start = start_sect(p)*sector_size;
663*4882a593Smuzhiyun sector_t size = nr_sects(p)*sector_size;
664*4882a593Smuzhiyun
665*4882a593Smuzhiyun if (!size)
666*4882a593Smuzhiyun continue;
667*4882a593Smuzhiyun if (is_extended_partition(p)) {
668*4882a593Smuzhiyun /*
669*4882a593Smuzhiyun * prevent someone doing mkfs or mkswap on an
670*4882a593Smuzhiyun * extended partition, but leave room for LILO
671*4882a593Smuzhiyun * FIXME: this uses one logical sector for > 512b
672*4882a593Smuzhiyun * sector, although it may not be enough/proper.
673*4882a593Smuzhiyun */
674*4882a593Smuzhiyun sector_t n = 2;
675*4882a593Smuzhiyun
676*4882a593Smuzhiyun n = min(size, max(sector_size, n));
677*4882a593Smuzhiyun put_partition(state, slot, start, n);
678*4882a593Smuzhiyun
679*4882a593Smuzhiyun strlcat(state->pp_buf, " <", PAGE_SIZE);
680*4882a593Smuzhiyun parse_extended(state, start, size, disksig);
681*4882a593Smuzhiyun strlcat(state->pp_buf, " >", PAGE_SIZE);
682*4882a593Smuzhiyun continue;
683*4882a593Smuzhiyun }
684*4882a593Smuzhiyun put_partition(state, slot, start, size);
685*4882a593Smuzhiyun set_info(state, slot, disksig);
686*4882a593Smuzhiyun if (p->sys_ind == LINUX_RAID_PARTITION)
687*4882a593Smuzhiyun state->parts[slot].flags = ADDPART_FLAG_RAID;
688*4882a593Smuzhiyun if (p->sys_ind == DM6_PARTITION)
689*4882a593Smuzhiyun strlcat(state->pp_buf, "[DM]", PAGE_SIZE);
690*4882a593Smuzhiyun if (p->sys_ind == EZD_PARTITION)
691*4882a593Smuzhiyun strlcat(state->pp_buf, "[EZD]", PAGE_SIZE);
692*4882a593Smuzhiyun }
693*4882a593Smuzhiyun
694*4882a593Smuzhiyun strlcat(state->pp_buf, "\n", PAGE_SIZE);
695*4882a593Smuzhiyun
696*4882a593Smuzhiyun /* second pass - output for each on a separate line */
697*4882a593Smuzhiyun p = (struct msdos_partition *) (0x1be + data);
698*4882a593Smuzhiyun for (slot = 1 ; slot <= 4 ; slot++, p++) {
699*4882a593Smuzhiyun unsigned char id = p->sys_ind;
700*4882a593Smuzhiyun int n;
701*4882a593Smuzhiyun
702*4882a593Smuzhiyun if (!nr_sects(p))
703*4882a593Smuzhiyun continue;
704*4882a593Smuzhiyun
705*4882a593Smuzhiyun for (n = 0; subtypes[n].parse && id != subtypes[n].id; n++)
706*4882a593Smuzhiyun ;
707*4882a593Smuzhiyun
708*4882a593Smuzhiyun if (!subtypes[n].parse)
709*4882a593Smuzhiyun continue;
710*4882a593Smuzhiyun subtypes[n].parse(state, start_sect(p) * sector_size,
711*4882a593Smuzhiyun nr_sects(p) * sector_size, slot);
712*4882a593Smuzhiyun }
713*4882a593Smuzhiyun put_dev_sector(sect);
714*4882a593Smuzhiyun return 1;
715*4882a593Smuzhiyun }
716