Blame view

block/partitions/msdos.c 15.2 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
  /*
   *  fs/partitions/msdos.c
   *
   *  Code extracted from drivers/block/genhd.c
   *  Copyright (C) 1991-1998  Linus Torvalds
   *
   *  Thanks to Branko Lankester, lankeste@fwi.uva.nl, who found a bug
   *  in the early extended-partition checks and added DM partitions
   *
   *  Support for DiskManager v6.0x added by Mark Lord,
   *  with information provided by OnTrack.  This now works for linux fdisk
   *  and LILO, as well as loadlin and bootln.  Note that disks other than
   *  /dev/hda *must* have a "DOS" type 0x51 partition in the first slot (hda1).
   *
   *  More flexible handling of extended partitions - aeb, 950831
   *
   *  Check partition table on IDE disks for common CHS translations
   *
   *  Re-organised Feb 1998 Russell King
   */
0607fd025   Frank Seidel   fat: detect media...
21
  #include <linux/msdos_fs.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
22
23
24
25
26
27
28
29
30
31
32
  
  #include "check.h"
  #include "msdos.h"
  #include "efi.h"
  
  /*
   * Many architectures don't like unaligned accesses, while
   * the nr_sects and start_sect partition table entries are
   * at a 2 (mod 4) address.
   */
  #include <asm/unaligned.h>
3fbf586cf   Daniel Taylor   fs/partitions/msd...
33
  #define SYS_IND(p)	get_unaligned(&p->sys_ind)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
34

