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

Last change on this file was f381e9b, checked in by Joel Sherrill <joel@…>, on 02/17/22 at 15:47:33

cpukit/libblock: Change license to BSD-2

Updates #3053.

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