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 rtems_bdpart
0007  *
0008  * @brief Block Device Partition Management
0009  */
0010 
0011 /*
0012  * Copyright (C) 2009, 2010 embedded brains GmbH & Co. KG
0013  *
0014  * Redistribution and use in source and binary forms, with or without
0015  * modification, are permitted provided that the following conditions
0016  * are met:
0017  * 1. Redistributions of source code must retain the above copyright
0018  *    notice, this list of conditions and the following disclaimer.
0019  * 2. Redistributions in binary form must reproduce the above copyright
0020  *    notice, this list of conditions and the following disclaimer in the
0021  *    documentation and/or other materials provided with the distribution.
0022  *
0023  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
0024  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
0025  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
0026  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
0027  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
0028  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
0029  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
0030  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
0031  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
0032  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
0033  * POSSIBILITY OF SUCH DAMAGE.
0034  */
0035 
0036 #ifdef HAVE_CONFIG_H
0037 #include "config.h"
0038 #endif
0039 
0040 #include <sys/stat.h>
0041 #include <fcntl.h>
0042 #include <string.h>
0043 
0044 #include <rtems.h>
0045 #include <rtems/bdbuf.h>
0046 #include <rtems/bdpart.h>
0047 #include <rtems/endian.h>
0048 
0049 #define RTEMS_BDPART_MBR_PARTITION_TYPE( type) \
0050   { \
0051     (type), 0xa2U, 0x2eU, 0x38U, \
0052     0x38U, 0xb5U, 0xdeU, 0x11U, \
0053     0xbcU, 0x13U, 0x00U, 0x1dU, \
0054     0x09U, 0xb0U, 0x5fU, 0xa4U \
0055   }
0056 
0057 static const uuid_t RTEMS_BDPART_MBR_MASTER_TYPE =
0058   RTEMS_BDPART_MBR_PARTITION_TYPE( RTEMS_BDPART_MBR_EMPTY);
0059 
0060 void rtems_bdpart_to_partition_type( uint8_t mbr_type, uuid_t type)
0061 {
0062   type [0] = mbr_type;
0063   memcpy( type + 1, RTEMS_BDPART_MBR_MASTER_TYPE + 1, sizeof( uuid_t) - 1);
0064 }
0065 
0066 bool rtems_bdpart_to_mbr_partition_type(
0067   const uuid_t type,
0068   uint8_t *mbr_type
0069 )
0070 {
0071   *mbr_type = rtems_bdpart_mbr_partition_type( type);
0072 
0073   return memcmp(
0074     type + 1,
0075     RTEMS_BDPART_MBR_MASTER_TYPE + 1,
0076     sizeof( uuid_t) - 1
0077   ) == 0;
0078 }
0079 
0080 /*
0081  * FIXME: This code should the deviceio interface and not the bdbug interface.
0082  */
0083 rtems_status_code rtems_bdpart_get_disk_data(
0084   const char *disk_name,
0085   int *fd_ptr,
0086   rtems_disk_device **dd_ptr,
0087   rtems_blkdev_bnum *disk_end
0088 )
0089 {
0090   rtems_status_code sc = RTEMS_SUCCESSFUL;
0091   int rv = 0;
0092   int fd;
0093   rtems_disk_device *dd = NULL;
0094   rtems_blkdev_bnum disk_begin = 0;
0095   rtems_blkdev_bnum block_size = 0;
0096 
0097   /* Open device file */
0098   fd = open( disk_name, O_RDWR);
0099   if (fd < 0) {
0100     sc = RTEMS_INVALID_NAME;
0101     goto out;
0102   }
0103 
0104   /* Get disk handle */
0105   rv = rtems_disk_fd_get_disk_device( fd, &dd);
0106   if (rv != 0) {
0107     sc = RTEMS_INVALID_NAME;
0108     goto error;
0109   }
0110 
0111   /* Get disk begin, end and block size */
0112   disk_begin = dd->start;
0113   *disk_end = dd->size;
0114   block_size = dd->block_size;
0115 
0116   /* Check block size */
0117   if (block_size < RTEMS_BDPART_BLOCK_SIZE) {
0118     sc = RTEMS_IO_ERROR;
0119     goto error;
0120   }
0121 
0122   /* Check that we have do not have a logical disk */
0123   if (disk_begin != 0) {
0124     sc = RTEMS_IO_ERROR;
0125     goto error;
0126   }
0127 
0128 error:
0129 
0130   if (sc == RTEMS_SUCCESSFUL && fd_ptr != NULL && dd_ptr != NULL) {
0131     *fd_ptr = fd;
0132     *dd_ptr = dd;
0133   } else {
0134     close( fd);
0135   }
0136 
0137 out:
0138   return sc;
0139 }
0140 
0141 static bool rtems_bdpart_is_valid_record( const uint8_t *data)
0142 {
0143   return data [RTEMS_BDPART_MBR_OFFSET_SIGNATURE_0]
0144       == RTEMS_BDPART_MBR_SIGNATURE_0
0145     && data [RTEMS_BDPART_MBR_OFFSET_SIGNATURE_1]
0146       == RTEMS_BDPART_MBR_SIGNATURE_1;
0147 }
0148 
0149 static rtems_blkdev_bnum rtems_bdpart_next_ebr( const uint8_t *data)
0150 {
0151   rtems_blkdev_bnum begin =
0152     rtems_uint32_from_little_endian( data + RTEMS_BDPART_MBR_OFFSET_BEGIN);
0153   uint8_t type = data [RTEMS_BDPART_MBR_OFFSET_TYPE];
0154 
0155   if (type == RTEMS_BDPART_MBR_EXTENDED) {
0156     return begin;
0157   } else {
0158     return 0;
0159   }
0160 }
0161 
0162 static rtems_status_code rtems_bdpart_read_mbr_partition(
0163   const uint8_t *data,
0164   rtems_bdpart_partition **p,
0165   const rtems_bdpart_partition *p_end,
0166   rtems_blkdev_bnum *ep_begin
0167 )
0168 {
0169   rtems_blkdev_bnum begin =
0170     rtems_uint32_from_little_endian( data + RTEMS_BDPART_MBR_OFFSET_BEGIN);
0171   rtems_blkdev_bnum size =
0172     rtems_uint32_from_little_endian( data + RTEMS_BDPART_MBR_OFFSET_SIZE);
0173   rtems_blkdev_bnum end = begin + size;
0174   uint8_t type = data [RTEMS_BDPART_MBR_OFFSET_TYPE];
0175 
0176   if (type == RTEMS_BDPART_MBR_EMPTY) {
0177     return RTEMS_SUCCESSFUL;
0178   } else if (*p == p_end) {
0179     return RTEMS_TOO_MANY;
0180   } else if (begin >= end) {
0181     return RTEMS_IO_ERROR;
0182   } else if (type == RTEMS_BDPART_MBR_EXTENDED) {
0183     if (ep_begin != NULL) {
0184       *ep_begin = begin;
0185     }
0186   } else {
0187     /* Increment partition index */
0188     ++(*p);
0189 
0190     /* Clear partition */
0191     memset( *p, 0, sizeof( rtems_bdpart_partition));
0192 
0193     /* Set values */
0194     (*p)->begin = begin;
0195     (*p)->end = end;
0196     rtems_bdpart_to_partition_type( type, (*p)->type);
0197     (*p)->flags = data [RTEMS_BDPART_MBR_OFFSET_FLAGS];
0198   }
0199 
0200   return RTEMS_SUCCESSFUL;
0201 }
0202 
0203 static rtems_status_code rtems_bdpart_read_record(
0204   rtems_disk_device *dd,
0205   rtems_blkdev_bnum index,
0206   rtems_bdbuf_buffer **block
0207 )
0208 {
0209   rtems_status_code sc = RTEMS_SUCCESSFUL;
0210 
0211   /* Release previous block if necessary */
0212   if (*block != NULL) {
0213     sc = rtems_bdbuf_release( *block);
0214     if (sc != RTEMS_SUCCESSFUL) {
0215       return sc;
0216     }
0217   }
0218 
0219   /* Read the record block */
0220   sc = rtems_bdbuf_read( dd, index, block);
0221   if (sc != RTEMS_SUCCESSFUL) {
0222     return sc;
0223   }
0224 
0225   /* just in case block did not get filled in */
0226   if ( *block == NULL ) {
0227     return RTEMS_INVALID_ADDRESS;
0228   }
0229 
0230   /* Check MBR signature */
0231   if (!rtems_bdpart_is_valid_record( (*block)->buffer)) {
0232     return RTEMS_IO_ERROR;
0233   }
0234 
0235   return RTEMS_SUCCESSFUL;
0236 }
0237 
0238 rtems_status_code rtems_bdpart_read(
0239   const char *disk_name,
0240   rtems_bdpart_format *format,
0241   rtems_bdpart_partition *pt,
0242   size_t *count
0243 )
0244 {
0245   rtems_status_code sc = RTEMS_SUCCESSFUL;
0246   rtems_status_code esc = RTEMS_SUCCESSFUL;
0247   rtems_bdbuf_buffer *block = NULL;
0248   rtems_bdpart_partition *p = pt - 1;
0249   const rtems_bdpart_partition *p_end = pt + (count != NULL ? *count : 0);
0250   rtems_blkdev_bnum ep_begin = 0; /* Extended partition begin */
0251   rtems_blkdev_bnum ebr = 0; /* Extended boot record block index */
0252   rtems_blkdev_bnum disk_end = 0;
0253   size_t i = 0;
0254   const uint8_t *data = NULL;
0255   int fd = -1;
0256   rtems_disk_device *dd = NULL;
0257 
0258   /* Check parameter */
0259   if (format == NULL || pt == NULL || count == NULL) {
0260     return RTEMS_INVALID_ADDRESS;
0261   }
0262 
0263   /* Set count to a save value */
0264   *count = 0;
0265 
0266   /* Get disk data */
0267   sc = rtems_bdpart_get_disk_data( disk_name, &fd, &dd, &disk_end);
0268   if (sc != RTEMS_SUCCESSFUL) {
0269     return sc;
0270   }
0271 
0272   /* Read MBR */
0273   sc = rtems_bdpart_read_record( dd, 0, &block);
0274   if (sc != RTEMS_SUCCESSFUL) {
0275     esc = sc;
0276     goto cleanup;
0277   }
0278 
0279   /* Read the first partition entry */
0280   data = block->buffer + RTEMS_BDPART_MBR_OFFSET_TABLE_0;
0281   sc = rtems_bdpart_read_mbr_partition( data, &p, p_end, &ep_begin);
0282   if (sc != RTEMS_SUCCESSFUL) {
0283     esc = sc;
0284     goto cleanup;
0285   }
0286 
0287   /* Determine if we have a MBR or GPT format */
0288   if (rtems_bdpart_mbr_partition_type( p->type) == RTEMS_BDPART_MBR_GPT) {
0289     esc = RTEMS_NOT_IMPLEMENTED;
0290     goto cleanup;
0291   }
0292 
0293   /* Set format */
0294   format->type = RTEMS_BDPART_FORMAT_MBR;
0295   format->mbr.disk_id = rtems_uint32_from_little_endian(
0296     block->buffer + RTEMS_BDPART_MBR_OFFSET_DISK_ID
0297   );
0298   format->mbr.dos_compatibility = true;
0299 
0300   /* Iterate through the rest of the primary partition table */
0301   for (i = 1; i < 4; ++i) {
0302     data += RTEMS_BDPART_MBR_TABLE_ENTRY_SIZE;
0303 
0304     sc = rtems_bdpart_read_mbr_partition( data, &p, p_end, &ep_begin);
0305     if (sc != RTEMS_SUCCESSFUL) {
0306       esc = sc;
0307       goto cleanup;
0308     }
0309   }
0310 
0311   /* Iterate through the logical partitions within the extended partition */
0312   ebr = ep_begin;
0313   while (ebr != 0) {
0314     rtems_blkdev_bnum tmp = 0;
0315 
0316     /* Read EBR */
0317     sc = rtems_bdpart_read_record( dd, ebr, &block);
0318     if (sc != RTEMS_SUCCESSFUL) {
0319       esc = sc;
0320       goto cleanup;
0321     }
0322 
0323     /* Read first partition entry */
0324     sc = rtems_bdpart_read_mbr_partition(
0325       block->buffer + RTEMS_BDPART_MBR_OFFSET_TABLE_0,
0326       &p,
0327       p_end,
0328       NULL
0329     );
0330     if (sc != RTEMS_SUCCESSFUL) {
0331       esc = sc;
0332       goto cleanup;
0333     }
0334 
0335     /* Adjust partition begin */
0336     tmp = p->begin + ebr;
0337     if (tmp > p->begin) {
0338       p->begin = tmp;
0339     } else {
0340       esc = RTEMS_IO_ERROR;
0341       goto cleanup;
0342     }
0343 
0344     /* Adjust partition end */
0345     tmp = p->end + ebr;
0346     if (tmp > p->end) {
0347       p->end = tmp;
0348     } else {
0349       esc = RTEMS_IO_ERROR;
0350       goto cleanup;
0351     }
0352 
0353     /* Read second partition entry for next EBR block */
0354     ebr = rtems_bdpart_next_ebr(
0355       block->buffer + RTEMS_BDPART_MBR_OFFSET_TABLE_1
0356     );
0357     if (ebr != 0) {
0358       /* Adjust partition EBR block index */
0359       tmp = ebr + ep_begin;
0360       if (tmp > ebr) {
0361         ebr = tmp;
0362       } else {
0363         esc = RTEMS_IO_ERROR;
0364         goto cleanup;
0365       }
0366     }
0367   }
0368 
0369   /* Return partition count */
0370   *count = (size_t) (p - pt + 1);
0371 
0372 cleanup:
0373 
0374   if (fd >= 0) {
0375     close( fd);
0376   }
0377 
0378   if (block != NULL) {
0379     rtems_bdbuf_release( block);
0380   }
0381 
0382   return esc;
0383 }