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 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 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 **/ 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 **/ 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 **/ 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