• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* ----------------------------------------------------------------------- *
2  *
3  *   Copyright 2009 Pierre-Alexandre Meyer
4  *
5  *   Some parts borrowed from chain.c32:
6  *
7  *   Copyright 2003-2009 H. Peter Anvin - All Rights Reserved
8  *   Copyright 2009 Intel Corporation; author: H. Peter Anvin
9  *
10  *   This file is part of Syslinux, and is made available under
11  *   the terms of the GNU General Public License version 2.
12  *
13  * ----------------------------------------------------------------------- */
14 
15 #include <stdlib.h>
16 
17 #include <disk/common.h>
18 #include <disk/geom.h>
19 #include <disk/msdos.h>
20 #include <disk/partition.h>
21 #include <disk/read.h>
22 
is_extended_partition(struct part_entry * ptab)23 static int is_extended_partition(struct part_entry *ptab)
24 {
25     return (ptab->ostype == 0x05 ||
26 	    ptab->ostype == 0x0f || ptab->ostype == 0x85);
27 }
28 
msdos_magic_present(const char * ptab)29 static int msdos_magic_present(const char *ptab)
30 {
31     return (*(uint16_t *) (ptab + 0x1fe) == 0xaa55);
32 }
33 
34 /**
35  * process_extended_partition - execute a callback for each partition contained listed in an ebr
36  * @drive_info:		driveinfo struct describing the drive
37  * @partition_offset:	Absolute start (lba) of the extended partition
38  * @ebr_offset:		Relative start (lba) of the current ebr processed within
39  *			the extended partition
40  * @callback:		Callback to execute
41  * @error:		Buffer for I/O errors
42  * @nb_part_seen:	Number of partitions found on the disk so far
43  **/
process_extended_partition(struct driveinfo * drive_info,const int partition_offset,const int ebr_offset,p_callback callback,int nb_part_seen)44 static int process_extended_partition(struct driveinfo *drive_info,
45 				      const int partition_offset,
46 				      const int ebr_offset,
47 				      p_callback callback, int nb_part_seen)
48 {
49     int status = 0;
50     /* The ebr is located at the first sector of the extended partition */
51     char *ebr = malloc(SECTOR * sizeof(char));
52 
53     if (read_sectors(drive_info, ebr, partition_offset + ebr_offset, 1) == -1)
54 	goto abort;
55 
56     /* Check msdos magic signature */
57     if (!msdos_magic_present(ebr))
58 	goto abort;
59 
60     struct part_entry *ptab =
61 	(struct part_entry *)(ebr + PARTITION_TABLES_OFFSET);
62 
63     for (int i = 0; i < 4; i++) {
64 	if (status == -1)
65 	    goto abort;
66 
67 	if (!is_extended_partition(&ptab[i])) {
68 	    /*
69 	     * This EBR partition table entry points to the
70 	     * logical partition associated to that EBR
71 	     */
72 	    int logical_partition_start = ebr_offset + ptab[i].start_lba;
73 
74 	    /* Last EBR in the extended partition? */
75 	    if (!logical_partition_start)
76 		continue;
77 
78 	    /*
79 	     * Check for garbage:
80 	     * 3rd and 4th entries in an EBR should be zero
81 	     * Some (malformed) partitioning software still add some
82 	     * data partitions there.
83 	     */
84 	    if (ptab[i].start_lba <= 0 || ptab[i].length <= 0)
85 		continue;
86 
87 	    nb_part_seen++;
88 	    callback(drive_info,
89 		     &ptab[i],
90 		     partition_offset + logical_partition_start, nb_part_seen);
91 	} else
92 	    status = process_extended_partition(drive_info,
93 						partition_offset,
94 						ptab[i].start_lba,
95 						callback, nb_part_seen);
96     }
97 
98     free(ebr);
99     return 0;
100 
101 abort:
102     free(ebr);
103     return -1;
104 }
105 
106 /**
107  * process_mbr - execute a callback for each partition contained in an {m,e}br
108  * @drive_info:	driveinfo struct describing the drive
109  * @ptab:	Pointer to the partition table
110  * @callback:	Callback to execute
111  **/
process_mbr(struct driveinfo * drive_info,struct part_entry * ptab,p_callback callback)112 static int process_mbr(struct driveinfo *drive_info, struct part_entry *ptab,
113 		       p_callback callback)
114 {
115     int status = 0;
116 
117     for (int i = 0; i < 4; i++) {
118 	if (status == -1)
119 	    return -1;
120 
121 	if (ptab[i].start_sect > 0) {
122 	    if (is_extended_partition(&ptab[i])) {
123 		callback(drive_info, &ptab[i], ptab[i].start_lba, i + 1);
124 		status =
125 		    process_extended_partition(drive_info, ptab[i].start_lba, 0,
126 					       callback, 4);
127 	    } else
128 		callback(drive_info, &ptab[i], ptab[i].start_lba, i + 1);
129 	}
130     }
131 
132     return 0;
133 }
134 
135 /**
136  * parse_partition_table - execute a callback for each partition entry
137  * @d:		driveinfo struct describing the drive
138  * @callback:	Callback to execute
139  *
140  * The signature of the callback should be the following:
141  *
142  * void callback(struct driveinfo *drive_info,
143  *		 struct part_entry *ptab,
144  *		 int offset_root,
145  *		 int nb_part_seen)
146  **/
parse_partition_table(struct driveinfo * d,p_callback callback)147 int parse_partition_table(struct driveinfo *d, p_callback callback)
148 {
149     char *mbr = malloc(SECTOR * sizeof(char));
150 
151     if (read_mbr(d->disk, mbr) == -1)
152 	return -1;
153     else {
154 	/* Check msdos magic signature */
155 	if (!msdos_magic_present(mbr))
156 	    return -1;
157 
158 	struct part_entry *ptab =
159 	    (struct part_entry *)(mbr + PARTITION_TABLES_OFFSET);
160 	return process_mbr(d, ptab, callback);
161     }
162 }
163