Home | History | Annotate | Download | only in disk
      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