/* OSX CLI Blesser Copyright (C) 2002 Eric C Wagner 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 (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. **************************************************************************/ /* Program return format is ##: string string Done where ## is as follows and string is a status string an optional string follows with additional info Done signifies the output is compete 0: Blessing was successful 1: Format type is Tivo 2: Format type is PC Linux 3: Format type is DOS 4: Format type is Mac 9: Format type is unknown key value as hex 10: Drive too small 11: Couldn't open drive errno value as int 12: Number partitions */ #include #include #include #include /* minimum of one gig for MFS partition */ #define minMFSSize 1024*1024*2 typedef unsigned long UInt32; typedef unsigned short UInt16; typedef unsigned char UInt8; typedef signed long SInt32; typedef signed short SInt16; typedef signed char SInt8; struct dpme { UInt16 dpme_signature ; UInt16 dpme_reserved_1 ; UInt32 dpme_map_entries ; UInt32 dpme_pblock_start ; UInt32 dpme_pblocks ; SInt8 dpme_name[32] ; /* name of partition */ SInt8 dpme_type[32] ; /* type of partition */ UInt32 dpme_lblock_start ; UInt32 dpme_lblocks ; UInt32 dpme_flags ; UInt32 dpme_boot_block ; UInt32 dpme_boot_bytes ; UInt8 *dpme_load_addr ; UInt8 *dpme_load_addr_2 ; UInt8 *dpme_goto_addr ; UInt8 *dpme_goto_addr_2 ; UInt32 dpme_checksum ; SInt8 dpme_process_id[16] ; UInt32 dpme_boot_args[32] ; UInt32 dpme_reserved_3[62] ; }; typedef struct dpme DPME; void noDrive(void); int CheckPriorFormat(FILE *); void ListPartitions(FILE*); void WriteBlockZero(FILE *); void WriteSignature(FILE *, UInt32); UInt32 WritePartitionMap(UInt32 numXPartitions, UInt32 XPartSizes[], char* XPartNames[], char* XPartTypes[], UInt32 driveSize, FILE* ); void usage(char*); char unixType[] = "Apple_UNIX_SRV2"; char typeName1[] = "swap"; char typeName2[] = "ext2"; int main(int argc,char *argv[]) { char *device; /* device path */ UInt32 dsize; /* number of blocks in device */ char **etype; /* extra type names */ char **ename; /* extra partition names */ UInt32 *esize; /* extra type sizes */ UInt32 i, j, num, extraSizeTotal; UInt32 MFSMediaStart; FILE *drive; /* the harddrive in question */ int checkFormat, checkPartitions; /* check for correct number of arguments */ if( (argc%2) != 1 || argc < 3) usage(argv[0]); dsize = atol(argv[2]); checkFormat = !strcmp(argv[2],"priorFormat"); checkPartitions = !strcmp(argv[2],"partitions"); if(argc==3 && (checkFormat || checkPartitions)) { drive = fopen(argv[1], "rb"); if(!drive) noDrive(); if( (CheckPriorFormat(drive)==1) && checkPartitions) ListPartitions(drive); exit(0); } drive = fopen(argv[1], "wb"); if(!drive) noDrive(); if(!dsize) usage(argv[0]); /* read in the extra partitions */ num = (argc-3)/2; extraSizeTotal = 0; if(num) { etype = (char**)malloc(sizeof(char*)*num); esize = (unsigned long*)malloc(sizeof(unsigned long)*num); ename = (char**)malloc(sizeof(char*)*num); for(i=3, j=0; i dsize) { printf("10: Error, drive is to small for selected options\n"); printf("Done\n"); return -2; } /* Write block zero */ WriteBlockZero(drive); /* Write the Partition Map */ MFSMediaStart = WritePartitionMap(num, esize, ename, etype, dsize, drive); /* Bless the disk */ WriteSignature(drive, MFSMediaStart); /* return gracefully */ fclose(drive); printf("0: Blessing Successful\nDone\n"); return 0; } void noDrive() { printf("11: Error, couldn't open drive\n" "%i\n", errno); printf("Done\n"); exit( -11); } inline UInt32 byteReverse(register UInt32 *value) { register UInt32 output; asm ("lwbrx %0,0,%1" : "=r"(output):"r"(value)); asm ("rotrwi %0,%1,16": "=r"(output):"r"(output)); return output; } UInt32* ByteSwap(UInt32* data, UInt32 *length) { /* creates a new data block with the endian 2byte reversed */ /* try to make sure the alignment of the data block is on a 4 byte boundary or this will go very slow */ UInt32 i; UInt32 *dataOut, *marker; *length += (4-(*length%4)); marker = dataOut = calloc(*length,1); for(i=0;i<*length; i+=4, data++,marker++) { *marker = byteReverse(data); } return dataOut; } void WriteSignature(FILE *drive, UInt32 MFS_Start) { char *sig[] = {"Add-on media file system disk, copyright TiVo Inc. 1999.", "TiVo\6\13\143\0", "asccd"}; UInt32 *data; UInt32 offsets[] = {0x07B00000, 0x1C6AA390, 0x30F9D8FC}; UInt32 i; UInt32 length; for (i=0; i<3; i++ ) { fseek(drive,offsets[i] + MFS_Start,SEEK_SET); length = strlen(sig[i])+1; /* make sure the null is included */ data = ByteSwap((UInt32*)sig[i], &length); fwrite(data, 1, length, drive); free(data); } } void WriteBlockZero(FILE *drive) { int i; unsigned long bytesWritten; struct { UInt16 signature; UInt8 pKernelPartition; UInt8 aKernelPartition; UInt8 BootParams[128]; UInt8 Hostname[32]; UInt32 IPaddress; UInt8 MACaddress[6]; UInt8 undefined[338]; } diskHeader = {0}; UInt32* data; diskHeader.signature = 0x1492; diskHeader.pKernelPartition = 3; diskHeader.aKernelPartition = 6; strcpy((char*)diskHeader.BootParams, (const char*)"root=/dev/hdb4"); strcpy((char*)diskHeader.Hostname, (const char*)"unnamed"); diskHeader.IPaddress = 0x0ABCDEF0; for(i=0;i<6;i++) diskHeader.MACaddress[i] = i+1; bytesWritten = sizeof(diskHeader); data = ByteSwap((UInt32*)&diskHeader, &bytesWritten); fseek(drive, 0, SEEK_SET); fwrite(data, 1, bytesWritten, drive); free(data); } void usage(char* name) { printf("Use the program as follows:\n" "%s device devicesize extratype extrasize ...\n" "\t where device is the drive you wish to bless,\n" "\t devicesize is the number of blocks the device has,\n" "\t extratype is the type of partition you wish to\n" "\t\tadd of size extrasize. Multiple partitions are allowed.\n\n" "Valid types recognized are %s and %s. If you\n" "enter something else the partition will be named\n" "that and will probably not work unless you know\n" "what you are doing.\n" "Note: this version doesn't format the extra partitions\n\n" "Version 1.0\n" "Copyright 2002\n" , name, typeName1, typeName2); exit(0); } int CheckPriorFormat(FILE *device) { /* checks the current format of the device */ UInt32 key; fseek(device, 0, SEEK_SET); fread( &key, 1, sizeof(key), device); if((key>>16)== 0x9214) { printf("1: Tivo\nDone\n"); return 1; } if( (0x00FF&(key>>16))==0xFA) { printf("2: PC Linux\nDone\n"); return 2; } if( (key&0xFFFF00FF) == 0xC033008E) { printf("3: DOS\nDone\n"); return 3; } if( (key>>16)==0x4552) { printf("4: Mac\nDone\n"); return 4; } printf("9: Unknown format type\n0x%X\nDone\n", key); return 9; } void ListPartitions(FILE* drive){ DPME *partition, *swapped; UInt32 i=1,numPartitions; UInt32 blockSize = sizeof(DPME); char fmtString[] = "|%32.32s|%32.32s|%d|%d|\n"; partition = calloc(1, sizeof(DPME)); fseek(drive, 512, SEEK_SET); fread(partition, sizeof(DPME), 1, drive); swapped = (DPME*)ByteSwap((UInt32*)partition, &blockSize); numPartitions = swapped->dpme_map_entries; printf("12: %d Partitions\n", numPartitions+1); printf(fmtString, "Boot Block", "Tivo", 1, 0); printf(fmtString,swapped->dpme_name, swapped->dpme_type, swapped->dpme_pblocks, swapped->dpme_pblock_start); free(partition); free(swapped); while(idpme_name, swapped->dpme_type, swapped->dpme_pblocks, swapped->dpme_pblock_start); free(swapped); } printf("Done, for real this time\n"); } UInt32 WritePartitionMap(UInt32 numXPartitions, UInt32 XPartSizes[], char* XPartNames[], char* XPartTypes[], UInt32 driveSize, FILE *drive ){ DPME *partition; UInt32 *writable; UInt32 bytesWritten; UInt32 numPartitions = 3+numXPartitions; UInt32 mediaSize; UInt32 i; UInt32 MFSMediaStart; UInt32 currentBlock=1; /* the partition partition */ bytesWritten=sizeof(DPME); partition = calloc(1, sizeof(DPME)); partition->dpme_signature = 0x504D; partition->dpme_map_entries = numPartitions; partition->dpme_pblock_start = currentBlock; partition->dpme_pblocks = 3+numXPartitions; strcpy((char*)partition->dpme_name, (const char*)"Apple"); strcpy((char*)partition->dpme_type, (const char*)"Apple_partition_map"); partition->dpme_lblocks = 3+numXPartitions; partition->dpme_flags = 0x00000033; /* valid, allocated, readable, writable */ currentBlock += (3+numXPartitions); writable = ByteSwap((UInt32*)partition, &bytesWritten); free(partition); fseek(drive, 512, SEEK_SET); fwrite(writable, bytesWritten-4,1, drive); free(writable); /* the MFS App Partition */ bytesWritten=sizeof(DPME); partition = calloc(1, sizeof(DPME)); partition->dpme_signature = 0x504D; partition->dpme_map_entries = numPartitions; partition->dpme_pblock_start = currentBlock; partition->dpme_pblocks = 8192; /* 8192 * 0.5k = 4 Meg */ strcpy((char*)partition->dpme_name, (const char*)"Second MFS application region"); strcpy((char*)partition->dpme_type, (const char*)"MFS"); partition->dpme_lblocks = 8192; partition->dpme_flags = 0x00000033; /* valid, allocated, readable, writable */ currentBlock += 8192; writable = ByteSwap((UInt32*)partition, &bytesWritten); free(partition); fseek(drive, 2*512, SEEK_SET); fwrite(writable, bytesWritten-4,1, drive); free(writable); /* the MFS media Partition */ mediaSize = driveSize - currentBlock; for(i=0;idpme_signature = 0x504D; partition->dpme_map_entries = numPartitions; partition->dpme_pblock_start = currentBlock; MFSMediaStart = currentBlock * 512; partition->dpme_pblocks = mediaSize; strcpy((char*)partition->dpme_name, (const char*)"Second MFS media region"); strcpy((char*)partition->dpme_type, (const char*)"MFS"); partition->dpme_lblocks = mediaSize; partition->dpme_flags = 0x00000033; /* valid, allocated, readable, writable */ writable = ByteSwap((UInt32*)partition, &bytesWritten); free(partition); fseek(drive,3*512, SEEK_SET); fwrite(writable, bytesWritten-4,1, drive); free(writable); /* xtra partitions */ currentBlock += mediaSize; for(i=0;idpme_signature = 0x504D; partition->dpme_map_entries = numPartitions; partition->dpme_pblock_start = currentBlock; partition->dpme_pblocks = XPartSizes[i]; strcpy((char*)partition->dpme_name, XPartNames[i]); strcpy((char*)partition->dpme_type, XPartTypes[i]); partition->dpme_lblocks = XPartSizes[i]; partition->dpme_flags = 0x00000033; /* valid, allocated, readable, writable */ currentBlock += XPartSizes[i]; writable = ByteSwap((UInt32*)partition, &bytesWritten); free(partition); fseek(drive, (4+i)*512, SEEK_SET); fwrite(writable, bytesWritten-4,1, drive); free(writable); } return MFSMediaStart; }