source: rtems/cpukit/libblock/src/ide_part_table.c @ c93fc2b3

4.115
Last change on this file since c93fc2b3 was c93fc2b3, checked in by Sebastian Huber <sebastian.huber@…>, on 02/28/12 at 13:57:01

libblock: rtems_ide_part_table_initialize() API

  • Property mode set to 100644
File size: 15.2 KB
RevLine 
[ef142d7]1/*****************************************************************************
2 *
3 * ide_part_table.c
4 *
5 * The implementation of library supporting "MS-DOS-style" partition table
6 *
7 *
8 * Copyright (C) 2002 OKTET Ltd., St.-Petersburg, Russia
9 *
10 * Author: Konstantin Abramenko <Konstantin.Abramenko@oktet.ru>
11 *         Alexander Kukuta <Alexander.Kukuta@oktet.ru>
12 *
13 *  The license and distribution terms for this file may be
14 *  found in the file LICENSE in this distribution or at
[5b38506]15 *  http://www.rtems.com/license/LICENSE.
[ef142d7]16 *
17 * $Id$
18 *
19 *****************************************************************************/
20
[006fa1ef]21#if HAVE_CONFIG_H
22#include "config.h"
23#endif
24
[dbe06865]25#include <string.h>
[ef142d7]26
[006fa1ef]27#include <rtems/ide_part_table.h>
28
[ef142d7]29/*
30 * get_sector --
31 *      gets sector from the disk
32 *
33 * PARAMETERS:
[03ad6b1d]34 *      fd         - file descriptor
[ef142d7]35 *      sector_num - number of sector to read
36 *      sector     - returned pointer to pointer to allocated
37 *                   sector_data_t structure
38 *
39 * RETURNS:
40 *      RTEMS_SUCCESSFUL, if success;
41 *      RTEMS_NO_MEMORY, if canot allocate memory for sector data;
42 *      other error codes returned by rtems_bdbuf_read().
43 *
44 * NOTES:
45 *      get_sector() operates with device via bdbuf library,
46 *      and does not support devices with sector size other than 512 bytes
47 */
48static rtems_status_code
[03ad6b1d]49get_sector(int fd,
50           uint32_t sector_num,
51           rtems_sector_data_t **sector)
[ef142d7]52{
[3899a537]53    rtems_sector_data_t *s;
[03ad6b1d]54    ssize_t              n;
55    off_t                off;
56    off_t                new_off;
[048dcd2b]57
[ef142d7]58    if (sector == NULL)
59    {
60        return RTEMS_INTERNAL_ERROR;
61    }
62
[03ad6b1d]63    off = sector_num * RTEMS_IDE_SECTOR_SIZE;
64    new_off = lseek(fd, off, SEEK_SET);
65    if (new_off != off) {
66        return RTEMS_IO_ERROR;
67    }
68
[3899a537]69    s = (rtems_sector_data_t *) malloc(sizeof(rtems_sector_data_t) + RTEMS_IDE_SECTOR_SIZE);
[ef142d7]70    if (s == NULL)
71    {
72        return RTEMS_NO_MEMORY;
73    }
[048dcd2b]74
[03ad6b1d]75    n = read(fd, s->data, RTEMS_IDE_SECTOR_SIZE);
76    if (n != RTEMS_IDE_SECTOR_SIZE)
[ef142d7]77    {
78        free(s);
[03ad6b1d]79        return RTEMS_IO_ERROR;
[ef142d7]80    }
[048dcd2b]81
[ef142d7]82    s->sector_num = sector_num;
83
84    *sector = s;
[048dcd2b]85
[ef142d7]86    return RTEMS_SUCCESSFUL;
87}
88
89
90/*
91 * msdos_signature_check --
92 *      checks if the partition table sector has msdos signature
93 *
94 * PARAMETERS:
95 *      sector - sector to check
96 *
97 * RETURNS:
[4f971343]98 *      true if sector has msdos signature, false otherwise
[ef142d7]99 */
[e03c37a]100static bool
[3899a537]101msdos_signature_check (rtems_sector_data_t *sector)
[ef142d7]102{
[c01d95b7]103    uint8_t *p = sector->data + RTEMS_IDE_PARTITION_MSDOS_SIGNATURE_OFFSET;
[ef142d7]104
105    return ((p[0] == RTEMS_IDE_PARTITION_MSDOS_SIGNATURE_DATA1) &&
106            (p[1] == RTEMS_IDE_PARTITION_MSDOS_SIGNATURE_DATA2));
107}
108
109
110/*
111 * is_extended --
112 *      checks if the partition type is extended
113 *
114 * PARAMETERS:
115 *      type - type of partition to check
116 *
117 * RETURNS:
[4f971343]118 *      true if partition type is extended, false otherwise
[ef142d7]119 */
[e03c37a]120static bool
[8b96149]121is_extended(uint8_t type)
[ef142d7]122{
123    return ((type == EXTENDED_PARTITION) || (type == LINUX_EXTENDED));
124}
125
[dbe06865]126/*
127 * is_fat_partition --
128 *      checks if the partition type is defined for FAT
129 *
130 * PARAMETERS:
131 *      type - type of partition to check
132 *
133 * RETURNS:
[4f971343]134 *      true if partition type is extended, false otherwise
[dbe06865]135 */
[e03c37a]136static bool
[8b96149]137is_fat_partition(uint8_t type)
[dbe06865]138{
[c01d95b7]139  static const uint8_t fat_part_types[] = {
[dbe06865]140    DOS_FAT12_PARTITION,DOS_FAT16_PARTITION,
141    DOS_P32MB_PARTITION,
142    FAT32_PARTITION    ,FAT32_LBA_PARTITION,
143    FAT16_LBA_PARTITION
144  };
145
146  return (NULL != memchr(fat_part_types,type,sizeof(fat_part_types)));
147}
148
[ef142d7]149
150/*
151 * data_to_part_desc --
152 *      parses raw partition table sector data
153 *      to partition description structure
154 *
155 * PARAMETERS:
156 *      data          - raw partition table sector data
157 *      new_part_desc - pointer to returned partition description structure
158 *
159 * RETURNS:
160 *      RTEMS_SUCCESSFUL, if success;
161 *      RTEMS_NO_MEMOTY, if cannot allocate memory for part_desc_t strucure;
162 *      RTEMS_INTERNAL_ERROR, if other error occurs.
163 */
164static rtems_status_code
[3899a537]165data_to_part_desc(uint8_t *data, rtems_part_desc_t **new_part_desc)
[ef142d7]166{
[3899a537]167    rtems_part_desc_t *part_desc;
168    uint32_t           temp;
[ef142d7]169
170    if (new_part_desc == NULL)
171    {
172        return RTEMS_INTERNAL_ERROR;
173    }
[048dcd2b]174
[ef142d7]175    *new_part_desc = NULL;
176
[3899a537]177    if ((part_desc = calloc(1, sizeof(rtems_part_desc_t))) == NULL)
[ef142d7]178    {
179        return RTEMS_NO_MEMORY;
180    }
181
182    part_desc->bootable = *(data + RTEMS_IDE_PARTITION_BOOTABLE_OFFSET);
183    part_desc->sys_type = *(data + RTEMS_IDE_PARTITION_SYS_TYPE_OFFSET);
184
185    /* read the offset start position and partition size in sectors */
186
187    /* due to incorrect data alignment one have to align data first */
[c01d95b7]188    memcpy(&temp, data + RTEMS_IDE_PARTITION_START_OFFSET, sizeof(uint32_t));
[ef142d7]189    part_desc->start = LE_TO_CPU_U32(temp);
190
[c01d95b7]191    memcpy(&temp, data + RTEMS_IDE_PARTITION_SIZE_OFFSET, sizeof(uint32_t));
[ef142d7]192    part_desc->size = LE_TO_CPU_U32(temp);
193
[dbe06865]194    /*
[8b96149]195     * use partitions that are
[dbe06865]196     * - extended
197     * or
198     * - FAT type and non-zero
199     */
200    if (is_extended(part_desc->sys_type) ||
[b2ac8a9]201       ((is_fat_partition(part_desc->sys_type)) && (part_desc->size != 0))) {
[dbe06865]202      *new_part_desc = part_desc;
203    }
[8b96149]204    else {
[dbe06865]205      /* empty partition */
206      free(part_desc);
[ef142d7]207    }
208    return RTEMS_SUCCESSFUL;
209}
210
211
212/*
213 * read_extended_partition --
214 *      recursively reads extended partition sector from the device
215 *      and constructs the partition table tree
216 *
217 * PARAMETERS:
[03ad6b1d]218 *      fd       - file descriptor
[8b96149]219 *      start    - start sector of primary extended partition, used for
[ef142d7]220 *                 calculation of absolute partition sector address
221 *      ext_part - description of extended partition to process
222 *
223 * RETURNS:
224 *      RTEMS_SUCCESSFUL if success,
225 *      RTEMS_NO_MEMOTY if cannot allocate memory for part_desc_t strucure,
226 *      RTEMS_INTERNAL_ERROR if other error occurs.
227 */
228static rtems_status_code
[03ad6b1d]229read_extended_partition(int fd, uint32_t start, rtems_part_desc_t *ext_part)
[ef142d7]230{
[3899a537]231    int                  i;
[b61ad65]232    rtems_sector_data_t *sector = NULL;
[3899a537]233    uint32_t             here;
234    uint8_t             *data;
235    rtems_part_desc_t   *new_part_desc;
236    rtems_status_code    rc;
[ef142d7]237
238    if ((ext_part == NULL) || (ext_part->disk_desc == NULL))
239    {
240        return RTEMS_INTERNAL_ERROR;
241    }
[048dcd2b]242
[ef142d7]243    /* get start sector of current extended partition */
244    here = ext_part->start;
245
246    /* get first extended partition sector */
247
[03ad6b1d]248    rc = get_sector(fd, here, &sector);
[ef142d7]249    if (rc != RTEMS_SUCCESSFUL)
250    {
[b61ad65]251        if (sector)
252            free(sector);
[ef142d7]253        return rc;
254    }
255
256    if (!msdos_signature_check(sector))
257    {
[b61ad65]258        free(sector);
[ef142d7]259        return RTEMS_INTERNAL_ERROR;
260    }
261
262    /* read and process up to 4 logical partition descriptors */
263
264    data = sector->data + RTEMS_IDE_PARTITION_TABLE_OFFSET;
265
[8b96149]266    for (i = 0; i < RTEMS_IDE_PARTITION_MAX_SUB_PARTITION_NUMBER; i++)
[ef142d7]267    {
268        /* if data_to_part_desc fails skip this partition
269         * and parse the next one
270         */
271        rc = data_to_part_desc(data, &new_part_desc);
272        if (rc != RTEMS_SUCCESSFUL)
273        {
274            free(sector);
275            return rc;
276        }
[048dcd2b]277
[ef142d7]278        if (new_part_desc == NULL)
279        {
280            data += RTEMS_IDE_PARTITION_DESCRIPTOR_SIZE;
281            continue;
282        }
283
284        ext_part->sub_part[i] = new_part_desc;
285        new_part_desc->ext_part = ext_part;
286        new_part_desc->disk_desc = ext_part->disk_desc;
287
[8b96149]288        if (is_extended(new_part_desc->sys_type))
[ef142d7]289        {
290            new_part_desc->log_id = EMPTY_PARTITION;
291            new_part_desc->start += start;
[03ad6b1d]292            read_extended_partition(fd, start, new_part_desc);
[ef142d7]293        }
[8b96149]294        else
[ef142d7]295        {
[3899a537]296            rtems_disk_desc_t *disk_desc = new_part_desc->disk_desc;
[ef142d7]297            disk_desc->partitions[disk_desc->last_log_id] = new_part_desc;
298            new_part_desc->log_id = ++disk_desc->last_log_id;
299            new_part_desc->start += here;
300            new_part_desc->end = new_part_desc->start + new_part_desc->size - 1;
301        }
302        data += RTEMS_IDE_PARTITION_DESCRIPTOR_SIZE;
303    }
304
305    free(sector);
[048dcd2b]306
[ef142d7]307    return RTEMS_SUCCESSFUL;
308}
309
310
311/*
312 * read_mbr --
313 *      reads Master Boot Record (sector 0) of physical device and
314 *      constructs disk description structure
315 *
316 * PARAMETERS:
317 *      disk_desc - returned disc description structure
318 *
319 * RETURNS:
320 *      RTEMS_SUCCESSFUL if success,
321 *      RTEMS_INTERNAL_ERROR otherwise
322 */
323static rtems_status_code
[03ad6b1d]324read_mbr(int fd, rtems_disk_desc_t *disk_desc)
[ef142d7]325{
[3899a537]326    int                  part_num;
[d3231fba]327    rtems_sector_data_t *sector = NULL;
[3899a537]328    rtems_part_desc_t   *part_desc;
329    uint8_t             *data;
330    rtems_status_code    rc;
[ef142d7]331
332    /* get MBR sector */
[03ad6b1d]333    rc = get_sector(fd, 0, &sector);
[ef142d7]334    if (rc != RTEMS_SUCCESSFUL)
335    {
[d3231fba]336        if (sector)
337            free(sector);
[ef142d7]338        return rc;
339    }
340
341    /* check if the partition table structure is MS-DOS style */
342    if (!msdos_signature_check(sector))
343    {
[b2ac8a9]344        free(sector);
[ef142d7]345        return RTEMS_INTERNAL_ERROR;
346    }
347
348    /* read and process 4 primary partition descriptors */
349
350    data = sector->data + RTEMS_IDE_PARTITION_TABLE_OFFSET;
351
352    for (part_num = 0;
353         part_num < RTEMS_IDE_PARTITION_MAX_SUB_PARTITION_NUMBER;
354         part_num++)
355    {
356        rc = data_to_part_desc(data, &part_desc);
357        if (rc != RTEMS_SUCCESSFUL)
358        {
359            free(sector);
360            return rc;
361        }
362
[8b96149]363        if (part_desc != NULL)
[ef142d7]364        {
365            part_desc->log_id = part_num + 1;
366            part_desc->disk_desc = disk_desc;
367            part_desc->end = part_desc->start + part_desc->size - 1;
368            disk_desc->partitions[part_num] = part_desc;
[8b96149]369        }
[ef142d7]370        else
371        {
372            disk_desc->partitions[part_num] = NULL;
373        }
374
375        data += RTEMS_IDE_PARTITION_DESCRIPTOR_SIZE;
376    }
377
378    free(sector);
[048dcd2b]379
[ef142d7]380    disk_desc->last_log_id = RTEMS_IDE_PARTITION_MAX_SUB_PARTITION_NUMBER;
381
382    /* There cannot be more than one extended partition,
383       but we are to process each primary partition */
384    for (part_num = 0;
385         part_num < RTEMS_IDE_PARTITION_MAX_SUB_PARTITION_NUMBER;
386         part_num++)
387    {
[eb961961]388        part_desc = disk_desc->partitions[part_num];
389        if (part_desc != NULL && is_extended(part_desc->sys_type))
[ef142d7]390        {
[03ad6b1d]391            read_extended_partition(fd, part_desc->start, part_desc);
[ef142d7]392        }
393    }
394
395    return RTEMS_SUCCESSFUL;
396}
397
398
399/*
400 * partition free --
401 *      frees partition description structure
402 *
403 * PARAMETERS:
404 *      part_desc - returned disc description structure
405 *
406 * RETURNS:
407 *      N/A
408 */
409static void
[3899a537]410partition_free(rtems_part_desc_t *part_desc)
[ef142d7]411{
412    int part_num;
413
414    if (part_desc == NULL)
415        return;
[048dcd2b]416
[ef142d7]417    if (is_extended(part_desc->sys_type))
418    {
419        for (part_num = 0;
420             part_num < RTEMS_IDE_PARTITION_MAX_SUB_PARTITION_NUMBER;
421             part_num++)
422        {
423            partition_free(part_desc->sub_part[part_num]);
424        }
425    }
[048dcd2b]426
[ef142d7]427    free(part_desc);
428}
429
430
431/*
[00d17034]432 * partition_table_free - frees disk descriptor structure
[ef142d7]433 *
434 * PARAMETERS:
435 *      disk_desc - disc descriptor structure to free
436 *
437 * RETURNS:
438 *      N/A
439 */
[00d17034]440static void
441partition_table_free(rtems_disk_desc_t *disk_desc)
[ef142d7]442{
443    int part_num;
444
[00d17034]445    for (part_num = 0;
446         part_num < RTEMS_IDE_PARTITION_MAX_SUB_PARTITION_NUMBER;
447         part_num++)
[ef142d7]448    {
449        partition_free(disk_desc->partitions[part_num]);
450    }
[048dcd2b]451
[ef142d7]452    free(disk_desc);
453}
454
455
456/*
[00d17034]457 * partition_table_get - reads partition table structure from the device
[ef142d7]458 *                            and creates disk description structure
459 *
460 * PARAMETERS:
461 *      dev_name - path to physical device in /dev filesystem
462 *      disk_desc       - returned disc description structure
463 *
464 * RETURNS:
465 *      RTEMS_SUCCESSFUL if success,
466 *      RTEMS_INTERNAL_ERROR otherwise
467 */
[00d17034]468static rtems_status_code
469partition_table_get(const char *dev_name, rtems_disk_desc_t *disk_desc)
[ef142d7]470{
471    struct stat         dev_stat;
472    rtems_status_code   rc;
[03ad6b1d]473    int                 fd;
474
475    fd = open(dev_name, O_RDONLY);
476    if (fd < 0)
477    {
478        return RTEMS_INTERNAL_ERROR;
479    }
[ef142d7]480
[03ad6b1d]481    rc = fstat(fd, &dev_stat);
[ef142d7]482    if (rc != RTEMS_SUCCESSFUL)
483    {
[03ad6b1d]484        close(fd);
[ef142d7]485        return RTEMS_INTERNAL_ERROR;
486    }
487
488    strncpy (disk_desc->dev_name, dev_name, 15);
[7baa484]489    disk_desc->dev = dev_stat.st_rdev;
[ef142d7]490    disk_desc->sector_size = (dev_stat.st_blksize) ? dev_stat.st_blksize :
491                                              RTEMS_IDE_SECTOR_SIZE;
492
[03ad6b1d]493    rc = read_mbr(fd, disk_desc);
494
495    close(fd);
[ef142d7]496
497    return rc;
498}
499
500
[00d17034]501/*
502 * rtems_ide_part_table_free - frees disk descriptor structure
503 *
504 * PARAMETERS:
505 *      disk_desc - disc descriptor structure to free
506 *
507 * RETURNS:
508 *      N/A
509 */
510void
511rtems_ide_part_table_free(rtems_disk_desc_t *disk_desc)
512{
513    partition_table_free( disk_desc );
514}
515
516
517/*
518 * rtems_ide_part_table_get - reads partition table structure from the device
519 *                            and creates disk description structure
520 *
521 * PARAMETERS:
522 *      dev_name - path to physical device in /dev filesystem
523 *      disk_desc       - returned disc description structure
524 *
525 * RETURNS:
526 *      RTEMS_SUCCESSFUL if success,
527 *      RTEMS_INTERNAL_ERROR otherwise
528 */
529rtems_status_code
530rtems_ide_part_table_get(const char *dev_name, rtems_disk_desc_t *disk_desc)
531{
532    return partition_table_get( dev_name, disk_desc );
533}
534
535
[ef142d7]536/*
537 * rtems_ide_part_table_initialize - initializes logical devices
538 *                                   on the physical IDE drive
539 *
540 * PARAMETERS:
541 *      dev_name - path to physical device in /dev filesystem
542 *
543 * RETURNS:
544 *      RTEMS_SUCCESSFUL if success,
545 *      RTEMS_NO_MEMOTY if cannot have not enough memory,
546 *      RTEMS_INTERNAL_ERROR if other error occurs.
547 */
548rtems_status_code
[c93fc2b3]549rtems_ide_part_table_initialize(const char *dev_name)
[ef142d7]550{
551    int                         part_num;
552    dev_t                       dev;
[3899a537]553    rtems_disk_desc_t          *disk_desc;
[ef142d7]554    rtems_device_major_number   major;
555    rtems_device_minor_number   minor;
556    rtems_status_code           rc;
[3899a537]557    rtems_part_desc_t          *part_desc;
[ef142d7]558
559    /* logical device name /dev/hdxyy */
560    char                        name[RTEMS_IDE_PARTITION_DEV_NAME_LENGTH_MAX];
561
[3899a537]562    disk_desc = (rtems_disk_desc_t *) calloc(1, sizeof(rtems_disk_desc_t));
[ef142d7]563    if (disk_desc == NULL)
564    {
565        return RTEMS_NO_MEMORY;
566    }
[048dcd2b]567
[ef142d7]568    /* get partition table */
[00d17034]569    rc = partition_table_get(dev_name, disk_desc);
[ef142d7]570    if (rc != RTEMS_SUCCESSFUL)
571    {
[47c2327]572        free(disk_desc);
[ef142d7]573        return rc;
574    }
575
576    /* To avoid device numbers conflicts we have to use for logic disk the same
577     * device major number as ATA device has, and minor number that equals to
578     * sum of logic disk partition number and the minor number of physical disk
579     */
580
581    rtems_filesystem_split_dev_t (disk_desc->dev, major, minor);
582
583    /* create logical disks on the physical one */
584    for (part_num = 0; part_num < disk_desc->last_log_id; part_num++)
585    {
586        sprintf(name, "%s%d", dev_name, part_num + 1);
587        dev = rtems_filesystem_make_dev_t(major, ++minor);
588
589        part_desc = disk_desc->partitions[part_num];
590        if (part_desc == NULL)
591        {
592            continue;
593        }
594
595        rc = rtems_disk_create_log(dev, disk_desc->dev, part_desc->start,
596                                   part_desc->size, name);
597        if (rc != RTEMS_SUCCESSFUL)
598        {
[d63a2c2]599            fprintf(stdout,"Cannot create device %s, error code %d\n", name, rc);
[ef142d7]600            continue;
601        }
602    }
603
[00d17034]604    partition_table_free(disk_desc);
[ef142d7]605
606    return RTEMS_SUCCESSFUL;
607}
Note: See TracBrowser for help on using the repository browser.