@ -5,6 +5,9 @@
* uses parts of afdisk
* Copyright ( C ) 2002 by David Roetzel < david @ roetzel . de >
*
* UUID / GUID definition stolen from kernel / include / uapi / linux / uuid . h
* Copyright ( C ) 2010 , Intel Corp . Huang Ying < ying . huang @ intel . com >
*
* This program is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
@ -29,17 +32,69 @@
# include <stdint.h>
# include <stdbool.h>
# include <ctype.h>
# include <inttypes.h>
# include <fcntl.h>
# include <stdint.h>
# include "cyg_crc.h"
# if __BYTE_ORDER == __BIG_ENDIAN
# define cpu_to_le16(x) bswap_16(x)
# define cpu_to_le32(x) bswap_32(x)
# define cpu_to_le64(x) bswap_64(x)
# elif __BYTE_ORDER == __LITTLE_ENDIAN
# define cpu_to_le16(x) (x)
# define cpu_to_le32(x) (x)
# define cpu_to_le64(x) (x)
# else
# error unknown endianness!
# endif
# define swap(a, b) \
do { typeof ( a ) __tmp = ( a ) ; ( a ) = ( b ) ; ( b ) = __tmp ; } while ( 0 )
typedef struct {
uint8_t b [ 16 ] ;
} guid_t ;
# define GUID_INIT(a, b, c, d0, d1, d2, d3, d4, d5, d6, d7) \
( ( guid_t ) \
{ { ( a ) & 0xff , ( ( a ) > > 8 ) & 0xff , ( ( a ) > > 16 ) & 0xff , ( ( a ) > > 24 ) & 0xff , \
( b ) & 0xff , ( ( b ) > > 8 ) & 0xff , \
( c ) & 0xff , ( ( c ) > > 8 ) & 0xff , \
( d0 ) , ( d1 ) , ( d2 ) , ( d3 ) , ( d4 ) , ( d5 ) , ( d6 ) , ( d7 ) } } )
# define GUID_STRING_LENGTH 36
# define GPT_SIGNATURE 0x5452415020494645ULL
# define GPT_REVISION 0x00010000
# define GUID_PARTITION_SYSTEM \
GUID_INIT ( 0xC12A7328 , 0xF81F , 0x11d2 , \
0xBA , 0x4B , 0x00 , 0xA0 , 0xC9 , 0x3E , 0xC9 , 0x3B )
# define GUID_PARTITION_BASIC_DATA \
GUID_INIT ( 0xEBD0A0A2 , 0xB9E5 , 0x4433 , \
0x87 , 0xC0 , 0x68 , 0xB6 , 0xB7 , 0x26 , 0x99 , 0xC7 )
# define GUID_PARTITION_BIOS_BOOT \
GUID_INIT ( 0x21686148 , 0x6449 , 0x6E6F , \
0x74 , 0x4E , 0x65 , 0x65 , 0x64 , 0x45 , 0x46 , 0x49 )
# define GPT_HEADER_SIZE 92
# define GPT_ENTRY_SIZE 128
# define GPT_ENTRY_MAX 128
# define GPT_ENTRY_NAME_SIZE 72
# define GPT_HEADER_SECTOR 1
# define GPT_FIRST_ENTRY_SECTOR 2
# define MBR_ENTRY_MAX 4
# define MBR_DISK_SIGNATURE_OFFSET 440
# define MBR_PARTITION_ENTRY_OFFSET 446
# define MBR_BOOT_SIGNATURE_OFFSET 510
# define DISK_SECTOR_SIZE 512
/* Partition table entry */
struct pte {
uint8_t active ;
@ -55,13 +110,43 @@ struct partinfo {
int type ;
} ;
/* GPT Partition table header */
struct gpth {
uint64_t signature ;
uint32_t revision ;
uint32_t size ;
uint32_t crc32 ;
uint32_t reserved ;
uint64_t self ;
uint64_t alternate ;
uint64_t first_usable ;
uint64_t last_usable ;
guid_t disk_guid ;
uint64_t first_entry ;
uint32_t entry_num ;
uint32_t entry_size ;
uint32_t entry_crc32 ;
} __attribute__ ( ( packed ) ) ;
/* GPT Partition table entry */
struct gpte {
guid_t type ;
guid_t guid ;
uint64_t start ;
uint64_t end ;
uint64_t attr ;
char name [ GPT_ENTRY_NAME_SIZE ] ;
} __attribute__ ( ( packed ) ) ;
int verbose = 0 ;
int active = 1 ;
int heads = - 1 ;
int sectors = - 1 ;
int kb_align = 0 ;
bool ignore_null_sized_partition = false ;
struct partinfo parts [ 4 ] ;
bool use_guid_partition_table = false ;
struct partinfo parts [ GPT_ENTRY_MAX ] ;
char * filename = NULL ;
@ -91,7 +176,7 @@ static long to_kbytes(const char *string)
end + + ;
if ( * end ) {
fp rintf( stderr , " garbage after end of number \n " ) ;
fp uts( " garbage after end of number \n " , stderr ) ;
return 0 ;
}
@ -132,20 +217,73 @@ static inline unsigned long round_to_kb(long sect) {
return ( ( sect - 1 ) / kb_align + 1 ) * kb_align ;
}
/* Compute a CRC for guid partition table */
static inline unsigned long gpt_crc32 ( void * buf , unsigned long len )
{
return cyg_crc32_accumulate ( ~ 0L , buf , len ) ^ ~ 0L ;
}
/* Parse a guid string to guid_t struct */
static inline int guid_parse ( char * buf , guid_t * guid )
{
char b [ 4 ] = { 0 } ;
char * p = buf ;
unsigned i = 0 ;
if ( strnlen ( buf , GUID_STRING_LENGTH ) ! = GUID_STRING_LENGTH )
return - 1 ;
for ( i = 0 ; i < sizeof ( guid_t ) ; i + + ) {
if ( * p = = ' - ' )
p + + ;
if ( * p = = ' \0 ' )
return - 1 ;
memcpy ( b , p , 2 ) ;
guid - > b [ i ] = strtol ( b , 0 , 16 ) ;
p + = 2 ;
}
swap ( guid - > b [ 0 ] , guid - > b [ 3 ] ) ;
swap ( guid - > b [ 1 ] , guid - > b [ 2 ] ) ;
swap ( guid - > b [ 4 ] , guid - > b [ 5 ] ) ;
swap ( guid - > b [ 6 ] , guid - > b [ 7 ] ) ;
return 0 ;
}
/* init an utf-16 string from utf-8 string */
static inline void init_utf16 ( char * str , uint16_t * buf , unsigned bufsize )
{
unsigned i , n = 0 ;
for ( i = 0 ; i < bufsize ; i + + ) {
if ( str [ n ] = = 0x00 ) {
buf [ i ] = 0x00 ;
return ;
} else if ( ( str [ n ] & 0x80 ) = = 0x00 ) { //0xxxxxxx
buf [ i ] = cpu_to_le16 ( str [ n + + ] ) ;
} else if ( ( str [ n ] & 0xE0 ) = = 0xC0 ) { //110xxxxx
buf [ i ] = cpu_to_le16 ( ( str [ n ] & 0x1F ) < < 6 | ( str [ n + 1 ] & 0x3F ) ) ;
n + = 2 ;
} else if ( ( str [ n ] & 0xF0 ) = = 0xE0 ) { //1110xxxx
buf [ i ] = cpu_to_le16 ( ( str [ n ] & 0x0F ) < < 12 | ( str [ n + 1 ] & 0x3F ) < < 6 | ( str [ n + 2 ] & 0x3F ) ) ;
n + = 3 ;
} else {
buf [ i ] = cpu_to_le16 ( ' ? ' ) ;
n + + ;
}
}
}
/* check the partition sizes and write the partition table */
static int gen_ptable ( uint32_t signature , int nr )
{
struct pte pte [ 4 ] ;
unsigned long sect = 0 ;
int i , fd , ret = - 1 , start , len ;
struct pte pte [ MBR_ENTRY_MAX ] ;
unsigned long s tart, len , s ect = 0 ;
int i , fd , ret = - 1 ;
memset ( pte , 0 , sizeof ( struct pte ) * 4 ) ;
memset ( pte , 0 , sizeof ( struct pte ) * MBR_ENTRY_MAX ) ;
for ( i = 0 ; i < nr ; i + + ) {
if ( ! parts [ i ] . size ) {
if ( ignore_null_sized_partition )
continue ;
fprintf ( stderr , " Invalid size in partition %d! \n " , i ) ;
return - 1 ;
return ret ;
}
pte [ i ] . active = ( ( i + 1 ) = = active ) ? 0x80 : 0 ;
@ -165,32 +303,175 @@ static int gen_ptable(uint32_t signature, int nr)
to_chs ( start + len - 1 , pte [ i ] . chs_end ) ;
if ( verbose )
fprintf ( stderr , " Partition %d: start=%ld, end=%ld, size=%ld \n " , i , ( long ) start * 512 , ( ( long ) start + ( long ) len ) * 512 , ( long ) len * 512 ) ;
printf ( " %ld \n " , ( long ) start * 512 ) ;
printf ( " %ld \n " , ( long ) len * 512 ) ;
fprintf ( stderr , " Partition %d: start=%ld, end=%ld, size=%ld \n " ,
i ,
( long ) start * DISK_SECTOR_SIZE ,
( long ) ( start + len ) * DISK_SECTOR_SIZE ,
( long ) len * DISK_SECTOR_SIZE ) ;
printf ( " %ld \n " , ( long ) start * DISK_SECTOR_SIZE ) ;
printf ( " %ld \n " , ( long ) len * DISK_SECTOR_SIZE ) ;
}
if ( ( fd = open ( filename , O_WRONLY | O_CREAT | O_TRUNC , 0644 ) ) < 0 ) {
fprintf ( stderr , " Can't open output file '%s' \n " , filename ) ;
return - 1 ;
return ret ;
}
lseek ( fd , MBR_DISK_SIGNATURE_OFFSET , SEEK_SET ) ;
if ( write ( fd , & signature , sizeof ( signature ) ) ! = sizeof ( signature ) ) {
fputs ( " write failed. \n " , stderr ) ;
goto fail ;
}
lseek ( fd , MBR_PARTITION_ENTRY_OFFSET , SEEK_SET ) ;
if ( write ( fd , pte , sizeof ( struct pte ) * MBR_ENTRY_MAX ) ! = sizeof ( struct pte ) * MBR_ENTRY_MAX ) {
fputs ( " write failed. \n " , stderr ) ;
goto fail ;
}
lseek ( fd , MBR_BOOT_SIGNATURE_OFFSET , SEEK_SET ) ;
if ( write ( fd , " \x55 \xaa " , 2 ) ! = 2 ) {
fputs ( " write failed. \n " , stderr ) ;
goto fail ;
}
ret = 0 ;
fail :
close ( fd ) ;
return ret ;
}
/* check the partition sizes and write the guid partition table */
static int gen_gptable ( uint32_t signature , guid_t guid , unsigned nr )
{
struct pte pte ;
struct gpth gpth = {
. signature = cpu_to_le64 ( GPT_SIGNATURE ) ,
. revision = cpu_to_le32 ( GPT_REVISION ) ,
. size = cpu_to_le32 ( GPT_HEADER_SIZE ) ,
. self = cpu_to_le64 ( GPT_HEADER_SECTOR ) ,
. first_usable = cpu_to_le64 ( GPT_FIRST_ENTRY_SECTOR + GPT_ENTRY_SIZE * GPT_ENTRY_MAX / DISK_SECTOR_SIZE ) ,
. first_entry = cpu_to_le64 ( GPT_FIRST_ENTRY_SECTOR ) ,
. disk_guid = guid ,
. entry_num = cpu_to_le32 ( GPT_ENTRY_MAX ) ,
. entry_size = cpu_to_le32 ( GPT_ENTRY_SIZE ) ,
} ;
struct gpte gpte [ GPT_ENTRY_MAX ] ;
uint64_t start , end , sect = 0 ;
int fd , ret = - 1 ;
unsigned i ;
memset ( gpte , 0 , GPT_ENTRY_SIZE * GPT_ENTRY_MAX ) ;
for ( i = 0 ; i < nr ; i + + ) {
if ( ! parts [ i ] . size ) {
if ( ignore_null_sized_partition )
continue ;
fprintf ( stderr , " Invalid size in partition %d! \n " , i ) ;
return ret ;
}
start = sect + sectors ;
if ( kb_align ! = 0 )
start = round_to_kb ( start ) ;
gpte [ i ] . start = cpu_to_le64 ( start ) ;
sect = start + parts [ i ] . size * 2 ;
if ( kb_align = = 0 )
sect = round_to_cyl ( sect ) ;
gpte [ i ] . end = cpu_to_le64 ( sect - 1 ) ;
gpte [ i ] . guid = guid ;
gpte [ i ] . guid . b [ sizeof ( guid_t ) - 1 ] + = i + 1 ;
if ( parts [ i ] . type = = 0xEF | | ( i + 1 ) = = ( unsigned ) active ) {
gpte [ i ] . type = GUID_PARTITION_SYSTEM ;
init_utf16 ( " EFI System Partition " , ( uint16_t * ) gpte [ i ] . name , GPT_ENTRY_NAME_SIZE / sizeof ( uint16_t ) ) ;
} else {
gpte [ i ] . type = GUID_PARTITION_BASIC_DATA ;
}
if ( verbose )
fprintf ( stderr , " Partition %d: start=% " PRIu64 " , end=% " PRIu64 " , size=% " PRIu64 " \n " ,
i ,
start * DISK_SECTOR_SIZE , sect * DISK_SECTOR_SIZE ,
( sect - start ) * DISK_SECTOR_SIZE ) ;
printf ( " % " PRIu64 " \n " , start * DISK_SECTOR_SIZE ) ;
printf ( " % " PRIu64 " \n " , ( sect - start ) * DISK_SECTOR_SIZE ) ;
}
gpte [ GPT_ENTRY_MAX - 1 ] . start = cpu_to_le64 ( GPT_FIRST_ENTRY_SECTOR + GPT_ENTRY_SIZE * GPT_ENTRY_MAX / DISK_SECTOR_SIZE ) ;
gpte [ GPT_ENTRY_MAX - 1 ] . end = cpu_to_le64 ( ( kb_align ? round_to_kb ( sectors ) : ( unsigned long ) sectors ) - 1 ) ;
gpte [ GPT_ENTRY_MAX - 1 ] . type = GUID_PARTITION_BIOS_BOOT ;
gpte [ GPT_ENTRY_MAX - 1 ] . guid = guid ;
gpte [ GPT_ENTRY_MAX - 1 ] . guid . b [ sizeof ( guid_t ) - 1 ] + = GPT_ENTRY_MAX ;
end = sect + sectors - 1 ;
pte . type = 0xEE ;
pte . start = cpu_to_le32 ( GPT_HEADER_SECTOR ) ;
pte . length = cpu_to_le32 ( end ) ;
to_chs ( GPT_HEADER_SECTOR , pte . chs_start ) ;
to_chs ( end , pte . chs_end ) ;
gpth . last_usable = cpu_to_le64 ( end - GPT_ENTRY_SIZE * GPT_ENTRY_MAX / DISK_SECTOR_SIZE - 1 ) ;
gpth . alternate = cpu_to_le64 ( end ) ;
gpth . entry_crc32 = cpu_to_le32 ( gpt_crc32 ( gpte , GPT_ENTRY_SIZE * GPT_ENTRY_MAX ) ) ;
gpth . crc32 = cpu_to_le32 ( gpt_crc32 ( ( char * ) & gpth , GPT_HEADER_SIZE ) ) ;
if ( ( fd = open ( filename , O_WRONLY | O_CREAT | O_TRUNC , 0644 ) ) < 0 ) {
fprintf ( stderr , " Can't open output file '%s' \n " , filename ) ;
return ret ;
}
lseek ( fd , 440 , SEEK_SET ) ;
lseek ( fd , MBR_DISK_SIGNATURE_OFFSET , SEEK_SET ) ;
if ( write ( fd , & signature , sizeof ( signature ) ) ! = sizeof ( signature ) ) {
fprintf ( stderr , " write failed. \n " ) ;
fp uts( " write failed. \n " , stderr ) ;
goto fail ;
}
lseek ( fd , 446 , SEEK_SET ) ;
if ( write ( fd , pte , sizeof ( struct pte ) * 4 ) ! = sizeof ( struct pte ) * 4 ) {
fprintf ( stderr , " write failed. \n " ) ;
lseek ( fd , MBR_PARTITION_ENTRY_OFFSET , SEEK_SET ) ;
if ( write ( fd , & pte , sizeof ( struct pte ) ) ! = sizeof ( struct pte ) ) {
fp uts( " write failed. \n " , stderr ) ;
goto fail ;
}
lseek ( fd , 510 , SEEK_SET ) ;
lseek ( fd , MBR_BOOT_SIGNATURE_OFFSET , SEEK_SET ) ;
if ( write ( fd , " \x55 \xaa " , 2 ) ! = 2 ) {
fprintf ( stderr , " write failed. \n " ) ;
fputs ( " write failed. \n " , stderr ) ;
goto fail ;
}
if ( write ( fd , & gpth , GPT_HEADER_SIZE ) ! = GPT_HEADER_SIZE ) {
fputs ( " write failed. \n " , stderr ) ;
goto fail ;
}
lseek ( fd , GPT_FIRST_ENTRY_SECTOR * DISK_SECTOR_SIZE , SEEK_SET ) ;
if ( write ( fd , & gpte , GPT_ENTRY_SIZE * GPT_ENTRY_MAX ) ! = GPT_ENTRY_SIZE * GPT_ENTRY_MAX ) {
fputs ( " write failed. \n " , stderr ) ;
goto fail ;
}
# ifdef WANT_ALTERNATE_PTABLE
/* The alternate partition table (We omit it by default) */
swap ( gpth . self , gpth . alternate ) ;
gpth . first_entry = cpu_to_le64 ( end - GPT_ENTRY_SIZE * GPT_ENTRY_MAX / DISK_SECTOR_SIZE ) ,
gpth . crc32 = 0 ;
gpth . crc32 = cpu_to_le32 ( gpt_crc32 ( & gpth , GPT_HEADER_SIZE ) ) ;
lseek ( fd , end * DISK_SECTOR_SIZE - GPT_ENTRY_SIZE * GPT_ENTRY_MAX , SEEK_SET ) ;
if ( write ( fd , & gpte , GPT_ENTRY_SIZE * GPT_ENTRY_MAX ) ! = GPT_ENTRY_SIZE * GPT_ENTRY_MAX ) {
fputs ( " write failed. \n " , stderr ) ;
goto fail ;
}
lseek ( fd , end * DISK_SECTOR_SIZE , SEEK_SET ) ;
if ( write ( fd , & gpth , GPT_HEADER_SIZE ) ! = GPT_HEADER_SIZE ) {
fputs ( " write failed. \n " , stderr ) ;
goto fail ;
}
lseek ( fd , ( end + 1 ) * DISK_SECTOR_SIZE - 1 , SEEK_SET ) ;
if ( write ( fd , " \x00 " , 1 ) ! = 1 ) {
fputs ( " write failed. \n " , stderr ) ;
goto fail ;
}
# endif
ret = 0 ;
fail :
@ -200,18 +481,20 @@ fail:
static void usage ( char * prog )
{
fprintf ( stderr , " Usage: %s [-v] [-n] -h <heads> -s <sectors> -o <outputfile> [-a 0..4] [-l <align kB>] [[-t <type>] -p <size>...] \n " , prog ) ;
fprintf ( stderr , " Usage: %s [-v] [-n] [-g] -h <heads> -s <sectors> -o <outputfile> [-a 0..4] [-l <align kB>] [-G <guid >] [[-t <type>] -p <size>...] \n " , prog ) ;
exit ( EXIT_FAILURE ) ;
}
int main ( int argc , char * * argv )
{
char type = 0x83 ;
unsigned char type = 0x83 ;
int ch ;
int part = 0 ;
uint32_t signature = 0x5452574F ; /* 'OWRT' */
guid_t guid = GUID_INIT ( signature , 0x2211 , 0x4433 , \
0x55 , 0x66 , 0x77 , 0x88 , 0x99 , 0xAA , 0xBB , 0x00 ) ;
while ( ( ch = getopt ( argc , argv , " h:s:p:a:t:o:vnl:S: " ) ) ! = - 1 ) {
while ( ( ch = getopt ( argc , argv , " h:s:p:a:t:o:vn g l:S:G :" ) ) ! = - 1 ) {
switch ( ch ) {
case ' o ' :
filename = optarg ;
@ -222,6 +505,9 @@ int main (int argc, char **argv)
case ' n ' :
ignore_null_sized_partition = true ;
break ;
case ' g ' :
use_guid_partition_table = 1 ;
break ;
case ' h ' :
heads = ( int ) strtoul ( optarg , NULL , 0 ) ;
break ;
@ -229,8 +515,8 @@ int main (int argc, char **argv)
sectors = ( int ) strtoul ( optarg , NULL , 0 ) ;
break ;
case ' p ' :
if ( part > 3 ) {
fp rintf( stderr , " Too many partitions \n " ) ;
if ( part > GPT_ENTRY_MAX - 1 | | ( ! use_guid_partition_table & & part > 3 ) ) {
fp uts( " Too many partitions \n " , stderr ) ;
exit ( EXIT_FAILURE ) ;
}
parts [ part ] . size = to_kbytes ( optarg ) ;
@ -250,6 +536,12 @@ int main (int argc, char **argv)
case ' S ' :
signature = strtoul ( optarg , NULL , 0 ) ;
break ;
case ' G ' :
if ( guid_parse ( optarg , & guid ) ) {
fputs ( " Invalid guid string \n " , stderr ) ;
exit ( EXIT_FAILURE ) ;
}
break ;
case ' ? ' :
default :
usage ( argv [ 0 ] ) ;
@ -259,5 +551,8 @@ int main (int argc, char **argv)
if ( argc | | ( heads < = 0 ) | | ( sectors < = 0 ) | | ! filename )
usage ( argv [ 0 ] ) ;
if ( use_guid_partition_table )
return gen_gptable ( signature , guid , part ) ? EXIT_FAILURE : EXIT_SUCCESS ;
return gen_ptable ( signature , part ) ? EXIT_FAILURE : EXIT_SUCCESS ;
}