Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:24:14

0001 /* SPDX-License-Identifier: BSD-2-Clause */
0002 
0003 /**
0004  * @file
0005  *
0006  * @ingroup libblock
0007  *
0008  * @brief Library supporting "MS-DOS-style" Partition Table
0009  */
0010 
0011 /*
0012  * Copyright (C) 2002 OKTET Ltd., St.-Petersburg, Russia
0013  *
0014  * Author: Konstantin Abramenko <Konstantin.Abramenko@oktet.ru>
0015  *         Alexander Kukuta <Alexander.Kukuta@oktet.ru>
0016  *
0017  * Redistribution and use in source and binary forms, with or without
0018  * modification, are permitted provided that the following conditions
0019  * are met:
0020  * 1. Redistributions of source code must retain the above copyright
0021  *    notice, this list of conditions and the following disclaimer.
0022  * 2. Redistributions in binary form must reproduce the above copyright
0023  *    notice, this list of conditions and the following disclaimer in the
0024  *    documentation and/or other materials provided with the distribution.
0025  *
0026  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0027  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0028  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0029  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0030  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0031  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0032  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0033  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0034  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0035  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0036  * POSSIBILITY OF SUCH DAMAGE.
0037  *
0038  */
0039 
0040 #ifdef HAVE_CONFIG_H
0041 #include "config.h"
0042 #endif
0043 
0044 #include <string.h>
0045 
0046 #include <rtems/ide_part_table.h>
0047 
0048 /*
0049  * get_sector --
0050  *      gets sector from the disk
0051  *
0052  * PARAMETERS:
0053  *      fd         - file descriptor
0054  *      sector_num - number of sector to read
0055  *      sector     - returned pointer to pointer to allocated
0056  *                   sector_data_t structure
0057  *
0058  * RETURNS:
0059  *      RTEMS_SUCCESSFUL, if success;
0060  *      RTEMS_NO_MEMORY, if canot allocate memory for sector data;
0061  *      other error codes returned by rtems_bdbuf_read().
0062  *
0063  * NOTES:
0064  *      get_sector() operates with device via bdbuf library,
0065  *      and does not support devices with sector size other than 512 bytes
0066  */
0067 static rtems_status_code
0068 get_sector(int fd,
0069            uint32_t sector_num,
0070            rtems_sector_data_t **sector)
0071 {
0072     rtems_sector_data_t *s;
0073     ssize_t              n;
0074     off_t                off;
0075     off_t                new_off;
0076 
0077     if (sector == NULL)
0078     {
0079         return RTEMS_INTERNAL_ERROR;
0080     }
0081 
0082     off = sector_num * RTEMS_IDE_SECTOR_SIZE;
0083     new_off = lseek(fd, off, SEEK_SET);
0084     if (new_off != off) {
0085         return RTEMS_IO_ERROR;
0086     }
0087 
0088     s = (rtems_sector_data_t *) malloc(sizeof(rtems_sector_data_t) + RTEMS_IDE_SECTOR_SIZE);
0089     if (s == NULL)
0090     {
0091         return RTEMS_NO_MEMORY;
0092     }
0093 
0094     n = read(fd, s->data, RTEMS_IDE_SECTOR_SIZE);
0095     if (n != RTEMS_IDE_SECTOR_SIZE)
0096     {
0097         free(s);
0098         return RTEMS_IO_ERROR;
0099     }
0100 
0101     s->sector_num = sector_num;
0102 
0103     *sector = s;
0104 
0105     return RTEMS_SUCCESSFUL;
0106 }
0107 
0108 
0109 /*
0110  * msdos_signature_check --
0111  *      checks if the partition table sector has msdos signature
0112  *
0113  * PARAMETERS:
0114  *      sector - sector to check
0115  *
0116  * RETURNS:
0117  *      true if sector has msdos signature, false otherwise
0118  */
0119 static bool
0120 msdos_signature_check (rtems_sector_data_t *sector)
0121 {
0122     uint8_t *p = sector->data + RTEMS_IDE_PARTITION_MSDOS_SIGNATURE_OFFSET;
0123 
0124     return ((p[0] == RTEMS_IDE_PARTITION_MSDOS_SIGNATURE_DATA1) &&
0125             (p[1] == RTEMS_IDE_PARTITION_MSDOS_SIGNATURE_DATA2));
0126 }
0127 
0128 
0129 /*
0130  * is_extended --
0131  *      checks if the partition type is extended
0132  *
0133  * PARAMETERS:
0134  *      type - type of partition to check
0135  *
0136  * RETURNS:
0137  *      true if partition type is extended, false otherwise
0138  */
0139 static bool
0140 is_extended(uint8_t type)
0141 {
0142     return ((type == EXTENDED_PARTITION) || (type == LINUX_EXTENDED));
0143 }
0144 
0145 /*
0146  * is_fat_partition --
0147  *      checks if the partition type is defined for FAT
0148  *
0149  * PARAMETERS:
0150  *      type - type of partition to check
0151  *
0152  * RETURNS:
0153  *      true if partition type is extended, false otherwise
0154  */
0155 static bool
0156 is_fat_partition(uint8_t type)
0157 {
0158   static const uint8_t fat_part_types[] = {
0159     DOS_FAT12_PARTITION,DOS_FAT16_PARTITION,
0160     DOS_P32MB_PARTITION,
0161     FAT32_PARTITION    ,FAT32_LBA_PARTITION,
0162     FAT16_LBA_PARTITION
0163   };
0164 
0165   return (NULL != memchr(fat_part_types,type,sizeof(fat_part_types)));
0166 }
0167 
0168 
0169 /*
0170  * data_to_part_desc --
0171  *      parses raw partition table sector data
0172  *      to partition description structure
0173  *
0174  * PARAMETERS:
0175  *      data          - raw partition table sector data
0176  *      new_part_desc - pointer to returned partition description structure
0177  *
0178  * RETURNS:
0179  *      RTEMS_SUCCESSFUL, if success;
0180  *      RTEMS_NO_MEMOTY, if cannot allocate memory for part_desc_t strucure;
0181  *      RTEMS_INTERNAL_ERROR, if other error occurs.
0182  */
0183 static rtems_status_code
0184 data_to_part_desc(uint8_t *data, rtems_part_desc_t **new_part_desc)
0185 {
0186     rtems_part_desc_t *part_desc;
0187     uint32_t           temp;
0188 
0189     if (new_part_desc == NULL)
0190     {
0191         return RTEMS_INTERNAL_ERROR;
0192     }
0193 
0194     *new_part_desc = NULL;
0195 
0196     if ((part_desc = calloc(1, sizeof(rtems_part_desc_t))) == NULL)
0197     {
0198         return RTEMS_NO_MEMORY;
0199     }
0200 
0201     part_desc->bootable = *(data + RTEMS_IDE_PARTITION_BOOTABLE_OFFSET);
0202     part_desc->sys_type = *(data + RTEMS_IDE_PARTITION_SYS_TYPE_OFFSET);
0203 
0204     /* read the offset start position and partition size in sectors */
0205 
0206     /* due to incorrect data alignment one have to align data first */
0207     memcpy(&temp, data + RTEMS_IDE_PARTITION_START_OFFSET, sizeof(uint32_t));
0208     part_desc->start = LE_TO_CPU_U32(temp);
0209 
0210     memcpy(&temp, data + RTEMS_IDE_PARTITION_SIZE_OFFSET, sizeof(uint32_t));
0211     part_desc->size = LE_TO_CPU_U32(temp);
0212 
0213     /*
0214      * use partitions that are
0215      * - extended
0216      * or
0217      * - FAT type and non-zero
0218      */
0219     if (is_extended(part_desc->sys_type) ||
0220        ((is_fat_partition(part_desc->sys_type)) && (part_desc->size != 0))) {
0221       *new_part_desc = part_desc;
0222     }
0223     else {
0224       /* empty partition */
0225       free(part_desc);
0226     }
0227     return RTEMS_SUCCESSFUL;
0228 }
0229 
0230 
0231 /*
0232  * read_extended_partition --
0233  *      recursively reads extended partition sector from the device
0234  *      and constructs the partition table tree
0235  *
0236  * PARAMETERS:
0237  *      fd       - file descriptor
0238  *      start    - start sector of primary extended partition, used for
0239  *                 calculation of absolute partition sector address
0240  *      ext_part - description of extended partition to process
0241  *
0242  * RETURNS:
0243  *      RTEMS_SUCCESSFUL if success,
0244  *      RTEMS_NO_MEMOTY if cannot allocate memory for part_desc_t strucure,
0245  *      RTEMS_INTERNAL_ERROR if other error occurs.
0246  */
0247 static rtems_status_code
0248 read_extended_partition(int fd, uint32_t start, rtems_part_desc_t *ext_part)
0249 {
0250     int                  i;
0251     rtems_sector_data_t *sector = NULL;
0252     uint32_t             here;
0253     uint8_t             *data;
0254     rtems_part_desc_t   *new_part_desc;
0255     rtems_status_code    rc;
0256 
0257     if ((ext_part == NULL) || (ext_part->disk_desc == NULL))
0258     {
0259         return RTEMS_INTERNAL_ERROR;
0260     }
0261 
0262     /* get start sector of current extended partition */
0263     here = ext_part->start;
0264 
0265     /* get first extended partition sector */
0266 
0267     rc = get_sector(fd, here, &sector);
0268     if (rc != RTEMS_SUCCESSFUL)
0269     {
0270         if (sector)
0271             free(sector);
0272         return rc;
0273     }
0274 
0275     if (!msdos_signature_check(sector))
0276     {
0277         free(sector);
0278         return RTEMS_INTERNAL_ERROR;
0279     }
0280 
0281     /* read and process up to 4 logical partition descriptors */
0282 
0283     data = sector->data + RTEMS_IDE_PARTITION_TABLE_OFFSET;
0284 
0285     for (i = 0; i < RTEMS_IDE_PARTITION_MAX_SUB_PARTITION_NUMBER; i++)
0286     {
0287         /* if data_to_part_desc fails skip this partition
0288          * and parse the next one
0289          */
0290         rc = data_to_part_desc(data, &new_part_desc);
0291         if (rc != RTEMS_SUCCESSFUL)
0292         {
0293             free(sector);
0294             return rc;
0295         }
0296 
0297         if (new_part_desc == NULL)
0298         {
0299             data += RTEMS_IDE_PARTITION_DESCRIPTOR_SIZE;
0300             continue;
0301         }
0302 
0303         ext_part->sub_part[i] = new_part_desc;
0304         new_part_desc->ext_part = ext_part;
0305         new_part_desc->disk_desc = ext_part->disk_desc;
0306 
0307         if (is_extended(new_part_desc->sys_type))
0308         {
0309             new_part_desc->log_id = EMPTY_PARTITION;
0310             new_part_desc->start += start;
0311             read_extended_partition(fd, start, new_part_desc);
0312         }
0313         else
0314         {
0315             rtems_disk_desc_t *disk_desc = new_part_desc->disk_desc;
0316             disk_desc->partitions[disk_desc->last_log_id] = new_part_desc;
0317             new_part_desc->log_id = ++disk_desc->last_log_id;
0318             new_part_desc->start += here;
0319             new_part_desc->end = new_part_desc->start + new_part_desc->size - 1;
0320         }
0321         data += RTEMS_IDE_PARTITION_DESCRIPTOR_SIZE;
0322     }
0323 
0324     free(sector);
0325 
0326     return RTEMS_SUCCESSFUL;
0327 }
0328 
0329 
0330 /*
0331  * read_mbr --
0332  *      reads Master Boot Record (sector 0) of physical device and
0333  *      constructs disk description structure
0334  *
0335  * PARAMETERS:
0336  *      disk_desc - returned disc description structure
0337  *
0338  * RETURNS:
0339  *      RTEMS_SUCCESSFUL if success,
0340  *      RTEMS_INTERNAL_ERROR otherwise
0341  */
0342 static rtems_status_code
0343 read_mbr(int fd, rtems_disk_desc_t *disk_desc)
0344 {
0345     int                  part_num;
0346     rtems_sector_data_t *sector = NULL;
0347     rtems_part_desc_t   *part_desc;
0348     uint8_t             *data;
0349     rtems_status_code    rc;
0350 
0351     /* get MBR sector */
0352     rc = get_sector(fd, 0, &sector);
0353     if (rc != RTEMS_SUCCESSFUL)
0354     {
0355         if (sector)
0356             free(sector);
0357         return rc;
0358     }
0359 
0360     /* check if the partition table structure is MS-DOS style */
0361     if (!msdos_signature_check(sector))
0362     {
0363         free(sector);
0364         return RTEMS_INTERNAL_ERROR;
0365     }
0366 
0367     /* read and process 4 primary partition descriptors */
0368 
0369     data = sector->data + RTEMS_IDE_PARTITION_TABLE_OFFSET;
0370 
0371     for (part_num = 0;
0372          part_num < RTEMS_IDE_PARTITION_MAX_SUB_PARTITION_NUMBER;
0373          part_num++)
0374     {
0375         rc = data_to_part_desc(data, &part_desc);
0376         if (rc != RTEMS_SUCCESSFUL)
0377         {
0378             free(sector);
0379             return rc;
0380         }
0381 
0382         if (part_desc != NULL)
0383         {
0384             part_desc->log_id = part_num + 1;
0385             part_desc->disk_desc = disk_desc;
0386             part_desc->end = part_desc->start + part_desc->size - 1;
0387             disk_desc->partitions[part_num] = part_desc;
0388         }
0389         else
0390         {
0391             disk_desc->partitions[part_num] = NULL;
0392         }
0393 
0394         data += RTEMS_IDE_PARTITION_DESCRIPTOR_SIZE;
0395     }
0396 
0397     free(sector);
0398 
0399     disk_desc->last_log_id = RTEMS_IDE_PARTITION_MAX_SUB_PARTITION_NUMBER;
0400 
0401     /* There cannot be more than one extended partition,
0402        but we are to process each primary partition */
0403     for (part_num = 0;
0404          part_num < RTEMS_IDE_PARTITION_MAX_SUB_PARTITION_NUMBER;
0405          part_num++)
0406     {
0407         part_desc = disk_desc->partitions[part_num];
0408         if (part_desc != NULL && is_extended(part_desc->sys_type))
0409         {
0410             read_extended_partition(fd, part_desc->start, part_desc);
0411             free(part_desc);
0412             disk_desc->partitions[part_num] = NULL;
0413         }
0414     }
0415 
0416     return RTEMS_SUCCESSFUL;
0417 }
0418 
0419 
0420 /*
0421  * partition free --
0422  *      frees partition description structure
0423  *
0424  * PARAMETERS:
0425  *      part_desc - returned disc description structure
0426  *
0427  * RETURNS:
0428  *      N/A
0429  */
0430 static void
0431 partition_free(rtems_part_desc_t *part_desc)
0432 {
0433     int part_num;
0434 
0435     if (part_desc == NULL)
0436         return;
0437 
0438     if (is_extended(part_desc->sys_type))
0439     {
0440         for (part_num = 0;
0441              part_num < RTEMS_IDE_PARTITION_MAX_SUB_PARTITION_NUMBER;
0442              part_num++)
0443         {
0444             partition_free(part_desc->sub_part[part_num]);
0445         }
0446     }
0447 
0448     free(part_desc);
0449 }
0450 
0451 
0452 /*
0453  * partition_table_free - frees disk descriptor structure
0454  *
0455  * PARAMETERS:
0456  *      disk_desc - disc descriptor structure to free
0457  *
0458  * RETURNS:
0459  *      N/A
0460  */
0461 static void
0462 partition_table_free(rtems_disk_desc_t *disk_desc)
0463 {
0464     int part_num;
0465 
0466     for (part_num = 0;
0467          part_num < RTEMS_IDE_PARTITION_MAX_SUB_PARTITION_NUMBER;
0468          part_num++)
0469     {
0470         partition_free(disk_desc->partitions[part_num]);
0471     }
0472 
0473     free(disk_desc);
0474 }
0475 
0476 
0477 /*
0478  * partition_table_get - reads partition table structure from the device
0479  *                            and creates disk description structure
0480  *
0481  * PARAMETERS:
0482  *      dev_name - path to physical device in /dev filesystem
0483  *      disk_desc       - returned disc description structure
0484  *
0485  * RETURNS:
0486  *      RTEMS_SUCCESSFUL if success,
0487  *      RTEMS_INTERNAL_ERROR otherwise
0488  */
0489 static rtems_status_code
0490 partition_table_get(const char *dev_name, rtems_disk_desc_t *disk_desc)
0491 {
0492     struct stat         dev_stat;
0493     rtems_status_code   rc;
0494     int                 fd;
0495 
0496     fd = open(dev_name, O_RDONLY);
0497     if (fd < 0)
0498     {
0499         return RTEMS_INTERNAL_ERROR;
0500     }
0501 
0502     rc = fstat(fd, &dev_stat);
0503     if (rc != RTEMS_SUCCESSFUL)
0504     {
0505         close(fd);
0506         return RTEMS_INTERNAL_ERROR;
0507     }
0508 
0509     strncpy (disk_desc->dev_name, dev_name, 15);
0510     disk_desc->sector_size = (dev_stat.st_blksize) ? dev_stat.st_blksize :
0511                                               RTEMS_IDE_SECTOR_SIZE;
0512 
0513     rc = read_mbr(fd, disk_desc);
0514 
0515     close(fd);
0516 
0517     return rc;
0518 }
0519 
0520 
0521 /*
0522  * rtems_ide_part_table_free - frees disk descriptor structure
0523  *
0524  * PARAMETERS:
0525  *      disk_desc - disc descriptor structure to free
0526  *
0527  * RETURNS:
0528  *      N/A
0529  */
0530 void
0531 rtems_ide_part_table_free(rtems_disk_desc_t *disk_desc)
0532 {
0533     partition_table_free( disk_desc );
0534 }
0535 
0536 
0537 /*
0538  * rtems_ide_part_table_get - reads partition table structure from the device
0539  *                            and creates disk description structure
0540  *
0541  * PARAMETERS:
0542  *      dev_name - path to physical device in /dev filesystem
0543  *      disk_desc       - returned disc description structure
0544  *
0545  * RETURNS:
0546  *      RTEMS_SUCCESSFUL if success,
0547  *      RTEMS_INTERNAL_ERROR otherwise
0548  */
0549 rtems_status_code
0550 rtems_ide_part_table_get(const char *dev_name, rtems_disk_desc_t *disk_desc)
0551 {
0552     return partition_table_get( dev_name, disk_desc );
0553 }
0554 
0555 
0556 /*
0557  * rtems_ide_part_table_initialize - initializes logical devices
0558  *                                   on the physical IDE drive
0559  *
0560  * PARAMETERS:
0561  *      dev_name - path to physical device in /dev filesystem
0562  *
0563  * RETURNS:
0564  *      RTEMS_SUCCESSFUL if success,
0565  *      RTEMS_NO_MEMOTY if cannot have not enough memory,
0566  *      RTEMS_INTERNAL_ERROR if other error occurs.
0567  */
0568 rtems_status_code
0569 rtems_ide_part_table_initialize(const char *dev_name)
0570 {
0571     int                         part_num;
0572     rtems_disk_desc_t          *disk_desc;
0573     rtems_status_code           rc;
0574     rtems_part_desc_t          *part_desc;
0575 
0576     /* logical device name /dev/hdxyy */
0577     char                        name[RTEMS_IDE_PARTITION_DEV_NAME_LENGTH_MAX];
0578 
0579     disk_desc = (rtems_disk_desc_t *) calloc(1, sizeof(rtems_disk_desc_t));
0580     if (disk_desc == NULL)
0581     {
0582         return RTEMS_NO_MEMORY;
0583     }
0584 
0585     /* get partition table */
0586     rc = partition_table_get(dev_name, disk_desc);
0587     if (rc != RTEMS_SUCCESSFUL)
0588     {
0589         free(disk_desc);
0590         return rc;
0591     }
0592 
0593     /* create logical disks on the physical one */
0594     for (part_num = 0; part_num < disk_desc->last_log_id; part_num++)
0595     {
0596         sprintf(name, "%s%d", dev_name, part_num + 1);
0597 
0598         part_desc = disk_desc->partitions[part_num];
0599         if (part_desc == NULL)
0600         {
0601             continue;
0602         }
0603 
0604         rc = rtems_blkdev_create_partition(name, dev_name, part_desc->start,
0605                                            part_desc->size);
0606         if (rc != RTEMS_SUCCESSFUL)
0607         {
0608             fprintf(stdout,"Cannot create device %s, error code %d\n", name, rc);
0609             continue;
0610         }
0611     }
0612 
0613     partition_table_free(disk_desc);
0614 
0615     return RTEMS_SUCCESSFUL;
0616 }