3fbf586cf   Daniel Taylor   fs/partitions/msd...
35
36
37
38
39
40
41
42
43
  static inline sector_t nr_sects(struct partition *p)
  {
  	return (sector_t)get_unaligned_le32(&p->nr_sects);
  }
  
  static inline sector_t start_sect(struct partition *p)
  {
  	return (sector_t)get_unaligned_le32(&p->start_sect);
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
  
  static inline int is_extended_partition(struct partition *p)
  {
  	return (SYS_IND(p) == DOS_EXTENDED_PARTITION ||
  		SYS_IND(p) == WIN98_EXTENDED_PARTITION ||
  		SYS_IND(p) == LINUX_EXTENDED_PARTITION);
  }
  
  #define MSDOS_LABEL_MAGIC1	0x55
  #define MSDOS_LABEL_MAGIC2	0xAA
  
  static inline int
  msdos_magic_present(unsigned char *p)
  {
  	return (p[0] == MSDOS_LABEL_MAGIC1 && p[1] == MSDOS_LABEL_MAGIC2);
  }
e1dfa92dc   Olaf Hering   [PATCH] ignore pa...
60
61
62
63
64
  /* Value is EBCDIC 'IBMA' */
  #define AIX_LABEL_MAGIC1	0xC9
  #define AIX_LABEL_MAGIC2	0xC2
  #define AIX_LABEL_MAGIC3	0xD4
  #define AIX_LABEL_MAGIC4	0xC1
1493bf217   Tejun Heo   block: use struct...
65
  static int aix_magic_present(struct parsed_partitions *state, unsigned char *p)
e1dfa92dc   Olaf Hering   [PATCH] ignore pa...
66
  {
4419d1ac7   Olaf Hering   [PATCH] relax che...
67
  	struct partition *pt = (struct partition *) (p + 0x1be);
e1dfa92dc   Olaf Hering   [PATCH] ignore pa...
68
69
  	Sector sect;
  	unsigned char *d;
4419d1ac7   Olaf Hering   [PATCH] relax che...
70
  	int slot, ret = 0;
e1dfa92dc   Olaf Hering   [PATCH] ignore pa...
71

a470e18f5   Olaf Hering   [PATCH] msdos par...
72
73
74
75
  	if (!(p[0] == AIX_LABEL_MAGIC1 &&
  		p[1] == AIX_LABEL_MAGIC2 &&
  		p[2] == AIX_LABEL_MAGIC3 &&
  		p[3] == AIX_LABEL_MAGIC4))
e1dfa92dc   Olaf Hering   [PATCH] ignore pa...
76
  		return 0;
4419d1ac7   Olaf Hering   [PATCH] relax che...
77
78
79
80
81
82
83
84
85
  	/* Assume the partition table is valid if Linux partitions exists */
  	for (slot = 1; slot <= 4; slot++, pt++) {
  		if (pt->sys_ind == LINUX_SWAP_PARTITION ||
  			pt->sys_ind == LINUX_RAID_PARTITION ||
  			pt->sys_ind == LINUX_DATA_PARTITION ||
  			pt->sys_ind == LINUX_LVM_PARTITION ||
  			is_extended_partition(pt))
  			return 0;
  	}
1493bf217   Tejun Heo   block: use struct...
86
  	d = read_part_sector(state, 7, &sect);
e1dfa92dc   Olaf Hering   [PATCH] ignore pa...
87
88
89
90
91
92
93
  	if (d) {
  		if (d[0] == '_' && d[1] == 'L' && d[2] == 'V' && d[3] == 'M')
  			ret = 1;
  		put_dev_sector(sect);
  	};
  	return ret;
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
94
95
96
97
98
99
100
101
102
103
  /*
   * Create devices for each logical partition in an extended partition.
   * The logical partitions form a linked list, with each entry being
   * a partition table with two entries.  The first entry
   * is the real data partition (with a start relative to the partition
   * table start).  The second is a pointer to the next logical partition
   * (with a start relative to the entire extended partition).
   * We do not create a Linux partition for the partition tables, but
   * only for the actual data partitions.
   */
1493bf217   Tejun Heo   block: use struct...
104
105
  static void parse_extended(struct parsed_partitions *state,
  			   sector_t first_sector, sector_t first_size)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
106
107
108
109
  {
  	struct partition *p;
  	Sector sect;
  	unsigned char *data;
3fbf586cf   Daniel Taylor   fs/partitions/msd...
110
  	sector_t this_sector, this_size;
1493bf217   Tejun Heo   block: use struct...
111
  	sector_t sector_size = bdev_logical_block_size(state->bdev) / 512;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
112
113
114
115
116
117
118
119
120
121
122
123
  	int loopct = 0;		/* number of links followed
  				   without finding a data partition */
  	int i;
  
  	this_sector = first_sector;
  	this_size = first_size;
  
  	while (1) {
  		if (++loopct > 100)
  			return;
  		if (state->next == state->limit)
  			return;
1493bf217   Tejun Heo   block: use struct...
124
  		data = read_part_sector(state, this_sector, &sect);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
  		if (!data)
  			return;
  
  		if (!msdos_magic_present(data + 510))
  			goto done; 
  
  		p = (struct partition *) (data + 0x1be);
  
  		/*
  		 * Usually, the first entry is the real data partition,
  		 * the 2nd entry is the next extended partition, or empty,
  		 * and the 3rd and 4th entries are unused.
  		 * However, DRDOS sometimes has the extended partition as
  		 * the first entry (when the data partition is empty),
  		 * and OS/2 seems to use all four entries.
  		 */
  
  		/* 
  		 * First process the data partition(s)
  		 */
  		for (i=0; i<4; i++, p++) {
3fbf586cf   Daniel Taylor   fs/partitions/msd...
146
147
  			sector_t offs, size, next;
  			if (!nr_sects(p) || is_extended_partition(p))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
148
149
150
151
  				continue;
  
  			/* Check the 3rd and 4th entries -
  			   these sometimes contain random garbage */
3fbf586cf   Daniel Taylor   fs/partitions/msd...
152
153
  			offs = start_sect(p)*sector_size;
  			size = nr_sects(p)*sector_size;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
154
155
156
157
158
159
160
161
162
163
164
165
  			next = this_sector + offs;
  			if (i >= 2) {
  				if (offs + size > this_size)
  					continue;
  				if (next < first_sector)
  					continue;
  				if (next + size > first_sector + first_size)
  					continue;
  			}
  
  			put_partition(state, state->next, next, size);
  			if (SYS_IND(p) == LINUX_RAID_PARTITION)
d18d7682c   Fabio Massimo Di Nitto   [PARTITION]: Add ...
166
  				state->parts[state->next].flags = ADDPART_FLAG_RAID;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
167
168
169
170
171
172
173
174
175
176
177
178
179
  			loopct = 0;
  			if (++state->next == state->limit)
  				goto done;
  		}
  		/*
  		 * Next, process the (first) extended partition, if present.
  		 * (So far, there seems to be no reason to make
  		 *  parse_extended()  recursive and allow a tree
  		 *  of extended partitions.)
  		 * It should be a link to the next logical partition.
  		 */
  		p -= 4;
  		for (i=0; i<4; i++, p++)
3fbf586cf   Daniel Taylor   fs/partitions/msd...
180
  			if (nr_sects(p) && is_extended_partition(p))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
181
182
183
  				break;
  		if (i == 4)
  			goto done;	 /* nothing left to do */
3fbf586cf   Daniel Taylor   fs/partitions/msd...
184
185
  		this_sector = first_sector + start_sect(p) * sector_size;
  		this_size = nr_sects(p) * sector_size;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
186
187
188
189
190
191
192
193
  		put_dev_sector(sect);
  	}
  done:
  	put_dev_sector(sect);
  }
  
  /* james@bpgc.com: Solaris has a nasty indicator: 0x82 which also
     indicates linux swap.  Be careful before believing this is Solaris. */
1493bf217   Tejun Heo   block: use struct...
194
195
  static void parse_solaris_x86(struct parsed_partitions *state,
  			      sector_t offset, sector_t size, int origin)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
196
197
198
199
200
  {
  #ifdef CONFIG_SOLARIS_X86_PARTITION
  	Sector sect;
  	struct solaris_x86_vtoc *v;
  	int i;
b84d87963   Mark   [PARTITION] MSDOS...
201
  	short max_nparts;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
202

1493bf217   Tejun Heo   block: use struct...
203
  	v = read_part_sector(state, offset + 1, &sect);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
204
205
206
207
208
209
  	if (!v)
  		return;
  	if (le32_to_cpu(v->v_sanity) != SOLARIS_X86_VTOC_SANE) {
  		put_dev_sector(sect);
  		return;
  	}
9c867fbe0   Alexey Dobriyan   partitions: fix s...
210
211
212
213
214
215
  	{
  		char tmp[1 + BDEVNAME_SIZE + 10 + 11 + 1];
  
  		snprintf(tmp, sizeof(tmp), " %s%d: <solaris:", state->name, origin);
  		strlcat(state->pp_buf, tmp, PAGE_SIZE);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
216
  	if (le32_to_cpu(v->v_version) != 1) {
9c867fbe0   Alexey Dobriyan   partitions: fix s...
217
218
219
220
221
222
  		char tmp[64];
  
  		snprintf(tmp, sizeof(tmp), "  cannot handle version %d vtoc>
  ",
  			 le32_to_cpu(v->v_version));
  		strlcat(state->pp_buf, tmp, PAGE_SIZE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
223
224
225
  		put_dev_sector(sect);
  		return;
  	}
b84d87963   Mark   [PARTITION] MSDOS...
226
227
228
  	/* Ensure we can handle previous case of VTOC with 8 entries gracefully */
  	max_nparts = le16_to_cpu (v->v_nparts) > 8 ? SOLARIS_X86_NUMSLICE : 8;
  	for (i=0; i<max_nparts && state->next<state->limit; i++) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
229
  		struct solaris_x86_slice *s = &v->v_slice[i];
9c867fbe0   Alexey Dobriyan   partitions: fix s...
230
  		char tmp[3 + 10 + 1 + 1];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
231
232
  		if (s->s_size == 0)
  			continue;
9c867fbe0   Alexey Dobriyan   partitions: fix s...
233
234
  		snprintf(tmp, sizeof(tmp), " [s%d]", i);
  		strlcat(state->pp_buf, tmp, PAGE_SIZE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
235
236
237
238
239
240
241
  		/* solaris partitions are relative to current MS-DOS
  		 * one; must add the offset of the current partition */
  		put_partition(state, state->next++,
  				 le32_to_cpu(s->s_start)+offset,
  				 le32_to_cpu(s->s_size));
  	}
  	put_dev_sector(sect);
9c867fbe0   Alexey Dobriyan   partitions: fix s...
242
243
  	strlcat(state->pp_buf, " >
  ", PAGE_SIZE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
244
245
  #endif
  }
486fd404f   Adrian Bunk   [PATCH] small par...
246
  #if defined(CONFIG_BSD_DISKLABEL)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
247
248
249
250
  /* 
   * Create devices for BSD partitions listed in a disklabel, under a
   * dos-like partition. See parse_extended() for more information.
   */
1493bf217   Tejun Heo   block: use struct...
251
252
253
  static void parse_bsd(struct parsed_partitions *state,
  		      sector_t offset, sector_t size, int origin, char *flavour,
  		      int max_partitions)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
254
255
256
257
  {
  	Sector sect;
  	struct bsd_disklabel *l;
  	struct bsd_partition *p;
9c867fbe0   Alexey Dobriyan   partitions: fix s...
258
  	char tmp[64];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
259

1493bf217   Tejun Heo   block: use struct...
260
  	l = read_part_sector(state, offset + 1, &sect);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
261
262
263
264
265
266
  	if (!l)
  		return;
  	if (le32_to_cpu(l->d_magic) != BSD_DISKMAGIC) {
  		put_dev_sector(sect);
  		return;
  	}
9c867fbe0   Alexey Dobriyan   partitions: fix s...
267
268
269
  
  	snprintf(tmp, sizeof(tmp), " %s%d: <%s:", state->name, origin, flavour);
  	strlcat(state->pp_buf, tmp, PAGE_SIZE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
270
271
272
273
  
  	if (le16_to_cpu(l->d_npartitions) < max_partitions)
  		max_partitions = le16_to_cpu(l->d_npartitions);
  	for (p = l->d_partitions; p - l->d_partitions < max_partitions; p++) {
3fbf586cf   Daniel Taylor   fs/partitions/msd...
274
  		sector_t bsd_start, bsd_size;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
275
276
277
278
279
280
281
282
283
284
285
  
  		if (state->next == state->limit)
  			break;
  		if (p->p_fstype == BSD_FS_UNUSED) 
  			continue;
  		bsd_start = le32_to_cpu(p->p_offset);
  		bsd_size = le32_to_cpu(p->p_size);
  		if (offset == bsd_start && size == bsd_size)
  			/* full parent partition, we have it already */
  			continue;
  		if (offset > bsd_start || offset+size < bsd_start+bsd_size) {
9c867fbe0   Alexey Dobriyan   partitions: fix s...
286
287
  			strlcat(state->pp_buf, "bad subpartition - ignored
  ", PAGE_SIZE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
288
289
290
291
292
  			continue;
  		}
  		put_partition(state, state->next++, bsd_start, bsd_size);
  	}
  	put_dev_sector(sect);
9c867fbe0   Alexey Dobriyan   partitions: fix s...
293
294
295
296
297
298
299
  	if (le16_to_cpu(l->d_npartitions) > max_partitions) {
  		snprintf(tmp, sizeof(tmp), " (ignored %d more)",
  			 le16_to_cpu(l->d_npartitions) - max_partitions);
  		strlcat(state->pp_buf, tmp, PAGE_SIZE);
  	}
  	strlcat(state->pp_buf, " >
  ", PAGE_SIZE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
300
301
  }
  #endif
1493bf217   Tejun Heo   block: use struct...
302
303
  static void parse_freebsd(struct parsed_partitions *state,
  			  sector_t offset, sector_t size, int origin)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
304
305
  {
  #ifdef CONFIG_BSD_DISKLABEL
1493bf217   Tejun Heo   block: use struct...
306
  	parse_bsd(state, offset, size, origin, "bsd", BSD_MAXPARTITIONS);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
307
308
  #endif
  }
1493bf217   Tejun Heo   block: use struct...
309
310
  static void parse_netbsd(struct parsed_partitions *state,
  			 sector_t offset, sector_t size, int origin)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
311
312
  {
  #ifdef CONFIG_BSD_DISKLABEL
1493bf217   Tejun Heo   block: use struct...
313
  	parse_bsd(state, offset, size, origin, "netbsd", BSD_MAXPARTITIONS);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
314
315
  #endif
  }
1493bf217   Tejun Heo   block: use struct...
316
317
  static void parse_openbsd(struct parsed_partitions *state,
  			  sector_t offset, sector_t size, int origin)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
318
319
  {
  #ifdef CONFIG_BSD_DISKLABEL
1493bf217   Tejun Heo   block: use struct...
320
321
  	parse_bsd(state, offset, size, origin, "openbsd",
  		  OPENBSD_MAXPARTITIONS);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
322
323
324
325
326
327
328
  #endif
  }
  
  /*
   * Create devices for Unixware partitions listed in a disklabel, under a
   * dos-like partition. See parse_extended() for more information.
   */
1493bf217   Tejun Heo   block: use struct...
329
330
  static void parse_unixware(struct parsed_partitions *state,
  			   sector_t offset, sector_t size, int origin)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
331
332
333
334
335
  {
  #ifdef CONFIG_UNIXWARE_DISKLABEL
  	Sector sect;
  	struct unixware_disklabel *l;
  	struct unixware_slice *p;
1493bf217   Tejun Heo   block: use struct...
336
  	l = read_part_sector(state, offset + 29, &sect);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
337
338
339
340
341
342
343
  	if (!l)
  		return;
  	if (le32_to_cpu(l->d_magic) != UNIXWARE_DISKMAGIC ||
  	    le32_to_cpu(l->vtoc.v_magic) != UNIXWARE_DISKMAGIC2) {
  		put_dev_sector(sect);
  		return;
  	}
9c867fbe0   Alexey Dobriyan   partitions: fix s...
344
345
346
347
348
349
  	{
  		char tmp[1 + BDEVNAME_SIZE + 10 + 12 + 1];
  
  		snprintf(tmp, sizeof(tmp), " %s%d: <unixware:", state->name, origin);
  		strlcat(state->pp_buf, tmp, PAGE_SIZE);
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
350
351
352
353
354
355
356
357
  	p = &l->vtoc.v_slice[1];
  	/* I omit the 0th slice as it is the same as whole disk. */
  	while (p - &l->vtoc.v_slice[0] < UNIXWARE_NUMSLICE) {
  		if (state->next == state->limit)
  			break;
  
  		if (p->s_label != UNIXWARE_FS_UNUSED)
  			put_partition(state, state->next++,
3fbf586cf   Daniel Taylor   fs/partitions/msd...
358
359
  				      le32_to_cpu(p->start_sect),
  				      le32_to_cpu(p->nr_sects));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
360
361
362
  		p++;
  	}
  	put_dev_sector(sect);
9c867fbe0   Alexey Dobriyan   partitions: fix s...
363
364
  	strlcat(state->pp_buf, " >
  ", PAGE_SIZE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
365
366
367
368
369
370
371
372
  #endif
  }
  
  /*
   * Minix 2.0.0/2.0.2 subpartition support.
   * Anand Krishnamurthy <anandk@wiproge.med.ge.com>
   * Rajeev V. Pillai    <rajeevvp@yahoo.com>
   */
1493bf217   Tejun Heo   block: use struct...
373
374
  static void parse_minix(struct parsed_partitions *state,
  			sector_t offset, sector_t size, int origin)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
375
376
377
378
379
380
  {
  #ifdef CONFIG_MINIX_SUBPARTITION
  	Sector sect;
  	unsigned char *data;
  	struct partition *p;
  	int i;
1493bf217   Tejun Heo   block: use struct...
381
  	data = read_part_sector(state, offset, &sect);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
382
383
384
385
386
387
388
389
390
391
  	if (!data)
  		return;
  
  	p = (struct partition *)(data + 0x1be);
  
  	/* The first sector of a Minix partition can have either
  	 * a secondary MBR describing its subpartitions, or
  	 * the normal boot sector. */
  	if (msdos_magic_present (data + 510) &&
  	    SYS_IND(p) == MINIX_PARTITION) { /* subpartition table present */
9c867fbe0   Alexey Dobriyan   partitions: fix s...
392
  		char tmp[1 + BDEVNAME_SIZE + 10 + 9 + 1];
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
393

9c867fbe0   Alexey Dobriyan   partitions: fix s...
394
395
  		snprintf(tmp, sizeof(tmp), " %s%d: <minix:", state->name, origin);
  		strlcat(state->pp_buf, tmp, PAGE_SIZE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
396
397
398
399
400
401
  		for (i = 0; i < MINIX_NR_SUBPARTITIONS; i++, p++) {
  			if (state->next == state->limit)
  				break;
  			/* add each partition in use */
  			if (SYS_IND(p) == MINIX_PARTITION)
  				put_partition(state, state->next++,
3fbf586cf   Daniel Taylor   fs/partitions/msd...
402
  					      start_sect(p), nr_sects(p));
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
403
  		}
9c867fbe0   Alexey Dobriyan   partitions: fix s...
404
405
  		strlcat(state->pp_buf, " >
  ", PAGE_SIZE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
406
407
408
409
410
411
412
  	}
  	put_dev_sector(sect);
  #endif /* CONFIG_MINIX_SUBPARTITION */
  }
  
  static struct {
  	unsigned char id;
1493bf217   Tejun Heo   block: use struct...
413
  	void (*parse)(struct parsed_partitions *, sector_t, sector_t, int);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
414
415
416
417
418
419
420
421
422
423
424
  } subtypes[] = {
  	{FREEBSD_PARTITION, parse_freebsd},
  	{NETBSD_PARTITION, parse_netbsd},
  	{OPENBSD_PARTITION, parse_openbsd},
  	{MINIX_PARTITION, parse_minix},
  	{UNIXWARE_PARTITION, parse_unixware},
  	{SOLARIS_X86_PARTITION, parse_solaris_x86},
  	{NEW_SOLARIS_X86_PARTITION, parse_solaris_x86},
  	{0, NULL},
  };
   
1493bf217   Tejun Heo   block: use struct...
425
  int msdos_partition(struct parsed_partitions *state)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
426
  {
1493bf217   Tejun Heo   block: use struct...
427
  	sector_t sector_size = bdev_logical_block_size(state->bdev) / 512;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
428
429
430
  	Sector sect;
  	unsigned char *data;
  	struct partition *p;
0607fd025   Frank Seidel   fat: detect media...
431
  	struct fat_boot_sector *fb;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
432
  	int slot;
1493bf217   Tejun Heo   block: use struct...
433
  	data = read_part_sector(state, 0, &sect);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
434
435
436
437
438
439
  	if (!data)
  		return -1;
  	if (!msdos_magic_present(data + 510)) {
  		put_dev_sector(sect);
  		return 0;
  	}
1493bf217   Tejun Heo   block: use struct...
440
  	if (aix_magic_present(state, data)) {
e1dfa92dc   Olaf Hering   [PATCH] ignore pa...
441
  		put_dev_sector(sect);
9c867fbe0   Alexey Dobriyan   partitions: fix s...
442
  		strlcat(state->pp_buf, " [AIX]", PAGE_SIZE);
e1dfa92dc   Olaf Hering   [PATCH] ignore pa...
443
444
  		return 0;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
445
446
447
448
449
450
451
452
453
  	/*
  	 * Now that the 55aa signature is present, this is probably
  	 * either the boot sector of a FAT filesystem or a DOS-type
  	 * partition table. Reject this in case the boot indicator
  	 * is not 0 or 0x80.
  	 */
  	p = (struct partition *) (data + 0x1be);
  	for (slot = 1; slot <= 4; slot++, p++) {
  		if (p->boot_ind != 0 && p->boot_ind != 0x80) {
0607fd025   Frank Seidel   fat: detect media...
454
455
456
457
458
459
460
461
  			/*
  			 * Even without a valid boot inidicator value
  			 * its still possible this is valid FAT filesystem
  			 * without a partition table.
  			 */
  			fb = (struct fat_boot_sector *) data;
  			if (slot == 1 && fb->reserved && fb->fats
  				&& fat_valid_media(fb->media)) {
9c867fbe0   Alexey Dobriyan   partitions: fix s...
462
463
  				strlcat(state->pp_buf, "
  ", PAGE_SIZE);
0607fd025   Frank Seidel   fat: detect media...
464
465
466
467
468
469
  				put_dev_sector(sect);
  				return 1;
  			} else {
  				put_dev_sector(sect);
  				return 0;
  			}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
  		}
  	}
  
  #ifdef CONFIG_EFI_PARTITION
  	p = (struct partition *) (data + 0x1be);
  	for (slot = 1 ; slot <= 4 ; slot++, p++) {
  		/* If this is an EFI GPT disk, msdos should ignore it. */
  		if (SYS_IND(p) == EFI_PMBR_OSTYPE_EFI_GPT) {
  			put_dev_sector(sect);
  			return 0;
  		}
  	}
  #endif
  	p = (struct partition *) (data + 0x1be);
  
  	/*
  	 * Look for partitions in two passes:
  	 * First find the primary and DOS-type extended partitions.
  	 * On the second pass look inside *BSD, Unixware and Solaris partitions.
  	 */
  
  	state->next = 5;
  	for (slot = 1 ; slot <= 4 ; slot++, p++) {
3fbf586cf   Daniel Taylor   fs/partitions/msd...
493
494
  		sector_t start = start_sect(p)*sector_size;
  		sector_t size = nr_sects(p)*sector_size;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
495
496
497
  		if (!size)
  			continue;
  		if (is_extended_partition(p)) {
8e0cc811e   OGAWA Hirofumi   fs/partition/msdo...
498
499
500
501
502
503
504
505
506
  			/*
  			 * prevent someone doing mkfs or mkswap on an
  			 * extended partition, but leave room for LILO
  			 * FIXME: this uses one logical sector for > 512b
  			 * sector, although it may not be enough/proper.
  			 */
  			sector_t n = 2;
  			n = min(size, max(sector_size, n));
  			put_partition(state, slot, start, n);
9c867fbe0   Alexey Dobriyan   partitions: fix s...
507
  			strlcat(state->pp_buf, " <", PAGE_SIZE);
1493bf217   Tejun Heo   block: use struct...
508
  			parse_extended(state, start, size);
9c867fbe0   Alexey Dobriyan   partitions: fix s...
509
  			strlcat(state->pp_buf, " >", PAGE_SIZE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
510
511
512
513
  			continue;
  		}
  		put_partition(state, slot, start, size);
  		if (SYS_IND(p) == LINUX_RAID_PARTITION)
cc9106247   Cesar Eduardo Barros   fs/partitions: us...
514
  			state->parts[slot].flags = ADDPART_FLAG_RAID;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
515
  		if (SYS_IND(p) == DM6_PARTITION)
9c867fbe0   Alexey Dobriyan   partitions: fix s...
516
  			strlcat(state->pp_buf, "[DM]", PAGE_SIZE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
517
  		if (SYS_IND(p) == EZD_PARTITION)
9c867fbe0   Alexey Dobriyan   partitions: fix s...
518
  			strlcat(state->pp_buf, "[EZD]", PAGE_SIZE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
519
  	}
9c867fbe0   Alexey Dobriyan   partitions: fix s...
520
521
  	strlcat(state->pp_buf, "
  ", PAGE_SIZE);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
522
523
524
525
526
527
  
  	/* second pass - output for each on a separate line */
  	p = (struct partition *) (0x1be + data);
  	for (slot = 1 ; slot <= 4 ; slot++, p++) {
  		unsigned char id = SYS_IND(p);
  		int n;
3fbf586cf   Daniel Taylor   fs/partitions/msd...
528
  		if (!nr_sects(p))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
529
530
531
532
533
534
535
  			continue;
  
  		for (n = 0; subtypes[n].parse && id != subtypes[n].id; n++)
  			;
  
  		if (!subtypes[n].parse)
  			continue;
1493bf217   Tejun Heo   block: use struct...
536
537
  		subtypes[n].parse(state, start_sect(p) * sector_size,
  				  nr_sects(p) * sector_size, slot);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
538
539
540
541
  	}
  	put_dev_sector(sect);
  	return 1;
  }