diff options
Diffstat (limited to 'sbin')
44 files changed, 12343 insertions, 0 deletions
diff --git a/sbin/pdisk/ATA_media.c b/sbin/pdisk/ATA_media.c new file mode 100644 index 00000000000..533c6216e2e --- /dev/null +++ b/sbin/pdisk/ATA_media.c @@ -0,0 +1,1158 @@ +/* + * ATA_media.c - + * + * Written by Eryk Vershen (eryk@apple.com) + */ + +/* + * Copyright 1997,1998 by Apple Computer, Inc. + * All Rights Reserved + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appears in all copies and + * that both the copyright notice and this permission notice appear in + * supporting documentation. + * + * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, + * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION + * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + + +// for printf() +#include <stdio.h> +// for malloc() & free() +#include <stdlib.h> +#include <ATA.h> +// for SCSI command structures +#include "MacSCSICommand.h" +#include "ATA_media.h" +#include "util.h" + + +/* + * Defines + */ +#define RESULT_OFFSET(type) \ + ((sizeof(type) == 1) ? 3 : ((sizeof(type) == 2) ? 1 : 0)) +#define TBTrapTableAddress(trapNum) (((trapNum & 0x03FF) << 2) + 0xE00) +#define SWAP_SHORTS(x) ((((x) & 0xFFFF) << 16) | (((x) >> 16) & 0xFFFF)) +#define LBA_CAPABLE 0x0200 + + +/* + * Types + */ +typedef struct ATA_info *ATA_INFO; + +struct ATA_info { + long lba; + long heads; + long sectors; +}; + +typedef struct ATA_media *ATA_MEDIA; + +struct ATA_media { + struct media m; + long id; + struct ATA_info info; +}; + +struct ATA_manager { + long exists; + long kind; + struct { + char major; + char minor; + } version; + short busCount; +}; + +typedef struct ATA_media_iterator *ATA_MEDIA_ITERATOR; + +struct ATA_media_iterator { + struct media_iterator m; + long bus; + long id; +}; + +struct ATA_identify_drive_info { /* word */ + unsigned short config_bits; /* 0 */ + unsigned short num_cylinders; /* 1 */ + unsigned short reserved2; /* 2 */ + unsigned short num_heads; /* 3 */ + unsigned short bytes_per_track; /* 4 */ + unsigned short bytes_per_sector; /* 5 */ + unsigned short sectors_per_track; /* 6 */ + unsigned short vendor7[3]; /* 7-9 */ + char serial_number[20]; /* 10-19 */ + unsigned short buffer_type; /* 20 */ + unsigned short buffer_size; /* 21 */ + unsigned short num_of_ecc_bytes; /* 22 */ + char firmware_rev[8]; /* 23-26 */ + char model_number[40]; /* 27-46 */ + unsigned short word47; /* 47 */ + unsigned short double_word_io; /* 48 */ + unsigned short capabilities; /* 49 */ + unsigned short reserved50; /* 50 */ + unsigned short pio_timing; /* 51 */ + unsigned short dma_timing; /* 52 */ + unsigned short current_is_valid; /* 53 */ + unsigned short cur_cylinders; /* 54 */ + unsigned short cur_heads; /* 55 */ + unsigned short cur_sec_per_track; /* 56 */ + unsigned long total_sectors; /* 57-58 */ + unsigned short multiple_sectors; /* 59 */ + unsigned long lba_sectors; /* 60-61 */ + unsigned short singleword_dma; /* 62 */ + unsigned short multiword_dma; /* 63 */ + unsigned short reserved64[64]; /* 64-127 */ + unsigned short vendor128[32]; /* 128-159 */ + unsigned short reserved160[96]; /* 160-255 */ +}; + +struct ATAPI_identify_drive_info { /* word */ + unsigned short config_bits; /* 0 */ + unsigned short retired1[9]; /* 1-9 */ + char serial_number[20]; /* 10-19 */ + unsigned short retired20[3]; /* 20-22 */ + char firmware_rev[8]; /* 23-26 */ + char model_number[40]; /* 27-46 */ + unsigned short retired47[2]; /* 47-48 */ + unsigned short capabilities; /* 49 */ + unsigned short reserved50; /* 50 */ + unsigned short pio_timing; /* 51 */ + unsigned short dma_timing; /* 52 */ + unsigned short current_is_valid; /* 53 */ + unsigned short retired54[8]; /* 54-61 */ + unsigned short singleword_dma; /* 62 */ + unsigned short multiword_dma; /* 63 */ + unsigned short pio_transfer; /* 64 */ + unsigned short min_cycle_time; /* 65 */ + unsigned short rec_cycle_time; /* 66 */ + unsigned short min_wo_flow; /* 67 */ + unsigned short min_with_flow; /* 68 */ + unsigned short reserved69[2]; /* 69-70 */ + unsigned short release_over; /* 71 */ + unsigned short release_service; /* 72 */ + unsigned short major_rev; /* 73 */ + unsigned short minor_rev; /* 74 */ + unsigned short reserved75[53]; /* 75-127 */ + unsigned short vendor128[32]; /* 128-159 */ + unsigned short reserved160[96]; /* 160-255 */ +}; + +/* Identifies the bus protocol type. */ +enum { + kDevUnknown = 0, + kDevATA = 1, + kDevATAPI = 2, + kDevPCMCIA = 3 +}; + + +/* + * Global Constants + */ +enum { + kNoDevice = 0x00FF, + kATAtimeout = 3000, + kATAcmdATAPIPacket = 0x00A0 /* ATAPI packet command */ +}; + + +/* + * Global Variables + */ +static long ata_inited = 0; +static struct ATA_manager ata_mgr; + +/* + * Forward declarations + */ +int ATAManagerPresent(void); +int ATAHardwarePresent(void); +pascal SInt16 ataManager(ataPB *pb); +void ata_init(void); +ATA_MEDIA new_ata_media(void); +long read_ata_media(MEDIA m, long long offset, unsigned long count, void *address); +long write_ata_media(MEDIA m, long long offset, unsigned long count, void *address); +long close_ata_media(MEDIA m); +long os_reload_ata_media(MEDIA m); +long compute_id(long bus, long device); +pascal SInt16 ataManager(ataPB *pb); +int ATA_ReadBlock(UInt32 deviceID, ATA_INFO info, UInt32 block_size, UInt32 block, UInt8 *address); +int ATA_WriteBlock(UInt32 deviceID, ATA_INFO info, UInt32 block_size, UInt32 block, UInt8 *address); +long get_info(long id, struct ATA_identify_drive_info *ip); +long get_pi_info(long id, struct ATAPI_identify_drive_info *ip); +long is_atapi(long id); +long read_atapi_media(MEDIA m, long long offset, unsigned long count, void *address); +long write_atapi_media(MEDIA m, long long offset, unsigned long count, void *address); +int ATAPI_ReadBlock(UInt32 deviceID, UInt32 block_size, UInt32 block, UInt8 *address); +int ATAPI_TestUnitReady(UInt32 deviceID); +int ATAPI_ReadCapacity(UInt32 deviceID, unsigned long *block_size, unsigned long *blocks); +ATA_MEDIA_ITERATOR new_ata_iterator(void); +void reset_ata_iterator(MEDIA_ITERATOR m); +char *step_ata_iterator(MEDIA_ITERATOR m); +void delete_ata_iterator(MEDIA_ITERATOR m); + + +/* + * Routines + */ +#if GENERATINGPOWERPC +pascal SInt16 +ataManager(ataPB *pb) +{ + #ifdef applec + #if sizeof(SInt16) > 4 + #error "Result types larger than 4 bytes are not supported." + #endif + #endif + long private_result; + + private_result = CallUniversalProc( + *(UniversalProcPtr*)TBTrapTableAddress(0xAAF1), + kPascalStackBased + | RESULT_SIZE(SIZE_CODE(sizeof(SInt16))) + | STACK_ROUTINE_PARAMETER(1, SIZE_CODE(sizeof(pb))), + pb); + return *(((SInt16*)&private_result) + RESULT_OFFSET(SInt16)); +} +#endif + + +int +ATAHardwarePresent(void) +{ + UInt16 configFlags; + + // Hardware configuration flags + configFlags = LMGetHWCfgFlags(); + + return ((configFlags & 0x0080) != 0); +} + + +int +ATAManagerPresent(void) +{ + if (ATAHardwarePresent()) { + return (TrapAvailable(kATATrap)); + } else { + return 0; + } +} + +void +ata_init(void) +{ + ataMgrInquiry pb; + OSErr status; + + if (ata_inited != 0) { + return; + } + ata_inited = 1; + + if (ATAManagerPresent() == 0) { + ata_mgr.exists = 0; + return; + } + + ata_mgr.exists = 1; + ata_mgr.kind = allocate_media_kind(); + + clear_memory((void *)&pb, sizeof(pb)); + + pb.ataPBFunctionCode = kATAMgrManagerInquiry; + pb.ataPBVers = kATAPBVers1; + + status = ataManager((ataPB*) &pb ); + + if (status != noErr) { + ata_mgr.exists = 0; + return; + } + ata_mgr.version.major = pb.ataMgrVersion.majorRev; + ata_mgr.version.minor = pb.ataMgrVersion.minorAndBugRev >> 4; + ata_mgr.busCount = pb.ataBusCnt; +} + + +ATA_MEDIA +new_ata_media(void) +{ + return (ATA_MEDIA) new_media(sizeof(struct ATA_media)); +} + + +#pragma mark - + + +long +compute_id(long bus, long device) +{ + long id; + + id = -1; + if (ata_mgr.version.major < 3) { + if (device != 0) { + /* bad device id */ + } else if (bus >= ata_mgr.busCount) { + /* bad bus id */ + } else { + id = bus & 0xFF; + } + } else { + if (device < 0 || device > 1) { + /* bad device id */ + } else if (bus >= ata_mgr.busCount) { + /* bad bus id */ + } else { + id = ((device & 0xFF) << 8) | (bus & 0xFF); + } + } + return id; +} + + +static long +get_info(long id, struct ATA_identify_drive_info *ip) +{ + ataIdentify pb; + ataDevConfiguration pb2; + OSErr status; + long rtn_value; + long atapi; + + if (sizeof(struct ATA_identify_drive_info) < 512) { + return 0; + } + clear_memory((void *)ip, sizeof(struct ATA_identify_drive_info)); + + clear_memory((void *)&pb, sizeof(pb)); + pb.ataPBFunctionCode = kATAMgrDriveIdentify; + pb.ataPBVers = kATAPBVers1; + pb.ataPBDeviceID = id; + pb.ataPBFlags = mATAFlagIORead | mATAFlagByteSwap; + pb.ataPBTimeOut = kATAtimeout; + pb.ataPBBuffer = (void*) ip; + + status = ataManager((ataPB*) &pb ); + + if (status != noErr) { + //printf("get info status = %d\n", status); + rtn_value = 0; + } else { + ip->total_sectors = SWAP_SHORTS(ip->total_sectors); + ip->lba_sectors = SWAP_SHORTS(ip->lba_sectors); + rtn_value = 1; + } + return rtn_value; +} + + +static long +is_atapi(long id) +{ + ataDevConfiguration pb; + OSErr status; + long atapi; + + atapi = 0; + if (ata_mgr.version.major >= 2) { + clear_memory((void *)&pb, sizeof(pb)); + pb.ataPBFunctionCode = kATAMgrGetDrvConfiguration; + pb.ataPBVers = kATAPBVers2; + pb.ataPBDeviceID = id; + pb.ataPBTimeOut = kATAtimeout; + + status = ataManager((ataPB*) &pb ); + if (status != noErr) { + //printf("is atatpi status = %d\n", status); + } else if (pb.ataDeviceType == kDevATAPI) { + atapi = 1; + /* the drive can be asleep or something in which case this doesn't work */ + /* how do we do reads */ + } + } + return atapi; +} + + +MEDIA +open_ata_as_media(long bus, long device) +{ + ATA_MEDIA a; + long id; + struct ATA_identify_drive_info info; + unsigned char *buf; + unsigned long total; + + if (ata_inited == 0) { + ata_init(); + } + + if (ata_mgr.exists == 0) { + //printf("ATA manager does not exist\n"); + return 0; + } + + id = compute_id(bus, device); + + if (id < 0) { + return 0; + + } else if (is_atapi(id)) { + a = (ATA_MEDIA) open_atapi_as_media(bus, device); + + } else { + a = 0; + if (get_info(id, &info) != 0) { + a = new_ata_media(); + if (a != 0) { + a->m.kind = ata_mgr.kind; + if ((info.capabilities & LBA_CAPABLE) != 0) { + total = info.lba_sectors; + a->info.lba = 1; + a->info.heads = 0; + a->info.sectors = 0; + } else { + /* Only CHS - Cylinder Head Sector addressing */ + total = info.total_sectors; + a->info.lba = 0; + a->info.heads = info.cur_heads; + a->info.sectors = info.cur_sec_per_track; + } + if (info.bytes_per_sector == 0) { + buf = malloc(2048); + if (ATA_ReadBlock(id, &a->info, 512, 0, buf)) { + a->m.grain = 512; /* XXX not right */ + } else if (ATA_ReadBlock(id, &a->info, 2048, 0, buf)) { + a->m.grain = 2048; /* XXX not right */ + } + free(buf); + } else { + a->m.grain = info.bytes_per_sector; + } + if (total == 0) { + a->m.size_in_bytes = ((long long)1000) * a->m.grain; /* XXX not right */ + } else { + a->m.size_in_bytes = ((long long)total) * a->m.grain; + } + a->m.do_read = read_ata_media; + a->m.do_write = write_ata_media; + a->m.do_close = close_ata_media; + a->m.do_os_reload = os_reload_ata_media; + a->id = id; + } + } else { + printf("ATA - couldn't get info\n"); + } + } + return (MEDIA) a; +} + + +long +read_ata_media(MEDIA m, long long offset, unsigned long count, void *address) +{ + ATA_MEDIA a; + ataIOPB pb; + OSErr status; + long rtn_value; + long block; + long block_count; + long block_size; + unsigned char *buffer; + int i; + + a = (ATA_MEDIA) m; + rtn_value = 0; + if (a == 0) { + /* no media */ + } else if (a->m.kind != ata_mgr.kind) { + /* wrong kind - XXX need to error here - this is an internal problem */ + } else if (count <= 0 || count % a->m.grain != 0) { + /* can't handle size */ + } else if (offset < 0 || offset % a->m.grain != 0) { + /* can't handle offset */ + } else if (offset + count > a->m.size_in_bytes) { + /* check for offset (and offset+count) too large */ + } else { + /* do a read on the physical device */ + block_size = a->m.grain; + block = offset / block_size; + block_count = count / block_size; + buffer = address; + rtn_value = 1; + for (i = 0; i < block_count; i++) { + if (ATA_ReadBlock(a->id, &a->info, block_size, block, buffer) == 0) { + rtn_value = 0; + break; + } + buffer += block_size; + block += 1; + } + } + return rtn_value; +} + + +long +write_ata_media(MEDIA m, long long offset, unsigned long count, void *address) +{ + ATA_MEDIA a; + long rtn_value; + long block; + long block_count; + long block_size; + unsigned char *buffer; + int i; + + a = (ATA_MEDIA) m; + rtn_value = 0; + if (a == 0) { + /* no media */ + } else if (a->m.kind != ata_mgr.kind) { + /* XXX need to error here - this is an internal problem */ + } else if (count <= 0 || count % a->m.grain != 0) { + /* can't handle size */ + } else if (offset < 0 || offset % a->m.grain != 0) { + /* can't handle offset */ + } else if (offset + count > a->m.size_in_bytes) { + /* check for offset (and offset+count) too large */ + } else { + /* do a write on the physical device */ + block_size = a->m.grain; + block = offset / block_size; + block_count = count / block_size; + buffer = address; + rtn_value = 1; + for (i = 0; i < block_count; i++) { + if (ATA_WriteBlock(a->id, &a->info, block_size, block, buffer) == 0) { + rtn_value = 0; + break; + } + buffer += block_size; + block += 1; + } + } + return rtn_value; +} + + +long +close_ata_media(MEDIA m) +{ + ATA_MEDIA a; + + a = (ATA_MEDIA) m; + if (a == 0) { + return 0; + } else if (a->m.kind != ata_mgr.kind) { + /* XXX need to error here - this is an internal problem */ + return 0; + } + /* XXX nothing to do - I think? */ + return 1; +} + + +long +os_reload_ata_media(MEDIA m) +{ + printf("Reboot your system so the partition table will be reread.\n"); + return 1; +} + + +int +ATA_ReadBlock(UInt32 deviceID, ATA_INFO info, UInt32 block_size, UInt32 block, UInt8 *address) +{ + ataIOPB pb; + OSErr status; + long slave; + long lba, cyl, head, sector; + + clear_memory((void *)&pb, sizeof(pb)); + pb.ataPBFunctionCode = kATAMgrExecIO; + pb.ataPBVers = kATAPBVers1; + pb.ataPBDeviceID = deviceID; + pb.ataPBFlags = mATAFlagTFRead | mATAFlagIORead ; + pb.ataPBTimeOut = kATAtimeout; + + pb.ataPBLogicalBlockSize = block_size; + pb.ataPBBuffer = address; + pb.ataPBByteCount = block_size; + if (info->lba) { + lba = 0x40; + sector = block & 0xFF; + head = (block >> 24) & 0xF; + cyl = (block >> 8) & 0xFFFF; + } else { + lba = 0x00; + sector = (block % info->sectors) + 1; + cyl = block / info->sectors; + head = cyl % info->heads; + cyl = cyl / info->heads; + } + + pb.ataPBTaskFile.ataTFCount = 1; + pb.ataPBTaskFile.ataTFSector = sector; + pb.ataPBTaskFile.ataTFCylinder = cyl; + if (deviceID & 0x0FF00) { + slave = 0x10; + } else { + slave = 0x0; + } + /* std | L/C | Drive | head */ + pb.ataPBTaskFile.ataTFSDH = 0xA0 | lba | slave | head; + pb.ataPBTaskFile.ataTFCommand = kATAcmdRead; + + status = ataManager((ataPB*) &pb ); + if (status != noErr) { + /* failure */ + //printf(" ATA read status = %d\n", status); + return 0; + } else { + return 1; + } +} + + +int +ATA_WriteBlock(UInt32 deviceID, ATA_INFO info, UInt32 block_size, UInt32 block, UInt8 *address) +{ + ataIOPB pb; + OSErr status; + long slave; + long lba, cyl, head, sector; + + clear_memory((void *)&pb, sizeof(pb)); + pb.ataPBFunctionCode = kATAMgrExecIO; + pb.ataPBVers = kATAPBVers1; + pb.ataPBDeviceID = deviceID; + pb.ataPBFlags = mATAFlagTFRead | mATAFlagIOWrite ; + pb.ataPBTimeOut = kATAtimeout; + + pb.ataPBLogicalBlockSize = block_size; + pb.ataPBBuffer = address; + pb.ataPBByteCount = block_size; + if (info->lba) { + lba = 0x40; + sector = block & 0xFF; + head = (block >> 24) & 0xF; + cyl = (block >> 8) & 0xFFFF; + } else { + lba = 0x00; + sector = (block % info->sectors) + 1; + cyl = block / info->sectors; + head = cyl % info->heads; + cyl = cyl / info->heads; + } + pb.ataPBTaskFile.ataTFCount = 1; + pb.ataPBTaskFile.ataTFSector = sector; + pb.ataPBTaskFile.ataTFCylinder = cyl; + if (deviceID & 0x0FF00) { + slave = 0x10; + } else { + slave = 0x0; + } + /* std | L/C | Drive | head */ + pb.ataPBTaskFile.ataTFSDH = 0xA0 | lba | slave | head; + pb.ataPBTaskFile.ataTFCommand = kATAcmdWrite; + + status = ataManager((ataPB*) &pb ); + if (status != noErr) { + /* failure */ + return 0; + } else { + return 1; + } +} + + +#pragma mark - + + +/* + * ATAPI stuff + */ +static long +get_pi_info(long id, struct ATAPI_identify_drive_info *ip) +{ + ataIdentify pb; + OSErr status; + long rtn_value; + + if (sizeof(struct ATAPI_identify_drive_info) < 512) { + return 0; + } + clear_memory((void *)ip, sizeof(struct ATAPI_identify_drive_info)); + + clear_memory((void *)&pb, sizeof(pb)); + pb.ataPBFunctionCode = kATAMgrDriveIdentify; + pb.ataPBVers = kATAPBVers1; + pb.ataPBDeviceID = id; + pb.ataPBFlags = mATAFlagIORead | mATAFlagByteSwap | mATAFlagProtocol1; + pb.ataPBTimeOut = kATAtimeout; + pb.ataPBBuffer = (void*) ip; + + status = ataManager((ataPB*) &pb ); + + if (status != noErr) { + //printf("get pi info status = %d\n", status); + rtn_value = 0; + } else { + rtn_value = 1; + } + return rtn_value; +} + + +MEDIA +open_atapi_as_media(long bus, long device) +{ + ATA_MEDIA a; + long id; + struct ATAPI_identify_drive_info info; + unsigned char *buf; + unsigned long block_size; + unsigned long blocks; + + if (ata_inited == 0) { + ata_init(); + } + + if (ata_mgr.exists == 0) { + return 0; + } + + id = compute_id(bus, device); + + if (!is_atapi(id)) { + a = 0; + + } else { + a = 0; + if (get_pi_info(id, &info) != 0 + && (info.capabilities & LBA_CAPABLE) != 0) { + if (ATAPI_TestUnitReady(id) != 0) { + a = new_ata_media(); + if (a != 0) { + a->m.kind = ata_mgr.kind; + if (ATAPI_ReadCapacity(id, &block_size, &blocks) == 0) { + block_size = 2048; + blocks = 1000; + } + a->m.grain = block_size; + a->m.size_in_bytes = ((long long)blocks) * a->m.grain; + a->m.do_read = read_atapi_media; + a->m.do_write = write_atapi_media; + a->m.do_close = close_ata_media; + a->m.do_os_reload = os_reload_ata_media; + a->id = id; + } + } else { + printf("ATAPI - unit not ready\n"); + } + } else { + printf("ATAPI - couldn't get info or not LBA capable\n"); + } + } + return (MEDIA) a; +} + + +long +read_atapi_media(MEDIA m, long long offset, unsigned long count, void *address) +{ + ATA_MEDIA a; + ataIOPB pb; + OSErr status; + long rtn_value; + long block; + long block_count; + long block_size; + unsigned char *buffer; + int i; + + a = (ATA_MEDIA) m; + rtn_value = 0; + if (a == 0) { + /* no media */ + } else if (a->m.kind != ata_mgr.kind) { + /* wrong kind - XXX need to error here - this is an internal problem */ + } else if (count <= 0 || count % a->m.grain != 0) { + /* can't handle size */ + } else if (offset < 0 || offset % a->m.grain != 0) { + /* can't handle offset */ + } else if (offset + count > a->m.size_in_bytes) { + /* check for offset (and offset+count) too large */ + } else { + /* XXX do a read on the physical device */ + block_size = a->m.grain; + block = offset / block_size; + block_count = count / block_size; + buffer = address; + rtn_value = 1; + for (i = 0; i < block_count; i++) { + if (ATAPI_ReadBlock(a->id, block_size, block, buffer) == 0) { + rtn_value = 0; + break; + } + buffer += block_size; + block += 1; + } + } + return rtn_value; +} + + +long +write_atapi_media(MEDIA m, long long offset, unsigned long count, void *address) +{ + return 0; +} + + +int +ATAPI_ReadBlock(UInt32 deviceID, UInt32 block_size, UInt32 block, UInt8 *address) +{ + ataIOPB pb; + OSErr status; + long slave; + ATAPICmdPacket cmdPacket; + SCSI_10_Byte_Command *gRead; + long count; + + clear_memory((void *)&pb, sizeof(pb)); + pb.ataPBFunctionCode = kATAMgrExecIO; + pb.ataPBVers = kATAPBVers1; + pb.ataPBDeviceID = deviceID; + pb.ataPBFlags = mATAFlagTFRead | mATAFlagIORead | mATAFlagProtocol1; + pb.ataPBTimeOut = kATAtimeout; + + pb.ataPBBuffer = address; + pb.ataPBByteCount = block_size; + pb.ataPBTaskFile.ataTFCylinder = block_size; + if (deviceID & 0x0FF00) { + slave = 0x10; + } else { + slave = 0x0; + } + /* std | L/C | Drive | head */ + pb.ataPBTaskFile.ataTFSDH = 0xA0 | 0x40 | slave; + pb.ataPBTaskFile.ataTFCommand = kATAcmdATAPIPacket; + pb.ataPBPacketPtr = &cmdPacket; + + cmdPacket.atapiPacketSize = 16; + clear_memory((void *)&cmdPacket.atapiCommandByte, 16); + gRead = (SCSI_10_Byte_Command *) &cmdPacket.atapiCommandByte[0]; + + gRead->opcode = kScsiCmdRead10; + + gRead->lbn4 = (block >> 24) & 0xFF; + gRead->lbn3 = (block >> 16) & 0xFF; + gRead->lbn2 = (block >> 8) & 0xFF; + gRead->lbn1 = block & 0xFF; + + count = 1; + gRead->len2 = (count >> 8) & 0xFF; + gRead->len1 = count & 0xFF; + + + status = ataManager((ataPB*) &pb ); + if (status != noErr) { + /* failure */ + //printf("ATAPI read status = %d\n", status); + return 0; + } else { + return 1; + } +} + + +int +ATAPI_TestUnitReady(UInt32 deviceID) +{ + ataIOPB pb; + OSErr status; + long slave; + ATAPICmdPacket cmdPacket; + SCSI_10_Byte_Command *gTestUnit; + + clear_memory((void *)&pb, sizeof(pb)); + pb.ataPBFunctionCode = kATAMgrExecIO; + pb.ataPBVers = kATAPBVers1; + pb.ataPBDeviceID = deviceID; + pb.ataPBFlags = mATAFlagTFRead | mATAFlagIORead | mATAFlagProtocol1; + pb.ataPBTimeOut = kATAtimeout; + + if (deviceID & 0x0FF00) { + slave = 0x10; + } else { + slave = 0x0; + } + /* std | L/C | Drive | head */ + pb.ataPBTaskFile.ataTFSDH = 0xA0 | 0x40 | slave; + pb.ataPBTaskFile.ataTFCommand = kATAcmdATAPIPacket; + pb.ataPBPacketPtr = &cmdPacket; + + cmdPacket.atapiPacketSize = 16; + clear_memory((void *)&cmdPacket.atapiCommandByte, 16); + gTestUnit = (SCSI_10_Byte_Command *) &cmdPacket.atapiCommandByte[0]; + + gTestUnit->opcode = kScsiCmdTestUnitReady; + + + status = ataManager((ataPB*) &pb ); + if (status != noErr) { + /* failure */ + //printf("ATAPI test unit ready status = %d\n", status); + return 0; + } else { + return 1; + } +} + + +int +ATAPI_ReadCapacity(UInt32 deviceID, unsigned long *block_size, unsigned long *blocks) +{ + ataIOPB pb; + OSErr status; + long slave; + ATAPICmdPacket cmdPacket; + SCSI_10_Byte_Command *gReadCap; + struct read_cap_data { + long addr; + long size; + } rcd; + + clear_memory((void *)&pb, sizeof(pb)); + pb.ataPBFunctionCode = kATAMgrExecIO; + pb.ataPBVers = kATAPBVers1; + pb.ataPBDeviceID = deviceID; + pb.ataPBFlags = mATAFlagTFRead | mATAFlagIORead | mATAFlagProtocol1; + pb.ataPBTimeOut = kATAtimeout; + + pb.ataPBBuffer = (unsigned char *)&rcd; + pb.ataPBByteCount = 8; + pb.ataPBTaskFile.ataTFCylinder = 8; + if (deviceID & 0x0FF00) { + slave = 0x10; + } else { + slave = 0x0; + } + /* std | L/C | Drive | head */ + pb.ataPBTaskFile.ataTFSDH = 0xA0 | 0x40 | slave; + pb.ataPBTaskFile.ataTFCommand = kATAcmdATAPIPacket; + pb.ataPBPacketPtr = &cmdPacket; + + cmdPacket.atapiPacketSize = 16; + clear_memory((void *)&cmdPacket.atapiCommandByte, 16); + gReadCap = (SCSI_10_Byte_Command *) &cmdPacket.atapiCommandByte[0]; + + gReadCap->opcode = kScsiCmdReadCapacity; + + + status = ataManager((ataPB*) &pb ); + if (status != noErr) { + /* failure */ + //printf("ATAPI read capacity status = %d\n", status); + return 0; + } else { + *blocks = rcd.addr; + *block_size = rcd.size; + return 1; + } +} + + +MEDIA +ATA_FindDevice(long dRefNum) +{ + ataDrvrRegister pb; + OSErr status; + + if (ATAManagerPresent()) { + clear_memory((void *)&pb, sizeof(pb)); + + pb.ataPBFunctionCode = kATAMgrFindDriverRefnum; + pb.ataPBVers = kATAPBVers1; + pb.ataPBDeviceID = 0xFFFF; + pb.ataPBTimeOut = kATAtimeout; + + pb.ataDeviceNextID = 1; + do { + status = ataManager((ataPB*) &pb); + + if (status != noErr) { + break; + } else if (pb.ataDrvrRefNum == dRefNum + && pb.ataPBDeviceID != kNoDevice) { + return open_ata_as_media(pb.ataPBDeviceID & 0xFF, + (pb.ataPBDeviceID >> 8) & 0xFF); + } else { + pb.ataPBDeviceID = pb.ataDeviceNextID; + } + } while (pb.ataPBDeviceID != kNoDevice); + } + return 0; +} + + +#pragma mark - + + +ATA_MEDIA_ITERATOR +new_ata_iterator(void) +{ + return (ATA_MEDIA_ITERATOR) new_media_iterator(sizeof(struct ATA_media_iterator)); +} + + +MEDIA_ITERATOR +create_ata_iterator(void) +{ + ATA_MEDIA_ITERATOR a; + + if (ata_inited == 0) { + ata_init(); + } + + if (ata_mgr.exists == 0) { + return 0; + } + + a = new_ata_iterator(); + if (a != 0) { + a->m.kind = ata_mgr.kind; + a->m.state = kInit; + a->m.do_reset = reset_ata_iterator; + a->m.do_step = step_ata_iterator; + a->m.do_delete = delete_ata_iterator; + a->bus = 0; + a->id = 0; + } + + return (MEDIA_ITERATOR) a; +} + + +void +reset_ata_iterator(MEDIA_ITERATOR m) +{ + ATA_MEDIA_ITERATOR a; + + a = (ATA_MEDIA_ITERATOR) m; + if (a == 0) { + /* no media */ + } else if (a->m.kind != ata_mgr.kind) { + /* wrong kind - XXX need to error here - this is an internal problem */ + } else if (a->m.state != kInit) { + a->m.state = kReset; + } +} + + +char * +step_ata_iterator(MEDIA_ITERATOR m) +{ + ATA_MEDIA_ITERATOR a; + char *result; + + a = (ATA_MEDIA_ITERATOR) m; + if (a == 0) { + /* no media */ + } else if (a->m.kind != ata_mgr.kind) { + /* wrong kind - XXX need to error here - this is an internal problem */ + } else { + switch (a->m.state) { + case kInit: + /* find # of buses (done in ata_init) */ + a->m.state = kReset; + /* fall through to reset */ + case kReset: + a->bus = 0 /* low bus id */; + a->id = 0 /* low device id */; + a->m.state = kIterating; + /* fall through to iterate */ + case kIterating: + while (1) { + if (a->bus >= ata_mgr.busCount/* max bus id */) { + break; + } + if (a->id > 1 /*max id for bus */) { + a->bus += 1; + a->id = 0 /* low device id */; + continue; /* try again */ + } + /* generate result */ + result = (char *) malloc(20); + if (result != NULL) { + sprintf(result, "/dev/ata%c.%c", '0'+a->bus, '0'+a->id); + } + + a->id += 1; /* next id */ + return result; + } + a->m.state = kEnd; + /* fall through to end */ + case kEnd: + default: + break; + } + } + return 0 /* no entry */; +} + + +void +delete_ata_iterator(MEDIA_ITERATOR m) +{ + return; +} + + +#pragma mark - + + +MEDIA +open_mklinux_ata_as_media(long index) +{ + long bus; + long id; + + bus = index / 2; + id = index % 2; + + return open_ata_as_media(bus, id); +} + + +char * +mklinux_ata_name(long bus, long id) +{ + char *result; + + result = (char *) malloc(20); + if (result != NULL) { + /* name is hda, hdb, hdc, hdd, ... + * in order (0,0) (0,1) (1,0) (1,1) ... + */ + sprintf(result, "/dev/hd%c", 'a' + (bus*2 + id)); + } + return result; +} diff --git a/sbin/pdisk/ATA_media.h b/sbin/pdisk/ATA_media.h new file mode 100644 index 00000000000..96a83172233 --- /dev/null +++ b/sbin/pdisk/ATA_media.h @@ -0,0 +1,64 @@ +/* + * ATA_media.h - + * + * Written by Eryk Vershen (eryk@apple.com) + */ + +/* + * Copyright 1997,1998 by Apple Computer, Inc. + * All Rights Reserved + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appears in all copies and + * that both the copyright notice and this permission notice appear in + * supporting documentation. + * + * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, + * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION + * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __ATA_media__ +#define __ATA_media__ + +#include "media.h" + + +/* + * Defines + */ + + +/* + * Types + */ + + +/* + * Global Constants + */ + + +/* + * Global Variables + */ + + +/* + * Forward declarations + */ +MEDIA ATA_FindDevice(long dRefNum); +MEDIA open_ata_as_media(long bus, long device); +MEDIA open_atapi_as_media(long bus, long device); +MEDIA_ITERATOR create_ata_iterator(void); +MEDIA open_mklinux_ata_as_media(long index); +char *mklinux_ata_name(long bus, long id); + +#endif /* __ATA_media__ */ diff --git a/sbin/pdisk/DoSCSICommand.c b/sbin/pdisk/DoSCSICommand.c new file mode 100644 index 00000000000..ea9cd49a373 --- /dev/null +++ b/sbin/pdisk/DoSCSICommand.c @@ -0,0 +1,649 @@ +/* + * DoScsiCommand.c + * + * This is the common entry to the original and asynchronous SCSI Manager calls: + * if the asynchronous SCSI Manager is requested, it calls it. Otherwise, it + * calls the original SCSI Manager and executes Request Sense if necessary. + * + * This function returns "autosense" in the SCSI_Sense_Data area. This will + * be formatted in the senseMessage string. + */ + +/* + * Copyright 1992, 1993, 1997, 1998 by Apple Computer, Inc. + * All Rights Reserved + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appears in all copies and + * that both the copyright notice and this permission notice appear in + * supporting documentation. + * + * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, + * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION + * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "DoScsiCommand.h" +#include "util.h" + + +// +// Defines +// +#define kSCSICommandTimeout (5 * 1000L) /* Five seconds */ +/* + * This is the maximum number of times we try to grab the SCSI Bus + */ +#define kMaxSCSIRetries 40 /* 10 seconds, 4 times/sec */ +/* + * This test is TRUE if the SCSI bus status indicates "busy" (which is the case + * if either the BSY or SEL bit is set). + */ +#ifndef kScsiStatBSY +#define kScsiStatBSY (1 << 6) +#endif +#ifndef kScsiStatSEL +#define kScsiStatSEL (1 << 1) +#endif +#define ScsiBusBusy() ((SCSIStat() & (kScsiStatBSY | kScsiStatSEL)) != 0) + + +// +// Types +// + + +// +// Global Constants +// + + +// +// Global Variables +// +int gSCSIHiBusID; +SCSIExecIOPB *gSCSIExecIOPBPtr; +UInt32 gSCSIExecIOPBPtrLen; + + +// +// Forward declarations +// +UInt16 GetCommandLength(const SCSI_CommandPtr cmdPtr); +Boolean IsVirtualMemoryRunning(void); + +OSErr OriginalSCSI( + DeviceIdent scsiDevice, + const SCSI_CommandPtr scsiCommand, + UInt8 scsiCommandLen, + Ptr dataBuffer, + ByteCount dataLength, + UInt32 scsiFlags, + ByteCount *actualTransferCount, + UInt8 *scsiStatusByte +); + +OSErr DoOriginalSCSICommand( + DeviceIdent scsiDevice, + const SCSI_CommandPtr theSCSICommand, + unsigned short cmdBlockLength, + Ptr dataBuffer, + ByteCount dataLength, + UInt32 scsiFlags, + ByteCount *actualTransferCount, + SCSI_Sense_Data *sensePtr +); + + +// +// Routines +// + +/* + * This returns TRUE if the command failed with "Illegal Request." We need this + * so we can ignore LogSense or ReadDefectData if the device doesn't support + * these functions. + */ +Boolean +IsIllegalRequest( + OSErr scsiStatus, + const SCSI_Sense_Data *senseDataPtr + ) +{ + Boolean result; +#define SENSE (*senseDataPtr) + + result = FALSE; + if (scsiStatus == scsiNonZeroStatus + && (SENSE.senseKey & kScsiSenseKeyMask) == kScsiSenseIllegalReq + && SENSE.additionalSenseLength >= 4) { + switch ((SENSE.additionalSenseCode << 8) | SENSE.additionalSenseQualifier) { + case 0x0000: + case 0x2000: + case 0x2022: /* Obsolete */ + result = TRUE; + break; + default: + break; + } + } + return (result); +#undef SENSE +} + + +/* + * This returns TRUE if the command failed with Device Not Ready (No Media Present) + */ +Boolean +IsNoMedia( + OSErr scsiStatus, + const SCSI_Sense_Data *senseDataPtr + ) +{ + Boolean result; +#define SENSE (*senseDataPtr) + + result = FALSE; + if (scsiStatus == scsiNonZeroStatus + && (SENSE.senseKey & kScsiSenseKeyMask) == kScsiSenseNotReady + && SENSE.additionalSenseLength >= 4) { + switch ((SENSE.additionalSenseCode << 8) | SENSE.additionalSenseQualifier) { + case 0x0000: + case 0x3A00: + result = TRUE; + break; + default: + break; + } + } + return (result); +#undef SENSE +} + + +/* + * Do one SCSI Command. If the device returns Check Condition, issue Request Sense + * (original SCSI Manager only) and interpret the sense data. The original SCSI + * command status is in SCB.status. If it is statusErr or scsiNonZeroStatus, + * the sense data is in SCB.sense and the Request Sense status is in + * SCB.requestSenseStatus. + * + * If sensePtr[0] is non-zero, there is a message. + */ +OSErr +DoSCSICommand( + DeviceIdent scsiDevice, + ConstStr255Param currentAction, + const SCSI_CommandPtr callerSCSICommand, + Ptr dataBuffer, + ByteCount dataLength, + UInt32 scsiFlags, + ByteCount *actualTransferCount, + SCSI_Sense_Data *sensePtr, + StringPtr senseMessage + ) +{ + OSErr status; + SCSI_Command theSCSICommand; + unsigned short cmdBlockLength; + +// SpinSpinner(&gCurrentInfoPtr->spinnerRecord); +// ShowProgressAction(currentAction); + /* + * Store the LUN information in the command block - this is needed + * for devices that only examine the command block for LUN values. + * (On SCSI-II, the asynchronous SCSI Manager also includes the + * LUN in the identify message). + */ + theSCSICommand = *callerSCSICommand; + theSCSICommand.scsi[1] &= ~0xE0; + theSCSICommand.scsi[1] |= (scsiDevice.LUN & 0x03) << 5; + cmdBlockLength = GetCommandLength(&theSCSICommand); + if (senseMessage != NULL) + senseMessage[0] = 0; + if (sensePtr != NULL) + sensePtr->errorCode = 0; + if (scsiDevice.bus == kOriginalSCSIBusAdaptor) { + status = DoOriginalSCSICommand( + scsiDevice, + &theSCSICommand, + cmdBlockLength, + dataBuffer, + dataLength, + scsiFlags, + actualTransferCount, + sensePtr + ); + } + else { + clear_memory(gSCSIExecIOPBPtr, gSCSIExecIOPBPtrLen); +#define PB (*gSCSIExecIOPBPtr) + PB.scsiPBLength = gSCSIExecIOPBPtrLen; + PB.scsiFunctionCode = SCSIExecIO; + PB.scsiDevice = scsiDevice; + PB.scsiTimeout = kSCSICommandTimeout; + /* + * Fiddle the flags so they're the least disruptive possible. + */ + PB.scsiFlags = scsiFlags | (scsiSIMQNoFreeze | scsiDontDisconnect); + if (sensePtr != NULL) { + PB.scsiSensePtr = (UInt8 *) sensePtr; + PB.scsiSenseLength = sizeof *sensePtr; + } + BlockMoveData(&theSCSICommand, &PB.scsiCDB.cdbBytes[0], cmdBlockLength); + PB.scsiCDBLength = cmdBlockLength; + if (dataBuffer != NULL) { + PB.scsiDataPtr = (UInt8 *) dataBuffer; + PB.scsiDataLength = dataLength; + PB.scsiDataType = scsiDataBuffer; + PB.scsiTransferType = scsiTransferPolled; + } + status = SCSIAction((SCSI_PB *) &PB); + if (status == noErr) + status = PB.scsiResult; + if (status == scsiSelectTimeout) + status = scsiDeviceNotThere; + if (actualTransferCount != NULL) { + /* + * Make sure that the actual transfer count does not exceed + * the allocation count (some devices spit extra data at us!) + */ + *actualTransferCount = dataLength - PB.scsiDataResidual; + if (*actualTransferCount > dataLength) + *actualTransferCount = dataLength; + } +#undef PB + } + if (status == scsiNonZeroStatus + && sensePtr != NULL + && sensePtr->errorCode != 0 + && senseMessage != NULL) { +// FormatSenseMessage(sensePtr, senseMessage); +// ShowProgressAction(senseMessage); + } + return (status); +} + + +/* + * Do a command with autosense using the original SCSI manager. + */ +OSErr +DoOriginalSCSICommand( + DeviceIdent scsiDevice, + const SCSI_CommandPtr theSCSICommand, + unsigned short cmdBlockLength, + Ptr dataBuffer, + ByteCount dataLength, + UInt32 scsiFlags, + ByteCount *actualTransferCount, + SCSI_Sense_Data *sensePtr + ) +{ + OSErr status; + UInt8 scsiStatusByte; + SCSI_Command scsiStatusCommand; + + status = OriginalSCSI( + scsiDevice, + theSCSICommand, + cmdBlockLength, + dataBuffer, + dataLength, + scsiFlags, + actualTransferCount, + &scsiStatusByte + ); + if (status == scsiNonZeroStatus + && scsiStatusByte == kScsiStatusCheckCondition + && sensePtr != NULL) { + CLEAR(scsiStatusCommand); + CLEAR(*sensePtr); + scsiStatusCommand.scsi6.opcode = kScsiCmdRequestSense; + scsiStatusCommand.scsi[1] |= (scsiDevice.LUN & 0x03) << 5; + scsiStatusCommand.scsi6.len = sizeof *sensePtr; + status = OriginalSCSI( + scsiDevice, + &scsiStatusCommand, + sizeof scsiStatusCommand.scsi6, + (Ptr) sensePtr, + sizeof *sensePtr, + scsiDirectionIn, + NULL, + &scsiStatusByte + ); + if (status != noErr && status != scsiDataRunError) { +#ifdef notdef + if (gDebugOnError && scsiStatusByte != kScsiStatusCheckCondition) { + Str255 work; + + pstrcpy(work, "\pAutosense failed "); + AppendSigned(work, status); + AppendChar(work, ' '); + AppendHexLeadingZeros(work, scsiStatusByte, 2); + DebugStr(work); + } +#endif + sensePtr->errorCode = 0; + status = scsiAutosenseFailed; + } + else { + status = scsiNonZeroStatus; + } + } + return (status); +} + + +OSErr +OriginalSCSI( + DeviceIdent scsiDevice, + const SCSI_CommandPtr scsiCommand, + UInt8 scsiCommandLen, + Ptr dataBuffer, + ByteCount dataLength, + UInt32 scsiFlags, + ByteCount *actualTransferCount, + UInt8 *scsiStatusBytePtr + ) +{ + OSErr status; /* Final status */ + OSErr completionStatus; /* Status from ScsiComplete */ + short totalTries; /* Get/Select retries */ + short getTries; /* Get retries */ + short iCount; /* Bus free counter */ + unsigned long watchdog; /* Timeout after this */ + unsigned long myTransferCount; /* Gets TIB loop counter */ + short scsiStatusByte; /* Gets SCSIComplete result */ + short scsiMsgByte; /* Gets SCSIComplete result */ + Boolean bufferHoldFlag; + /* + * The TIB has the following format: + * [0] scInc user buffer transferQuantum or transferSize + * [1] scAdd &theTransferCount 1 + * [2] scLoop -> tib[0] transferSize / transferQuantum + * [3] scStop + * The intent of this is to return, in actualTransferCount, the number + * of times we cycled through the tib[] loop. This will be the actual + * transfer count if transferQuantum equals one, or the number of + * "blocks" if transferQuantum is the length of one sector. + */ + SCSIInstr tib[4]; /* Current TIB */ + + status = noErr; + bufferHoldFlag = FALSE; + scsiStatusByte = 0xFF; + scsiMsgByte = 0xFF; + myTransferCount = 0; + /* + * If there is a data transfer, setup the tib. + */ + if (dataBuffer != NULL) { + tib[0].scOpcode = scInc; + tib[0].scParam1 = (unsigned long) dataBuffer; + tib[0].scParam2 = 1; + tib[1].scOpcode = scAdd; + tib[1].scParam1 = (unsigned long) &myTransferCount; + tib[1].scParam2 = 1; + tib[2].scOpcode = scLoop; + tib[2].scParam1 = (-2 * sizeof (SCSIInstr)); + tib[2].scParam2 = dataLength / tib[0].scParam2; + tib[3].scOpcode = scStop; + tib[3].scParam1 = 0; + tib[3].scParam2 = 0; + } + if (IsVirtualMemoryRunning() && dataBuffer != NULL) { + /* + * Lock down the user buffer, if any. In a real-world application + * or driver, this would be done before calling the SCSI interface. + */ +#ifdef notdef + FailOSErr( + HoldMemory(dataBuffer, dataLength), + "\pCan't lock data buffer in physical memory" + ); +#else + HoldMemory(dataBuffer, dataLength); +#endif + bufferHoldFlag = TRUE; + } + /* + * Arbitrate for the scsi bus. This will fail if some other device is + * accessing the bus at this time (which is unlikely). + * + *** Do not set breakpoints or call any functions that may require device + *** I/O (such as display code that accesses font resources between + *** SCSIGet and SCSIComplete, + * + */ + for (totalTries = 0; totalTries < kMaxSCSIRetries; totalTries++) { + for (getTries = 0; getTries < 4; getTries++) { + /* + * Wait for the bus to go free. + */ + watchdog = TickCount() + 300; /* 5 second timeout */ + while (ScsiBusBusy()) { + if (/*gStopNow || StopNow() ||*/ TickCount() > watchdog) { + status = scsiBusy; + goto exit; + } + } + /* + * The bus is free, try to grab it + */ + for (iCount = 0; iCount < 4; iCount++) { + if ((status = SCSIGet()) == noErr) + break; + } + if (status == noErr) { + break; /* Success: we have the bus */ + } + /* + * The bus became busy again. Try to wait for it to go free. + */ + for (iCount = 0; + /*gStopNow == FALSE && StopNow() == FALSE &&*/ iCount < 100 && ScsiBusBusy(); + iCount++) + ; + } /* The getTries loop */ + if (status != noErr) { + /* + * The SCSI Manager thinks the bus is not busy and not selected, + * but "someone" has set its internal semaphore that signals + * that the SCSI Manager itself is busy. The application will have + * to handle this problem. (We tried getTries * 4 times). + */ + status = scsiBusy; + goto exit; + } + /* + * We now own the SCSI bus. Try to select the device. + */ + if ((status = SCSISelect(scsiDevice.targetID)) != noErr) { + switch (status) { + /* + * We get scBadParmsErr if we try to arbitrate for the initiator. + */ + case scBadParmsErr: status = scsiTIDInvalid; break; + case scCommErr: status = scsiDeviceNotThere; break; + case scArbNBErr: status = scsiBusy; break; + case scSequenceErr: status = scsiRequestInvalid; break; + } + goto exit; + } + /* + * From this point on, we must exit through SCSIComplete() even if an + * error is detected. Send a command to the selected device. There are + * several failure modes, including an illegal command (such as a + * write to a read-only device). If the command failed because of + * "device busy", we will try it again. + */ + status = SCSICmd((Ptr) scsiCommand, scsiCommandLen); + if (status != noErr) { + switch (status) { + case scCommErr: status = scsiCommandTimeout; break; + case scPhaseErr: status = scsiSequenceFailed; break; + } + } + if (status == noErr && dataBuffer != NULL) { + /* + * This command requires a data transfer. + */ + if (scsiFlags == scsiDirectionOut) { + status = SCSIWrite((Ptr) tib); + } else { + status = SCSIRead((Ptr) tib); + } + switch (status) { + case scCommErr: status = scsiCommandTimeout; break; + case scBadParmsErr: status = scsiRequestInvalid; break; + case scPhaseErr: status = noErr; /* Don't care */ break; + case scCompareErr: /* Can't happen */ break; + } + } + /* + * SCSIComplete "runs" the bus-phase algorithm until the bitter end, + * returning the status and command-completion message bytes.. + */ + completionStatus = SCSIComplete( + &scsiStatusByte, + &scsiMsgByte, + 5 * 60L + ); + if (status == noErr && completionStatus != noErr) { + switch (completionStatus) { + case scCommErr: status = scsiCommandTimeout; break; + case scPhaseErr: status = scsiSequenceFailed; break; + case scComplPhaseErr: status = scsiSequenceFailed; break; + } + } + if (completionStatus == noErr && scsiStatusByte == kScsiStatusBusy) { + /* + * ScsiComplete is happy. If the device is busy, + * pause for 1/4 second and try again. + */ + watchdog = TickCount() + 15; + while (TickCount() < watchdog) + ; + continue; /* Do next totalTries attempt */ + } + /* + * This is the normal exit (success) or final failure exit. + */ + break; + } /* totalTries loop */ +exit: + + if (bufferHoldFlag) { + (void) UnholdMemory(dataBuffer, dataLength); + } + /* + * Return the number of bytes transferred to the caller. If the caller + * supplied an actual count and the count is no greater than the maximum, + * ignore any phase errors. + */ + if (actualTransferCount != NULL) { + *actualTransferCount = myTransferCount; + if (*actualTransferCount > dataLength) { + *actualTransferCount = dataLength; + } + } + /* + * Also, there is a bug in the combination of System 7.0.1 and the 53C96 + * that may cause the real SCSI Status Byte to be in the Message byte. + */ + if (scsiStatusByte == kScsiStatusGood + && scsiMsgByte == kScsiStatusCheckCondition) { + scsiStatusByte = kScsiStatusCheckCondition; + } + if (status == noErr) { + switch (scsiStatusByte) { + case kScsiStatusGood: break; + case kScsiStatusBusy: status = scsiBusy; break; + case 0xFF: status = scsiProvideFail; break; + default: status = scsiNonZeroStatus; break; + } + } + if (status == noErr + && (scsiFlags & scsiDirectionMask) != scsiDirectionNone + && myTransferCount != dataLength) { + status = scsiDataRunError; + } + if (scsiStatusBytePtr != NULL) { + *scsiStatusBytePtr = scsiStatusByte; + } + return (status); +} + + +UInt16 +GetCommandLength( + const SCSI_CommandPtr cmdPtr + ) +{ + unsigned short result; + /* + * Look at the "group code" in the command operation. Return zero + * error for the reserved (3, 4) and vendor-specific command (6, 7) + * command groups. Otherwise, set the command length from the group code + * value as specified in the SCSI-II spec. + */ + switch (cmdPtr->scsi6.opcode & 0xE0) { + case (0 << 5): result = 6; break; + case (1 << 5): + case (2 << 5): result = 10; break; + case (5 << 5): result = 12; break; + default: result = 0; break; + } + return (result); +} + + +Boolean +IsVirtualMemoryRunning(void) +{ + OSErr status; + long response; + + status = Gestalt(gestaltVMAttr, &response); + /* + * VM is active iff Gestalt succeeded and the response is appropriate. + */ + return (status == noErr && ((response & (1 << gestaltVMPresent)) != 0)); +} + + +void +AllocatePB() +{ + OSErr status; + SCSIBusInquiryPB busInquiryPB; +#define PB (busInquiryPB) + + if (gSCSIExecIOPBPtr == NULL) { + CLEAR(PB); + PB.scsiPBLength = sizeof PB; + PB.scsiFunctionCode = SCSIBusInquiry; + PB.scsiDevice.bus = 0xFF; /* Get info about the XPT */ + status = SCSIAction((SCSI_PB *) &PB); + if (status == noErr) + status = PB.scsiResult; + if (PB.scsiHiBusID == 0xFF) { + gSCSIHiBusID = -1; + } else { + gSCSIHiBusID = PB.scsiHiBusID; + } + gSCSIExecIOPBPtrLen = PB.scsiMaxIOpbSize; + if (gSCSIExecIOPBPtrLen != 0) + gSCSIExecIOPBPtr = (SCSIExecIOPB *) NewPtrClear(gSCSIExecIOPBPtrLen); + } +#undef PB +} diff --git a/sbin/pdisk/DoSCSICommand.h b/sbin/pdisk/DoSCSICommand.h new file mode 100644 index 00000000000..34d7e6cd8dd --- /dev/null +++ b/sbin/pdisk/DoSCSICommand.h @@ -0,0 +1,130 @@ +/* + * DoScsiCommand.h - + * + * Modifed by Eryk Vershen (eryk@apple.com) + * from an original by Martin Minow + */ + +/* + * Copyright 1993-1998 by Apple Computer, Inc. + * All Rights Reserved + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appears in all copies and + * that both the copyright notice and this permission notice appear in + * supporting documentation. + * + * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, + * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION + * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __DoScsiCommand__ +#define __DoScsiCommand__ + +#include <SCSI.h> +#include "MacSCSICommand.h" + + +/* + * Defines + */ +#ifndef EXTERN +#define EXTERN extern +#endif + +#ifndef TRUE +#define TRUE 1 +#define FALSE 0 +#endif + +#ifndef NULL +#define NULL 0 +#endif + +#define kOriginalSCSIBusAdaptor (0xFF) + +#define SameSCSIDevice(a, b) ((*((UInt32 *) &a)) == (*((UInt32 *) &b))) + +/* + * Cheap 'n dirty memory clear routine. + */ +#define CLEAR(dst) clear_memory((void *) &dst, sizeof dst) + + +/* + * Types + */ +#if !defined(__NewTypesDefined__) +#define __NewTypesDefined__ +typedef signed char SInt8; +typedef signed short SInt16; +typedef signed long SInt32; +typedef unsigned char UInt8; +typedef unsigned short UInt16; +typedef unsigned long UInt32; +typedef unsigned long ItemCount; +typedef unsigned long ByteCount; +#endif + + +/* + * Global Constants + */ +enum { + bit0 = (1 << 0), + bit1 = (1 << 1), + bit2 = (1 << 2), + bit3 = (1 << 3), + bit4 = (1 << 4), + bit5 = (1 << 5), + bit6 = (1 << 6), + bit7 = (1 << 7) +}; + + +/* + * Global Variables + */ +EXTERN int gSCSIHiBusID; +EXTERN SCSIExecIOPB *gSCSIExecIOPBPtr; +EXTERN UInt32 gSCSIExecIOPBPtrLen; + + +/* + * Forward declarations + */ +void AllocatePB(); +Boolean IsIllegalRequest(OSErr scsiStatus, const SCSI_Sense_Data *senseDataPtr); +Boolean IsNoMedia(OSErr scsiStatus, const SCSI_Sense_Data *senseDataPtr); +/* + * All SCSI Commands come here. + * if scsiDevice.busID == kOriginalSCSIBusAdaptor, IM-IV SCSI will be called. + * scsiFlags should be scsiDirectionNone, scsiDirectionIn, or scsiDirectionOut + * actualTransferCount may be NULL if you don't care. + * Both old and new SCSI return SCSI Manager 4.3 errors. + * + * DoSCSICommand throws really serious errors, but returns SCSI errors such + * as dataRunError and scsiDeviceNotThere. + */ +OSErr DoSCSICommand( + DeviceIdent scsiDevice, + ConstStr255Param currentAction, + const SCSI_CommandPtr callerSCSICommand, + Ptr dataBuffer, + ByteCount dataLength, + UInt32 scsiFlags, + ByteCount *actualTransferCount, + SCSI_Sense_Data *sensePtr, + StringPtr senseMessage +); + + +#endif /* __DoScsiCommand__ */ diff --git a/sbin/pdisk/HISTORY b/sbin/pdisk/HISTORY new file mode 100644 index 00000000000..6ad9ac091ab --- /dev/null +++ b/sbin/pdisk/HISTORY @@ -0,0 +1,54 @@ +A short history of pdisk +------------------------ +11/1996 - Spent a week to create a minimal partitioner + that reads maps, initializes maps, can add and delete partitions. + Released as version 0.1 to MkLinux team + +12/1996 - Spent three weeks adding more commands, writing + documentation, fixing bugs and making it prettier. + Released version 0.2 to Gilbert + Fixed a few more bugs. + Released as version 0.3 + +01/1997 - Spent two weeks creating MacOS version and fixing + a few more bugs. + Released as version 0.4 + +03/1997 - Spent an evening adding device driver deletion + and a couple of flags to private version. + +07/1997 - Some one else ported it to Rhapsody. + Spent a couple of weeks adding variable block + size support to Rhapsody version. + Took the time to stop using rich man's source code control + (multiple copies) in linux/mac and put sources under RCS. + Folded linux/mac version changes into Rhapsody and + brought some of the Rhapsody changes into linux/mac + +09/1997 - Fixed bugs in MacOS version of variable block size. + Added new dump routines. + Added case-insensitive string matching. + Released one copy of version 0.5a3 source internally. + +10/1997 - Wrote MacOS documentation + Minor fixes + +11/1997 - A few more fixes + Released as version 0.5 + +12/1997 - Integrated new media abstraction + (includes support for ATA and ATAPI on MacOS) + +01/1998 - Added media iterators (to fix grunge in dump.c) + Added os_reload_media (to get rid of ioctl's in write_partition_map) + Added rename partition command ('n' in edit mode) + Added /dev/hd? and /dev/scd? to MkLinux list all disks + Added 68k target to CW project + +02/1998 - Released version 0.6 + Added support for ATA/IDE disks without LBA capability + Fixed bug - create partition with unmodified size failed + Added support for new (DR3) MkLinux names - show MkLinux + name when displaying under another name and allow the + MkLinux name to be used on input. + Released version 0.7 diff --git a/sbin/pdisk/MacSCSICommand.h b/sbin/pdisk/MacSCSICommand.h new file mode 100644 index 00000000000..b02b66f90ae --- /dev/null +++ b/sbin/pdisk/MacSCSICommand.h @@ -0,0 +1,420 @@ +/* + File: MacSCSICommand.h + + Contains: SCSI specific definitions. + + Written by: Martin Minow + +*/ + +/* + * Copyright 1995, 1997 by Apple Computer, Inc. + * All Rights Reserved + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appears in all copies and + * that both the copyright notice and this permission notice appear in + * supporting documentation. + * + * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, + * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION + * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * Scsi-specific definitions. + */ +#ifndef __MacSCSICommand__ +#define __MacSCSICommand__ + +/* + * The 6-byte commands are used for most simple + * I/O requests. + */ +struct SCSI_6_Byte_Command { /* Six-byte command */ + unsigned char opcode; /* 0 */ + unsigned char lbn3; /* 1 lbn in low 5 */ + unsigned char lbn2; /* 2 */ + unsigned char lbn1; /* 3 */ + unsigned char len; /* 4 */ + unsigned char ctrl; /* 5 */ +}; +typedef struct SCSI_6_Byte_Command SCSI_6_Byte_Command; + +struct SCSI_10_Byte_Command { /* Ten-byte command */ + unsigned char opcode; /* 0 */ + unsigned char lun; /* 1 */ + unsigned char lbn4; /* 2 */ + unsigned char lbn3; /* 3 */ + unsigned char lbn2; /* 4 */ + unsigned char lbn1; /* 5 */ + unsigned char pad; /* 6 */ + unsigned char len2; /* 7 */ + unsigned char len1; /* 8 */ + unsigned char ctrl; /* 9 */ +}; +typedef struct SCSI_10_Byte_Command SCSI_10_Byte_Command; + +struct SCSI_12_Byte_Command { /* Twelve-byte command */ + unsigned char opcode; /* 0 */ + unsigned char lun; /* 1 */ + unsigned char lbn4; /* 2 */ + unsigned char lbn3; /* 3 */ + unsigned char lbn2; /* 4 */ + unsigned char lbn1; /* 5 */ + unsigned char len4; /* 6 */ + unsigned char len3; /* 7 */ + unsigned char len2; /* 8 */ + unsigned char len1; /* 9 */ + unsigned char pad; /* 10 */ + unsigned char ctrl; /* 11 */ +}; +typedef struct SCSI_12_Byte_Command SCSI_12_Byte_Command; + +/* + * This union defines all scsi commands. + */ +union SCSI_Command { + SCSI_6_Byte_Command scsi6; + SCSI_10_Byte_Command scsi10; + SCSI_12_Byte_Command scsi12; + unsigned char scsi[12]; +}; +typedef union SCSI_Command SCSI_Command, *SCSI_CommandPtr; + +/* + * Returned by a read-capacity command. + */ +struct SCSI_Capacity_Data { + unsigned char lbn4; /* Number */ + unsigned char lbn3; /* of */ + unsigned char lbn2; /* logical */ + unsigned char lbn1; /* blocks */ + unsigned char len4; /* Length */ + unsigned char len3; /* of each */ + unsigned char len2; /* logical block */ + unsigned char len1; /* in bytes */ +}; +typedef struct SCSI_Capacity_Data SCSI_Capacity_Data; + +struct SCSI_Inquiry_Data { /* Inquiry returns this */ + unsigned char devType; /* 0 Device type, */ + unsigned char devTypeMod; /* 1 Device type modifier */ + unsigned char version; /* 2 ISO/ECMA/ANSI version */ + unsigned char format; /* 3 Response data format */ + unsigned char length; /* 4 Additional Length */ + unsigned char reserved5; /* 5 Reserved */ + unsigned char reserved6; /* 6 Reserved */ + unsigned char flags; /* 7 Capability flags */ + unsigned char vendor[8]; /* 8-15 Vendor-specific */ + unsigned char product[16]; /* 16-31 Product id */ + unsigned char revision[4]; /* 32-35 Product revision */ + unsigned char vendorSpecific[20]; /* 36-55 Vendor stuff */ + unsigned char moreReserved[40]; /* 56-95 Reserved */ +}; +typedef struct SCSI_Inquiry_Data SCSI_Inquiry_Data; + +/* + * This bit may be set in SCSI_Inquiry_Data.devTypeMod + */ +enum { + kScsiInquiryRMB = 0x80 /* Removable medium if set */ +}; +/* + * These bits may be set in SCSI_Inquiry_Data.flags + */ +enum { + kScsiInquiryRelAdr = 0x80, /* Has relative addressing */ + kScsiInquiryWBus32 = 0x40, /* Wide (32-bit) transfers */ + kScsiInquiryWBus16 = 0x20, /* Wide (16-bit) transfers */ + kScsiInquirySync = 0x10, /* Synchronous transfers */ + kScsiInquiryLinked = 0x08, /* Linked commands ok */ + kScsiInquiryReserved = 0x04, + kScsiInquiryCmdQue = 0x02, /* Tagged cmd queuing ok */ + kScsiInquirySftRe = 0x01 /* Soft reset alternative */ +}; + +/* + * These bits may be set in SCSI_Inquiry_Data.devType + */ +enum { + kScsiDevTypeDirect = 0, + kScsiDevTypeSequential, + kScsiDevTypePrinter, + kScsiDevTypeProcessor, + kScsiDevTypeWorm, /* Write-once, read mult */ + kScsiDevTypeCDROM, + kScsiDevTypeScanner, + kScsiDevTypeOptical, + kScsiDevTypeChanger, + kScsiDevTypeComm, + kScsiDevTypeGraphicArts0A, + kScsiDevTypeGraphicArts0B, + kScsiDevTypeFirstReserved, /* Reserved sequence start */ + kScsiDevTypeUnknownOrMissing = 0x1F, + kScsiDevTypeMask = 0x1F +}; +/* + * These are device type qualifiers. We need them to distinguish between "unknown" + * and "missing" devices. + */ +enum { + kScsiDevTypeQualifierConnected = 0x00, /* Exists and is connected */ + kScsiDevTypeQualifierNotConnected = 0x20, /* Logical unit exists */ + kScsiDevTypeQualifierReserved = 0x40, + kScsiDevTypeQualifierMissing = 0x60, /* No such logical unit */ + kScsiDevTypeQualifierVendorSpecific = 0x80, /* Other bits are unspecified */ + kScsiDevTypeQualifierMask = 0xE0 +}; +#define kScsiDevTypeMissing \ + (kScsiDevTypeUnknownOrMissing | kScsiDevTypeQualifierMissing) + +/* + * This is the data that is returned after a GetExtendedStatus + * request. The errorCode gives a general indication of the error, + * which may be qualified by the additionalSenseCode and + * additionalSenseQualifier fields. These may be device (vendor) + * specific values, however. The info[] field contains additional + * information. For a media error, it contains the failing + * logical block number (most-significant byte first). + */ +struct SCSI_Sense_Data { /* Request Sense result */ + unsigned char errorCode; /* 0 Class code, valid lbn */ + unsigned char segmentNumber; /* 1 Segment number */ + unsigned char senseKey; /* 2 Sense key and flags */ + unsigned char info[4]; + unsigned char additionalSenseLength; + unsigned char reservedForCopy[4]; + unsigned char additionalSenseCode; + unsigned char additionalSenseQualifier; + unsigned char fruCode; /* Field replacable unit code */ + unsigned char senseKeySpecific[2]; + unsigned char additional[101]; +}; +typedef struct SCSI_Sense_Data SCSI_Sense_Data; +/* + * The high-bit of errorCode signals whether there is a logical + * block. The low value signals whether there is a valid sense + */ +#define kScsiSenseHasLBN 0x80 /* Logical block number set */ +#define kScsiSenseInfoValid 0x70 /* Is sense key valid? */ +#define kScsiSenseInfoMask 0x70 /* Mask for sense info */ +/* + * These bits may be set in the sense key + */ +#define kScsiSenseKeyMask 0x0F +#define kScsiSenseILI 0x20 /* Illegal logical Length */ +#define kScsiSenseEOM 0x40 /* End of media */ +#define kScsiSenseFileMark 0x80 /* End of file mark */ + +/* + * SCSI sense codes. (Returned after request sense). + */ +#define kScsiSenseNone 0x00 /* No error */ +#define kScsiSenseRecoveredErr 0x01 /* Warning */ +#define kScsiSenseNotReady 0x02 /* Device not ready */ +#define kScsiSenseMediumErr 0x03 /* Device medium error */ +#define kScsiSenseHardwareErr 0x04 /* Device hardware error */ +#define kScsiSenseIllegalReq 0x05 /* Illegal request for dev. */ +#define kScsiSenseUnitAtn 0x06 /* Unit attention (not err) */ +#define kScsiSenseDataProtect 0x07 /* Data protection */ +#define kScsiSenseBlankCheck 0x08 /* Tape-specific error */ +#define kScsiSenseVendorSpecific 0x09 /* Vendor-specific error */ +#define kScsiSenseCopyAborted 0x0a /* Copy request cancelled */ +#define kScsiSenseAbortedCmd 0x0b /* Initiator aborted cmd. */ +#define kScsiSenseEqual 0x0c /* Comparison equal */ +#define kScsiSenseVolumeOverflow 0x0d /* Write past end mark */ +#define kScsiSenseMiscompare 0x0e /* Comparison failed */ +#define kScsiSenseCurrentErr 0x70 +#define kScsiSenseDeferredErr 0x71 + +/* + * Mode sense parameter header + */ +struct SCSI_ModeParamHeader { + unsigned char modeDataLength; + unsigned char mediumType; + unsigned char deviceSpecific; + unsigned char blockDescriptorLength; +}; +typedef struct SCSI_ModeParamHeader SCSI_ModeParamHeader; + +struct SCSI_ModeParamBlockDescriptor { + unsigned char densityCode; + unsigned char numberOfBlocks[3]; + unsigned char reserved; + unsigned char blockLength[3]; +}; +typedef struct SCSI_ModeParamBlockDescriptor SCSI_ModeParamBlockDescriptor; + +union SCSI_ModeParamPage { + unsigned char data[1]; + struct { + unsigned char code; + unsigned char length; + } page; +}; +typedef union SCSI_ModeParamPage SCSI_ModeParamPage; + +/* + * LogSense parameter header + */ +struct SCSI_LogSenseParamHeader { + unsigned char pageCode; + unsigned char reserved; + unsigned char pageLength[2]; +}; +typedef struct SCSI_LogSenseParamHeader SCSI_LogSenseParamHeader; + +/* + * Log parameter pages are variable-length with a fixed length header. + */ +union SCSI_LogSenseParamPage { + unsigned char data[1]; + struct { + unsigned char parameterCode[2]; + unsigned char flags; + unsigned char parameterLength; + } page; +}; +typedef union SCSI_LogSenseParamPage SCSI_LogSenseParamPage; + +/* + * SCSI command status (from status phase) + */ +#define kScsiStatusGood 0x00 /* Normal completion */ +#define kScsiStatusCheckCondition 0x02 /* Need GetExtendedStatus */ +#define kScsiStatusConditionMet 0x04 +#define kScsiStatusBusy 0x08 /* Device busy (self-test?) */ +#define kScsiStatusIntermediate 0x10 /* Intermediate status */ +#define kScsiStatusResConflict 0x18 /* Reservation conflict */ +#define kScsiStatusQueueFull 0x28 /* Target can't do command */ +#define kScsiStatusReservedMask 0x3e /* Vendor specific? */ + +/* + * SCSI command codes. Commands defined as ...6, ...10, ...12, are + * six-byte, ten-byte, and twelve-byte variants of the indicated command. + */ +/* + * These commands are supported for all devices. + */ +#define kScsiCmdChangeDefinition 0x40 +#define kScsiCmdCompare 0x39 +#define kScsiCmdCopy 0x18 +#define kScsiCmdCopyAndVerify 0x3a +#define kScsiCmdInquiry 0x12 +#define kScsiCmdLogSelect 0x4c +#define kScsiCmdLogSense 0x4d +#define kScsiCmdModeSelect10 0x55 +#define kScsiCmdModeSelect6 0x15 +#define kScsiCmdModeSense10 0x5a +#define kScsiCmdModeSense6 0x1a +#define kScsiCmdReadBuffer 0x3c +#define kScsiCmdRecvDiagResult 0x1c +#define kScsiCmdRequestSense 0x03 +#define kScsiCmdSendDiagnostic 0x1d +#define kScsiCmdTestUnitReady 0x00 +#define kScsiCmdWriteBuffer 0x3b + +/* + * These commands are supported by direct-access devices only. + */ +#define kScsiCmdFormatUnit 0x04 +#define kSCSICmdCopy 0x18 +#define kSCSICmdCopyAndVerify 0x3a +#define kScsiCmdLockUnlockCache 0x36 +#define kScsiCmdPrefetch 0x34 +#define kScsiCmdPreventAllowRemoval 0x1e +#define kScsiCmdRead6 0x08 +#define kScsiCmdRead10 0x28 +#define kScsiCmdReadCapacity 0x25 +#define kScsiCmdReadDefectData 0x37 +#define kScsiCmdReadLong 0x3e +#define kScsiCmdReassignBlocks 0x07 +#define kScsiCmdRelease 0x17 +#define kScsiCmdReserve 0x16 +#define kScsiCmdRezeroUnit 0x01 +#define kScsiCmdSearchDataEql 0x31 +#define kScsiCmdSearchDataHigh 0x30 +#define kScsiCmdSearchDataLow 0x32 +#define kScsiCmdSeek6 0x0b +#define kScsiCmdSeek10 0x2b +#define kScsiCmdSetLimits 0x33 +#define kScsiCmdStartStopUnit 0x1b +#define kScsiCmdSynchronizeCache 0x35 +#define kScsiCmdVerify 0x2f +#define kScsiCmdWrite6 0x0a +#define kScsiCmdWrite10 0x2a +#define kScsiCmdWriteAndVerify 0x2e +#define kScsiCmdWriteLong 0x3f +#define kScsiCmdWriteSame 0x41 + +/* + * These commands are supported by sequential devices. + */ +#define kScsiCmdRewind 0x01 +#define kScsiCmdWriteFilemarks 0x10 +#define kScsiCmdSpace 0x11 +#define kScsiCmdLoadUnload 0x1B +/* + * ANSI SCSI-II for CD-ROM devices. + */ +#define kScsiCmdReadCDTableOfContents 0x43 + +/* + * Message codes (for Msg In and Msg Out phases). + */ +#define kScsiMsgAbort 0x06 +#define kScsiMsgAbortTag 0x0d +#define kScsiMsgBusDeviceReset 0x0c +#define kScsiMsgClearQueue 0x0e +#define kScsiMsgCmdComplete 0x00 +#define kScsiMsgDisconnect 0x04 +#define kScsiMsgIdentify 0x80 +#define kScsiMsgIgnoreWideResdue 0x23 +#define kScsiMsgInitiateRecovery 0x0f +#define kScsiMsgInitiatorDetectedErr 0x05 +#define kScsiMsgLinkedCmdComplete 0x0a +#define kScsiMsgLinkedCmdCompleteFlag 0x0b +#define kScsiMsgParityErr 0x09 +#define kScsiMsgRejectMsg 0x07 +#define kScsiMsgModifyDataPtr 0x00 /* Extended msg */ +#define kScsiMsgNop 0x08 +#define kScsiMsgHeadOfQueueTag 0x21 /* Two byte msg */ +#define kScsiMsgOrderedQueueTag 0x22 /* Two byte msg */ +#define kScsiMsgSimpleQueueTag 0x20 /* Two byte msg */ +#define kScsiMsgReleaseRecovery 0x10 +#define kScsiMsgRestorePointers 0x03 +#define kScsiMsgSaveDataPointers 0x02 +#define kScsiMsgSyncXferReq 0x01 /* Extended msg */ +#define kScsiMsgWideDataXferReq 0x03 /* Extended msg */ +#define kScsiMsgTerminateIOP 0x11 +#define kScsiMsgExtended 0x01 +#define kScsiMsgEnableDisconnectMask 0x40 + +#define kScsiMsgTwoByte 0x20 +#define kScsiMsgTwoByteMin 0x20 +#define kScsiMsgTwoByteMax 0x2f + +/* + * Default timeout times for SCSI commands (times are in Msec). + */ +#define kScsiNormalCompletionTime (500L) /* 1/2 second */ +/* + * Dratted DAT tape. + */ +#define kScsiDATCompletionTime (60L * 1000L); /* One minute */ +/* + * Yes, we do allow 90 seconds for spin-up of those dratted tape drives. + */ +#define kScsiSpinUpCompletionTime (90L * 1000L) + + +#endif /* __MacSCSICommand__ */ diff --git a/sbin/pdisk/README b/sbin/pdisk/README new file mode 100644 index 00000000000..71fe528e05d --- /dev/null +++ b/sbin/pdisk/README @@ -0,0 +1,144 @@ +Product name: pdisk +Version: 0.7 +Ship date: 18 February 1998 +Company name: Apple Computer +Author name: Eryk Vershen <eryk@apple.com> + +Description: A low-level Apple partition table editor for (Mk)Linux. + A MacOS version exists for "standalone" use. + +What's New: Added support for ATA/IDE disks without LBA capability + Fixed bug - create partition with unmodified size failed + Added support for new (DR3) MkLinux names - show MkLinux + name when displaying under another name and allow the + MkLinux name to be used on input. + +Last time: MacOS version handles IDE/ATA and ATAPI devices. + Added interactive mode + Added ability to rename a partition + Added 68k target to MacOS CodeWarrior project + +Requirements: MkLinux - just run the binary + Linux - recompile for your hardware + MacOS - Distributed binaries for PowerPC or 68000 + I haven't tried it except on 7.6.1 and 8.0 + +Price: Free + +Legalese: + Copyright 1996,1997,1998 by Apple Computer, Inc. + All Rights Reserved + + Permission to use, copy, modify, and distribute this software and + its documentation for any purpose and without fee is hereby granted, + provided that the above copyright notice appears in all copies and + that both the copyright notice and this permission notice appear in + supporting documentation. + + APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE + INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + FOR A PARTICULAR PURPOSE. + + IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR + CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, + NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION + WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +Contact Info: Go to <http://www.mklinux.apple.com> to find out about MkLinux. + Go to the Faq-O-Matic (there should be a pointer or three + in the MkLinux pages) and search for 'pdisk'. + You can send mail to the author. There is no guarantee of + a response, but it is your best hope of getting a bug fixed + or a feature added. + + +Other info: + + +READ the html file or the man page. + + +Finding out about apple partitioning +------------------------------------ +The best curently available documentation on the Apple disk partitioning scheme +is "Inside Macintosh: Devices" pages 3-12 to 3-15 combined with the info +in "Inside Macintosh - Volume V" pages V-576 to V-582. This, unfortunately, +does not cover everything. + + +Building the macintosh application +---------------------------------- +I have only built this under Code Warrior Pro. The project file is included. +Thanks to Martin Minow for the SCSI support code. + + +Some notes on the apple partitioning +------------------------------------ +The apple disk partitioning scheme was developed in 1986. It attempted to +be forward thinking as it was intended to handle drives of sizes up to several +hundred megabytes. There was a design document, but like most such documents +it was neither complete nor unambiguous. + +While the original intent was to handle various block sizes, in practice +most devices use a partitioning block size of 512 bytes. +Since the various address fields are 32 bits unsigned this means the format +can handle disks up to 2 Terabytes in size. (32bits + 9 bits = 41 bits) +Because the format was designed around SCSI, there is no knowledge of +cylinders or heads, all block address are in absolute sector form. +A correct map should describe every block on the disk except for block zero. + +An aside on CDROMs. Most old apple CDROMs have incorrect data in block zero. +Since the HFS file-system could only handle 512 byte blocks, apple drives had +a special mode where they would do deblocking (i.e. converting 2k blocks +into four 512byte blocks and accepting 512byte block addresses.) The partition +maps laid down on these disks are for the deblocked form. In many cases the +partition maps they contain have only the minimum number of fields correct. +At least one CDROM I have seen doesn't even contain a partition map at all, +but is simply an HFS volume. +Bootable CD-ROMs have even stranger partition maps since two are laid down: +one at 2K offsets and one at 512-byte offsets. If you notice that these +overlap then you begin to get an idea of how wierd these maps can be. + +The documentation in Inside Macintosh is only partially correct. +The boot-arguments field was left out. A/UX used the boot arguments field +for something that was called the bzb (block zero block - don't ask me why). +This structure evolved over the course of A/UX. I have recapitulated this +in the dpme.h header file. + + +Making a disk with Apple & Intel partitioning +--------------------------------------------- +Don't cringe. I know it is an awful hack, but sometimes... +While I don't recommend doing this, it can be useful. +The procedure below is what we did. + +The intel map can contain NO MORE THAN FOUR PRIMARY PARTITIONS. +You can't have any extended or logical partitions. (Well, you might get it +to work but I wouldn't want to try it.) The disk will NOT BE INTEL BOOTABLE. + +1) Use pdisk to initialize an apple partition map. Don't add any partitions + yet, just write the map out and quit. + +2) Use fdisk to create the primary partitions. Go into the expert 'x' menu + in fdisk and print out the table with the sector addresses. Write the + start and lengths down some where. Write the table out. + +3) Use pdisk again. Shrink the partition map down, if necessary, so it + does not overlap any intel partition. Create an apple partition for each + intel partition using the start and length value you got from fdisk. + Write out the map and quit. + +At present file systems are not compatible between Linux & MkLinux, but you +can tar stuff into these partitions and tar them out on another machine. + + + +Good luck, + +-eryk vershen + software mechanic + + work: eryk@apple.com + non-work: eryk@cfcl.com diff --git a/sbin/pdisk/SCSI_media.c b/sbin/pdisk/SCSI_media.c new file mode 100644 index 00000000000..fb7bb587ecc --- /dev/null +++ b/sbin/pdisk/SCSI_media.c @@ -0,0 +1,1091 @@ +/* + * SCSI_media.c - + * + * Written by Eryk Vershen (eryk@apple.com) + */ + +/* + * Copyright 1997,1998 by Apple Computer, Inc. + * All Rights Reserved + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appears in all copies and + * that both the copyright notice and this permission notice appear in + * supporting documentation. + * + * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, + * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION + * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + + +// for printf() & sprintf() +#include <stdio.h> +// for malloc() & free() +#include <stdlib.h> +#include "DoSCSICommand.h" +#include "SCSI_media.h" +#include "util.h" + + +/* + * Defines + */ +#define DriverRefNumToSCSI(x) ((signed short) (~(x) - 32)) + + +/* + * Types + */ +typedef struct SCSI_media *SCSI_MEDIA; + +struct SCSI_media { + struct media m; + long bus; + long id; +}; + +struct bus_entry { + long bus; + long sort_value; + long max_id; + long master_id; +}; + +struct SCSI_manager { + long exists; + long kind; + long bus_count; + struct bus_entry *bus_list; +}; + +typedef struct SCSI_media_iterator *SCSI_MEDIA_ITERATOR; + +struct SCSI_media_iterator { + struct media_iterator m; + long bus_index; + long bus; + long id; +}; + +struct mklinux_order_cache { + struct cache_item *first; + struct cache_item *last; + long next_disk; + long next_cdrom; + long loaded; +}; + +struct cache_item { + struct cache_item *next; + long bus; + long id; + long value; + long is_cdrom; + long unsure; +}; + + +/* + * Global Constants + */ +enum { + kNoDevice = 0x00FF +}; + +enum { + kRequiredSCSIinquiryLength = 36 +}; + + +/* + * Global Variables + */ +static long scsi_inited = 0; +static struct SCSI_manager scsi_mgr; +static struct mklinux_order_cache mklinux_order; + + +/* + * Forward declarations + */ +int AsyncSCSIPresent(void); +void scsi_init(void); +SCSI_MEDIA new_scsi_media(void); +long read_scsi_media(MEDIA m, long long offset, unsigned long count, void *address); +long write_scsi_media(MEDIA m, long long offset, unsigned long count, void *address); +long close_scsi_media(MEDIA m); +long os_reload_scsi_media(MEDIA m); +long compute_id(long bus, long device); +int SCSI_ReadBlock(UInt32 id, UInt32 bus, UInt32 block_size, UInt32 block, UInt8 *address); +int SCSI_WriteBlock(UInt32 id, UInt32 bus, UInt32 block_size, UInt32 block, UInt8 *address); +int DoTestUnitReady(UInt8 targetID, int bus); +int DoReadCapacity(UInt32 id, UInt32 bus, UInt32 *blockCount, UInt32 *blockSize); +SCSI_MEDIA_ITERATOR new_scsi_iterator(void); +void reset_scsi_iterator(MEDIA_ITERATOR m); +char *step_scsi_iterator(MEDIA_ITERATOR m); +void delete_scsi_iterator(MEDIA_ITERATOR m); +void fill_bus_entry(struct bus_entry *entry, long bus); +/*long get_bus_sort_value(long bus);*/ +int bus_entry_compare(const void* a, const void* b); +int DoInquiry(UInt32 id, UInt32 bus, UInt32 *devType); +void probe_all(void); +void probe_scsi_device(long bus, long id, int unsure); +long lookup_scsi_device(long bus, long id, int *is_cdrom, int *unsure); +long lookup_scsi_index(long index, int is_cdrom, long *bus, long *id); +void add_to_cache(long bus, long id, int is_cdrom, int unsure); +void init_mklinux_cache(void); +void clear_mklinux_cache(void); +void mark_mklinux_cache_loaded(void); +int mklinux_cache_loaded(void); + + +/* + * Routines + */ +int +AsyncSCSIPresent(void) +{ + return (TrapAvailable(_SCSIAtomic)); +} + + +void +scsi_init(void) +{ + int i; + int old_scsi; + + if (scsi_inited != 0) { + return; + } + scsi_inited = 1; + + scsi_mgr.exists = 1; + scsi_mgr.kind = allocate_media_kind(); + + if (AsyncSCSIPresent()) { + AllocatePB(); + + scsi_mgr.bus_count = gSCSIHiBusID + 1; + old_scsi = 0; + } else { + scsi_mgr.bus_count = 1; + old_scsi = 1; + } + + scsi_mgr.bus_list = (struct bus_entry *) + calloc(scsi_mgr.bus_count, sizeof(struct bus_entry)); + + if (scsi_mgr.bus_list == 0) { + scsi_mgr.bus_count = 0; + } else { + for (i = 0; i < scsi_mgr.bus_count; i++) { + if (old_scsi) { + scsi_mgr.bus_list[i].bus = 0xFF; + } else { + scsi_mgr.bus_list[i].bus = i; + } + fill_bus_entry(&scsi_mgr.bus_list[i], i); + } + qsort((void *)scsi_mgr.bus_list, /* address of array */ + scsi_mgr.bus_count, /* number of elements */ + sizeof(struct bus_entry), /* size of element */ + bus_entry_compare); /* element comparison routine */ + } + + init_mklinux_cache(); +} + +void +fill_bus_entry(struct bus_entry *entry, long bus) +{ + OSErr status; + SCSIBusInquiryPB pb; + long len; + long result; + long x, y; + + if (!AsyncSCSIPresent()) { + entry->sort_value = 0; + entry->max_id = 7; + entry->master_id = 7; + return; + } + len = sizeof(SCSIBusInquiryPB); + clear_memory((Ptr) &pb, len); + pb.scsiPBLength = len; + pb.scsiFunctionCode = SCSIBusInquiry; + pb.scsiDevice.bus = bus; + status = SCSIAction((SCSI_PB *) &pb); + if (status != noErr) { + result = 6; + } else { + switch (pb.scsiHBAslotType) { + case scsiMotherboardBus: x = 0; break; + case scsiPDSBus: x = 1; break; + case scsiNuBus: x = 2; break; + case scsiPCIBus: x = 3; break; + case scsiFireWireBridgeBus: x = 4; break; + case scsiPCMCIABus: x = 5; break; + default: x = 7 + pb.scsiHBAslotType; break; + }; + + switch (pb.scsiFeatureFlags & scsiBusInternalExternalMask) { + case scsiBusInternal: y = 0; break; + case scsiBusInternalExternal: y = 1; break; + case scsiBusExternal: y = 2; break; + default: + case scsiBusInternalExternalUnknown: y = 3; break; + }; + result = x * 4 + y; + } + entry->sort_value = result; + entry->max_id = pb.scsiMaxLUN; + entry->master_id = pb.scsiInitiatorID; +} + + +int +bus_entry_compare(const void* a, const void* b) +{ + long result; + + const struct bus_entry *x = (const struct bus_entry *) a; + const struct bus_entry *y = (const struct bus_entry *) b; + + result = x->sort_value - y->sort_value; + if (result == 0) { + result = x->bus - y->bus; + } + return result; +} + + +SCSI_MEDIA +new_scsi_media(void) +{ + return (SCSI_MEDIA) new_media(sizeof(struct SCSI_media)); +} + + +MEDIA +open_old_scsi_as_media(long device) +{ + return open_scsi_as_media(kOriginalSCSIBusAdaptor, device); +} + + +MEDIA +open_scsi_as_media(long bus, long device) +{ + SCSI_MEDIA a; + UInt32 blockCount; + UInt32 blockSize; + + if (scsi_inited == 0) { + scsi_init(); + } + + if (scsi_mgr.exists == 0) { + return 0; + } + + a = 0; + if (DoTestUnitReady(device, bus) > 0) { + if (DoReadCapacity(device, bus, &blockCount, &blockSize) != 0) { + a = new_scsi_media(); + if (a != 0) { + a->m.kind = scsi_mgr.kind; + a->m.grain = blockSize; + a->m.size_in_bytes = ((long long)blockCount) * blockSize; + a->m.do_read = read_scsi_media; + a->m.do_write = write_scsi_media; + a->m.do_close = close_scsi_media; + a->m.do_os_reload = os_reload_scsi_media; + a->bus = bus; + a->id = device; + } + } + } + return (MEDIA) a; +} + + +long +read_scsi_media(MEDIA m, long long offset, unsigned long count, void *address) +{ + SCSI_MEDIA a; + long rtn_value; + long block; + long block_count; + long block_size; + unsigned char *buffer; + int i; + + block = (long) offset; +//printf("scsi %d count %d\n", block, count); + a = (SCSI_MEDIA) m; + rtn_value = 0; + if (a == 0) { + /* no media */ + } else if (a->m.kind != scsi_mgr.kind) { + /* wrong kind - XXX need to error here - this is an internal problem */ + } else if (count <= 0 || count % a->m.grain != 0) { + /* can't handle size */ + } else if (offset < 0 || offset % a->m.grain != 0) { + /* can't handle offset */ + } else if (offset + count > a->m.size_in_bytes) { + /* check for offset (and offset+count) too large */ + } else { + /* XXX do a read on the physical device */ + block_size = a->m.grain; + block = offset / block_size; + block_count = count / block_size; + buffer = address; + rtn_value = 1; + for (i = 0; i < block_count; i++) { + if (SCSI_ReadBlock(a->id, a->bus, block_size, block, buffer) == 0) { + rtn_value = 0; + break; + } + buffer += block_size; + block += 1; + } + } + return rtn_value; +} + + +long +write_scsi_media(MEDIA m, long long offset, unsigned long count, void *address) +{ + SCSI_MEDIA a; + long rtn_value; + long block; + long block_count; + long block_size; + unsigned char *buffer; + int i; + + a = (SCSI_MEDIA) m; + rtn_value = 0; + if (a == 0) { + /* no media */ + } else if (a->m.kind != scsi_mgr.kind) { + /* XXX need to error here - this is an internal problem */ + } else if (count <= 0 || count % a->m.grain != 0) { + /* can't handle size */ + } else if (offset < 0 || offset % a->m.grain != 0) { + /* can't handle offset */ + } else if (offset + count > a->m.size_in_bytes) { + /* check for offset (and offset+count) too large */ + } else { + /* XXX do a write on the physical device */ + block_size = a->m.grain; + block = offset / block_size; + block_count = count / block_size; + buffer = address; + rtn_value = 1; + for (i = 0; i < block_count; i++) { + if (SCSI_WriteBlock(a->id, a->bus, block_size, block, buffer) == 0) { + rtn_value = 0; + break; + } + buffer += block_size; + block += 1; + } + } + return rtn_value; +} + + +long +close_scsi_media(MEDIA m) +{ + SCSI_MEDIA a; + + a = (SCSI_MEDIA) m; + if (a == 0) { + return 0; + } else if (a->m.kind != scsi_mgr.kind) { + /* XXX need to error here - this is an internal problem */ + return 0; + } + /* XXX nothing to do - I think? */ + return 1; +} + + +long +os_reload_scsi_media(MEDIA m) +{ + printf("Reboot your system so the partition table will be reread.\n"); + return 1; +} + + +#pragma mark - + + +int +DoTestUnitReady(UInt8 targetID, int bus) +{ + OSErr status; + Str255 errorText; + char* msg; + static const SCSI_6_Byte_Command gTestUnitReadyCommand = { + kScsiCmdTestUnitReady, 0, 0, 0, 0, 0 + }; + SCSI_Sense_Data senseData; + DeviceIdent scsiDevice; + int rtn_value; + + scsiDevice.diReserved = 0; + scsiDevice.bus = bus; + scsiDevice.targetID = targetID; + scsiDevice.LUN = 0; + + status = DoSCSICommand( + scsiDevice, + "\pTest Unit Ready", + (SCSI_CommandPtr) &gTestUnitReadyCommand, + NULL, + 0, + scsiDirectionNone, + NULL, + &senseData, + errorText + ); + if (status == scsiNonZeroStatus) { + rtn_value = -1; + } else if (status != noErr) { + rtn_value = 0; + } else { + rtn_value = 1; + } + return rtn_value; +} + + +int +SCSI_ReadBlock(UInt32 id, UInt32 bus, UInt32 block_size, UInt32 block, UInt8 *address) +{ + OSErr status; + Str255 errorText; + char* msg; + static SCSI_10_Byte_Command gReadCommand = { + kScsiCmdRead10, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + SCSI_Sense_Data senseData; + DeviceIdent scsiDevice; + int rtn_value; + long count; + +//printf("scsi read %d:%d block %d size %d\n", bus, id, block, block_size); + scsiDevice.diReserved = 0; + scsiDevice.bus = bus; + scsiDevice.targetID = id; + scsiDevice.LUN = 0; + + gReadCommand.lbn4 = (block >> 24) & 0xFF; + gReadCommand.lbn3 = (block >> 16) & 0xFF; + gReadCommand.lbn2 = (block >> 8) & 0xFF; + gReadCommand.lbn1 = block & 0xFF; + + count = 1; + gReadCommand.len2 = (count >> 8) & 0xFF; + gReadCommand.len1 = count & 0xFF; + + status = DoSCSICommand( + scsiDevice, + "\pRead", + (SCSI_CommandPtr) &gReadCommand, + (Ptr) address, + count * block_size, + scsiDirectionIn, + NULL, + &senseData, + errorText + ); + if (status == noErr) { + rtn_value = 1; + } else { + rtn_value = 0; + } + return rtn_value; +} + + +int +SCSI_WriteBlock(UInt32 id, UInt32 bus, UInt32 block_size, UInt32 block, UInt8 *address) +{ + OSErr status; + Str255 errorText; + char* msg; + static SCSI_10_Byte_Command gWriteCommand = { + kScsiCmdWrite10, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + SCSI_Sense_Data senseData; + DeviceIdent scsiDevice; + int rtn_value; + long count; + + scsiDevice.diReserved = 0; + scsiDevice.bus = bus; + scsiDevice.targetID = id; + scsiDevice.LUN = 0; + + gWriteCommand.lbn4 = (block >> 24) & 0xFF; + gWriteCommand.lbn3 = (block >> 16) & 0xFF; + gWriteCommand.lbn2 = (block >> 8) & 0xFF; + gWriteCommand.lbn1 = block & 0xFF; + + count = 1; + gWriteCommand.len2 = (count >> 8) & 0xFF; + gWriteCommand.len1 = count & 0xFF; + + status = DoSCSICommand( + scsiDevice, + "\pWrite", + (SCSI_CommandPtr) &gWriteCommand, + (Ptr) address, + count * block_size, + scsiDirectionOut, + NULL, + &senseData, + errorText + ); + if (status == noErr) { + rtn_value = 1; + } else { + rtn_value = 0; + } + return rtn_value; +} + + +int +DoReadCapacity(UInt32 id, UInt32 bus, UInt32 *blockCount, UInt32 *blockSize) +{ + OSErr status; + Str255 errorText; + static const SCSI_10_Byte_Command gCapacityCommand = { + kScsiCmdReadCapacity, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + SCSI_Sense_Data senseData; + DeviceIdent scsiDevice; + SCSI_Capacity_Data capacityData; + UInt32 temp; + int rtn_value; + + scsiDevice.diReserved = 0; + scsiDevice.bus = bus; + scsiDevice.targetID = id; + scsiDevice.LUN = 0; + + CLEAR(capacityData); + + status = DoSCSICommand( + scsiDevice, + "\pRead Capacity", + (SCSI_CommandPtr) &gCapacityCommand, + (Ptr) &capacityData, + sizeof (SCSI_Capacity_Data), + scsiDirectionIn, + NULL, + &senseData, + errorText + ); + + if (status == noErr) { + temp = capacityData.lbn4; + temp = (temp << 8) | capacityData.lbn3; + temp = (temp << 8) | capacityData.lbn2; + temp = (temp << 8) | capacityData.lbn1; + *blockCount = temp; + + temp = capacityData.len4; + temp = (temp << 8) | capacityData.len3; + temp = (temp << 8) | capacityData.len2; + temp = (temp << 8) | capacityData.len1; + *blockSize = temp; + + rtn_value = 1; + } else { + rtn_value = 0; + } + return rtn_value; +} + + +int +DoInquiry(UInt32 id, UInt32 bus, UInt32 *devType) +{ + OSErr status; + Str255 errorText; + static const SCSI_6_Byte_Command gInquiryCommand = { + kScsiCmdInquiry, 0, 0, 0, kRequiredSCSIinquiryLength, 0 + }; + SCSI_Sense_Data senseData; + DeviceIdent scsiDevice; + SCSI_Inquiry_Data inquiryData; + UInt32 temp; + int rtn_value; + + scsiDevice.diReserved = 0; + scsiDevice.bus = bus; + scsiDevice.targetID = id; + scsiDevice.LUN = 0; + + CLEAR(inquiryData); + + status = DoSCSICommand( + scsiDevice, + "\pInquiry", + (SCSI_CommandPtr) &gInquiryCommand, + (Ptr) &inquiryData, + kRequiredSCSIinquiryLength, + scsiDirectionIn, + NULL, + &senseData, + errorText + ); + + if (status == noErr) { + *devType = inquiryData.devType & kScsiDevTypeMask; + rtn_value = 1; + } else { + rtn_value = 0; + } + return rtn_value; +} + + +MEDIA +SCSI_FindDevice(long dRefNum) +{ + SCSIDriverPB pb; + OSErr status; + short targetID; + + status = nsvErr; + if (AsyncSCSIPresent()) { + clear_memory((Ptr) &pb, sizeof pb); + + pb.scsiPBLength = sizeof (SCSIDriverPB); + pb.scsiCompletion = NULL; + pb.scsiFlags = 0; + pb.scsiFunctionCode = SCSILookupRefNumXref; + pb.scsiDevice.bus = kNoDevice; /* was *((long *) &pb.scsiDevice) = 0xFFFFFFFFL; */ + + do { + status = SCSIAction((SCSI_PB *) &pb); + + if (status != noErr) { + break; + } else if (pb.scsiDriver == dRefNum + && pb.scsiDevice.bus != kNoDevice) { + return open_scsi_as_media(pb.scsiDevice.bus, pb.scsiDevice.targetID); + + } else { + pb.scsiDevice = pb.scsiNextDevice; + } + } + while (pb.scsiDevice.bus != kNoDevice); + } + if (status == nsvErr) { + /* + * The asynchronous SCSI Manager is missing or the + * driver didn't register with the SCSI Manager.*/ + targetID = DriverRefNumToSCSI(dRefNum); + if (targetID >= 0 && targetID <= 6) { + return open_old_scsi_as_media(targetID); + } + } + return 0; +} + + +#pragma mark - + + +SCSI_MEDIA_ITERATOR +new_scsi_iterator(void) +{ + return (SCSI_MEDIA_ITERATOR) new_media_iterator(sizeof(struct SCSI_media_iterator)); +} + + +MEDIA_ITERATOR +create_scsi_iterator(void) +{ + SCSI_MEDIA_ITERATOR a; + + if (scsi_inited == 0) { + scsi_init(); + } + + if (scsi_mgr.exists == 0) { + return 0; + } + + a = new_scsi_iterator(); + if (a != 0) { + a->m.kind = scsi_mgr.kind; + a->m.state = kInit; + a->m.do_reset = reset_scsi_iterator; + a->m.do_step = step_scsi_iterator; + a->m.do_delete = delete_scsi_iterator; + a->bus_index = 0; + a->bus = 0; + a->id = 0; + } + + return (MEDIA_ITERATOR) a; +} + + +void +reset_scsi_iterator(MEDIA_ITERATOR m) +{ + SCSI_MEDIA_ITERATOR a; + + a = (SCSI_MEDIA_ITERATOR) m; + if (a == 0) { + /* no media */ + } else if (a->m.kind != scsi_mgr.kind) { + /* wrong kind - XXX need to error here - this is an internal problem */ + } else if (a->m.state != kInit) { + a->m.state = kReset; + } +} + + +char * +step_scsi_iterator(MEDIA_ITERATOR m) +{ + SCSI_MEDIA_ITERATOR a; + char *result; + + a = (SCSI_MEDIA_ITERATOR) m; + if (a == 0) { + /* no media */ + } else if (a->m.kind != scsi_mgr.kind) { + /* wrong kind - XXX need to error here - this is an internal problem */ + } else { + switch (a->m.state) { + case kInit: + /* find # of buses - done in AllocatePB() out of scsi_init() */ + a->m.state = kReset; + /* fall through to reset */ + case kReset: + a->bus_index = 0 /* first bus id */; + a->bus = scsi_mgr.bus_list[a->bus_index].bus; + a->id = 0 /* first device id */; + a->m.state = kIterating; + clear_mklinux_cache(); + /* fall through to iterate */ + case kIterating: + while (1) { + if (a->bus_index >= scsi_mgr.bus_count /* max bus id */) { + break; + } + if (a->id == scsi_mgr.bus_list[a->bus_index].master_id) { + /* next id */ + a->id += 1; + } + if (a->id > scsi_mgr.bus_list[a->bus_index].max_id) { + a->bus_index += 1; + a->bus = scsi_mgr.bus_list[a->bus_index].bus; + a->id = 0 /* first device id */; + continue; /* try again */ + } + /* generate result */ + result = (char *) malloc(20); + if (result != NULL) { + if (a->bus == 0xFF) { + sprintf(result, "/dev/scsi%c", '0'+a->id); + probe_scsi_device(a->bus, a->id, 1); + } else { + sprintf(result, "/dev/scsi%c.%c", '0'+a->bus, '0'+a->id); + /* only probe out of iterate; so always added in order. */ + probe_scsi_device(a->bus, a->id, 0); + } + } + + a->id += 1; /* next id */ + return result; + } + a->m.state = kEnd; + /* fall through to end */ + case kEnd: + mark_mklinux_cache_loaded(); + default: + break; + } + } + return 0 /* no entry */; +} + + +void +delete_scsi_iterator(MEDIA_ITERATOR m) +{ + return; +} + + +#pragma mark - + + +MEDIA +open_mklinux_scsi_as_media(long index, int is_cdrom) +{ + MEDIA m; + long bus; + long id; + + if (lookup_scsi_index(index, is_cdrom, &bus, &id) > 0) { + m = open_scsi_as_media(bus, id); + } else { + m = 0; + } + + return m; +} + + +char * +mklinux_old_scsi_name(long id) +{ + mklinux_scsi_name(kOriginalSCSIBusAdaptor, id); +} + + +char * +mklinux_scsi_name(long bus, long id) +{ + char *result = 0; + long value; + int is_cdrom; + int unsure; + char *suffix; + + /* name is sda, sdb, sdc, ... + * in order by buses and ids, but only count responding devices ... + */ + if ((value = lookup_scsi_device(bus, id, &is_cdrom, &unsure)) >= 0) { + result = (char *) malloc(20); + if (result != NULL) { + if (unsure) { + suffix = " ?"; + } else { + suffix = ""; + } + if (is_cdrom) { + sprintf(result, "/dev/scd%c%s", '0' + value, suffix); + } else { + sprintf(result, "/dev/sd%c%s", 'a' + value, suffix); + } + } + } + return result; +} + + +void +probe_all(void) +{ + MEDIA_ITERATOR iter; + char *name; + + iter = create_scsi_iterator(); + if (iter == 0) { + return; + } + + printf("finding devices "); + fflush(stdout); + while ((name = step_media_iterator(iter)) != 0) { + /* step does the probe for us */ + printf("."); + fflush(stdout); + free(name); + } + delete_media_iterator(iter); + printf("\n"); + fflush(stdout); +} + + +void +probe_scsi_device(long bus, long id, int unsure) +{ + UInt32 devType; + + if (DoInquiry(id, bus, &devType)) { + if (devType == kScsiDevTypeDirect || devType == kScsiDevTypeWorm + || devType == kScsiDevTypeOptical) { + add_to_cache(bus, id, 0, unsure); + } else if (devType == kScsiDevTypeCDROM) { + add_to_cache(bus, id, 1, unsure); + } + } +} + + +long +lookup_scsi_device(long bus, long id, int *is_cdrom, int *unsure) +{ + /* walk down list looking for bus and id ? + * + * only probe out of iterate (so always add in order) + * reset list if we reset the iterate + */ + struct cache_item *item; + struct cache_item *next; + long result = -1; + int count = 0; + + if (scsi_inited == 0) { + scsi_init(); + } + + while (1) { + count++; + for (item = mklinux_order.first; item != NULL; item = item->next) { + if (item->bus == bus && item->id == id) { + result = item->value; + *is_cdrom = item->is_cdrom; + *unsure = item->unsure; + break; + } + } + if (count < 2 && result < 0) { + probe_all(); + } else { + break; + } + }; + + return result; +} + + +/* + * This has the same structure as lookup_scsi_device() except we are + * matching on the value & type rather than the bus & id. + */ +long +lookup_scsi_index(long index, int is_cdrom, long *bus, long *id) +{ + struct cache_item *item; + struct cache_item *next; + long result = 0; + int count = 0; + + if (scsi_inited == 0) { + scsi_init(); + } + + while (1) { + count++; + for (item = mklinux_order.first; item != NULL; item = item->next) { + if (item->value == index && item->is_cdrom == is_cdrom + && item->unsure == 0) { + result = 1; + *bus = item->bus; + *id = item->id; + break; + } + } + if (count < 2 && result == 0 && !mklinux_cache_loaded()) { + probe_all(); + } else { + break; + } + }; + + return result; +} + + +void +add_to_cache(long bus, long id, int is_cdrom, int unsure) +{ + struct cache_item *item; + + item = malloc(sizeof(struct cache_item)); + if (item == NULL) { + return; + } else { + item->bus = bus; + item->id = id; + item->is_cdrom = is_cdrom; + item->unsure = unsure; + if (is_cdrom) { + item->value = mklinux_order.next_cdrom; + mklinux_order.next_cdrom++; + } else { + item->value = mklinux_order.next_disk; + mklinux_order.next_disk++; + } + item->next = 0; + } + if (mklinux_order.first == NULL) { + mklinux_order.first = item; + mklinux_order.last = item; + } else { + mklinux_order.last->next = item; + mklinux_order.last = item; + } +} + + +void +init_mklinux_cache(void) +{ + mklinux_order.first = NULL; + clear_mklinux_cache(); +} + + +void +clear_mklinux_cache(void) +{ + struct cache_item *item; + struct cache_item *next; + + for (item = mklinux_order.first; item != NULL; item = next) { + next = item->next; + free(item); + } + /* back to starting value */ + mklinux_order.first = NULL; + mklinux_order.last = NULL; + mklinux_order.next_disk = 0; + mklinux_order.next_cdrom = 0; + mklinux_order.loaded = 0; +} + + +void +mark_mklinux_cache_loaded(void) +{ + mklinux_order.loaded = 1; +} + + +int +mklinux_cache_loaded(void) +{ + return mklinux_order.loaded; +} diff --git a/sbin/pdisk/SCSI_media.h b/sbin/pdisk/SCSI_media.h new file mode 100644 index 00000000000..481c0ff289a --- /dev/null +++ b/sbin/pdisk/SCSI_media.h @@ -0,0 +1,65 @@ +/* + * SCSI_media.h - + * + * Written by Eryk Vershen (eryk@apple.com) + */ + +/* + * Copyright 1997,1998 by Apple Computer, Inc. + * All Rights Reserved + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appears in all copies and + * that both the copyright notice and this permission notice appear in + * supporting documentation. + * + * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, + * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION + * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __SCSI_media__ +#define __SCSI_media__ + +#include "media.h" + + +/* + * Defines + */ + + +/* + * Types + */ + + +/* + * Global Constants + */ + + +/* + * Global Variables + */ + + +/* + * Forward declarations + */ +MEDIA SCSI_FindDevice(long dRefNum); +MEDIA open_old_scsi_as_media(long device); +MEDIA open_scsi_as_media(long bus, long device); +MEDIA_ITERATOR create_scsi_iterator(void); +MEDIA open_mklinux_scsi_as_media(long index, int is_cdrom); +char *mklinux_scsi_name(long bus, long id); +char *mklinux_old_scsi_name(long id); + +#endif /* __SCSI_media__ */ diff --git a/sbin/pdisk/bitfield.c b/sbin/pdisk/bitfield.c new file mode 100644 index 00000000000..795cffcae45 --- /dev/null +++ b/sbin/pdisk/bitfield.c @@ -0,0 +1,101 @@ +// +// bitfield.c - extract and set bit fields +// +// Written by Eryk Vershen (eryk@apple.com) +// +// See comments in bitfield.h +// + +/* + * Copyright 1996, 1997 by Apple Computer, Inc. + * All Rights Reserved + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appears in all copies and + * that both the copyright notice and this permission notice appear in + * supporting documentation. + * + * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, + * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION + * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "bitfield.h" + + +// +// Defines +// + + +// +// Types +// + + +// +// Global Constants +// +const unsigned long masks[] = { + 0x00000000, + 0x00000001, 0x00000003, 0x00000007, 0x0000000F, + 0x0000001F, 0x0000003F, 0x0000007F, 0x000000FF, + 0x000001FF, 0x000003FF, 0x000007FF, 0x00000FFF, + 0x00001FFF, 0x00003FFF, 0x00007FFF, 0x0000FFFF, + 0x0001FFFF, 0x0003FFFF, 0x0007FFFF, 0x000FFFFF, + 0x001FFFFF, 0x003FFFFF, 0x007FFFFF, 0x00FFFFFF, + 0x01FFFFFF, 0x03FFFFFF, 0x07FFFFFF, 0x0FFFFFFF, + 0x1FFFFFFF, 0x3FFFFFFF, 0x7FFFFFFF, 0xFFFFFFFF +}; + + +// +// Global Variables +// + + +// +// Forward declarations +// + + +// +// Routines +// +unsigned long +bitfield_set(unsigned long *bf, int base, int length, unsigned long value) +{ + unsigned long t; + unsigned long m; + int s; + + // compute shift & mask, coerce value to correct number of bits, + // zap the old bits and stuff the new value + // return the masked value in case someone wants it. + s = (base + 1) - length; + m = masks[length]; + t = value & m; + *bf = (*bf & ~(m << s)) | (t << s); + return t; +} + + +unsigned long +bitfield_get(unsigned long bf, int base, int length) +{ + unsigned long m; + int s; + + // compute shift & mask + // return the correct number of bits (shifted to low end) + s = (base + 1) - length; + m = masks[length]; + return ((bf >> s) & m); +} diff --git a/sbin/pdisk/bitfield.h b/sbin/pdisk/bitfield.h new file mode 100644 index 00000000000..4114ec28f46 --- /dev/null +++ b/sbin/pdisk/bitfield.h @@ -0,0 +1,72 @@ +// +// bitfield.h - extract and set bit fields +// +// Written by Eryk Vershen (eryk@apple.com) +// +// Bitfields are not particularly transportable between big and little +// endian machines. Big endian machines lay out bitfields starting +// from the most significant bit of the (one, two or four byte) number, +// whereas little endian machines lay out bitfields starting from the +// least signifcant bit. +// +// These routines were written to support some bitfields in a disk +// data structure (partition map) whose original definition was on +// a big-endian machine. +// +// They only work on 32-bit values because I didn't need 16-bit support. +// The bits in the long word are numbered from 0 (least significant) to +// 31 (most significant). +// + +/* + * Copyright 1996,1998 by Apple Computer, Inc. + * All Rights Reserved + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appears in all copies and + * that both the copyright notice and this permission notice appear in + * supporting documentation. + * + * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, + * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION + * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __bitfield__ +#define __bitfield__ + + +// +// Defines +// + + +// +// Types +// + + +// +// Global Constants +// + + +// +// Global Variables +// + + +// +// Forward declarations +// +unsigned long bitfield_set(unsigned long *bf, int base, int length, unsigned long value); +unsigned long bitfield_get(unsigned long bf, int base, int length); + +#endif /* __bitfield__ */ diff --git a/sbin/pdisk/convert.c b/sbin/pdisk/convert.c new file mode 100644 index 00000000000..e7f8016bc1a --- /dev/null +++ b/sbin/pdisk/convert.c @@ -0,0 +1,203 @@ +// +// convert.c - Little-endian conversion +// +// Written by Eryk Vershen (eryk@apple.com) +// +// See comments in convert.h +// + +/* + * Copyright 1996,1997,1998 by Apple Computer, Inc. + * All Rights Reserved + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appears in all copies and + * that both the copyright notice and this permission notice appear in + * supporting documentation. + * + * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, + * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION + * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifdef __linux__ +#include <endian.h> +#else +#define LITTLE_ENDIAN 1234 +#define BIG_ENDIAN 4321 +#define BYTE_ORDER 4321 +#endif + +#include "convert.h" + + +// +// Defines +// + + +// +// Types +// + + +// +// Global Constants +// + + +// +// Global Variables +// + + +// +// Forward declarations +// +void reverse2(u8 *bytes); +void reverse4(u8 *bytes); + + +// +// Routines +// +int +convert_dpme(DPME *data, int to_cpu_form) +{ +#if BYTE_ORDER == LITTLE_ENDIAN + // Since we will toss the block if the signature doesn't match + // we don't need to check the signature down here. + reverse2((u8 *)&data->dpme_signature); + reverse2((u8 *)&data->dpme_reserved_1); + reverse4((u8 *)&data->dpme_map_entries); + reverse4((u8 *)&data->dpme_pblock_start); + reverse4((u8 *)&data->dpme_pblocks); + reverse4((u8 *)&data->dpme_lblock_start); + reverse4((u8 *)&data->dpme_lblocks); + reverse4((u8 *)&data->dpme_flags); + reverse4((u8 *)&data->dpme_boot_block); + reverse4((u8 *)&data->dpme_boot_bytes); + reverse4((u8 *)&data->dpme_load_addr); + reverse4((u8 *)&data->dpme_load_addr_2); + reverse4((u8 *)&data->dpme_goto_addr); + reverse4((u8 *)&data->dpme_goto_addr_2); + reverse4((u8 *)&data->dpme_checksum); + convert_bzb((BZB *)data->dpme_bzb, to_cpu_form); +#endif + return 0; +} + + +#if BYTE_ORDER == LITTLE_ENDIAN +int +convert_bzb(BZB *data, int to_cpu_form) +{ + // Since the data here varies according to the type of partition we + // do not want to convert willy-nilly. We use the flag to determine + // whether to check for the signature before or after we flip the bytes. + if (to_cpu_form) { + reverse4((u8 *)&data->bzb_magic); + if (data->bzb_magic != BZBMAGIC) { + reverse4((u8 *)&data->bzb_magic); + if (data->bzb_magic != BZBMAGIC) { + return 0; + } + } + } else { + if (data->bzb_magic != BZBMAGIC) { + return 0; + } + reverse4((u8 *)&data->bzb_magic); + } + reverse2((u8 *)&data->bzb_inode); + reverse4((u8 *)&data->bzb_flags); + reverse4((u8 *)&data->bzb_tmade); + reverse4((u8 *)&data->bzb_tmount); + reverse4((u8 *)&data->bzb_tumount); + return 0; +} +#endif + + +int +convert_block0(Block0 *data, int to_cpu_form) +{ +#if BYTE_ORDER == LITTLE_ENDIAN + DDMap *m; + u16 count; + int i; + + // Since this data is optional we do not want to convert willy-nilly. + // We use the flag to determine whether to check for the signature + // before or after we flip the bytes and to determine which form of + // the count to use. + if (to_cpu_form) { + reverse2((u8 *)&data->sbSig); + if (data->sbSig != BLOCK0_SIGNATURE) { + reverse2((u8 *)&data->sbSig); + if (data->sbSig != BLOCK0_SIGNATURE) { + return 0; + } + } + } else { + if (data->sbSig != BLOCK0_SIGNATURE) { + return 0; + } + reverse2((u8 *)&data->sbSig); + } + reverse2((u8 *)&data->sbBlkSize); + reverse4((u8 *)&data->sbBlkCount); + reverse2((u8 *)&data->sbDevType); + reverse2((u8 *)&data->sbDevId); + reverse4((u8 *)&data->sbData); + if (to_cpu_form) { + reverse2((u8 *)&data->sbDrvrCount); + count = data->sbDrvrCount; + } else { + count = data->sbDrvrCount; + reverse2((u8 *)&data->sbDrvrCount); + } + + if (count > 0) { + m = (DDMap *) data->sbMap; + for (i = 0; i < count; i++) { + reverse4((u8 *)&m[i].ddBlock); + reverse2((u8 *)&m[i].ddSize); + reverse2((u8 *)&m[i].ddType); + } + } +#endif + return 0; +} + + +void +reverse2(u8 *bytes) +{ + u8 t; + + t = *bytes; + *bytes = bytes[1]; + bytes[1] = t; +} + + +void +reverse4(u8 *bytes) +{ + u8 t; + + t = *bytes; + *bytes = bytes[3]; + bytes[3] = t; + t = bytes[1]; + bytes[1] = bytes[2]; + bytes[2] = t; +} diff --git a/sbin/pdisk/convert.h b/sbin/pdisk/convert.h new file mode 100644 index 00000000000..c905c6f5bf9 --- /dev/null +++ b/sbin/pdisk/convert.h @@ -0,0 +1,65 @@ +// +// convert.h - Little-endian conversion +// +// Written by Eryk Vershen (eryk@apple.com) +// +// The approach taken to conversion is fairly simply. +// Keep the in-memory copy in the machine's normal form and +// Convert as necessary when reading and writing. +// + +/* + * Copyright 1996,1998 by Apple Computer, Inc. + * All Rights Reserved + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appears in all copies and + * that both the copyright notice and this permission notice appear in + * supporting documentation. + * + * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, + * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION + * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __convert__ +#define __convert__ + +#include "dpme.h" + + +// +// Defines +// + + +// +// Types +// + + +// +// Global Constants +// + + +// +// Global Variables +// + + +// +// Forward declarations +// +int convert_block0(Block0 *data, int to_cpu_form); +int convert_bzb(BZB *data, int to_cpu_form); +int convert_dpme(DPME *data, int to_cpu_form); + +#endif /* __convert__ */ diff --git a/sbin/pdisk/deblock_media.c b/sbin/pdisk/deblock_media.c new file mode 100644 index 00000000000..cb752d70554 --- /dev/null +++ b/sbin/pdisk/deblock_media.c @@ -0,0 +1,334 @@ +/* + * deblock_media.c - + * + * Written by Eryk Vershen (eryk@apple.com) + */ + +/* + * Copyright 1997,1998 by Apple Computer, Inc. + * All Rights Reserved + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appears in all copies and + * that both the copyright notice and this permission notice appear in + * supporting documentation. + * + * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, + * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION + * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + + +// for malloc() & free() +#include <stdlib.h> +// for memcpy() +#include <string.h> + +#include "deblock_media.h" + + +/* + * Defines + */ + + +/* + * Types + */ +typedef struct deblock_media *DEBLOCK_MEDIA; + +struct deblock_media { + struct media m; + long need_filtering; + MEDIA next_media; + unsigned long next_block_size; + unsigned char *buffer; +}; + +struct deblock_globals { + long exists; + long kind; +}; + + +/* + * Global Constants + */ + + +/* + * Global Variables + */ +static long deblock_inited = 0; +static struct deblock_globals deblock_info; + +/* + * Forward declarations + */ +void deblock_init(void); +DEBLOCK_MEDIA new_deblock_media(void); +long read_deblock_media(MEDIA m, long long offset, unsigned long count, void *address); +long write_deblock_media(MEDIA m, long long offset, unsigned long count, void *address); +long close_deblock_media(MEDIA m); +long os_reload_deblock_media(MEDIA m); + + +/* + * Routines + */ +void +deblock_init(void) +{ + if (deblock_inited != 0) { + return; + } + deblock_inited = 1; + + deblock_info.kind = allocate_media_kind(); +} + + +DEBLOCK_MEDIA +new_deblock_media(void) +{ + return (DEBLOCK_MEDIA) new_media(sizeof(struct deblock_media)); +} + + +MEDIA +open_deblock_media(long new_block_size, MEDIA m) +{ + DEBLOCK_MEDIA a; + unsigned long block_size; + + if (deblock_inited == 0) { + deblock_init(); + } + + a = 0; + if (m != 0) { + block_size = media_granularity(m); + + if (new_block_size == block_size) { + return m; + + } else if (new_block_size > block_size) { + if ((new_block_size % block_size) == 0) { + /* no filtering necessary */ + a = new_deblock_media(); + if (a != 0) { + a->need_filtering = 0; + a->next_block_size = block_size; + a->buffer = 0; + } + } else { + /* too hard to bother with */ + } + } else /* new_block_size < block_size */ { + if ((block_size % new_block_size) == 0) { + /* block & unblock */ + a = new_deblock_media(); + if (a != 0) { + a->need_filtering = 1; + a->next_block_size = block_size; + a->buffer = malloc(block_size); + } + } else { + /* too hard to bother with */ + } + } + if (a != 0) { + a->m.kind = deblock_info.kind; + a->m.grain = new_block_size; + a->m.size_in_bytes = media_total_size(m); + a->m.do_read = read_deblock_media; + a->m.do_write = write_deblock_media; + a->m.do_close = close_deblock_media; + a->m.do_os_reload = os_reload_deblock_media; + a->next_media = m; + } + } + return (MEDIA) a; +} + + +long +read_deblock_media(MEDIA m, long long offset, unsigned long count, void *address) +{ + DEBLOCK_MEDIA a; + long rtn_value; + unsigned long next_size; + unsigned long partial_offset; + unsigned long partial_count; + long long cur_offset; + unsigned long remainder; + unsigned char *addr; + + a = (DEBLOCK_MEDIA) m; + rtn_value = 0; + if (a == 0) { + /* no media */ + } else if (a->m.kind != deblock_info.kind) { + /* wrong kind - XXX need to error here - this is an internal problem */ + } else if (count <= 0 || count % a->m.grain != 0) { + /* can't handle size */ + } else if (offset < 0 || offset % a->m.grain != 0) { + /* can't handle offset */ + } else if (a->need_filtering == 0) { + rtn_value = read_media(a->next_media, offset, count, address); + } else { + next_size = a->next_block_size; + addr = address; + cur_offset = offset; + remainder = count; + rtn_value = 1; + + /* read partial */ + partial_offset = cur_offset % next_size; + if (partial_offset != 0) { + partial_count = next_size - partial_offset; + if (partial_count > remainder) { + partial_count = remainder; + } + rtn_value = read_media(a->next_media, cur_offset - partial_offset, next_size, a->buffer); + if (rtn_value != 0) { + memcpy (addr, a->buffer + partial_offset, partial_count); + addr += partial_count; + cur_offset += partial_count; + remainder -= partial_count; + } + } + /* read fulls as long as needed */ + if (rtn_value != 0 && remainder > next_size) { + partial_count = remainder - (remainder % next_size); + rtn_value = read_media(a->next_media, cur_offset, partial_count, addr); + addr += partial_count; + cur_offset += partial_count; + remainder -= partial_count; + } + /* read partial */ + if (rtn_value != 0 && remainder > 0) { + partial_count = remainder; + rtn_value = read_media(a->next_media, cur_offset, next_size, a->buffer); + if (rtn_value != 0) { + memcpy (addr, a->buffer, partial_count); + } + } + } + return rtn_value; +} + + +long +write_deblock_media(MEDIA m, long long offset, unsigned long count, void *address) +{ + DEBLOCK_MEDIA a; + long rtn_value; + unsigned long next_size; + unsigned long partial_offset; + unsigned long partial_count; + long long cur_offset; + unsigned long remainder; + unsigned char *addr; + + a = (DEBLOCK_MEDIA) m; + rtn_value = 0; + if (a == 0) { + /* no media */ + } else if (a->m.kind != deblock_info.kind) { + /* wrong kind - XXX need to error here - this is an internal problem */ + } else if (count <= 0 || count % a->m.grain != 0) { + /* can't handle size */ + } else if (offset < 0 || offset % a->m.grain != 0) { + /* can't handle offset */ + } else if (a->need_filtering == 0) { + rtn_value = write_media(a->next_media, offset, count, address); + } else { + next_size = a->next_block_size; + addr = address; + cur_offset = offset; + remainder = count; + rtn_value = 1; + + /* write partial */ + partial_offset = cur_offset % next_size; + if (partial_offset != 0) { + partial_count = next_size - partial_offset; + if (partial_count > remainder) { + partial_count = remainder; + } + rtn_value = read_media(a->next_media, cur_offset - partial_offset, next_size, a->buffer); + if (rtn_value != 0) { + memcpy (a->buffer + partial_offset, addr, partial_count); + rtn_value = write_media(a->next_media, cur_offset - partial_offset, next_size, a->buffer); + addr += partial_count; + cur_offset += partial_count; + remainder -= partial_count; + } + } + /* write fulls as long as needed */ + if (rtn_value != 0 && remainder > next_size) { + partial_count = remainder - (remainder % next_size); + rtn_value = write_media(a->next_media, cur_offset, partial_count, addr); + addr += partial_count; + cur_offset += partial_count; + remainder -= partial_count; + } + /* write partial */ + if (rtn_value != 0 && remainder > 0) { + partial_count = remainder; + rtn_value = read_media(a->next_media, cur_offset, next_size, a->buffer); + if (rtn_value != 0) { + memcpy (a->buffer, addr, partial_count); + rtn_value = write_media(a->next_media, cur_offset, next_size, a->buffer); + } + } + } + /* recompute size to handle file media */ + a->m.size_in_bytes = media_total_size(a->next_media); + return rtn_value; +} + + +long +close_deblock_media(MEDIA m) +{ + DEBLOCK_MEDIA a; + + a = (DEBLOCK_MEDIA) m; + if (a == 0) { + return 0; + } else if (a->m.kind != deblock_info.kind) { + /* XXX need to error here - this is an internal problem */ + return 0; + } + + close_media(a->next_media); + free(a->buffer); + return 1; +} + + +long +os_reload_deblock_media(MEDIA m) +{ + DEBLOCK_MEDIA a; + + a = (DEBLOCK_MEDIA) m; + if (a == 0) { + return 0; + } else if (a->m.kind != deblock_info.kind) { + /* XXX need to error here - this is an internal problem */ + return 0; + } + + os_reload_media(a->next_media); + return 1; +} diff --git a/sbin/pdisk/deblock_media.h b/sbin/pdisk/deblock_media.h new file mode 100644 index 00000000000..04c5dfeba33 --- /dev/null +++ b/sbin/pdisk/deblock_media.h @@ -0,0 +1,59 @@ +/* + * deblock_media.h - + * + * Written by Eryk Vershen (eryk@apple.com) + */ + +/* + * Copyright 1997,1998 by Apple Computer, Inc. + * All Rights Reserved + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appears in all copies and + * that both the copyright notice and this permission notice appear in + * supporting documentation. + * + * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, + * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION + * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __deblock_media__ +#define __deblock_media__ + +#include "media.h" + + +/* + * Defines + */ + + +/* + * Types + */ + + +/* + * Global Constants + */ + + +/* + * Global Variables + */ + + +/* + * Forward declarations + */ +MEDIA open_deblock_media(long new_block_size, MEDIA m); + +#endif /* __deblock_media__ */ diff --git a/sbin/pdisk/dpme.h b/sbin/pdisk/dpme.h new file mode 100644 index 00000000000..e3d7084dfe5 --- /dev/null +++ b/sbin/pdisk/dpme.h @@ -0,0 +1,219 @@ +// +// dpme.h - Disk Partition Map Entry (dpme) +// +// Written by Eryk Vershen (eryk@apple.com) +// +// This file describes structures and values related to the standard +// Apple SCSI disk partitioning scheme. +// +// Each entry is (and shall remain) 512 bytes long. +// +// For more information see: +// "Inside Macintosh: Devices" pages 3-12 to 3-15. +// "Inside Macintosh - Volume V" pages V-576 to V-582 +// "Inside Macintosh - Volume IV" page IV-292 +// +// There is a kernel file with much of the same info (under different names): +// /usr/src/mklinux-1.0DR2/osfmk/src/mach_kernel/ppc/POWERMAC/mac_label.h +// + +/* + * Copyright 1996 by Apple Computer, Inc. + * All Rights Reserved + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appears in all copies and + * that both the copyright notice and this permission notice appear in + * supporting documentation. + * + * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, + * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION + * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#ifndef __dpme__ +#define __dpme__ + +#include "bitfield.h" + +// +// Defines +// +#define BLOCK0_SIGNATURE 0x4552 /* Signature value. */ + +#define DPISTRLEN 32 +#define DPME_SIGNATURE 0x504D + +// A/UX only stuff (tradition!) +#define dpme_bzb dpme_boot_args +#define BZBMAGIC 0xABADBABE /* BZB magic number */ +#define FST ((u8) 0x1) /* standard UNIX FS */ +#define FSTEFS ((u8) 0x2) /* Autorecovery FS */ +#define FSTSFS ((u8) 0x3) /* Swap FS */ + + +// +// Types +// +typedef unsigned char u8; +typedef unsigned short u16; +typedef unsigned long u32; + + +// Physical block zero of the disk has this format +struct Block0 { + u16 sbSig; /* unique value for SCSI block 0 */ + u16 sbBlkSize; /* block size of device */ + u32 sbBlkCount; /* number of blocks on device */ + u16 sbDevType; /* device type */ + u16 sbDevId; /* device id */ + u32 sbData; /* not used */ + u16 sbDrvrCount; /* driver descriptor count */ + u16 sbMap[247]; /* descriptor map */ +}; +typedef struct Block0 Block0; + +// Where &sbMap[0] is actually an array DDMap[sbDrvrCount] +// kludge to get around alignment junk +struct DDMap { + u32 ddBlock; /* 1st driver's starting block (in sbBlkSize blocks!) */ + u16 ddSize; /* size of 1st driver (512-byte blks) */ + u16 ddType; /* system type (1 for Mac+) */ +}; +typedef struct DDMap DDMap; + + +// Each partition map entry (blocks 1 through n) has this format +struct dpme { + u16 dpme_signature ; + u16 dpme_reserved_1 ; + u32 dpme_map_entries ; + u32 dpme_pblock_start ; + u32 dpme_pblocks ; + char dpme_name[DPISTRLEN] ; /* name of partition */ + char dpme_type[DPISTRLEN] ; /* type of partition */ + u32 dpme_lblock_start ; + u32 dpme_lblocks ; + u32 dpme_flags; +#if 0 + u32 dpme_reserved_2 : 23 ; /* Bit 9 through 31. */ + u32 dpme_os_specific_1 : 1 ; /* Bit 8. */ + u32 dpme_os_specific_2 : 1 ; /* Bit 7. */ + u32 dpme_os_pic_code : 1 ; /* Bit 6. */ + u32 dpme_writable : 1 ; /* Bit 5. */ + u32 dpme_readable : 1 ; /* Bit 4. */ + u32 dpme_bootable : 1 ; /* Bit 3. */ + u32 dpme_in_use : 1 ; /* Bit 2. */ + u32 dpme_allocated : 1 ; /* Bit 1. */ + u32 dpme_valid : 1 ; /* Bit 0. */ +#endif + u32 dpme_boot_block ; + u32 dpme_boot_bytes ; + u8 *dpme_load_addr ; + u8 *dpme_load_addr_2 ; + u8 *dpme_goto_addr ; + u8 *dpme_goto_addr_2 ; + u32 dpme_checksum ; + char dpme_process_id[16] ; + u32 dpme_boot_args[32] ; + u32 dpme_reserved_3[62] ; +}; +typedef struct dpme DPME; + +#define dpme_diskdriver_set(p, v) bitfield_set(&p->dpme_flags, 9, 1, v) +#define dpme_chainable_set(p, v) bitfield_set(&p->dpme_flags, 8, 1, v) + +#define dpme_os_specific_1_set(p, v) bitfield_set(&p->dpme_flags, 8, 1, v) +#define dpme_os_specific_2_set(p, v) bitfield_set(&p->dpme_flags, 7, 1, v) +#define dpme_os_pic_code_set(p, v) bitfield_set(&p->dpme_flags, 6, 1, v) +#define dpme_writable_set(p, v) bitfield_set(&p->dpme_flags, 5, 1, v) +#define dpme_readable_set(p, v) bitfield_set(&p->dpme_flags, 4, 1, v) +#define dpme_bootable_set(p, v) bitfield_set(&p->dpme_flags, 3, 1, v) +#define dpme_in_use_set(p, v) bitfield_set(&p->dpme_flags, 2, 1, v) +#define dpme_allocated_set(p, v) bitfield_set(&p->dpme_flags, 1, 1, v) +#define dpme_valid_set(p, v) bitfield_set(&p->dpme_flags, 0, 1, v) + +#define dpme_diskdriver_get(p) bitfield_get(p->dpme_flags, 9, 1) +#define dpme_chainable_get(p) bitfield_get(p->dpme_flags, 8, 1) + +#define dpme_os_specific_1_get(p) bitfield_get(p->dpme_flags, 8, 1) +#define dpme_os_specific_2_get(p) bitfield_get(p->dpme_flags, 7, 1) +#define dpme_os_pic_code_get(p) bitfield_get(p->dpme_flags, 6, 1) +#define dpme_writable_get(p) bitfield_get(p->dpme_flags, 5, 1) +#define dpme_readable_get(p) bitfield_get(p->dpme_flags, 4, 1) +#define dpme_bootable_get(p) bitfield_get(p->dpme_flags, 3, 1) +#define dpme_in_use_get(p) bitfield_get(p->dpme_flags, 2, 1) +#define dpme_allocated_get(p) bitfield_get(p->dpme_flags, 1, 1) +#define dpme_valid_get(p) bitfield_get(p->dpme_flags, 0, 1) + + +// A/UX only data structures (sentimental reasons?) + +// Alternate block map (aka bad block remaping) [Never really used] +struct abm /* altblk map info stored in bzb */ +{ + u32 abm_size; /* size of map in bytes */ + u32 abm_ents; /* number of used entries */ + u32 abm_start; /* start of altblk map */ +}; +typedef struct abm ABM; + +// BZB (Block Zero Block, but I can't remember the etymology) +// Where &dpme_boot_args[0] is actually the address of a struct bzb +// kludge to get around alignment junk +struct bzb /* block zero block format */ +{ + u32 bzb_magic; /* magic number */ + u8 bzb_cluster; /* Autorecovery cluster grouping */ + u8 bzb_type; /* FS type */ + u16 bzb_inode; /* bad block inode number */ + u32 bzb_flags; +#if 0 + u16 bzb_root:1, /* FS is a root FS */ + bzb_usr:1, /* FS is a usr FS */ + bzb_crit:1, /* FS is a critical FS */ + bzb_rsrvd:8, /* reserved for later use */ + bzb_slice:5; /* slice number to associate with plus one */ + u16 bzb_filler; /* pad bitfield to 32 bits */ +#endif + u32 bzb_tmade; /* time of FS creation */ + u32 bzb_tmount; /* time of last mount */ + u32 bzb_tumount; /* time of last umount */ + ABM bzb_abm; /* altblk map info */ + u32 bzb_fill2[7]; /* for expansion of ABM (ha!ha!) */ + u8 bzb_mount_point[64]; /* default mount point name */ +}; +typedef struct bzb BZB; + +#define bzb_root_set(p, v) bitfield_set(&p->bzb_flags, 31, 1, v) +#define bzb_usr_set(p, v) bitfield_set(&p->bzb_flags, 30, 1, v) +#define bzb_crit_set(p, v) bitfield_set(&p->bzb_flags, 29, 1, v) +#define bzb_slice_set(p, v) bitfield_set(&p->bzb_flags, 20, 5, v) + +#define bzb_root_get(p) bitfield_get(p->bzb_flags, 31, 1) +#define bzb_usr_get(p) bitfield_get(p->bzb_flags, 30, 1) +#define bzb_crit_get(p) bitfield_get(p->bzb_flags, 29, 1) +#define bzb_slice_get(p) bitfield_get(p->bzb_flags, 20, 5) + + +// +// Global Constants +// + + +// +// Global Variables +// + + +// +// Forward declarations +// + +#endif /* __dpme__ */ diff --git a/sbin/pdisk/dump.c b/sbin/pdisk/dump.c new file mode 100644 index 00000000000..7c326c824c0 --- /dev/null +++ b/sbin/pdisk/dump.c @@ -0,0 +1,804 @@ +// +// dump.c - dumping partition maps +// +// Written by Eryk Vershen (eryk@apple.com) +// + +/* + * Copyright 1996,1997,1998 by Apple Computer, Inc. + * All Rights Reserved + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appears in all copies and + * that both the copyright notice and this permission notice appear in + * supporting documentation. + * + * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, + * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION + * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +// for *printf() +#include <stdio.h> + +// for malloc() & free() +#ifndef __linux__ +#include <stdlib.h> +//#include <unistd.h> +#else +#include <malloc.h> +#endif + +// for strcmp() +#include <string.h> +// for O_RDONLY +#include <fcntl.h> +// for errno +#include <errno.h> + +#include "dump.h" +#include "pathname.h" +#include "io.h" +#include "errors.h" + + +// +// Defines +// +#if DPISTRLEN != 32 +#error Change in strlen in partition entries! Fix constants +#endif + +#define get_align_long(x) (*(x)) + + +// +// Types +// +typedef struct names { + char *abbr; + char *full; +} NAMES; + + +// +// Global Constants +// +NAMES plist[] = { + {"Drvr", "Apple_Driver"}, + {"Free", "Apple_Free"}, + {" HFS", "Apple_HFS"}, + {" MFS", "Apple_MFS"}, + {"PDOS", "Apple_PRODOS"}, + {"junk", "Apple_Scratch"}, + {"unix", "Apple_UNIX_SVR2"}, + {" map", "Apple_partition_map"}, + {0, 0}, +}; + +const char * kStringEmpty = ""; +const char * kStringNot = " not"; + + +// +// Global Variables +// +int aflag = AFLAG_DEFAULT; /* abbreviate partition types */ +int pflag = PFLAG_DEFAULT; /* show physical limits of partition */ + + +// +// Forward declarations +// +void adjust_value_and_compute_prefix(double *value, int *prefix); +void dump_block_zero(partition_map_header *map); +void dump_partition_entry(partition_map *entry, int type_length, int name_length, int digits); +int get_max_base_or_length(partition_map_header *map); +int get_max_name_string_length(partition_map_header *map); +int get_max_type_string_length(partition_map_header *map); +int strnlen(char *s, int n); + + +// +// Routines +// +int +dump(char *name) +{ + partition_map_header *map; + int junk; + + map = open_partition_map(name, &junk, 0); + if (map == NULL) { + //error(-1, "No partition map in '%s'", name); + return 0; + } + + dump_partition_map(map, 1); + + close_partition_map(map); + + return 1; +} + + +void +dump_block_zero(partition_map_header *map) +{ + Block0 *p; + DDMap *m; + int i; + double value; + int prefix; + + p = map->misc; + if (p->sbSig != BLOCK0_SIGNATURE) { + return; + } + + value = ((double)p->sbBlkCount) * p->sbBlkSize; + adjust_value_and_compute_prefix(&value, &prefix); + printf("\nDevice block size=%u, Number of Blocks=%lu (%1.1f%c)\n", + p->sbBlkSize, p->sbBlkCount, value, prefix); + + printf("DeviceType=0x%x, DeviceId=0x%x\n", + p->sbDevType, p->sbDevId); + if (p->sbDrvrCount > 0) { + printf("Drivers-\n"); + m = (DDMap *) p->sbMap; + for (i = 0; i < p->sbDrvrCount; i++) { + printf("%u: @ %lu for %u, type=0x%x\n", i+1, + get_align_long(&m[i].ddBlock), + m[i].ddSize, m[i].ddType); + } + } + printf("\n"); +} + + +void +dump_partition_map(partition_map_header *map, int disk_order) +{ + partition_map * entry; + int max_type_length; + int max_name_length; + int digits; + char *alternate; + + if (map == NULL) { + bad_input("No partition map exists"); + return; + } + alternate = get_mklinux_name(map->name); + if (alternate) { + printf("\nPartition map (with %d byte blocks) on '%s' (%s)\n", + map->logical_block, map->name, alternate); + free(alternate); + } else { + printf("\nPartition map (with %d byte blocks) on '%s'\n", + map->logical_block, map->name); + } + + digits = number_of_digits(get_max_base_or_length(map)); + if (digits < 6) { + digits = 6; + } + if (aflag) { + max_type_length = 4; + } else { + max_type_length = get_max_type_string_length(map); + if (max_type_length < 4) { + max_type_length = 4; + } + } + max_name_length = get_max_name_string_length(map); + if (max_name_length < 6) { + max_name_length = 6; + } + printf(" #: %*s %-*s %*s %-*s ( size )\n", + max_type_length, "type", + max_name_length, "name", + digits, "length", digits, "base"); + + if (disk_order) { + for (entry = map->disk_order; entry != NULL; + entry = entry->next_on_disk) { + + dump_partition_entry(entry, max_type_length, max_name_length, digits); + } + } else { + for (entry = map->base_order; entry != NULL; + entry = entry->next_by_base) { + + dump_partition_entry(entry, max_type_length, max_name_length, digits); + } + } + dump_block_zero(map); +} + + +void +dump_partition_entry(partition_map *entry, int type_length, int name_length, int digits) +{ + partition_map_header *map; + int j; + DPME *p; + char *s; + u32 size; + double bytes; + int driver; + + map = entry->the_map; + p = entry->data; + driver = entry->contains_driver? '*': ' '; + if (aflag) { + s = "????"; + for (j = 0; plist[j].abbr != 0; j++) { + if (strcmp(p->dpme_type, plist[j].full) == 0) { + s = plist[j].abbr; + break; + } + } + printf("%2ld: %.4s%c%-*.32s ", + entry->disk_address, s, driver, name_length, p->dpme_name); + } else { + printf("%2ld: %*.32s%c%-*.32s ", + entry->disk_address, type_length, p->dpme_type, + driver, name_length, p->dpme_name); + } + + if (pflag) { + printf("%*lu ", digits, p->dpme_pblocks); + size = p->dpme_pblocks; + } else if (p->dpme_lblocks + p->dpme_lblock_start != p->dpme_pblocks) { + printf("%*lu+", digits, p->dpme_lblocks); + size = p->dpme_lblocks; + } else if (p->dpme_lblock_start != 0) { + printf("%*lu ", digits, p->dpme_lblocks); + size = p->dpme_lblocks; + } else { + printf("%*lu ", digits, p->dpme_pblocks); + size = p->dpme_pblocks; + } + if (pflag || p->dpme_lblock_start == 0) { + printf("@ %-*lu", digits, p->dpme_pblock_start); + } else { + printf("@~%-*lu", digits, p->dpme_pblock_start + p->dpme_lblock_start); + } + + bytes = ((double)size) * map->logical_block; + adjust_value_and_compute_prefix(&bytes, &j); + if (j != ' ' && j != 'K') { + printf(" (%#5.1f%c)", bytes, j); + } + +#if 0 + // Old A/UX fields that no one pays attention to anymore. + bp = (BZB *) (p->dpme_bzb); + j = -1; + if (bp->bzb_magic == BZBMAGIC) { + switch (bp->bzb_type) { + case FSTEFS: + s = "EFS"; + break; + case FSTSFS: + s = "SFS"; + j = 1; + break; + case FST: + default: + if (bzb_root_get(bp) != 0) { + if (bzb_usr_get(bp) != 0) { + s = "RUFS"; + } else { + s = "RFS"; + } + j = 0; + } else if (bzb_usr_get(bp) != 0) { + s = "UFS"; + j = 2; + } else { + s = "FS"; + } + break; + } + if (bzb_slice_get(bp) != 0) { + printf(" s%1d %4s", bzb_slice_get(bp)-1, s); + } else if (j >= 0) { + printf(" S%1d %4s", j, s); + } else { + printf(" %4s", s); + } + if (bzb_crit_get(bp) != 0) { + printf(" K%1d", bp->bzb_cluster); + } else if (j < 0) { + printf(" "); + } else { + printf(" k%1d", bp->bzb_cluster); + } + if (bp->bzb_mount_point[0] != 0) { + printf(" %.64s", bp->bzb_mount_point); + } + } +#endif + printf("\n"); +} + + +void +list_all_disks() +{ + MEDIA_ITERATOR iter; + MEDIA m; + DPME * data; + char *name; + long mark; + + data = (DPME *) malloc(PBLOCK_SIZE); + if (data == NULL) { + error(errno, "can't allocate memory for try buffer"); + return; + } + + for (iter = first_media_kind(&mark); iter != 0; iter = next_media_kind(&mark)) { + + while ((name = step_media_iterator(iter)) != 0) { + + if ((m = open_pathname_as_media(name, O_RDONLY)) == 0) { + error(errno, "can't open file '%s'", name); + } else { + close_media(m); + + dump(name); + } + free(name); + } + + delete_media_iterator(iter); + } + + free(data); +} + + +void +show_data_structures(partition_map_header *map) +{ + Block0 *zp; + DDMap *m; + int i; + int j; + partition_map * entry; + DPME *p; + BZB *bp; + char *s; + + if (map == NULL) { + printf("No partition map exists\n"); + return; + } + printf("Header:\n"); + printf("map %d blocks out of %d, media %lu blocks (%d byte blocks)\n", + map->blocks_in_map, map->maximum_in_map, + map->media_size, map->logical_block); + printf("Map is%s writeable", (map->writeable)?kStringEmpty:kStringNot); + printf(", but%s changed\n", (map->changed)?kStringEmpty:kStringNot); + printf("\n"); + + if (map->misc == NULL) { + printf("No block zero\n"); + } else { + zp = map->misc; + + printf("Block0:\n"); + printf("signature 0x%x", zp->sbSig); + if (zp->sbSig == BLOCK0_SIGNATURE) { + printf("\n"); + } else { + printf(" should be 0x%x\n", BLOCK0_SIGNATURE); + } + printf("Block size=%u, Number of Blocks=%lu\n", + zp->sbBlkSize, zp->sbBlkCount); + printf("DeviceType=0x%x, DeviceId=0x%x, sbData=0x%lx\n", + zp->sbDevType, zp->sbDevId, zp->sbData); + if (zp->sbDrvrCount == 0) { + printf("No drivers\n"); + } else { + printf("%u driver%s-\n", zp->sbDrvrCount, + (zp->sbDrvrCount>1)?"s":kStringEmpty); + m = (DDMap *) zp->sbMap; + for (i = 0; i < zp->sbDrvrCount; i++) { + printf("%u: @ %lu for %u, type=0x%x\n", i+1, + get_align_long(&m[i].ddBlock), + m[i].ddSize, m[i].ddType); + } + } + } + printf("\n"); + +/* +u32 dpme_boot_args[32] ; +u32 dpme_reserved_3[62] ; +*/ + printf(" #: type length base " + "flags (logical)\n"); + for (entry = map->disk_order; entry != NULL; entry = entry->next_on_disk) { + p = entry->data; + printf("%2ld: %20.32s ", + entry->disk_address, p->dpme_type); + printf("%7lu @ %-7lu ", p->dpme_pblocks, p->dpme_pblock_start); + printf("%c%c%c%c%c%c%c%c%c%c%c%c ", + (dpme_valid_get(p))?'V':'.', + (dpme_allocated_get(p))?'A':'.', + (dpme_in_use_get(p))?'I':'.', + (dpme_bootable_get(p))?'B':'.', + (dpme_readable_get(p))?'R':'.', + (dpme_writable_get(p))?'W':'.', + (dpme_os_pic_code_get(p))?'P':'.', + (dpme_os_specific_2_get(p))?'2':'.', + (dpme_chainable_get(p))?'C':'.', + (dpme_diskdriver_get(p))?'D':'.', + (bitfield_get(p->dpme_flags, 30, 1))?'M':'.', + (bitfield_get(p->dpme_flags, 31, 1))?'X':'.'); + if (p->dpme_lblock_start != 0 || p->dpme_pblocks != p->dpme_lblocks) { + printf("(%lu @ %lu)", p->dpme_lblocks, p->dpme_lblock_start); + } + printf("\n"); + } + printf("\n"); + printf(" #: booter bytes load_address " + "goto_address checksum processor\n"); + for (entry = map->disk_order; entry != NULL; entry = entry->next_on_disk) { + p = entry->data; + printf("%2ld: ", entry->disk_address); + printf("%7lu ", p->dpme_boot_block); + printf("%7lu ", p->dpme_boot_bytes); + printf("%8lx ", (u32)p->dpme_load_addr); + printf("%8lx ", (u32)p->dpme_load_addr_2); + printf("%8lx ", (u32)p->dpme_goto_addr); + printf("%8lx ", (u32)p->dpme_goto_addr_2); + printf("%8lx ", p->dpme_checksum); + printf("%.32s", p->dpme_process_id); + printf("\n"); + } + printf("\n"); +/* +xx: cccc RU *dd s... +*/ + printf(" #: type RU *slice mount_point (A/UX only fields)\n"); + for (entry = map->disk_order; entry != NULL; entry = entry->next_on_disk) { + p = entry->data; + printf("%2ld: ", entry->disk_address); + + bp = (BZB *) (p->dpme_bzb); + j = -1; + if (bp->bzb_magic == BZBMAGIC) { + switch (bp->bzb_type) { + case FSTEFS: + s = "esch"; + break; + case FSTSFS: + s = "swap"; + j = 1; + break; + case FST: + default: + s = "fsys"; + if (bzb_root_get(bp) != 0) { + j = 0; + } else if (bzb_usr_get(bp) != 0) { + j = 2; + } + break; + } + printf("%4s ", s); + printf("%c%c ", + (bzb_root_get(bp))?'R':' ', + (bzb_usr_get(bp))?'U':' '); + if (bzb_slice_get(bp) != 0) { + printf(" %2ld", bzb_slice_get(bp)-1); + } else if (j >= 0) { + printf(" *%2d", j); + } else { + printf(" "); + } + if (bp->bzb_mount_point[0] != 0) { + printf(" %.64s", bp->bzb_mount_point); + } + } + printf("\n"); + } +} + + +void +full_dump_partition_entry(partition_map_header *map, int index) +{ + partition_map * cur; + DPME *p; + int i; + u32 t; + + cur = find_entry_by_disk_address(index, map); + if (cur == NULL) { + printf("No such partition\n"); + return; + } + + p = cur->data; + printf(" signature: 0x%x\n", p->dpme_signature); + printf(" reserved1: 0x%x\n", p->dpme_reserved_1); + printf(" number of map entries: %ld\n", p->dpme_map_entries); + printf(" physical start: %10lu length: %10lu\n", p->dpme_pblock_start, p->dpme_pblocks); + printf(" logical start: %10lu length: %10lu\n", p->dpme_lblock_start, p->dpme_lblocks); + + printf(" flags: 0x%lx\n", (u32)p->dpme_flags); + printf(" "); + if (dpme_valid_get(p)) printf("valid "); + if (dpme_allocated_get(p)) printf("alloc "); + if (dpme_in_use_get(p)) printf("in-use "); + if (dpme_bootable_get(p)) printf("boot "); + if (dpme_readable_get(p)) printf("read "); + if (dpme_writable_get(p)) printf("write "); + if (dpme_os_pic_code_get(p)) printf("pic "); + t = p->dpme_flags >> 7; + for (i = 7; i <= 31; i++) { + if (t & 0x1) { + printf("%d ", i); + } + t = t >> 1; + } + printf("\n"); + + printf(" name: '%.32s'\n", p->dpme_name); + printf(" type: '%.32s'\n", p->dpme_type); + + printf(" boot start block: %10lu\n", p->dpme_boot_block); + printf("boot length (in bytes): %10lu\n", p->dpme_boot_bytes); + printf(" load address: 0x%08lx 0x%08lx\n", + (u32)p->dpme_load_addr, (u32)p->dpme_load_addr_2); + printf(" start address: 0x%08lx 0x%08lx\n", + (u32)p->dpme_goto_addr, (u32)p->dpme_goto_addr_2); + printf(" checksum: 0x%08lx\n", p->dpme_checksum); + printf(" processor: '%.32s'\n", p->dpme_process_id); + printf("boot args field -"); + dump_block((unsigned char *)p->dpme_boot_args, 32*4); + printf("dpme_reserved_3 -"); + dump_block((unsigned char *)p->dpme_reserved_3, 62*4); +} + + +void +dump_block(unsigned char *addr, int len) +{ + int i; + int j; + int limit1; + int limit; +#define LINE_LEN 16 +#define UNIT_LEN 4 +#define OTHER_LEN 8 + + for (i = 0; i < len; i = limit) { + limit1 = i + LINE_LEN; + if (limit1 > len) { + limit = len; + } else { + limit = limit1; + } + printf("\n%03x: ", i); + for (j = i; j < limit1; j++) { + if (j % UNIT_LEN == 0) { + printf(" "); + } + if (j < limit) { + printf("%02x", addr[j]); + } else { + printf(" "); + } + } + printf(" "); + for (j = i; j < limit; j++) { + if (j % OTHER_LEN == 0) { + printf(" "); + } + if (addr[j] < ' ') { + printf("."); + } else { + printf("%c", addr[j]); + } + } + } + printf("\n"); +} + +void +full_dump_block_zero(partition_map_header *map) +{ + Block0 *zp; + DDMap *m; + int i; + + if (map == NULL) { + printf("No partition map exists\n"); + return; + } + + if (map->misc == NULL) { + printf("No block zero\n"); + return; + } + zp = map->misc; + + printf(" signature: 0x%x\n", zp->sbSig); + printf(" size of a block: %d\n", zp->sbBlkSize); + printf(" number of blocks: %ld\n", zp->sbBlkCount); + printf(" device type: 0x%x\n", zp->sbDevType); + printf(" device id: 0x%x\n", zp->sbDevId); + printf(" data: 0x%lx\n", zp->sbData); + printf(" driver count: %d\n", zp->sbDrvrCount); + m = (DDMap *) zp->sbMap; + for (i = 0; &m[i].ddType < &zp->sbMap[247]; i++) { + if (m[i].ddBlock == 0 && m[i].ddSize == 0 && m[i].ddType == 0) { + break; + } + printf(" driver %3u block: %ld\n", i+1, m[i].ddBlock); + printf(" size in blocks: %d\n", m[i].ddSize); + printf(" driver type: 0x%x\n", m[i].ddType); + } + printf("remainder of block -"); + dump_block((unsigned char *)&m[i].ddBlock, (&zp->sbMap[247]-((unsigned short *)&m[i].ddBlock))*2); +} + +void +display_patches(partition_map *entry) +{ + long long offset; + MEDIA m; + static unsigned char *patch_block; + + offset = entry->data->dpme_pblock_start; + m = entry->the_map->m; + offset = ((long long) entry->data->dpme_pblock_start) * entry->the_map->logical_block; + if (patch_block == NULL) { + patch_block = (unsigned char *) malloc(PBLOCK_SIZE); + if (patch_block == NULL) { + error(errno, "can't allocate memory for patch block buffer"); + return; + } + } + if (read_media(m, (long long)offset, PBLOCK_SIZE, (char *)patch_block) == 0) { + error(errno, "Can't read patch block"); + return; + } + dump_block(patch_block, PBLOCK_SIZE); +} + +int +strnlen(char *s, int n) +{ + int i; + + for (i = 0; i < n; i++) { + if (*s == 0) { + break; + } + s++; + } + return i; +} + +int +get_max_type_string_length(partition_map_header *map) +{ + partition_map * entry; + int max; + int length; + + if (map == NULL) { + return 0; + } + + max = 0; + + for (entry = map->disk_order; entry != NULL; entry = entry->next_on_disk) { + length = strnlen(entry->data->dpme_type, DPISTRLEN); + if (length > max) { + max = length; + } + } + + return max; +} + +int +get_max_name_string_length(partition_map_header *map) +{ + partition_map * entry; + int max; + int length; + + if (map == NULL) { + return 0; + } + + max = 0; + + for (entry = map->disk_order; entry != NULL; entry = entry->next_on_disk) { + length = strnlen(entry->data->dpme_name, DPISTRLEN); + if (length > max) { + max = length; + } + } + + return max; +} + +int +get_max_base_or_length(partition_map_header *map) +{ + partition_map * entry; + int max; + + if (map == NULL) { + return 0; + } + + max = 0; + + for (entry = map->disk_order; entry != NULL; entry = entry->next_on_disk) { + if (entry->data->dpme_pblock_start > max) { + max = entry->data->dpme_pblock_start; + } + if (entry->data->dpme_pblocks > max) { + max = entry->data->dpme_pblocks; + } + if (entry->data->dpme_lblock_start > max) { + max = entry->data->dpme_lblock_start; + } + if (entry->data->dpme_lblocks > max) { + max = entry->data->dpme_lblocks; + } + } + + return max; +} + +void +adjust_value_and_compute_prefix(double *value, int *prefix) +{ + double bytes; + int multiplier; + + bytes = *value; + if (bytes < 1024.0) { + multiplier = ' '; + } else { + bytes = bytes / 1024.0; + if (bytes < 1024.0) { + multiplier = 'K'; + } else { + bytes = bytes / 1024.0; + if (bytes < 1024.0) { + multiplier = 'M'; + } else { + bytes = bytes / 1024.0; + if (bytes < 1024.0) { + multiplier = 'G'; + } else { + bytes = bytes / 1024.0; + multiplier = 'T'; + } + } + } + } + *value = bytes; + *prefix = multiplier; +} diff --git a/sbin/pdisk/dump.h b/sbin/pdisk/dump.h new file mode 100644 index 00000000000..f6dcd0ab600 --- /dev/null +++ b/sbin/pdisk/dump.h @@ -0,0 +1,70 @@ +// +// dump.h - dumping partition maps +// +// Written by Eryk Vershen (eryk@apple.com) +// + +/* + * Copyright 1996,1997 by Apple Computer, Inc. + * All Rights Reserved + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appears in all copies and + * that both the copyright notice and this permission notice appear in + * supporting documentation. + * + * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, + * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION + * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __dump__ +#define __dump__ + +#include "partition_map.h" + + +// +// Defines +// +#define AFLAG_DEFAULT 0 +#define PFLAG_DEFAULT 1 + + +// +// Types +// + + +// +// Global Constants +// + + +// +// Global Variables +// +extern int aflag; +extern int pflag; + + +// +// Forward declarations +// +void display_patches(partition_map *entry); +int dump(char *name); +void dump_block(unsigned char *addr, int len); +void dump_partition_map(partition_map_header *map, int disk_order); +void full_dump_partition_entry(partition_map_header *map, int index); +void full_dump_block_zero(partition_map_header *map); +void list_all_disks(); +void show_data_structures(partition_map_header *map); + +#endif /* __dump__ */ diff --git a/sbin/pdisk/errors.c b/sbin/pdisk/errors.c new file mode 100644 index 00000000000..9f4051cc98d --- /dev/null +++ b/sbin/pdisk/errors.c @@ -0,0 +1,169 @@ +// +// errors.c - error & help routines +// +// Written by Eryk Vershen (eryk@apple.com) +// + +/* + * Copyright 1996,1997,1998 by Apple Computer, Inc. + * All Rights Reserved + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appears in all copies and + * that both the copyright notice and this permission notice appear in + * supporting documentation. + * + * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, + * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION + * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +// for *printf() +#include <stdio.h> + +// for exit() +#ifndef __linux__ +#include <stdlib.h> +#endif +// for strrchr +#include <string.h> + +// for va_start(), etc. +#include <stdarg.h> + +#include "errors.h" + + +// +// Defines +// + + +// +// Types +// + + +// +// Global Constants +// + + +// +// Global Variables +// +char *program_name; +#ifdef NeXT +extern int errno; +extern int sys_nerr; +extern const char * const sys_errlist[]; +#endif + + +// +// Forward declarations +// + + +// +// Routines +// +void +init_program_name(char **argv) +{ +#ifdef __linux__ + if ((program_name = strrchr(argv[0], '/')) != (char *)NULL) { + program_name++; + } else { + program_name = argv[0]; + } +#else + program_name = "pdisk"; +#endif +} + + +void +do_help() +{ + printf("\t%s [-h|--help]\n", program_name); + printf("\t%s [-v|--version]\n", program_name); + printf("\t%s [-l|--list [name ...]]\n", program_name); + printf("\t%s [-r|--readonly] name ...\n", program_name); + printf("\t%s [-i|--interactive]\n", program_name); + printf("\t%s name ...\n", program_name); +} + + +void +usage(char *kind) +{ + error(-1, "bad usage - %s\n", kind); + hflag = 1; +} + + +// +// Print a message on standard error and exit with value. +// Values in the range of system error numbers will add +// the perror(3) message. +// +void +fatal(int value, char *fmt, ...) +{ + va_list ap; + + fprintf(stderr, "%s: ", program_name); + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + +#if defined(__linux__) || defined(NeXT) + if (value > 0 && value < sys_nerr) { + fprintf(stderr, " (%s)\n", sys_errlist[value]); + } else { + fprintf(stderr, "\n"); + } +#else + fprintf(stderr, "\n"); +#endif + +#ifndef __linux__ + printf("Processing stopped: Choose 'Quit' from the file menu to quit.\n\n"); +#endif + exit(value); +} + + +// +// Print a message on standard error. +// Values in the range of system error numbers will add +// the perror(3) message. +// +void +error(int value, char *fmt, ...) +{ + va_list ap; + + fprintf(stderr, "%s: ", program_name); + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + +#if defined(__linux__) || defined(NeXT) + if (value > 0 && value < sys_nerr) { + fprintf(stderr, " (%s)\n", sys_errlist[value]); + } else { + fprintf(stderr, "\n"); + } +#else + fprintf(stderr, "\n"); +#endif +} diff --git a/sbin/pdisk/errors.h b/sbin/pdisk/errors.h new file mode 100644 index 00000000000..bd2861d3006 --- /dev/null +++ b/sbin/pdisk/errors.h @@ -0,0 +1,62 @@ +// +// errors.h - error & help routines +// +// Written by Eryk Vershen (eryk@apple.com) +// + +/* + * Copyright 1996 by Apple Computer, Inc. + * All Rights Reserved + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appears in all copies and + * that both the copyright notice and this permission notice appear in + * supporting documentation. + * + * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, + * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION + * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __errors__ +#define __errors__ + + +// +// Defines +// + + +// +// Types +// + + +// +// Global Constants +// + + +// +// Global Variables +// +extern int hflag; + + +// +// Forward declarations +// +void do_help(); +void init_program_name(char **argv); +void error(int value, char *fmt, ...); +void fatal(int value, char *fmt, ...); +void usage(char *kind); + +#endif /* __errors__ */ diff --git a/sbin/pdisk/file_media.c b/sbin/pdisk/file_media.c new file mode 100644 index 00000000000..1b1e66f52fe --- /dev/null +++ b/sbin/pdisk/file_media.c @@ -0,0 +1,527 @@ +/* + * file_media.c - + * + * Written by Eryk Vershen (eryk@apple.com) + */ + +/* + * Copyright 1997,1998 by Apple Computer, Inc. + * All Rights Reserved + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appears in all copies and + * that both the copyright notice and this permission notice appear in + * supporting documentation. + * + * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, + * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION + * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +// for printf() +#include <stdio.h> +// for malloc() & free() +#include <stdlib.h> +// for lseek(), read(), write(), close() +#include <unistd.h> +// for open() +#include <fcntl.h> +// for LONG_MAX +#include <limits.h> +// for errno +#include <errno.h> + +#ifdef __linux__ +#include <sys/ioctl.h> +#include <linux/fs.h> +#include <linux/hdreg.h> +#include <sys/stat.h> +#endif + +#include "file_media.h" +#include "errors.h" + + +/* + * Defines + */ +#ifdef __linux__ +#define LOFF_MAX 9223372036854775807LL +extern __loff_t llseek __P ((int __fd, __loff_t __offset, int __whence)); +#else +#define loff_t long +#define llseek lseek +#define LOFF_MAX LONG_MAX +#endif + + +/* + * Types + */ +typedef struct file_media *FILE_MEDIA; + +struct file_media { + struct media m; + int fd; + int regular_file; +}; + +struct file_media_globals { + long exists; + long kind; +}; + +typedef struct file_media_iterator *FILE_MEDIA_ITERATOR; + +struct file_media_iterator { + struct media_iterator m; + long style; + long index; +}; + + +/* + * Global Constants + */ +int potential_block_sizes[] = { + 1, 512, 1024, 2048, + 0 +}; + +enum { + kSCSI_Disks = 0, + kATA_Devices = 1, + kSCSI_CDs = 2, + kMaxStyle = 2 +}; + + +/* + * Global Variables + */ +static long file_inited = 0; +static struct file_media_globals file_info; + +/* + * Forward declarations + */ +int compute_block_size(int fd); +void file_init(void); +FILE_MEDIA new_file_media(void); +long read_file_media(MEDIA m, long long offset, unsigned long count, void *address); +long write_file_media(MEDIA m, long long offset, unsigned long count, void *address); +long close_file_media(MEDIA m); +long os_reload_file_media(MEDIA m); +FILE_MEDIA_ITERATOR new_file_iterator(void); +void reset_file_iterator(MEDIA_ITERATOR m); +char *step_file_iterator(MEDIA_ITERATOR m); +void delete_file_iterator(MEDIA_ITERATOR m); + + +/* + * Routines + */ +void +file_init(void) +{ + if (file_inited != 0) { + return; + } + file_inited = 1; + + file_info.kind = allocate_media_kind(); +} + + +FILE_MEDIA +new_file_media(void) +{ + return (FILE_MEDIA) new_media(sizeof(struct file_media)); +} + + +int +compute_block_size(int fd) +{ + int size; + int max_size; + loff_t x; + long t; + int i; + char *buffer; + + max_size = 0; + for (i = 0; ; i++) { + size = potential_block_sizes[i]; + if (size == 0) { + break; + } + if (max_size < size) { + max_size = size; + } + } + + buffer = malloc(max_size); + if (buffer != 0) { + for (i = 0; ; i++) { + size = potential_block_sizes[i]; + if (size == 0) { + break; + } + if ((x = llseek(fd, (loff_t)0, 0)) < 0) { + error(errno, "Can't seek on file"); + break; + } + if ((t = read(fd, buffer, size)) == size) { + free(buffer); + return size; + } + } + } + return 0; +} + + +MEDIA +open_file_as_media(char *file, int oflag) +{ + FILE_MEDIA a; + int fd; + loff_t off; +#ifdef __linux__ + struct stat info; +#endif + + if (file_inited == 0) { + file_init(); + } + + a = 0; + fd = open(file, oflag); + if (fd >= 0) { + a = new_file_media(); + if (a != 0) { + a->m.kind = file_info.kind; + a->m.grain = compute_block_size(fd); + off = llseek(fd, (loff_t)0, 2); /* seek to end of media */ +#if !defined(__linux__) && !defined(__unix__) + if (off <= 0) { + off = 1; /* XXX not right? */ + } +#endif + //printf("file size = %Ld\n", off); + a->m.size_in_bytes = (long long) off; + a->m.do_read = read_file_media; + a->m.do_write = write_file_media; + a->m.do_close = close_file_media; + a->m.do_os_reload = os_reload_file_media; + a->fd = fd; + a->regular_file = 0; +#ifdef __linux__ + if (fstat(fd, &info) < 0) { + error(errno, "can't stat file '%s'", file); + } else { + a->regular_file = S_ISREG(info.st_mode); + } +#endif + } else { + close(fd); + } + } + return (MEDIA) a; +} + + +long +read_file_media(MEDIA m, long long offset, unsigned long count, void *address) +{ + FILE_MEDIA a; + long rtn_value; + loff_t off; + int t; + + a = (FILE_MEDIA) m; + rtn_value = 0; + if (a == 0) { + /* no media */ + //printf("no media\n"); + } else if (a->m.kind != file_info.kind) { + /* wrong kind - XXX need to error here - this is an internal problem */ + //printf("wrong kind\n"); + } else if (count <= 0 || count % a->m.grain != 0) { + /* can't handle size */ + //printf("bad size\n"); + } else if (offset < 0 || offset % a->m.grain != 0) { + /* can't handle offset */ + //printf("bad offset\n"); + } else if (offset + count > a->m.size_in_bytes && a->m.size_in_bytes != (long long) 0) { + /* check for offset (and offset+count) too large */ + //printf("offset+count too large\n"); + } else if (offset + count > (long long) LOFF_MAX) { + /* check for offset (and offset+count) too large */ + //printf("offset+count too large 2\n"); + } else { + /* do the read */ + off = offset; + if ((off = llseek(a->fd, off, 0)) >= 0) { + if ((t = read(a->fd, address, count)) == count) { + rtn_value = 1; + } else { + //printf("read failed\n"); + } + } else { + //printf("lseek failed\n"); + } + } + return rtn_value; +} + + +long +write_file_media(MEDIA m, long long offset, unsigned long count, void *address) +{ + FILE_MEDIA a; + long rtn_value; + loff_t off; + int t; + + a = (FILE_MEDIA) m; + rtn_value = 0; + if (a == 0) { + /* no media */ + } else if (a->m.kind != file_info.kind) { + /* wrong kind - XXX need to error here - this is an internal problem */ + } else if (count <= 0 || count % a->m.grain != 0) { + /* can't handle size */ + } else if (offset < 0 || offset % a->m.grain != 0) { + /* can't handle offset */ + } else if (offset + count > (long long) LOFF_MAX) { + /* check for offset (and offset+count) too large */ + } else { + /* do the write */ + off = offset; + if ((off = llseek(a->fd, off, 0)) >= 0) { + if ((t = write(a->fd, address, count)) == count) { + if (off + count > a->m.size_in_bytes) { + a->m.size_in_bytes = off + count; + } + rtn_value = 1; + } + } + } + return rtn_value; +} + + +long +close_file_media(MEDIA m) +{ + FILE_MEDIA a; + + a = (FILE_MEDIA) m; + if (a == 0) { + return 0; + } else if (a->m.kind != file_info.kind) { + /* XXX need to error here - this is an internal problem */ + return 0; + } + + close(a->fd); + return 1; +} + + +long +os_reload_file_media(MEDIA m) +{ + FILE_MEDIA a; + long rtn_value; +#ifdef __linux__ + int i; + int saved_errno; +#endif + + a = (FILE_MEDIA) m; + rtn_value = 0; + if (a == 0) { + /* no media */ + } else if (a->m.kind != file_info.kind) { + /* wrong kind - XXX need to error here - this is an internal problem */ + } else if (a->regular_file) { + /* okay - nothing to do */ + rtn_value = 1; + } else { +#ifdef __linux__ + sync(); + sleep(2); + if ((i = ioctl(a->fd, BLKRRPART)) != 0) { + saved_errno = errno; + } else { + // some kernel versions (1.2.x) seem to have trouble + // rereading the partition table, but if asked to do it + // twice, the second time works. - biro@yggdrasil.com */ + sync(); + sleep(2); + if ((i = ioctl(a->fd, BLKRRPART)) != 0) { + saved_errno = errno; + } + } + + // printf("Syncing disks.\n"); + sync(); + sleep(4); /* for sync() */ + + if (i < 0) { + error(saved_errno, "Re-read of partition table failed"); + printf("Reboot your system to ensure the " + "partition table is updated.\n"); + } +#endif + rtn_value = 1; + } + return rtn_value; +} + + +#pragma mark - + + +FILE_MEDIA_ITERATOR +new_file_iterator(void) +{ + return (FILE_MEDIA_ITERATOR) new_media_iterator(sizeof(struct file_media_iterator)); +} + + +MEDIA_ITERATOR +create_file_iterator(void) +{ + FILE_MEDIA_ITERATOR a; + + if (file_inited == 0) { + file_init(); + } + + a = new_file_iterator(); + if (a != 0) { + a->m.kind = file_info.kind; + a->m.state = kInit; + a->m.do_reset = reset_file_iterator; + a->m.do_step = step_file_iterator; + a->m.do_delete = delete_file_iterator; + a->style = 0; + a->index = 0; + } + + return (MEDIA_ITERATOR) a; +} + + +void +reset_file_iterator(MEDIA_ITERATOR m) +{ + FILE_MEDIA_ITERATOR a; + + a = (FILE_MEDIA_ITERATOR) m; + if (a == 0) { + /* no media */ + } else if (a->m.kind != file_info.kind) { + /* wrong kind - XXX need to error here - this is an internal problem */ + } else if (a->m.state != kInit) { + a->m.state = kReset; + } +} + + +char * +step_file_iterator(MEDIA_ITERATOR m) +{ + FILE_MEDIA_ITERATOR a; + char *result; + struct stat info; + + a = (FILE_MEDIA_ITERATOR) m; + if (a == 0) { + /* no media */ + } else if (a->m.kind != file_info.kind) { + /* wrong kind - XXX need to error here - this is an internal problem */ + } else { + switch (a->m.state) { + case kInit: + a->m.state = kReset; + /* fall through to reset */ + case kReset: + a->style = 0 /* first style */; + a->index = 0 /* first index */; + a->m.state = kIterating; + /* fall through to iterate */ + case kIterating: + while (1) { + if (a->style > kMaxStyle) { + break; + } +#ifndef notdef + /* if old version of mklinux then skip CD drive */ + if (a->style == kSCSI_Disks && a->index == 3) { + a->index += 1; + } +#endif + /* generate result */ + result = (char *) malloc(20); + if (result != NULL) { + /* + * for DR3 we should actually iterate through: + * + * /dev/sd[a...] # first missing is end of list + * /dev/hd[a...] # may be holes in sequence + * /dev/scd[0...] # first missing is end of list + * + * and stop in each group when either a stat of + * the name fails or if an open fails (except opens + * will fail if you run not as root) + */ + switch (a->style) { + case kSCSI_Disks: + sprintf(result, "/dev/sd%c", 'a'+(int)a->index); + break; + case kATA_Devices: + sprintf(result, "/dev/hd%c", 'a'+(int)a->index); + break; + case kSCSI_CDs: + sprintf(result, "/dev/scd%c", '0'+(int)a->index); + break; + } + if (stat(result, &info) < 0) { + a->style += 1; /* next style */ + a->index = 0; /* first index again */ + free(result); + continue; + } + } + + a->index += 1; /* next index */ + return result; + } + a->m.state = kEnd; + /* fall through to end */ + case kEnd: + default: + break; + } + } + return 0 /* no entry */; +} + + +void +delete_file_iterator(MEDIA_ITERATOR m) +{ + return; +} diff --git a/sbin/pdisk/file_media.h b/sbin/pdisk/file_media.h new file mode 100644 index 00000000000..27e477b2504 --- /dev/null +++ b/sbin/pdisk/file_media.h @@ -0,0 +1,60 @@ +/* + * file_media.h - + * + * Written by Eryk Vershen (eryk@apple.com) + */ + +/* + * Copyright 1997,1998 by Apple Computer, Inc. + * All Rights Reserved + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appears in all copies and + * that both the copyright notice and this permission notice appear in + * supporting documentation. + * + * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, + * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION + * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __file_media__ +#define __file_media__ + +#include "media.h" + + +/* + * Defines + */ + + +/* + * Types + */ + + +/* + * Global Constants + */ + + +/* + * Global Variables + */ + + +/* + * Forward declarations + */ +MEDIA open_file_as_media(char *file, int oflag); +MEDIA_ITERATOR create_file_iterator(void); + +#endif /* __file_media__ */ diff --git a/sbin/pdisk/io.c b/sbin/pdisk/io.c new file mode 100644 index 00000000000..64d2ed495cb --- /dev/null +++ b/sbin/pdisk/io.c @@ -0,0 +1,463 @@ +// +// io.c - simple io and input parsing routines +// +// Written by Eryk Vershen (eryk@apple.com) +// + +/* + * Copyright 1996,1997,1998 by Apple Computer, Inc. + * All Rights Reserved + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appears in all copies and + * that both the copyright notice and this permission notice appear in + * supporting documentation. + * + * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, + * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION + * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +// for *printf() +#include <stdio.h> + +// for malloc() & free() +#if !defined(__linux__) && !defined(__unix__) +#include <stdlib.h> +#else +#include <malloc.h> +#endif +// for strncpy() +#include <string.h> +// for va_start(), etc. +#include <stdarg.h> +// for errno +#include <errno.h> + +#include "io.h" +#include "errors.h" + + +// +// Defines +// +#define BAD_DIGIT 17 /* must be greater than any base */ +#define STRING_CHUNK 16 +#define UNGET_MAX_COUNT 10 +#ifndef __linux__ +#ifndef __unix__ +#define SCSI_FD 8 +#endif +#ifdef NeXT +#define loff_t off_t +#define llseek lseek +#else +#define loff_t long +#define llseek lseek +#endif +#endif + + +// +// Types +// + + +// +// Global Constants +// +const long kDefault = -1; + + +// +// Global Variables +// +short unget_buf[UNGET_MAX_COUNT+1]; +int unget_count; +char io_buffer[MAXIOSIZE]; + + +// +// Forward declarations +// +long get_number(int first_char); +char* get_string(int eos); +int my_getch(); +void my_ungetch(int c); + + +// +// Routines +// +int +my_getch() +{ + if (unget_count > 0) { + return (unget_buf[--unget_count]); + } else { + return (getc(stdin)); + } +} + + +void +my_ungetch(int c) +{ + // In practice there is never more than one character in + // the unget_buf, but what's a little overkill among friends? + + if (unget_count < UNGET_MAX_COUNT) { + unget_buf[unget_count++] = c; + } else { + fatal(-1, "Programmer error in my_ungetch()."); + } +} + + +void +flush_to_newline(int keep_newline) +{ + int c; + + for (;;) { + c = my_getch(); + + if (c <= 0) { + break; + } else if (c == '\n') { + if (keep_newline) { + my_ungetch(c); + } + break; + } else { + // skip + } + } + return; +} + + +int +get_okay(char *prompt, int default_value) +{ + int c; + + flush_to_newline(0); + printf(prompt); + + for (;;) { + c = my_getch(); + + if (c <= 0) { + break; + } else if (c == ' ' || c == '\t') { + // skip blanks and tabs + } else if (c == '\n') { + my_ungetch(c); + return default_value; + } else if (c == 'y' || c == 'Y') { + return 1; + } else if (c == 'n' || c == 'N') { + return 0; + } else { + flush_to_newline(0); + printf(prompt); + } + } + return -1; +} + + +int +get_command(char *prompt, int promptBeforeGet, int *command) +{ + int c; + + if (promptBeforeGet) { + printf(prompt); + } + for (;;) { + c = my_getch(); + + if (c <= 0) { + break; + } else if (c == ' ' || c == '\t') { + // skip blanks and tabs + } else if (c == '\n') { + printf(prompt); + } else { + *command = c; + return 1; + } + } + return 0; +} + + +int +get_number_argument(char *prompt, long *number, long default_value) +{ + int c; + int result = 0; + + for (;;) { + c = my_getch(); + + if (c <= 0) { + break; + } else if (c == ' ' || c == '\t') { + // skip blanks and tabs + } else if (c == '\n') { + if (default_value == kDefault) { + printf(prompt); + } else { + my_ungetch(c); + *number = default_value; + result = 1; + break; + } + } else if ('0' <= c && c <= '9') { + *number = get_number(c); + result = 1; + break; + } else { + my_ungetch(c); + *number = 0; + break; + } + } + return result; +} + + +long +get_number(int first_char) +{ + register int c; + int base; + int digit; + int ret_value; + + if (first_char != '0') { + c = first_char; + base = 10; + digit = BAD_DIGIT; + } else if ((c=my_getch()) == 'x' || c == 'X') { + c = my_getch(); + base = 16; + digit = BAD_DIGIT; + } else { + my_ungetch(c); + c = first_char; + base = 8; + digit = 0; + } + ret_value = 0; + for (ret_value = 0; ; c = my_getch()) { + if (c >= '0' && c <= '9') { + digit = c - '0'; + } else if (c >='A' && c <= 'F') { + digit = 10 + (c - 'A'); + } else if (c >='a' && c <= 'f') { + digit = 10 + (c - 'a'); + } else { + digit = BAD_DIGIT; + } + if (digit >= base) { + break; + } + ret_value = ret_value * base + digit; + } + my_ungetch(c); + return(ret_value); +} + + +int +get_string_argument(char *prompt, char **string, int reprompt) +{ + int c; + int result = 0; + + for (;;) { + c = my_getch(); + + if (c <= 0) { + break; + } else if (c == ' ' || c == '\t') { + // skip blanks and tabs + } else if (c == '\n') { + if (reprompt) { + printf(prompt); + } else { + my_ungetch(c); + *string = NULL; + break; + } + } else if (c == '"' || c == '\'') { + *string = get_string(c); + result = 1; + break; + } else if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') + || (c == '-' || c == '/' || c == '.' || c == ':')) { + my_ungetch(c); + *string = get_string(' '); + result = 1; + break; + } else { + my_ungetch(c); + *string = NULL; + break; + } + } + return result; +} + + +char * +get_string(int eos) +{ + int c; + char *s; + char *ret_value; + char *limit; + int length; + + ret_value = (char *) malloc(STRING_CHUNK); + if (ret_value == NULL) { + error(errno, "can't allocate memory for string buffer"); + return NULL; + } + length = STRING_CHUNK; + limit = ret_value + length; + + c = my_getch(); + for (s = ret_value; ; c = my_getch()) { + if (s >= limit) { + // expand string + limit = (char *) malloc(length+STRING_CHUNK); + if (limit == NULL) { + error(errno, "can't allocate memory for string buffer"); + ret_value[length-1] = 0; + break; + } + strncpy(limit, ret_value, length); + free(ret_value); + s = limit + (s - ret_value); + ret_value = limit; + length += STRING_CHUNK; + limit = ret_value + length; + } + if (c <= 0 || c == eos || (eos == ' ' && c == '\t')) { + *s++ = 0; + break; + } else if (c == '\n') { + *s++ = 0; + my_ungetch(c); + break; + } else { + *s++ = c; + } + } + return(ret_value); +} + + +unsigned long +get_multiplier(long divisor) +{ + int c; + unsigned long result; + unsigned long extra; + + c = my_getch(); + + extra = 1; + if (c <= 0 || divisor <= 0) { + result = 0; + } else if (c == 't' || c == 'T') { + result = 1024*1024; + extra = 1024*1024; + } else if (c == 'g' || c == 'G') { + result = 1024*1024*1024; + } else if (c == 'm' || c == 'M') { + result = 1024*1024; + } else if (c == 'k' || c == 'K') { + result = 1024; + } else { + my_ungetch(c); + result = 1; + } + if (result > 1) { + if (extra > 1) { + result /= divisor; + if (result >= 4096) { + /* overflow -> 20bits + >12bits */ + result = 0; + } else { + result *= extra; + } + } else if (result >= divisor) { + result /= divisor; + } else { + result = 1; + } + } + return result; +} + + +int +get_partition_modifier(void) +{ + int c; + int result; + + result = 0; + + c = my_getch(); + + if (c == 'p' || c == 'P') { + result = 1; + } else if (c > 0) { + my_ungetch(c); + } + return result; +} + + +int +number_of_digits(unsigned long value) +{ + int j; + + j = 1; + while (value > 9) { + j++; + value = value / 10; + } + return j; +} + + +// +// Print a message on standard error & flush the input. +// +void +bad_input(char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + fprintf(stderr, "\n"); + flush_to_newline(1); +} diff --git a/sbin/pdisk/io.h b/sbin/pdisk/io.h new file mode 100644 index 00000000000..dd5a2525187 --- /dev/null +++ b/sbin/pdisk/io.h @@ -0,0 +1,67 @@ +// +// io.h - simple io and input parsing routines +// +// Written by Eryk Vershen (eryk@apple.com) +// + +/* + * Copyright 1996,1997,1998 by Apple Computer, Inc. + * All Rights Reserved + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appears in all copies and + * that both the copyright notice and this permission notice appear in + * supporting documentation. + * + * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, + * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION + * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __io__ +#define __io__ + + +// +// Defines +// +#define MAXIOSIZE 2048 + + +// +// Types +// + + +// +// Global Constants +// +extern const long kDefault; + + +// +// Global Variables +// + + +// +// Forward declarations +// +void bad_input(char *fmt, ...); +void flush_to_newline(int keep_newline); +int get_command(char *prompt, int promptBeforeGet, int *command); +unsigned long get_multiplier(long divisor); +int get_number_argument(char *prompt, long *number, long default_value); +int get_okay(char *prompt, int default_value); +int get_partition_modifier(void); +int get_string_argument(char *prompt, char **string, int reprompt); +int number_of_digits(unsigned long value); + +#endif /* __io__ */ diff --git a/sbin/pdisk/layout_dump.c b/sbin/pdisk/layout_dump.c new file mode 100644 index 00000000000..9868d844b5b --- /dev/null +++ b/sbin/pdisk/layout_dump.c @@ -0,0 +1,180 @@ +/* + * layout_dump.c - + * + * Written by Eryk Vershen (eryk@apple.com) + */ + +/* + * Copyright 1996,1997 by Apple Computer, Inc. + * All Rights Reserved + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appears in all copies and + * that both the copyright notice and this permission notice appear in + * supporting documentation. + * + * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, + * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION + * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +// for printf() +#include <stdio.h> +// for strlen() +#include <string.h> +#include "layout_dump.h" + + +/* + * Defines + */ + + +/* + * Types + */ + + +/* + * Global Constants + */ +unsigned char bitmasks[] = { + 0x01, 0x03, 0x07, 0x0F, + 0x1F, 0x3F, 0x7F, 0xFF +}; + + +/* + * Global Variables + */ + + +/* + * Forward declarations + */ + + +/* + * Routines + */ +void +dump_using_layout(void *buffer, layout *desc) +{ + layout *entry; + int byte_length; + long value; + int max_name; + int i; + + max_name = 0; + for (entry = desc; entry->format != kEnd; entry++) { + value = strlen(entry->name); + if (value > max_name) { + max_name = value; + } + } + + + for (entry = desc; entry->format != kEnd; entry++) { + + if (entry->format != kBit) { + printf("%*s: ", max_name, entry->name); + + byte_length = entry->bit_length / 8; + + if (entry->bit_offset != 0 || (entry->bit_length % 8) != 0) { + printf("entry %d, can't handle bitfields yet.\n", entry - desc); + continue; + } + + value = 0; + for (i = entry->byte_offset; byte_length > 0;i++) { + value = value << 8; + value |= ((unsigned char *)buffer)[i]; + byte_length--; + } + } else { + if (entry->bit_offset < 0 || entry->bit_offset > 8) { + printf("entry %d, bad bit offset (%d).\n", entry - desc, entry->bit_offset); + continue; + } else if (entry->bit_length <= 0 + || entry->bit_length > (entry->bit_offset + 1)) { + printf("entry %d, bad bit length (%d,%d).\n", entry - desc, + entry->bit_offset, entry->bit_length); + continue; + } + value = (((unsigned char *)buffer)[entry->byte_offset] + & bitmasks[entry->bit_offset]) + >> ((entry->bit_offset + 1) - entry->bit_length); + } + + switch (entry->format) { + case kHex: + printf("0x%x\n", value); + break; + case kDec: + byte_length = entry->bit_length / 8; + switch (byte_length) { + case 4: printf("%d\n", (signed long)value); break; + case 2: printf("%d\n", (signed short)value); break; + case 1: printf("%d\n", (signed char)value); break; + } + break; + case kUns: + byte_length = entry->bit_length / 8; + switch (byte_length) { + case 4: printf("%u\n", (unsigned long)value); break; + case 2: printf("%u\n", (unsigned short)value); break; + case 1: printf("%u\n", (unsigned char)value); break; + } + break; + case kBit: + if (value) { + printf("%*s %s\n", max_name, "", entry->name); + } + break; + default: + printf("entry %d, unknown format (%d).\n", entry - desc, entry->format); + break; + } + } +} + + +void +DumpRawBuffer(unsigned char *bufferPtr, int length ) +{ + register int i; + int lineStart; + int lineLength; + short c; + +#define kLineSize 16 + for (lineStart = 0; lineStart < length; lineStart += lineLength) { + lineLength = kLineSize; + if (lineStart + lineLength > length) + lineLength = length - lineStart; + printf("%03x %3d:", lineStart, lineStart); + for (i = 0; i < lineLength; i++) + printf(" %02x", bufferPtr[lineStart + i] & 0xFF); + for (; i < kLineSize; i++) + printf(" "); + printf(" "); + for (i = 0; i < lineLength; i++) { + c = bufferPtr[lineStart + i] & 0xFF; + if (c > ' ' && c < '~') + printf("%c", c); + else { + printf("."); + } + } + printf("\n"); + } +} diff --git a/sbin/pdisk/layout_dump.h b/sbin/pdisk/layout_dump.h new file mode 100644 index 00000000000..a7c352ff086 --- /dev/null +++ b/sbin/pdisk/layout_dump.h @@ -0,0 +1,78 @@ +/* + * layout_dump.h - + * + * Written by Eryk Vershen (eryk@apple.com) + */ + +/* + * Copyright 1997,1998 by Apple Computer, Inc. + * All Rights Reserved + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appears in all copies and + * that both the copyright notice and this permission notice appear in + * supporting documentation. + * + * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, + * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION + * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __layout_dump__ +#define __layout_dump__ + + +/* + * Defines + */ + + +/* + * Types + */ +enum { + kEnd, + kHex, + kDec, + kUns, + kBit +}; + +typedef struct { + short byte_offset; + short bit_offset; + short bit_length; + short format; + char *name; +} layout; + + +/* + * Global Constants + */ + + +/* + * Global Variables + */ + + +/* + * Forward declarations + */ + + +/* + * Routines + */ +void dump_using_layout(void *buffer, layout *desc); +void DumpRawBuffer(unsigned char *bufferPtr, int length); + +#endif /* __layout_dump__ */ diff --git a/sbin/pdisk/makefile b/sbin/pdisk/makefile new file mode 100644 index 00000000000..4b68e7be69b --- /dev/null +++ b/sbin/pdisk/makefile @@ -0,0 +1,197 @@ +# +# Makefile for pdisk +# + +MAN_PAGE= \ + pdisk.8 + +MAC_DOC= \ + pdisk.html + +DOCS= \ + HISTORY \ + README \ + $(MAN_PAGE) \ + $(MAC_DOC) + +SERVER_README = \ + dist.README + +SERVER_MESSAGE = \ + dist.message + +DOCS_INTERNAL= \ + HISTORY.ALL \ + HOWTO.DISTRIBUTE \ + To_do_list \ + command-language \ + pdisk.man.html \ + $(SERVER_README) \ + $(SERVER_MESSAGE) + +SUPPORT= \ + make_filename \ + make_depend \ + make_tags \ + checkin_files \ + MPWcompare \ + name_latest \ + next_release + +MAC_SOURCE= \ + ATA_media.c \ + ATA_media.h \ + DoSCSICommand.c \ + DoSCSICommand.h \ + MacSCSICommand.h \ + SCSI_media.c \ + SCSI_media.h \ + pdisk.r + +UNIX_SOURCE= \ + bitfield.c \ + bitfield.h \ + convert.c \ + convert.h \ + deblock_media.c \ + deblock_media.h \ + dpme.h \ + dump.c \ + dump.h \ + errors.c \ + errors.h \ + file_media.c \ + file_media.h \ + io.c \ + io.h \ + layout_dump.c \ + layout_dump.h \ + makefile \ + media.c \ + media.h \ + partition_map.c \ + partition_map.h \ + pathname.c \ + pathname.h \ + pdisk.c \ + pdisk.h \ + util.c \ + util.h \ + validate.c \ + validate.h \ + version.h + +UNIX_OBJECTS = \ + pdisk.o \ + dump.o \ + partition_map.o \ + convert.o \ + io.o \ + errors.o \ + bitfield.o \ + deblock_media.o \ + file_media.o \ + media.o \ + pathname.o \ + util.o \ + validate.o + + +ALL_FILES= $(DOCS) $(DOCS_INTERNAL) $(SUPPORT) $(MAC_SOURCE) $(UNIX_SOURCE) + +UNIX_BINARY= \ + pdisk + +# +# these names have '__' in place of ' ' to avoid quoting nightmares +# +MAC_PROJECT= \ + pdisk.mac.bin \ + pdisk.mac__Data/CW__Settings.stg.bin \ + pdisk.mac__Data/pdisk.tdt.bin \ + pdisk.mac__Data/pdisk__68k.tdt.bin + +# Constructed under MacOS using CodeWarrior from MAC_PROJECT & sources +MAC_BINARY= \ + pdisk.hqx + +MAC_68KBINARY= \ + pdisk_68k.hqx + + +CFLAGS = -Wall +DIST_TAR_FLAGS = cvf + + +all: pdisk + +pdisk: $(UNIX_OBJECTS) + +clean: + rm -f *.o $(UNIX_BINARY) list.src + +clobber: clean + rm -f $(ALL_FILES) $(MAC_BINARY) $(MAC_68KBINARY) tags + +# note the sed to reinsert the spaces in the Mac names +list.src: $(MAC_SOURCE) $(DOCS) $(UNIX_SOURCE) $(MAC_PROJECT) + echo $(MAC_SOURCE) $(DOCS) $(UNIX_SOURCE) $(MAC_PROJECT) |\ + tr ' ' '\n' | sed -e 's/__/ /g' -e 's,^,pdisk/,' >list.src + +# +# this depends on this source directory being named 'pdisk' +# +distribution: list.src + cd ..; tar $(DIST_TAR_FLAGS) pdisk/dist/pdisk.src.tar.`date +%y%m%d` --files-from pdisk/list.src + tar $(DIST_TAR_FLAGS) dist/pdisk.bin.tar.`date +%y%m%d` $(UNIX_BINARY) $(MAN_PAGE) + cp $(MAC_DOC) dist/$(MAC_DOC).`date +%y%m%d` + cp $(MAC_BINARY) dist/$(MAC_BINARY).`date +%y%m%d` + cp $(MAC_68KBINARY) dist/$(MAC_68KBINARY).`date +%y%m%d` + cp $(SERVER_README) dist/README + cp $(SERVER_MESSAGE) dist/.message + +checkin: + ./checkin_files $(ALL_FILES) + +checkout: $(ALL_FILES) + +diff: + rcsdiff $(ALL_FILES) 2>&1 + +name: + ./name_latest $(ALL_FILES) + +# +# in lieu of a real dependency generator +# +convert.h: dpme.h +deblock_media.h: media.h +dpme.h: bitfield.h +dump.h: partition_map.h +file_media.h: media.h +partition_map.h: dpme.h media.h +pathname.h: media.h +validate.h: partition_map.h + +bitfield.o: bitfield.c bitfield.h +convert.o: convert.c convert.h +deblock_media.o: deblock_media.c deblock_media.h +dump.o: dump.c dump.h pathname.h io.h errors.h +errors.o: errors.c errors.h +file_media.o: file_media.c file_media.h errors.h +io.o: io.c io.h errors.h +layout_dump.o: layout_dump.c layout_dump.h +media.o: media.c media.h +partition_map.o: partition_map.c partition_map.h pathname.h deblock_media.h io.h convert.h util.h errors.h +pathname.o: pathname.c pathname.h file_media.h +pdisk.o: pdisk.c pdisk.h io.h partition_map.h pathname.h errors.h dump.h validate.h version.h util.h +util.o: util.c version.h util.h +validate.o: validate.c validate.h deblock_media.h pathname.h convert.h io.h errors.h + + +# +# fake dependencies used only by list.src {for $(MAC_PROJECT)} +# +pdisk.mac__Data/CW__Settings.stg.bin: +pdisk.mac__Data/pdisk.tdt.bin: +pdisk.mac__Data/pdisk__68k.tdt.bin: diff --git a/sbin/pdisk/media.c b/sbin/pdisk/media.c new file mode 100644 index 00000000000..85fa899ce6c --- /dev/null +++ b/sbin/pdisk/media.c @@ -0,0 +1,226 @@ +/* + * media.c - + * + * Written by Eryk Vershen (eryk@apple.com) + */ + +/* + * Copyright 1997,1998 by Apple Computer, Inc. + * All Rights Reserved + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appears in all copies and + * that both the copyright notice and this permission notice appear in + * supporting documentation. + * + * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, + * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION + * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + + +// for printf() +#include <stdio.h> +// for malloc() & free() +#include <stdlib.h> + +#include "media.h" + + +/* + * Defines + */ + + +/* + * Types + */ + + +/* + * Global Constants + */ + + +/* + * Global Variables + */ +static media_kind = 0; + +/* + * Forward declarations + */ + + +/* + * Routines + */ +long +allocate_media_kind(void) +{ + media_kind++; + return media_kind; +} + + +MEDIA +new_media(long size) +{ + return (MEDIA) malloc(size); +} + + +void +delete_media(MEDIA m) +{ + if (m == 0) { + return; + } + free(m); +} + + +unsigned long +media_granularity(MEDIA m) +{ + if (m == 0) { + return 0; + } else { + return m->grain; + } +} + + +long long +media_total_size(MEDIA m) +{ + if (m == 0) { + return 0; + } else { + return m->size_in_bytes; + } +} + + +long +read_media(MEDIA m, long long offset, unsigned long count, void *address) +{ + long result; + + if (m != 0 && m->do_read != 0) { + //printf("media: read type %d, offset %Ld, count %d\n\t", m->kind, offset, count); + result = (*m->do_read)(m, offset, count, address); + //printf(" - returns %d\n", result); + return result; + } else { + return 0; + } +} + + +long +write_media(MEDIA m, long long offset, unsigned long count, void *address) +{ + long result; + + if (m != 0 && m->do_write != 0) { + //printf("media: write type %d, offset %Ld, count %d\n\t", m->kind, offset, count); + result = (*m->do_write)(m, offset, count, address); + //printf(" - returns %d\n", result); + return result; + } else { + return 0; + } +} + + +void +close_media(MEDIA m) +{ + if (m == 0) { + return; + } + if (m->kind != 0) { + if (m->do_close != 0) { + (*m->do_close)(m); + } + m->kind = 0; + delete_media(m); + } +} + + +void +os_reload_media(MEDIA m) +{ + if (m != 0 && m->do_os_reload != 0) { + (*m->do_os_reload)(m); + } +} + + +#pragma mark - + + + +MEDIA_ITERATOR +new_media_iterator(long size) +{ + return (MEDIA_ITERATOR) malloc(size); +} + + +void +private_delete_media_iterator(MEDIA_ITERATOR m) +{ + if (m == 0) { + return; + } + free(m); +} + + +void +reset_media_iterator(MEDIA_ITERATOR m) +{ + if (m != 0 && m->do_reset != 0) { + (*m->do_reset)(m); + } +} + + +char * +step_media_iterator(MEDIA_ITERATOR m) +{ + char *result; + + if (m != 0 && m->do_step != 0) { + result = (*m->do_step)(m); + } else { + result = 0; + } + return result; +} + + +void +delete_media_iterator(MEDIA_ITERATOR m) +{ + if (m == 0) { + return; + } + if (m->kind != 0) { + if (m->do_delete != 0) { + (*m->do_delete)(m); + } + m->kind = 0; + private_delete_media_iterator(m); + } +} diff --git a/sbin/pdisk/media.h b/sbin/pdisk/media.h new file mode 100644 index 00000000000..f631e157a52 --- /dev/null +++ b/sbin/pdisk/media.h @@ -0,0 +1,139 @@ +/* + * media.h - + * + * Written by Eryk Vershen (eryk@apple.com) + */ + +/* + * Copyright 1997,1998 by Apple Computer, Inc. + * All Rights Reserved + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appears in all copies and + * that both the copyright notice and this permission notice appear in + * supporting documentation. + * + * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, + * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION + * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __media__ +#define __media__ + + +/* + * Media is an abstraction of a disk device. + * + * A media object has the following visible attributes: + * + * a granularity (e.g. 512, 1024, 1, etc.) + * a total size in bytes + * + * And the following operations are available: + * + * open + * read @ byte offset for size in bytes + * write @ byte offset for size in bytes + * close + * + * XXX Should really split public media interface from "protected" interface. + */ + + +/* + * Defines + */ + + +/* + * Types + */ +/* those whose use media objects need just the pointer type */ +typedef struct media *MEDIA; + +/* those who define media objects need the struct and internal routine types */ +typedef long (*media_read)(MEDIA m, long long offset, unsigned long count, void *address); +typedef long (*media_write)(MEDIA m, long long offset, unsigned long count, void *address); +typedef long (*media_close)(MEDIA m); +typedef long (*media_os_reload)(MEDIA m); + +struct media { + long kind; /* kind of media - SCSI, IDE, etc. */ + unsigned long grain; /* granularity (offset & size) */ + long long size_in_bytes; /* offset granularity */ + media_read do_read; /* device specific routines */ + media_write do_write; + media_close do_close; + media_os_reload do_os_reload; + /* specific media kinds will add extra info */ +}; + +/* those whose use media object iterators need just the pointer type */ +typedef struct media_iterator *MEDIA_ITERATOR; + +/* those who define media object iterators need the struct and internal routine types */ +typedef void (*media_iterator_reset)(MEDIA_ITERATOR m); +typedef char* (*media_iterator_step)(MEDIA_ITERATOR m); +typedef void (*media_iterator_delete)(MEDIA_ITERATOR m); + +typedef enum { + kInit, + kReset, + kIterating, + kEnd +} media_iterator_state; + +struct media_iterator { + long kind; /* kind of media - SCSI, IDE, etc. */ + media_iterator_state state; /* init, reset, iterating, at_end */ + media_iterator_reset do_reset; /* device specific routines */ + media_iterator_step do_step; + media_iterator_delete do_delete; + /* specific media kinds will add extra info */ +}; + + +/* + * Global Constants + */ + + +/* + * Global Variables + */ + + +/* + * Forward declarations + */ +/* those whose use media objects need these routines */ +unsigned long media_granularity(MEDIA m); +long long media_total_size(MEDIA m); +long read_media(MEDIA m, long long offset, unsigned long count, void *address); +long write_media(MEDIA m, long long offset, unsigned long count, void *address); +void close_media(MEDIA m); +void os_reload_media(MEDIA m); + +/* those who define media objects need these routines also */ +long allocate_media_kind(void); +MEDIA new_media(long size); +void delete_media(MEDIA m); + +/* those whose use media object iterators need these routines */ +void reset_media_iterator(MEDIA_ITERATOR m); +char *step_media_iterator(MEDIA_ITERATOR m); +void delete_media_iterator(MEDIA_ITERATOR m); + +/* those who define media object iterators need these routines also */ +MEDIA_ITERATOR new_media_iterator(long size); +void private_delete_media_iterator(MEDIA_ITERATOR m); + +#endif /* __media__ */ diff --git a/sbin/pdisk/partition_map.c b/sbin/pdisk/partition_map.c new file mode 100644 index 00000000000..af3d8c355b7 --- /dev/null +++ b/sbin/pdisk/partition_map.c @@ -0,0 +1,1310 @@ +// +// partition_map.c - partition map routines +// +// Written by Eryk Vershen (eryk@apple.com) +// + +/* + * Copyright 1996,1997,1998 by Apple Computer, Inc. + * All Rights Reserved + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appears in all copies and + * that both the copyright notice and this permission notice appear in + * supporting documentation. + * + * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, + * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION + * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +// for *printf() +#include <stdio.h> + +// for malloc(), calloc() & free() +#ifndef __linux__ +#include <stdlib.h> +#else +#include <malloc.h> +#endif + +// for strncpy() & strcmp() +#include <string.h> +// for O_RDONLY & O_RDWR +#include <fcntl.h> +// for errno +#include <errno.h> + +#include "partition_map.h" +#include "pathname.h" +#include "deblock_media.h" +#include "io.h" +#include "convert.h" +#include "util.h" +#include "errors.h" + + +// +// Defines +// +#define APPLE_HFS_FLAGS_VALUE 0x4000037f +#define get_align_long(x) (*(x)) +#define put_align_long(y, x) ((*(x)) = (y)) +// #define TEST_COMPUTE + + +// +// Types +// + + +// +// Global Constants +// +const char * kFreeType = "Apple_Free"; +const char * kMapType = "Apple_partition_map"; +const char * kUnixType = "Apple_UNIX_SVR2"; +const char * kHFSType = "Apple_HFS"; +const char * kPatchType = "Apple_Patches"; + +const char * kFreeName = "Extra"; + +enum add_action { + kReplace = 0, + kAdd = 1, + kSplit = 2 +}; + +// +// Global Variables +// +extern int cflag; + + +// +// Forward declarations +// +int add_data_to_map(struct dpme *data, long index, partition_map_header *map); +int coerce_block0(partition_map_header *map); +int contains_driver(partition_map *entry); +void combine_entry(partition_map *entry); +long compute_device_size(partition_map_header *map, partition_map_header *oldmap); +DPME* create_data(const char *name, const char *dptype, u32 base, u32 length); +void delete_entry(partition_map *entry); +void insert_in_base_order(partition_map *entry); +void insert_in_disk_order(partition_map *entry); +int read_block(partition_map_header *map, unsigned long num, char *buf); +int read_partition_map(partition_map_header *map); +void remove_driver(partition_map *entry); +void remove_from_disk_order(partition_map *entry); +void renumber_disk_addresses(partition_map_header *map); +void sync_device_size(partition_map_header *map); +int write_block(partition_map_header *map, unsigned long num, char *buf); + + +// +// Routines +// +partition_map_header * +open_partition_map(char *name, int *valid_file, int ask_logical_size) +{ + MEDIA m; + partition_map_header * map; + int writeable; + int size; + + m = open_pathname_as_media(name, (rflag)?O_RDONLY:O_RDWR); + if (m == 0) { + m = open_pathname_as_media(name, O_RDONLY); + if (m == 0) { + error(errno, "can't open file '%s'", name); + *valid_file = 0; + return NULL; + } else { + writeable = 0; + } + } else { + writeable = 1; + } + *valid_file = 1; + + map = (partition_map_header *) malloc(sizeof(partition_map_header)); + if (map == NULL) { + error(errno, "can't allocate memory for open partition map"); + close_media(m); + return NULL; + } + map->name = name; + map->writeable = (rflag)?0:writeable; + map->changed = 0; + map->disk_order = NULL; + map->base_order = NULL; + + map->physical_block = media_granularity(m); /* preflight */ + m = open_deblock_media(PBLOCK_SIZE, m); + map->m = m; + map->misc = (Block0 *) malloc(PBLOCK_SIZE); + if (map->misc == NULL) { + error(errno, "can't allocate memory for block zero buffer"); + close_media(map->m); + free(map); + return NULL; + } else if (read_media(map->m, (long long) 0, PBLOCK_SIZE, (char *)map->misc) == 0 + || convert_block0(map->misc, 1) + || coerce_block0(map)) { + // if I can't read block 0 I might as well give up + error(-1, "Can't read block 0 from '%s'", name); + close_partition_map(map); + return NULL; + } + map->physical_block = map->misc->sbBlkSize; + //printf("physical block size is %d\n", map->physical_block); + + if (ask_logical_size && interactive) { + size = PBLOCK_SIZE; + printf("A logical block is %d bytes: ", size); + flush_to_newline(0); + get_number_argument("what should be the logical block size? ", + (long *)&size, size); + size = (size / PBLOCK_SIZE) * PBLOCK_SIZE; + if (size < PBLOCK_SIZE) { + size = PBLOCK_SIZE; + } + map->logical_block = size; + } else { + map->logical_block = PBLOCK_SIZE; + } + if (map->logical_block > MAXIOSIZE) { + map->logical_block = MAXIOSIZE; + } + if (map->logical_block > map->physical_block) { + map->physical_block = map->logical_block; + } + map->blocks_in_map = 0; + map->maximum_in_map = -1; + map->media_size = compute_device_size(map, map); + sync_device_size(map); + + if (read_partition_map(map) < 0) { + // some sort of failure reading the map + } else { + // got it! + ; + return map; + } + close_partition_map(map); + return NULL; +} + + +void +close_partition_map(partition_map_header *map) +{ + partition_map * entry; + partition_map * next; + + if (map == NULL) { + return; + } + + free(map->misc); + + for (entry = map->disk_order; entry != NULL; entry = next) { + next = entry->next_on_disk; + free(entry->data); + free(entry); + } + close_media(map->m); + free(map); +} + + +int +read_partition_map(partition_map_header *map) +{ + DPME *data; + u32 limit; + int index; + int old_logical; + double d; + +//printf("called read_partition_map\n"); +//printf("logical = %d, physical = %d\n", map->logical_block, map->physical_block); + data = (DPME *) malloc(PBLOCK_SIZE); + if (data == NULL) { + error(errno, "can't allocate memory for disk buffers"); + return -1; + } + + if (read_block(map, 1, (char *)data) == 0) { + error(-1, "Can't read block 1 from '%s'", map->name); + free(data); + return -1; + } else if (convert_dpme(data, 1) + || data->dpme_signature != DPME_SIGNATURE) { + old_logical = map->logical_block; + map->logical_block = 512; + while (map->logical_block <= map->physical_block) { + if (read_block(map, 1, (char *)data) == 0) { + error(-1, "Can't read block 1 from '%s'", map->name); + free(data); + return -1; + } else if (convert_dpme(data, 1) == 0 + && data->dpme_signature == DPME_SIGNATURE) { + d = map->media_size; + map->media_size = (d * old_logical) / map->logical_block; + break; + } + map->logical_block *= 2; + } + if (map->logical_block > map->physical_block) { + error(-1, "No valid block 1 on '%s'", map->name); + free(data); + return -1; + } + } +//printf("logical = %d, physical = %d\n", map->logical_block, map->physical_block); + + limit = data->dpme_map_entries; + index = 1; + while (1) { + if (add_data_to_map(data, index, map) == 0) { + free(data); + return -1; + } + + if (index >= limit) { + break; + } else { + index++; + } + + data = (DPME *) malloc(PBLOCK_SIZE); + if (data == NULL) { + error(errno, "can't allocate memory for disk buffers"); + return -1; + } + + if (read_block(map, index, (char *)data) == 0) { + error(-1, "Can't read block %u from '%s'", index, map->name); + free(data); + return -1; + } else if (convert_dpme(data, 1) + || (data->dpme_signature != DPME_SIGNATURE && dflag == 0) + || (data->dpme_map_entries != limit && dflag == 0)) { + error(-1, "Bad data in block %u from '%s'", index, map->name); + free(data); + return -1; + } + } + return 0; +} + + +void +write_partition_map(partition_map_header *map) +{ + MEDIA m; + char *block; + partition_map * entry; + int i = 0; + int result; + + m = map->m; + if (map->misc != NULL) { + convert_block0(map->misc, 0); + result = write_block(map, 0, (char *)map->misc); + convert_block0(map->misc, 1); + } else { + block = (char *) calloc(1, PBLOCK_SIZE); + if (block != NULL) { + result = write_block(map, 0, block); + free(block); + } + } + if (result == 0) { + error(errno, "Unable to write block zero"); + } + for (entry = map->disk_order; entry != NULL; entry = entry->next_on_disk) { + convert_dpme(entry->data, 0); + result = write_block(map, entry->disk_address, (char *)entry->data); + convert_dpme(entry->data, 1); + i = entry->disk_address; + if (result == 0) { + error(errno, "Unable to write block %d", i); + } + } + // zap the block after the map (if possible) to get around a bug. + if (map->maximum_in_map > 0 && i < map->maximum_in_map) { + i += 1; + block = (char *) malloc(PBLOCK_SIZE); + if (block != NULL) { + if (read_block(map, i, block)) { + block[0] = 0; + write_block(map, i, block); + } + free(block); + } + } + if (interactive) + printf("The partition table has been altered!\n\n"); + + os_reload_media(map->m); +} + + +int +add_data_to_map(struct dpme *data, long index, partition_map_header *map) +{ + partition_map *entry; + +//printf("add data %d to map\n", index); + entry = (partition_map *) malloc(sizeof(partition_map)); + if (entry == NULL) { + error(errno, "can't allocate memory for map entries"); + return 0; + } + entry->next_on_disk = NULL; + entry->prev_on_disk = NULL; + entry->next_by_base = NULL; + entry->prev_by_base = NULL; + entry->disk_address = index; + entry->the_map = map; + entry->data = data; + entry->contains_driver = contains_driver(entry); + + insert_in_disk_order(entry); + insert_in_base_order(entry); + + map->blocks_in_map++; + if (map->maximum_in_map < 0) { + if (istrncmp(data->dpme_type, kMapType, DPISTRLEN) == 0) { + map->maximum_in_map = data->dpme_pblocks; + } + } + + return 1; +} + + +partition_map_header * +init_partition_map(char *name, partition_map_header* oldmap) +{ + partition_map_header *map; + + if (oldmap != NULL) { + printf("map already exists\n"); + if (get_okay("do you want to reinit? [n/y]: ", 0) != 1) { + return oldmap; + } + } + + map = create_partition_map(name, oldmap); + if (map == NULL) { + return oldmap; + } + close_partition_map(oldmap); + + add_partition_to_map("Apple", kMapType, + 1, (map->media_size <= 128? 2: 63), map); + return map; +} + + +partition_map_header * +create_partition_map(char *name, partition_map_header *oldmap) +{ + MEDIA m; + partition_map_header * map; + DPME *data; + unsigned long default_number; + unsigned long number; + int size; + unsigned long multiple; + + m = open_pathname_as_media(name, (rflag)?O_RDONLY:O_RDWR); + if (m == 0) { + error(errno, "can't open file '%s' for %sing", name, + (rflag)?"read":"writ"); + return NULL; + } + + map = (partition_map_header *) malloc(sizeof(partition_map_header)); + if (map == NULL) { + error(errno, "can't allocate memory for open partition map"); + close_media(m); + return NULL; + } + map->name = name; + map->writeable = (rflag)?0:1; + map->changed = 1; + map->disk_order = NULL; + map->base_order = NULL; + + if (oldmap != NULL) { + size = oldmap->physical_block; + } else { + size = media_granularity(m); + } + m = open_deblock_media(PBLOCK_SIZE, m); + map->m = m; + if (interactive) { + printf("A physical block is %d bytes: ", size); + flush_to_newline(0); + get_number_argument("what should be the physical block size? ", + (long *)&size, size); + size = (size / PBLOCK_SIZE) * PBLOCK_SIZE; + if (size < PBLOCK_SIZE) { + size = PBLOCK_SIZE; + } + } + if (map->physical_block > MAXIOSIZE) { + map->physical_block = MAXIOSIZE; + } + map->physical_block = size; + // printf("block size is %d\n", map->physical_block); + + if (oldmap != NULL) { + size = oldmap->logical_block; + } else { + size = PBLOCK_SIZE; + } + if (interactive) { + printf("A logical block is %d bytes: ", size); + flush_to_newline(0); + get_number_argument("what should be the logical block size? ", + (long *)&size, size); + size = (size / PBLOCK_SIZE) * PBLOCK_SIZE; + if (size < PBLOCK_SIZE) { + size = PBLOCK_SIZE; + } + } + if (size > map->physical_block) { + size = map->physical_block; + } + map->logical_block = size; + + map->blocks_in_map = 0; + map->maximum_in_map = -1; + + number = compute_device_size(map, oldmap); + if (interactive) { + printf("size of 'device' is %lu blocks (%d byte blocks): ", + number, map->logical_block); + default_number = number; + flush_to_newline(0); + do { + if (get_number_argument("what should be the size? ", + (long *)&number, default_number) == 0) { + printf("Not a number\n"); + flush_to_newline(1); + number = 0; + } else { + multiple = get_multiplier(map->logical_block); + if (multiple == 0) { + printf("Bad multiplier\n"); + number = 0; + } else if (multiple != 1) { + if (0xFFFFFFFF/multiple < number) { + printf("Number too large\n"); + number = 0; + } else { + number *= multiple; + } + } + } + default_number = kDefault; + } while (number == 0); + + if (number < 4) { + number = 4; + } + printf("new size of 'device' is %lu blocks (%d byte blocks)\n", + number, map->logical_block); + } + map->media_size = number; + + map->misc = (Block0 *) calloc(1, PBLOCK_SIZE); + if (map->misc == NULL) { + error(errno, "can't allocate memory for block zero buffer"); + } else { + // got it! + coerce_block0(map); + sync_device_size(map); + + data = (DPME *) calloc(1, PBLOCK_SIZE); + if (data == NULL) { + error(errno, "can't allocate memory for disk buffers"); + } else { + // set data into entry + data->dpme_signature = DPME_SIGNATURE; + data->dpme_map_entries = 1; + data->dpme_pblock_start = 1; + data->dpme_pblocks = map->media_size - 1; + strncpy(data->dpme_name, kFreeName, DPISTRLEN); + strncpy(data->dpme_type, kFreeType, DPISTRLEN); + data->dpme_lblock_start = 0; + data->dpme_lblocks = data->dpme_pblocks; + dpme_writable_set(data, 1); + dpme_readable_set(data, 1); + dpme_bootable_set(data, 0); + dpme_in_use_set(data, 0); + dpme_allocated_set(data, 0); + dpme_valid_set(data, 1); + + if (add_data_to_map(data, 1, map) == 0) { + free(data); + } else { + return map; + } + } + } + close_partition_map(map); + return NULL; +} + + +int +coerce_block0(partition_map_header *map) +{ + Block0 *p; + + p = map->misc; + if (p == NULL) { + return 1; + } + if (p->sbSig != BLOCK0_SIGNATURE) { + p->sbSig = BLOCK0_SIGNATURE; + if (map->physical_block == 1) { + p->sbBlkSize = PBLOCK_SIZE; + } else { + p->sbBlkSize = map->physical_block; + } + p->sbBlkCount = 0; + p->sbDevType = 0; + p->sbDevId = 0; + p->sbData = 0; + p->sbDrvrCount = 0; + } + return 0; // we do this simply to make it easier to call this function +} + + +int +add_partition_to_map(const char *name, const char *dptype, u32 base, u32 length, + partition_map_header *map) +{ + partition_map * cur; + DPME *data; + enum add_action act; + int limit; + u32 adjusted_base = 0; + u32 adjusted_length = 0; + u32 new_base = 0; + u32 new_length = 0; + + // find a block that starts includes base and length + cur = map->base_order; + while (cur != NULL) { + if (cur->data->dpme_pblock_start <= base + && (base + length) <= + (cur->data->dpme_pblock_start + cur->data->dpme_pblocks)) { + break; + } else { + cur = cur->next_by_base; + } + } + // if it is not Extra then punt + if (cur == NULL + || istrncmp(cur->data->dpme_type, kFreeType, DPISTRLEN) != 0) { + printf("requested base and length is not " + "within an existing free partition\n"); + return 0; + } + // figure out what to do and sizes + data = cur->data; + if (data->dpme_pblock_start == base) { + // replace or add + if (data->dpme_pblocks == length) { + act = kReplace; + } else { + act = kAdd; + adjusted_base = base + length; + adjusted_length = data->dpme_pblocks - length; + } + } else { + // split or add + if (data->dpme_pblock_start + data->dpme_pblocks == base + length) { + act = kAdd; + adjusted_base = data->dpme_pblock_start; + adjusted_length = base - adjusted_base; + } else { + act = kSplit; + new_base = data->dpme_pblock_start; + new_length = base - new_base; + adjusted_base = base + length; + adjusted_length = data->dpme_pblocks - (length + new_length); + } + } + // if the map will overflow then punt + if (map->maximum_in_map < 0) { + limit = map->media_size; + } else { + limit = map->maximum_in_map; + } + if (map->blocks_in_map + act > limit) { + printf("the map is not big enough\n"); + return 0; + } + + data = create_data(name, dptype, base, length); + if (data == NULL) { + return 0; + } + if (act == kReplace) { + free(cur->data); + cur->data = data; + } else { + // adjust this block's size + cur->data->dpme_pblock_start = adjusted_base; + cur->data->dpme_pblocks = adjusted_length; + cur->data->dpme_lblocks = adjusted_length; + // insert new with block address equal to this one + if (add_data_to_map(data, cur->disk_address, map) == 0) { + free(data); + } else if (act == kSplit) { + data = create_data(kFreeName, kFreeType, new_base, new_length); + if (data != NULL) { + // insert new with block address equal to this one + if (add_data_to_map(data, cur->disk_address, map) == 0) { + free(data); + } + } + } + } + // renumber disk addresses + renumber_disk_addresses(map); + // mark changed + map->changed = 1; + return 1; +} + + +DPME * +create_data(const char *name, const char *dptype, u32 base, u32 length) +{ + DPME *data; + + data = (DPME *) calloc(1, PBLOCK_SIZE); + if (data == NULL) { + error(errno, "can't allocate memory for disk buffers"); + } else { + // set data into entry + data->dpme_signature = DPME_SIGNATURE; + data->dpme_map_entries = 1; + data->dpme_pblock_start = base; + data->dpme_pblocks = length; + strncpy(data->dpme_name, name, DPISTRLEN); + strncpy(data->dpme_type, dptype, DPISTRLEN); + data->dpme_lblock_start = 0; + data->dpme_lblocks = data->dpme_pblocks; + if (strcmp(data->dpme_type, kHFSType) == 0) { /* XXX this is gross, fix it! */ + data->dpme_flags = APPLE_HFS_FLAGS_VALUE; + } + else { + dpme_writable_set(data, 1); + dpme_readable_set(data, 1); + dpme_bootable_set(data, 0); + dpme_in_use_set(data, 0); + dpme_allocated_set(data, 1); + dpme_valid_set(data, 1); + } + } + return data; +} + + +void +renumber_disk_addresses(partition_map_header *map) +{ + partition_map * cur; + long index; + + // reset disk addresses + cur = map->disk_order; + index = 1; + while (cur != NULL) { + cur->disk_address = index++; + cur->data->dpme_map_entries = map->blocks_in_map; + cur = cur->next_on_disk; + } +} + + +long +compute_device_size(partition_map_header *map, partition_map_header *oldmap) +{ +#ifdef TEST_COMPUTE + unsigned long length; + struct hd_geometry geometry; + struct stat info; + loff_t pos; +#endif + char* data; + unsigned long l, r, x = 0; + long long size; + int valid = 0; +#ifdef TEST_COMPUTE + int fd; + + fd = map->fd->fd; + printf("\n"); + if (fstat(fd, &info) < 0) { + printf("stat of device failed\n"); + } else { + printf("stat: mode = 0%o, type=%s\n", info.st_mode, + (S_ISREG(info.st_mode)? "Regular": + (S_ISBLK(info.st_mode)?"Block":"Other"))); + printf("size = %d, blocks = %d\n", + info.st_size, info.st_size/map->logical_block); + } + + if (ioctl(fd, BLKGETSIZE, &length) < 0) { + printf("get device size failed\n"); + } else { + printf("BLKGETSIZE:size in blocks = %u\n", length); + } + + if (ioctl(fd, HDIO_GETGEO, &geometry) < 0) { + printf("get device geometry failed\n"); + } else { + printf("HDIO_GETGEO: heads=%d, sectors=%d, cylinders=%d, start=%d, total=%d\n", + geometry.heads, geometry.sectors, + geometry.cylinders, geometry.start, + geometry.heads*geometry.sectors*geometry.cylinders); + } + + if ((pos = llseek(fd, (loff_t)0, SEEK_END)) < 0) { + printf("llseek to end of device failed\n"); + } else if ((pos = llseek(fd, (loff_t)0, SEEK_CUR)) < 0) { + printf("llseek to end of device failed on second try\n"); + } else { + printf("llseek: pos = %d, blocks=%d\n", pos, pos/map->logical_block); + } +#endif + + if (cflag == 0 && oldmap != NULL && oldmap->misc->sbBlkCount != 0) { + return (oldmap->misc->sbBlkCount + * (oldmap->physical_block / map->logical_block)); + } + + size = media_total_size(map->m); + if (size != 0) { + return (long)(size / map->logical_block); + } + + // else case + + data = (char *) malloc(PBLOCK_SIZE); + if (data == NULL) { + error(errno, "can't allocate memory for try buffer"); + x = 0; + } else { + // double till off end + l = 0; + r = 1024; + while (read_block(map, r, data) != 0) { + l = r; + if (r <= 1024) { + r = r * 1024; + } else { + r = r * 2; + } + if (r >= 0x80000000) { + r = 0xFFFFFFFE; + break; + } + } + // binary search for end + while (l <= r) { + x = (r - l) / 2 + l; + if ((valid = read_block(map, x, data)) != 0) { + l = x + 1; + } else { + if (x > 0) { + r = x - 1; + } else { + break; + } + } + } + if (valid != 0) { + x = x + 1; + } + // printf("size in blocks = %d\n", x); + free(data); + } + + return x; +} + + +void +sync_device_size(partition_map_header *map) +{ + Block0 *p; + unsigned long size; + double d; + + p = map->misc; + if (p == NULL) { + return; + } + d = map->media_size; + size = (d * map->logical_block) / map->physical_block; + if (p->sbBlkCount != size) { + p->sbBlkCount = size; + } +} + + +void +delete_partition_from_map(partition_map *entry) +{ + partition_map_header *map; + DPME *data; + + if (istrncmp(entry->data->dpme_type, kMapType, DPISTRLEN) == 0) { + printf("Can't delete entry for the map itself\n"); + return; + } + if (entry->contains_driver) { + printf("This program can't install drivers\n"); + if (get_okay("are you sure you want to delete this driver? [n/y]: ", 0) != 1) { + return; + } + } + data = create_data(kFreeName, kFreeType, + entry->data->dpme_pblock_start, entry->data->dpme_pblocks); + if (data == NULL) { + return; + } + if (entry->contains_driver) { + remove_driver(entry); // update block0 if necessary + } + free(entry->data); + entry->data = data; + combine_entry(entry); + map = entry->the_map; + renumber_disk_addresses(map); + map->changed = 1; +} + + +int +contains_driver(partition_map *entry) +{ + partition_map_header *map; + Block0 *p; + DDMap *m; + int i; + int f; + u32 start; + + map = entry->the_map; + p = map->misc; + if (p == NULL) { + return 0; + } + if (p->sbSig != BLOCK0_SIGNATURE) { + return 0; + } + if (map->logical_block > p->sbBlkSize) { + return 0; + } else { + f = p->sbBlkSize / map->logical_block; + } + if (p->sbDrvrCount > 0) { + m = (DDMap *) p->sbMap; + for (i = 0; i < p->sbDrvrCount; i++) { + start = get_align_long(&m[i].ddBlock); + if (entry->data->dpme_pblock_start <= f*start + && f*(start + m[i].ddSize) + <= (entry->data->dpme_pblock_start + + entry->data->dpme_pblocks)) { + return 1; + } + } + } + return 0; +} + + +void +combine_entry(partition_map *entry) +{ + partition_map *p; + u32 end; + + if (entry == NULL + || istrncmp(entry->data->dpme_type, kFreeType, DPISTRLEN) != 0) { + return; + } + if (entry->next_by_base != NULL) { + p = entry->next_by_base; + if (istrncmp(p->data->dpme_type, kFreeType, DPISTRLEN) != 0) { + // next is not free + } else if (entry->data->dpme_pblock_start + entry->data->dpme_pblocks + != p->data->dpme_pblock_start) { + // next is not contiguous (XXX this is bad) + printf("next entry is not contiguous\n"); + // start is already minimum + // new end is maximum of two ends + end = p->data->dpme_pblock_start + p->data->dpme_pblocks; + if (end > entry->data->dpme_pblock_start + entry->data->dpme_pblocks) { + entry->data->dpme_pblocks = end - entry->data->dpme_pblock_start; + } + entry->data->dpme_lblocks = entry->data->dpme_pblocks; + delete_entry(p); + } else { + entry->data->dpme_pblocks += p->data->dpme_pblocks; + entry->data->dpme_lblocks = entry->data->dpme_pblocks; + delete_entry(p); + } + } + if (entry->prev_by_base != NULL) { + p = entry->prev_by_base; + if (istrncmp(p->data->dpme_type, kFreeType, DPISTRLEN) != 0) { + // previous is not free + } else if (p->data->dpme_pblock_start + p->data->dpme_pblocks + != entry->data->dpme_pblock_start) { + // previous is not contiguous (XXX this is bad) + printf("previous entry is not contiguous\n"); + // new end is maximum of two ends + end = p->data->dpme_pblock_start + p->data->dpme_pblocks; + if (end < entry->data->dpme_pblock_start + entry->data->dpme_pblocks) { + end = entry->data->dpme_pblock_start + entry->data->dpme_pblocks; + } + entry->data->dpme_pblocks = end - p->data->dpme_pblock_start; + // new start is previous entry's start + entry->data->dpme_pblock_start = p->data->dpme_pblock_start; + entry->data->dpme_lblocks = entry->data->dpme_pblocks; + delete_entry(p); + } else { + entry->data->dpme_pblock_start = p->data->dpme_pblock_start; + entry->data->dpme_pblocks += p->data->dpme_pblocks; + entry->data->dpme_lblocks = entry->data->dpme_pblocks; + delete_entry(p); + } + } + entry->contains_driver = contains_driver(entry); +} + + +void +delete_entry(partition_map *entry) +{ + partition_map_header *map; + partition_map *p; + + map = entry->the_map; + map->blocks_in_map--; + + remove_from_disk_order(entry); + + p = entry->next_by_base; + if (map->base_order == entry) { + map->base_order = p; + } + if (p != NULL) { + p->prev_by_base = entry->prev_by_base; + } + if (entry->prev_by_base != NULL) { + entry->prev_by_base->next_by_base = p; + } + + free(entry->data); + free(entry); +} + + +partition_map * +find_entry_by_disk_address(long index, partition_map_header *map) +{ + partition_map * cur; + + cur = map->disk_order; + while (cur != NULL) { + if (cur->disk_address == index) { + break; + } + cur = cur->next_on_disk; + } + return cur; +} + + +partition_map * +find_entry_by_type(const char *type_name, partition_map_header *map) +{ + partition_map * cur; + + cur = map->base_order; + while (cur != NULL) { + if (istrncmp(cur->data->dpme_type, type_name, DPISTRLEN) == 0) { + break; + } + cur = cur->next_by_base; + } + return cur; +} + + +void +move_entry_in_map(long old_index, long index, partition_map_header *map) +{ + partition_map * cur; + + cur = find_entry_by_disk_address(old_index, map); + if (cur == NULL) { + printf("No such partition\n"); + } else { + remove_from_disk_order(cur); + cur->disk_address = index; + insert_in_disk_order(cur); + renumber_disk_addresses(map); + map->changed = 1; + } +} + + +void +remove_from_disk_order(partition_map *entry) +{ + partition_map_header *map; + partition_map *p; + + map = entry->the_map; + p = entry->next_on_disk; + if (map->disk_order == entry) { + map->disk_order = p; + } + if (p != NULL) { + p->prev_on_disk = entry->prev_on_disk; + } + if (entry->prev_on_disk != NULL) { + entry->prev_on_disk->next_on_disk = p; + } + entry->next_on_disk = NULL; + entry->prev_on_disk = NULL; +} + + +void +insert_in_disk_order(partition_map *entry) +{ + partition_map_header *map; + partition_map * cur; + + // find position in disk list & insert + map = entry->the_map; + cur = map->disk_order; + if (cur == NULL || entry->disk_address <= cur->disk_address) { + map->disk_order = entry; + entry->next_on_disk = cur; + if (cur != NULL) { + cur->prev_on_disk = entry; + } + entry->prev_on_disk = NULL; + } else { + for (cur = map->disk_order; cur != NULL; cur = cur->next_on_disk) { + if (cur->disk_address <= entry->disk_address + && (cur->next_on_disk == NULL + || entry->disk_address <= cur->next_on_disk->disk_address)) { + entry->next_on_disk = cur->next_on_disk; + cur->next_on_disk = entry; + entry->prev_on_disk = cur; + if (entry->next_on_disk != NULL) { + entry->next_on_disk->prev_on_disk = entry; + } + break; + } + } + } +} + + +void +insert_in_base_order(partition_map *entry) +{ + partition_map_header *map; + partition_map * cur; + + // find position in base list & insert + map = entry->the_map; + cur = map->base_order; + if (cur == NULL + || entry->data->dpme_pblock_start <= cur->data->dpme_pblock_start) { + map->base_order = entry; + entry->next_by_base = cur; + if (cur != NULL) { + cur->prev_by_base = entry; + } + entry->prev_by_base = NULL; + } else { + for (cur = map->base_order; cur != NULL; cur = cur->next_by_base) { + if (cur->data->dpme_pblock_start <= entry->data->dpme_pblock_start + && (cur->next_by_base == NULL + || entry->data->dpme_pblock_start + <= cur->next_by_base->data->dpme_pblock_start)) { + entry->next_by_base = cur->next_by_base; + cur->next_by_base = entry; + entry->prev_by_base = cur; + if (entry->next_by_base != NULL) { + entry->next_by_base->prev_by_base = entry; + } + break; + } + } + } +} + + +void +resize_map(long new_size, partition_map_header *map) +{ + partition_map * entry; + partition_map * next; + int incr; + + // find map entry + entry = find_entry_by_type(kMapType, map); + + if (entry == NULL) { + printf("Couldn't find entry for map!\n"); + return; + } + next = entry->next_by_base; + + // same size + if (new_size == entry->data->dpme_pblocks) { + // do nothing + return; + } + + // make it smaller + if (new_size < entry->data->dpme_pblocks) { + if (next == NULL + || istrncmp(next->data->dpme_type, kFreeType, DPISTRLEN) != 0) { + incr = 1; + } else { + incr = 0; + } + if (new_size < map->blocks_in_map + incr) { + printf("New size would be too small\n"); + return; + } + goto doit; + } + + // make it larger + if (next == NULL + || istrncmp(next->data->dpme_type, kFreeType, DPISTRLEN) != 0) { + printf("No free space to expand into\n"); + return; + } + if (entry->data->dpme_pblock_start + entry->data->dpme_pblocks + != next->data->dpme_pblock_start) { + printf("No contiguous free space to expand into\n"); + return; + } + if (new_size > entry->data->dpme_pblocks + next->data->dpme_pblocks) { + printf("No enough free space\n"); + return; + } +doit: + entry->data->dpme_type[0] = 0; + delete_partition_from_map(entry); + add_partition_to_map("Apple", kMapType, 1, new_size, map); + map->maximum_in_map = new_size; +} + + +void +remove_driver(partition_map *entry) +{ + partition_map_header *map; + Block0 *p; + DDMap *m; + int i; + int j; + int f; + u32 start; + + map = entry->the_map; + p = map->misc; + if (p == NULL) { + return; + } + if (p->sbSig != BLOCK0_SIGNATURE) { + return; + } + if (map->logical_block > p->sbBlkSize) { + /* this is not supposed to happen, but let's just ignore it. */ + return; + } else { + /* + * compute the factor to convert the block numbers in block0 + * into partition map block numbers. + */ + f = p->sbBlkSize / map->logical_block; + } + if (p->sbDrvrCount > 0) { + m = (DDMap *) p->sbMap; + for (i = 0; i < p->sbDrvrCount; i++) { + start = get_align_long(&m[i].ddBlock); + + /* zap the driver if it is wholly contained in the partition */ + if (entry->data->dpme_pblock_start <= f*start + && f*(start + m[i].ddSize) + <= (entry->data->dpme_pblock_start + + entry->data->dpme_pblocks)) { + // delete this driver + // by copying down later ones and zapping the last + for (j = i+1; j < p->sbDrvrCount; j++, i++) { + put_align_long(get_align_long(&m[j].ddBlock), &m[i].ddBlock); + m[i].ddSize = m[j].ddSize; + m[i].ddType = m[j].ddType; + } + put_align_long(0, &m[i].ddBlock); + m[i].ddSize = 0; + m[i].ddType = 0; + p->sbDrvrCount -= 1; + return; /* XXX if we continue we will delete other drivers? */ + } + } + } +} + +int +read_block(partition_map_header *map, unsigned long num, char *buf) +{ +//printf("read block %d\n", num); + return read_media(map->m, ((long long) num) * map->logical_block, + PBLOCK_SIZE, (void *)buf); +} + + +int +write_block(partition_map_header *map, unsigned long num, char *buf) +{ + return write_media(map->m, ((long long) num) * map->logical_block, + PBLOCK_SIZE, (void *)buf); +} diff --git a/sbin/pdisk/partition_map.h b/sbin/pdisk/partition_map.h new file mode 100644 index 00000000000..5390bfe543e --- /dev/null +++ b/sbin/pdisk/partition_map.h @@ -0,0 +1,107 @@ +// +// partition_map.h - partition map routines +// +// Written by Eryk Vershen (eryk@apple.com) +// + +/* + * Copyright 1996,1998 by Apple Computer, Inc. + * All Rights Reserved + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appears in all copies and + * that both the copyright notice and this permission notice appear in + * supporting documentation. + * + * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, + * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION + * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __partition_map__ +#define __partition_map__ + +#include "dpme.h" +#include "media.h" + + +// +// Defines +// +#define PBLOCK_SIZE 512 + + +// +// Types +// +struct partition_map_header { + MEDIA m; + char *name; + struct partition_map * disk_order; + struct partition_map * base_order; + Block0 *misc; + int writeable; + int changed; + int physical_block; // must be == sbBlockSize + int logical_block; // must be <= physical_block + int blocks_in_map; + int maximum_in_map; + unsigned long media_size; // in logical_blocks +}; +typedef struct partition_map_header partition_map_header; + +struct partition_map { + struct partition_map * next_on_disk; + struct partition_map * prev_on_disk; + struct partition_map * next_by_base; + struct partition_map * prev_by_base; + long disk_address; + struct partition_map_header * the_map; + int contains_driver; + DPME *data; +}; +typedef struct partition_map partition_map; + + +// +// Global Constants +// +extern const char * kFreeType; +extern const char * kMapType; +extern const char * kUnixType; +extern const char * kHFSType; +extern const char * kFreeName; +extern const char * kPatchType; + + +// +// Global Variables +// +extern int rflag; +extern int interactive; +extern int dflag; + + +// +// Forward declarations +// +int add_partition_to_map(const char *name, const char *dptype, u32 base, u32 length, partition_map_header *map); +void close_partition_map(partition_map_header *map); +partition_map_header* create_partition_map(char *name, partition_map_header *oldmap); +void delete_partition_from_map(partition_map *entry); +partition_map* find_entry_by_disk_address(long index, partition_map_header *map); +partition_map* find_entry_by_type(const char *type_name, partition_map_header *map); +partition_map_header* init_partition_map(char *name, partition_map_header* oldmap); +void move_entry_in_map(long old_index, long index, partition_map_header *map); +partition_map_header* open_partition_map(char *name, int *valid_file, int ask_logical_size); +void resize_map(long new_size, partition_map_header *map); +void write_partition_map(partition_map_header *map); + +#endif /* __partition_map__ */ diff --git a/sbin/pdisk/pathname.c b/sbin/pdisk/pathname.c new file mode 100644 index 00000000000..aba083a00bc --- /dev/null +++ b/sbin/pdisk/pathname.c @@ -0,0 +1,229 @@ +/* + * pathname.c - + * + * Written by Eryk Vershen (eryk@apple.com) + */ + +/* + * Copyright 1997,1998 by Apple Computer, Inc. + * All Rights Reserved + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appears in all copies and + * that both the copyright notice and this permission notice appear in + * supporting documentation. + * + * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, + * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION + * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + + +// for strncmp() +#include <string.h> + +#include "pathname.h" +#include "file_media.h" + +#ifndef __linux__ +#include "SCSI_media.h" +#include "ATA_media.h" +#endif + + +/* + * Defines + */ + + +/* + * Types + */ + + +/* + * Global Constants + */ + + +/* + * Global Variables + */ + + +/* + * Forward declarations + */ + + +/* + * Routines + */ + +/* + * Note that open_pathname_as_media() and get_mklinux_name() have almost + * identical structures. If one changes the other must also! + */ +MEDIA +open_pathname_as_media(char *path, int oflag) +{ + MEDIA m = 0; +#if !defined(__linux__) && !defined(__unix__) + long id; + long bus; + + if (strncmp("/dev/", path, 5) == 0) { + if (strncmp("/dev/scsi", path, 9) == 0) { + if (path[9] >= '0' && path[9] <= '7' && path[10] == 0) { + id = path[9] - '0'; + m = open_old_scsi_as_media(id); + } else if (path[9] >= '0' && path[9] <= '7' && path[10] == '.' + && path[11] >= '0' && path[11] <= '7' && path[12] == 0) { + id = path[11] - '0'; + bus = path[9] - '0'; + m = open_scsi_as_media(bus, id); + } + } else if (strncmp("/dev/ata", path, 8) == 0 + || strncmp("/dev/ide", path, 8) == 0) { + if (path[8] >= '0' && path[8] <= '7' && path[9] == 0) { + bus = path[8] - '0'; + m = open_ata_as_media(bus, 0); + } else if (path[8] >= '0' && path[8] <= '7' && path[9] == '.' + && path[10] >= '0' && path[10] <= '1' && path[11] == 0) { + id = path[10] - '0'; + bus = path[8] - '0'; + m = open_ata_as_media(bus, id); + } + } else if (strncmp("/dev/sd", path, 7) == 0) { + if (path[7] >= 'a' && path[7] <= 'z' && path[8] == 0) { + id = path[7] - 'a'; + m = open_mklinux_scsi_as_media(id, 0); + } + } else if (strncmp("/dev/scd", path, 8) == 0) { + if (path[8] >= '0' && path[8] <= '9' && path[9] == 0) { + id = path[8] - '0'; + m = open_mklinux_scsi_as_media(id, 1); + } + } else if (strncmp("/dev/hd", path, 7) == 0) { + if (path[7] >= 'a' && path[7] <= 'z' && path[8] == 0) { + id = path[7] - 'a'; + m = open_mklinux_ata_as_media(id); + } + } + } else +#endif + + { + m = open_file_as_media(path, oflag); + } + return m; +} + + +char * +get_mklinux_name(char *path) +{ + char *result = 0; +#if !defined(__linux__) && !defined(__unix__) + long id; + long bus; + + if (strncmp("/dev/", path, 5) == 0) { + if (strncmp("/dev/scsi", path, 9) == 0) { + if (path[9] >= '0' && path[9] <= '7' && path[10] == 0) { + /* old scsi */ + id = path[9] - '0'; + result = mklinux_old_scsi_name(id); + } else if (path[9] >= '0' && path[9] <= '7' && path[10] == '.' + && path[11] >= '0' && path[11] <= '7' && path[12] == 0) { + /* new scsi */ + id = path[11] - '0'; + bus = path[9] - '0'; + result = mklinux_scsi_name(bus, id); + } + } else if (strncmp("/dev/ata", path, 8) == 0 + || strncmp("/dev/ide", path, 8) == 0) { + if (path[8] >= '0' && path[8] <= '7' && path[9] == 0) { + /* ata/ide - master device */ + bus = path[8] - '0'; + result = mklinux_ata_name(bus, 0); + } else if (path[8] >= '0' && path[8] <= '7' && path[9] == '.' + && path[10] >= '0' && path[10] <= '1' && path[11] == 0) { + /* ata/ide */ + id = path[10] - '0'; + bus = path[8] - '0'; + result = mklinux_ata_name(bus, id); + } + } + } +#endif + + return result; +} + + +MEDIA_ITERATOR +first_media_kind(long *state) +{ + *state = 0; + return next_media_kind(state); +} + + +MEDIA_ITERATOR +next_media_kind(long *state) +{ + MEDIA_ITERATOR result; + long index; + + result = 0; + index = *state; + + switch (index) { + case 0: +#if defined(__linux__) || defined(__unix__) + result = create_file_iterator(); +#endif + index = 1; + if (result != 0) { + break; + } + /* fall through to next interface */ + + case 1: +#if !defined(__linux__) && !defined(__unix__) + result = create_ata_iterator(); +#endif + index = 2; + if (result != 0) { + break; + } + /* fall through to next interface */ + + case 2: +#if !defined(__linux__) && !defined(__unix__) + result = create_scsi_iterator(); +#endif + index = 3; + if (result != 0) { + break; + } + /* fall through to next interface */ + + case 3: + default: + break; + } + + *state = index; + return result; +} + + diff --git a/sbin/pdisk/pathname.h b/sbin/pdisk/pathname.h new file mode 100644 index 00000000000..598287ae873 --- /dev/null +++ b/sbin/pdisk/pathname.h @@ -0,0 +1,62 @@ +/* + * pathname.h - + * + * Written by Eryk Vershen (eryk@apple.com) + */ + +/* + * Copyright 1997,1998 by Apple Computer, Inc. + * All Rights Reserved + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appears in all copies and + * that both the copyright notice and this permission notice appear in + * supporting documentation. + * + * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, + * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION + * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __pathname__ +#define __pathname__ + +#include "media.h" + + +/* + * Defines + */ + + +/* + * Types + */ + + +/* + * Global Constants + */ + + +/* + * Global Variables + */ + + +/* + * Forward declarations + */ +MEDIA open_pathname_as_media(char *path, int oflag); +MEDIA_ITERATOR first_media_kind(long *state); +MEDIA_ITERATOR next_media_kind(long *state); +char *get_mklinux_name(char *name); + +#endif /* __pathname__ */ diff --git a/sbin/pdisk/pdisk.8 b/sbin/pdisk/pdisk.8 new file mode 100644 index 00000000000..510f8c32fdb --- /dev/null +++ b/sbin/pdisk/pdisk.8 @@ -0,0 +1,210 @@ +.TH PDISK 8 "26 September 1997" "MkLinux DR2" "Linux Programmer's Manual" +.SH NAME +pdisk \- Apple partition table editor for Linux +.SH SYNOPSIS +.B pdisk +.B "[\-h|\--help]" +.br +.B pdisk +.B "[\-i|\--interactive]" +.br +.B pdisk +.B "[\-l|\--list [name ...]]" +.br +.B pdisk +device ... +.br +.B pdisk +.B "[\-v|\--version] [\-r|\--readonly] [\-abbr] [\--logical] [\-c|\--compute_size]" +.SH DESCRIPTION +.B pdisk +is a menu driven program which partitions disks using the standard Apple +disk partitioning scheme described in "Inside Macintosh: Devices". +It does not support the intel/dos partitioning scheme supported by +.BR fdisk . +The +.I device +is usually one of the following: + +.nf +.RS +/dev/sda +/dev/sdb +/dev/sdc +/dev/sdd +/dev/sde +/dev/sdf +/dev/sdg +/dev/hda +/dev/hdb + +.RE +.fi +MkLinux interprets device names differently than standard Linux. +In MkLinux /dev/sda is the device at SCSI id 0, /dev/sdb is the device at SCSI +id 1, and so on. +In standard Linux /dev/sda is the first hard disk on the SCSI bus (i.e. the +one with the lowest id), /dev/sdb is the second hard disk, and so on. +The +.I partition +is a +.I device +name followed by a partition number. +The partition number is the index (starting from one) of the partition +map entry in the partition map. +For example, +.B /dev/sda2 +is the partition described by the second entry in the partiton map on /dev/sda. + +.SH OPTIONS +.TP +.B \-v | \--version +Prints version number of the +.B pdisk +program. +.TP +.B \-h | \--help +Prints a rather lame set of help messages for the +.B pdisk +program. +.TP +.B \-i | \--interactive +Causes +.B pdisk +to go into an interactive mode similar to the MacOS version of the program. +.TP +.B \-l | \--list +If no +.IR name s +are present then lists the partition tables for +.BR /dev/sda , +.BR /dev/sdb , +.BR /dev/sdc , +.BR /dev/sdd , +.BR /dev/sde , +.BR /dev/sdf , +and +.BR /dev/sdg . +Otherwise, lists the partition tables for the specified +.IR name s. +.TP +.B \-r | \--readonly +Prevents +.B pdisk +from writing to the device. +.TP +.B \-c | \--compute_size +Causes +.B pdisk +to always ignore the device size listed in the partition table +and compute the device size by other means. +.SH "Editing Partition Tables" +An argument which is simply the name of a +.I device +indicates that +.B pdisk +should edit the partition table of that device. + +The current top level editing commands are: + +.nf +.RS +h command help +p print the partition table +P (print ordered by base address) +i initialize partition map +s change size of partition map +c create new partition (standard MkLinux type) +C (create with type also specified) +n (re)name a partition +d delete a partition +r reorder partition entry in map +w write the partition table +q quit editing (don't save changes) + +.RE +.fi +Commands which take arguments prompt for each argument in turn. +You can also type any number of the arguments separated by spaces +and those prompts will be skipped. +The only exception to typeahead are the confirmation prompts on the +.B i +and +.B w +commands. +The idea being that if we expect you to confirm the decision we +shouldn't undermine that by allowing you to be precipitate about it. + +Partitions are always specified by their number, +which the index of the partition entry in the partition map. +Most of the commands will change the index numbers of all partitions +after the affected partition. +You are advised to print the table as frequently as necessary. + +Creating more than fifteen partitions is not advised. +There is currently a bug in the some (all?) of the kernels which causes +access to the whole disk fail if more than fifteen partitions are in the map. + +The +.B c +(create new partition) command is the only one with complicated arguments. +The first argument is the base address (in blocks) of the partition. +Besides a raw number, you can also specify a partition number followed +by the letter 'p' to indicate that the first block of the new partition should +be the same as the first block of that existing free space partition. +The second argument is the length of the partition in blocks. +This can be a raw number or can be a partition number followed by the +letter 'p' to use the size of that partition or can be a number followed +by 'k', 'm', or 'g' to indicate the size in kilobytes, megabytes, or gigabytes +respectively. +(These are powers of 1024, of course, not powers of 1000.) +The last argument is the name of the partition. +This can be a single word without quotes, or a string surrounded by +single or double quotes. +The type of the created partition is the correct type for MkLinux. + +The +.B C +command is identical to the +.B c +command, with the addition of a partition type argument after the +other arguments. + +The +.B n +(name) command allows the name of a partition to be changed. +Note that the various "Apple_Driver" partitions depend +on the name field for proper functioning. +I am not aware of any other partition types with this limitation. + +The +.B r +(reorder) command allows the index number of partitions to be changed. +The index numbers are constrained to be a contiguous sequence. + +The +.B i +(initalize) command prompts for the size of the device. +This was done to get around a bug in the kernel where it reports the wrong +size for the device. + +The +.B w +(write) command does write the partition map out, +but there is currently a bug in the interaction between MkLinux and Mach +which causes the partition map not to be reinterpreted. +In order to use the new partition map you must reboot. + +.SH BUGS +Some people believe there should really be just one disk partitioning utility. +.br +.B pdisk +should be able to create HFS partitions that work. +.br +Even more help should be available during user input. +.SH "SEE ALSO" +.BR fdisk (8), +.BR mkswap (8), +.BR mkfs (8) +.SH AUTHOR +Eryk Vershen (eryk@apple.com) diff --git a/sbin/pdisk/pdisk.c b/sbin/pdisk/pdisk.c new file mode 100644 index 00000000000..033a16c1fe7 --- /dev/null +++ b/sbin/pdisk/pdisk.c @@ -0,0 +1,1004 @@ +// +// pdisk - an editor for Apple format partition tables +// +// Written by Eryk Vershen (eryk@apple.com) +// +// Still under development (as of 15 January 1998) +// + +/* + * Copyright 1996,1997,1998 by Apple Computer, Inc. + * All Rights Reserved + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appears in all copies and + * that both the copyright notice and this permission notice appear in + * supporting documentation. + * + * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, + * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION + * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +// for printf() +#include <stdio.h> + +#ifdef __linux__ +#include <getopt.h> +#include <malloc.h> +#else +// for malloc() & free() +#include <stdlib.h> +// for SIOUXsettings +#include <SIOUX.h> +#endif + +// for strncpy() & strlen() +#include <string.h> +// for O_RDONLY +#include <fcntl.h> +// for errno +#include <errno.h> + +#ifdef __linux__ +#include <sys/ioctl.h> +#include <linux/fs.h> +#include <linux/hdreg.h> +#endif + +#include "pdisk.h" +#include "io.h" +#include "partition_map.h" +#include "pathname.h" +#include "errors.h" +#include "dump.h" +#include "validate.h" +#include "version.h" +#include "util.h" + + +// +// Defines +// +#define ARGV_CHUNK 5 +#define CFLAG_DEFAULT 0 +#define DFLAG_DEFAULT 0 +#define HFLAG_DEFAULT 0 +#define INTERACT_DEFAULT 0 +#define LFLAG_DEFAULT 0 +#define RFLAG_DEFAULT 0 +#define VFLAG_DEFAULT 0 + + +// +// Types +// + + +// +// Global Constants +// +enum getopt_values { + kLongOption = 0, + kBadOption = '?', + kOptionArg = 1000, + kListOption = 1001, + kLogicalOption = 1002 +}; + + +// +// Global Variables +// +int lflag = LFLAG_DEFAULT; /* list the device */ +char *lfile; /* list */ +int vflag = VFLAG_DEFAULT; /* show version */ +int hflag = HFLAG_DEFAULT; /* show help */ +int dflag = DFLAG_DEFAULT; /* turn on debugging commands and printout */ +int rflag = RFLAG_DEFAULT; /* open device read Only */ +int interactive = INTERACT_DEFAULT; +int cflag = CFLAG_DEFAULT; /* compute device size */ + +static int first_get = 1; + + +// +// Forward declarations +// +void do_change_map_size(partition_map_header *map); +void do_create_partition(partition_map_header *map, int get_type); +void do_delete_partition(partition_map_header *map); +void do_display_block(partition_map_header *map, char *alt_name); +void do_display_entry(partition_map_header *map); +void do_examine_patch_partition(partition_map_header *map); +int do_expert(partition_map_header *map, char *name); +void do_rename_partition(partition_map_header *map); +void do_reorder(partition_map_header *map); +void do_write_partition_map(partition_map_header *map); +void edit(char *name, int ask_logical_size); +int get_base_argument(long *number, partition_map_header *map); +int get_command_line(int *argc, char ***argv); +int get_size_argument(long *number, partition_map_header *map); +int get_options(int argc, char **argv); +void interact(); +void print_edit_notes(); +void print_expert_notes(); +void print_top_notes(); + + +// +// Routines +// +int +main(int argc, char **argv) +{ +#ifdef __linux__ + int name_index; +#else + printf("This app uses the SIOUX console library\n"); + printf("Choose 'Quit' from the file menu to quit.\n\n"); + printf("Use fake disk names (/dev/scsi<bus>.<id>; i.e. /dev/scsi0.1, /dev/scsi1.3, etc.).\n\n"); + + SIOUXSettings.autocloseonquit = 0; /* Do we close the SIOUX window on program termination ... */ + SIOUXSettings.asktosaveonclose = 0; /* Do we offer to save on a close ... */ +#endif + + init_program_name(argv); + + if (sizeof(DPME) != PBLOCK_SIZE) { + fatal(-1, "Size of partion map entry (%d) " + "is not equal to block size (%d)\n", + sizeof(DPME), PBLOCK_SIZE); + } + if (sizeof(Block0) != PBLOCK_SIZE) { + fatal(-1, "Size of block zero structure (%d) " + "is not equal to block size (%d)\n", + sizeof(Block0), PBLOCK_SIZE); + } + if (strcmp(VERSION, get_version_string()) != 0) { + fatal(-1, "Version string static form (%s) does not match dynamic form (%s)\n", + VERSION, get_version_string()); + } + +#ifdef __linux__ + name_index = get_options(argc, argv); + + if (vflag) { + printf("version " VERSION " (" RELEASE_DATE ")\n"); + } + if (hflag) { + do_help(); + } else if (interactive) { + interact(); + } else if (lflag) { + if (lfile != NULL) { + dump(lfile); + } else if (name_index < argc) { + while (name_index < argc) { + dump(argv[name_index++]); + } + } else { + list_all_disks(); + } + } else if (name_index < argc) { + while (name_index < argc) { + edit(argv[name_index++], 0); + } + } else if (!vflag) { + usage("no device argument"); + do_help(); + } + return 0; +#else + interactive = 1; + + interact(); + + SIOUXSettings.autocloseonquit = 1; + //printf("Processing stopped: Choose 'Quit' from the file menu to quit.\n\n"); + exit(0); +#endif +} + + +void +print_top_notes() +{ + printf("Notes:\n"); + printf(" Disks have fake names of the form /dev/scsi<bus>.<id>\n"); + printf(" For example, /dev/scsi0.1, /dev/scsi1.3, and so on.\n"); + printf(" MkLinux style names are also allowed (i.e /dev/sda or /dev/hda),\n"); + printf(" and these names follow the MkLinux DR3 conventions.\n"); + printf("\n"); +} + + +void +interact() +{ + char *name; + int command; + int ask_logical_size; + + while (get_command("Top level command (? for help): ", first_get, &command)) { + first_get = 0; + ask_logical_size = 0; + + switch (command) { + case '?': + print_top_notes(); + // fall through + case 'H': + case 'h': + printf("Commands are:\n"); + printf(" h print help\n"); + printf(" v print the version number and release date\n"); + printf(" l list device's map\n"); + printf(" L list all devices' maps\n"); + printf(" e edit device's map\n"); + printf(" E (edit map with specified block size)\n"); + printf(" r toggle readonly flag\n"); + if (dflag) { + printf(" a toggle abbreviate flag\n"); + printf(" p toggle physical flag\n"); + printf(" c toggle compute size flag\n"); + printf(" d toggle debug flag\n"); + printf(" x examine block n of device\n"); + } + printf(" q quit the program\n"); + break; + case 'Q': + case 'q': + return; + break; + case 'V': + case 'v': + printf("version " VERSION " (" RELEASE_DATE ")\n"); + break; + case 'L': + list_all_disks(); + break; + case 'l': + if (get_string_argument("Name of device: ", &name, 1) == 0) { + bad_input("Bad name"); + break; + } + dump(name); + free(name); + break; + case 'E': + ask_logical_size = 1; + case 'e': + if (get_string_argument("Name of device: ", &name, 1) == 0) { + bad_input("Bad name"); + break; + } + edit(name, ask_logical_size); + free(name); + break; + case 'R': + case 'r': + if (rflag) { + rflag = 0; + } else { + rflag = 1; + } + printf("Now in %s mode.\n", (rflag)?"readonly":"read/write"); + break; + case 'A': + case 'a': + if (dflag) { + if (aflag) { + aflag = 0; + } else { + aflag = 1; + } + printf("Now in %s mode.\n", (aflag)?"abbreviate":"full type"); + } else { + goto do_error; + } + break; + case 'P': + case 'p': + if (dflag) { + if (pflag) { + pflag = 0; + } else { + pflag = 1; + } + printf("Now in %s mode.\n", (pflag)?"physical":"logical"); + } else { + goto do_error; + } + break; + case 'D': + case 'd': + if (dflag) { + dflag = 0; + } else { + dflag = 1; + } + printf("Now in %s mode.\n", (dflag)?"debug":"normal"); + break; + case 'C': + case 'c': + if (dflag) { + if (cflag) { + cflag = 0; + } else { + cflag = 1; + } + printf("Now in %s device size mode.\n", (cflag)?"always compute":"use existing"); + } else { + goto do_error; + } + break; + case 'X': + case 'x': + if (dflag) { + do_display_block(0, 0); + } else { + goto do_error; + } + break; + default: + do_error: + bad_input("No such command (%c)", command); + break; + } + } +} + + +#ifdef __linux__ +int +get_options(int argc, char **argv) +{ + int c; + static struct option long_options[] = + { + // name has_arg &flag val + {"help", no_argument, 0, 'h'}, + {"list", optional_argument, 0, kListOption}, + {"version", no_argument, 0, 'v'}, + {"debug", no_argument, 0, 'd'}, + {"readonly", no_argument, 0, 'r'}, + {"abbr", no_argument, 0, 'a'}, + {"logical", no_argument, 0, kLogicalOption}, + {"interactive", no_argument, 0, 'i'}, + {"compute_size", no_argument, 0, 'c'}, + {0, 0, 0, 0} + }; + int option_index = 0; + extern int optind; + extern char *optarg; + int flag = 0; + + lflag = LFLAG_DEFAULT; + lfile = NULL; + vflag = VFLAG_DEFAULT; + hflag = HFLAG_DEFAULT; + dflag = DFLAG_DEFAULT; + rflag = RFLAG_DEFAULT; + aflag = AFLAG_DEFAULT; + pflag = PFLAG_DEFAULT; + interactive = INTERACT_DEFAULT; + cflag = CFLAG_DEFAULT; + + optind = 0; // reset option scanner logic + while ((c = getopt_long(argc, argv, "hlvdric", long_options, + &option_index)) >= 0) { + switch (c) { + case kLongOption: + // option_index would be used here + break; + case 'h': + hflag = (HFLAG_DEFAULT)?0:1; + break; + case kListOption: + if (optarg != NULL) { + lfile = optarg; + } + // fall through + case 'l': + lflag = (LFLAG_DEFAULT)?0:1; + break; + case 'v': + vflag = (VFLAG_DEFAULT)?0:1; + break; + case 'd': + dflag = (DFLAG_DEFAULT)?0:1; + break; + case 'c': + cflag = (CFLAG_DEFAULT)?0:1; + break; + case 'r': + rflag = (RFLAG_DEFAULT)?0:1; + break; + case 'i': + interactive = (INTERACT_DEFAULT)?0:1; + break; + case 'a': + aflag = (AFLAG_DEFAULT)?0:1; + break; + case kLogicalOption: + pflag = (PFLAG_DEFAULT)?0:1; + break; + case kBadOption: + default: + flag = 1; + break; + } + } + if (flag) { + usage("bad arguments"); + } + return optind; +} +#endif + + +void +print_edit_notes() +{ + printf("Notes:\n"); + printf(" Base and length fields are blocks, which vary in size between media.\n"); + printf(" The base field can be <nth>p; i.e. use the base of the nth partition.\n"); + printf(" The length field can be a length followed by k, m, g or t to indicate\n"); + printf(" kilo, mega, giga, or tera bytes; also the length can be <nth>p; i.e. use\n"); + printf(" the length of the nth partition.\n"); + printf(" The name of a partition is descriptive text.\n"); + printf("\n"); +} + + +// +// Edit the file +// +void +edit(char *name, int ask_logical_size) +{ + partition_map_header *map; + int command; + int order; + int get_type; + int valid_file; + + map = open_partition_map(name, &valid_file, ask_logical_size); + if (!valid_file) { + return; + } + + printf("Edit %s -\n", name); + + while (get_command("Command (? for help): ", first_get, &command)) { + first_get = 0; + order = 1; + get_type = 0; + + switch (command) { + case '?': + print_edit_notes(); + // fall through + case 'H': + case 'h': + printf("Commands are:\n"); + printf(" h help\n"); + printf(" p print the partition table\n"); + printf(" P (print ordered by base address)\n"); + printf(" i initialize partition map\n"); + printf(" s change size of partition map\n"); + printf(" c create new partition (standard MkLinux type)\n"); + printf(" C (create with type also specified)\n"); + printf(" n (re)name a partition\n"); + printf(" d delete a partition\n"); + printf(" r reorder partition entry in map\n"); + if (!rflag) { + printf(" w write the partition table\n"); + } + printf(" q quit editing (don't save changes)\n"); + if (dflag) { + printf(" x extra extensions for experts\n"); + } + break; + case 'P': + order = 0; + // fall through + case 'p': + dump_partition_map(map, order); + break; + case 'Q': + case 'q': + flush_to_newline(1); + goto finis; + break; + case 'I': + case 'i': + map = init_partition_map(name, map); + break; + case 'C': + get_type = 1; + // fall through + case 'c': + do_create_partition(map, get_type); + break; + case 'N': + case 'n': + do_rename_partition(map); + break; + case 'D': + case 'd': + do_delete_partition(map); + break; + case 'R': + case 'r': + do_reorder(map); + break; + case 'S': + case 's': + do_change_map_size(map); + break; + case 'X': + case 'x': + if (!dflag) { + goto do_error; + } else if (do_expert(map, name)) { + flush_to_newline(1); + goto finis; + } + break; + case 'W': + case 'w': + if (!rflag) { + do_write_partition_map(map); + } else { + goto do_error; + } + break; + default: + do_error: + bad_input("No such command (%c)", command); + break; + } + } +finis: + + close_partition_map(map); +} + + +void +do_create_partition(partition_map_header *map, int get_type) +{ + long base; + long length; + char *name; + char *type_name; + + if (map == NULL) { + bad_input("No partition map exists"); + return; + } + if (!rflag && map->writeable == 0) { + printf("The map is not writeable.\n"); + } +// XXX add help feature (i.e. '?' in any argument routine prints help string) + if (get_base_argument(&base, map) == 0) { + return; + } + if (get_size_argument(&length, map) == 0) { + return; + } + + if (get_string_argument("Name of partition: ", &name, 1) == 0) { + bad_input("Bad name"); + return; + } + if (get_type == 0) { + add_partition_to_map(name, kUnixType, base, length, map); + goto xit1; + + } else if (get_string_argument("Type of partition: ", &type_name, 1) == 0) { + bad_input("Bad type"); + goto xit1; + } else { + if (istrncmp(type_name, kFreeType, DPISTRLEN) == 0) { + bad_input("Can't create a partition with the Free type"); + goto xit2; + } + if (istrncmp(type_name, kMapType, DPISTRLEN) == 0) { + bad_input("Can't create a partition with the Map type"); + goto xit2; + } + add_partition_to_map(name, type_name, base, length, map); + } +xit2: + free(type_name); +xit1: + free(name); + return; +} + + +int +get_base_argument(long *number, partition_map_header *map) +{ + partition_map * entry; + int result = 0; + + if (get_number_argument("First block: ", number, kDefault) == 0) { + bad_input("Bad block number"); + } else { + result = 1; + if (get_partition_modifier()) { + entry = find_entry_by_disk_address(*number, map); + if (entry == NULL) { + bad_input("Bad partition number"); + result = 0; + } else { + *number = entry->data->dpme_pblock_start; + } + } + } + return result; +} + + +int +get_size_argument(long *number, partition_map_header *map) +{ + partition_map * entry; + int result = 0; + unsigned long multiple; + + if (get_number_argument("Length in blocks: ", number, kDefault) == 0) { + bad_input("Bad length"); + } else { + multiple = get_multiplier(map->logical_block); + if (multiple == 0) { + bad_input("Bad multiplier"); + } else if (multiple != 1) { + *number *= multiple; + result = 1; + } else if (get_partition_modifier()) { + entry = find_entry_by_disk_address(*number, map); + if (entry == NULL) { + bad_input("Bad partition number"); + } else { + *number = entry->data->dpme_pblocks; + result = 1; + } + } else { + result = 1; + } + } + return result; +} + + +void +do_rename_partition(partition_map_header *map) +{ + partition_map * entry; + long index; + char *name; + + if (map == NULL) { + bad_input("No partition map exists"); + return; + } + if (!rflag && map->writeable == 0) { + printf("The map is not writeable.\n"); + } + if (get_number_argument("Partition number: ", &index, kDefault) == 0) { + bad_input("Bad partition number"); + return; + } + if (get_string_argument("New name of partition: ", &name, 1) == 0) { + bad_input("Bad name"); + return; + } + + // find partition and change it + entry = find_entry_by_disk_address(index, map); + if (entry == NULL) { + printf("No such partition\n"); + } else { + // stuff name into partition map entry data + strncpy(entry->data->dpme_name, name, DPISTRLEN); + map->changed = 1; + } + free(name); + return; +} + + +void +do_delete_partition(partition_map_header *map) +{ + partition_map * cur; + long index; + + if (map == NULL) { + bad_input("No partition map exists"); + return; + } + if (!rflag && map->writeable == 0) { + printf("The map is not writeable.\n"); + } + if (get_number_argument("Partition number: ", &index, kDefault) == 0) { + bad_input("Bad partition number"); + return; + } + + // find partition and delete it + cur = find_entry_by_disk_address(index, map); + if (cur == NULL) { + printf("No such partition\n"); + } else { + delete_partition_from_map(cur); + } +} + + +void +do_reorder(partition_map_header *map) +{ + long old_index; + long index; + + if (map == NULL) { + bad_input("No partition map exists"); + return; + } + if (!rflag && map->writeable == 0) { + printf("The map is not writeable.\n"); + } + if (get_number_argument("Partition number: ", &old_index, kDefault) == 0) { + bad_input("Bad partition number"); + return; + } + if (get_number_argument("New number: ", &index, kDefault) == 0) { + bad_input("Bad partition number"); + return; + } + + move_entry_in_map(old_index, index, map); +} + + +void +do_write_partition_map(partition_map_header *map) +{ + if (map == NULL) { + bad_input("No partition map exists"); + return; + } + if (map->changed == 0) { + bad_input("The map has not been changed."); + return; + } + if (map->writeable == 0) { + bad_input("The map is not writeable."); + return; + } + printf("Writing the map destroys what was there before. "); + if (get_okay("Is that okay? [n/y]: ", 0) != 1) { + return; + } + + write_partition_map(map); + + // exit(0); +} + + +void +print_expert_notes() +{ + printf("Notes:\n"); + printf(" The expert commands are for low level and experimental features.\n"); + printf(" These commands are available only when debug mode is on.\n"); + printf("\n"); +} + + +int +do_expert(partition_map_header *map, char *name) +{ + int command; + int quit = 0; + + while (get_command("Expert command (? for help): ", first_get, &command)) { + first_get = 0; + + switch (command) { + case '?': + print_expert_notes(); + // fall through + case 'H': + case 'h': + printf("Commands are:\n"); + printf(" h print help\n"); + printf(" d dump block n\n"); + printf(" p print the partition table\n"); + if (dflag) { + printf(" P (show data structures - debugging)\n"); + } + printf(" f full display of nth entry\n"); + printf(" v validate map\n"); + printf(" e examine patch partition\n"); + printf(" q return to main edit menu\n"); + printf(" Q quit without saving changes\n"); + break; + case 'q': + flush_to_newline(1); + goto finis; + break; + case 'Q': + quit = 1; + goto finis; + break; + case 'P': + if (dflag) { + show_data_structures(map); + break; + } + // fall through + case 'p': + dump_partition_map(map, 1); + break; + case 'D': + case 'd': + do_display_block(map, name); + break; + case 'F': + case 'f': + do_display_entry(map); + break; + case 'V': + case 'v': + validate_map(map); + break; + case 'E': + case 'e': + do_examine_patch_partition(map); + break; + default: + do_error: + bad_input("No such command (%c)", command); + break; + } + } +finis: + return quit; +} + +void +do_change_map_size(partition_map_header *map) +{ + long size; + + if (map == NULL) { + bad_input("No partition map exists"); + return; + } + if (!rflag && map->writeable == 0) { + printf("The map is not writeable.\n"); + } + if (get_number_argument("New size: ", &size, kDefault) == 0) { + bad_input("Bad size"); + return; + } + resize_map(size, map); +} + + +void +do_display_block(partition_map_header *map, char *alt_name) +{ + MEDIA m; + long number; + char *name; + static unsigned char *display_block; + static int display_g; + int g; + + if (map != NULL) { + name = 0; + m = map->m; + g = map->logical_block; + } else { + if (alt_name == 0) { + if (get_string_argument("Name of device: ", &name, 1) == 0) { + bad_input("Bad name"); + return; + } + } else { + name = malloc(strlen(alt_name)+1); + strcpy(name, alt_name); + } + m = open_pathname_as_media(name, O_RDONLY); + if (m == 0) { + error(errno, "can't open file '%s'", name); + free(name); + return; + } + g = media_granularity(m); + if (g < PBLOCK_SIZE) { + g = PBLOCK_SIZE; + } + } + if (get_number_argument("Block number: ", &number, kDefault) == 0) { + bad_input("Bad block number"); + goto xit; + } + if (display_block == NULL || display_g < g) { + if (display_block != NULL) { + free(display_block); + display_g = 0; + } + display_block = (unsigned char *) malloc(g); + if (display_block == NULL) { + error(errno, "can't allocate memory for display block buffer"); + goto xit; + } + display_g = g; + } + if (read_media(m, ((long long)number) * g, g, (char *)display_block) != 0) { + dump_block((unsigned char*) display_block, g); + } + +xit: + if (name) { + close_media(m); + free(name); + } + return; +} + + +void +do_display_entry(partition_map_header *map) +{ + long number; + + if (map == NULL) { + bad_input("No partition map exists"); + return; + } + if (get_number_argument("Partition number: ", &number, kDefault) == 0) { + bad_input("Bad partition number"); + return; + } + if (number == 0) { + full_dump_block_zero(map); + } else { + full_dump_partition_entry(map, number); + } +} + + +void +do_examine_patch_partition(partition_map_header *map) +{ + partition_map * entry; + + if (map == NULL) { + bad_input("No partition map exists"); + return; + } + entry = find_entry_by_type(kPatchType, map); + if (entry == NULL) { + printf("No patch partition\n"); + } else { + display_patches(entry); + } +} diff --git a/sbin/pdisk/pdisk.h b/sbin/pdisk/pdisk.h new file mode 100644 index 00000000000..3f32c9c3841 --- /dev/null +++ b/sbin/pdisk/pdisk.h @@ -0,0 +1,57 @@ +// +// pdisk.h - general header for pdisk program +// +// Written by Eryk Vershen (eryk@apple.com) +// + +/* + * Copyright 1996,1997 by Apple Computer, Inc. + * All Rights Reserved + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appears in all copies and + * that both the copyright notice and this permission notice appear in + * supporting documentation. + * + * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, + * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION + * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __pdisk__ +#define __pdisk__ + + +// +// Defines +// +#define BOOT_PARTITION_PROCESS_ID "powerpc" + + +// +// Types +// + + +// +// Global Constants +// + + +// +// Global Variables +// + + +// +// Forward declarations +// + +#endif /* __pdisk__ */ diff --git a/sbin/pdisk/pdisk.html b/sbin/pdisk/pdisk.html new file mode 100644 index 00000000000..cb757faa8c7 --- /dev/null +++ b/sbin/pdisk/pdisk.html @@ -0,0 +1,395 @@ +<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN//2.0"> +<!--This file created 11/5/97 10:18 PM by Claris Home Page version 2.0--> +<HTML> +<HEAD> + <TITLE>pdisk for the Mac OS</TITLE> + <META NAME=GENERATOR CONTENT="Claris Home Page 2.0"> + <X-SAS-WINDOW TOP=42 BOTTOM=477 LEFT=4 RIGHT=556> +</HEAD> +<BODY BGCOLOR="#FFFFFF"> + +<H2>Overview</H2> + +<H3>What is pdisk?</H3> + +<P>A simple editor for Apple disk partition format. There are two +main versions of pdisk: one for MkLinux and one for the Mac OS. This +document describes the Mac OS version of pdisk. Much of this document +is also relevant to the MkLinux version, but check the manual page +(pdisk.8) also.</P> + +<H3>What is the Apple disk partition format?</H3> + +<P>Most operating systems have ways to divide disks into several +pieces - so that an entire disk does not have to be devoted to one +filesystem, or even to one operating system. This division of the +disk is usually called partitioning. In some systems the partitioning +information is built into the operating system code, but that tends to +be restrictive. In the Mac OS the partitioning information is stored +on the first few blocks of the disk.</P> + +<P>The Apple disk partition scheme was developed in 1986 by the A/UX +team with input from the Mac OS and Apple II teams. There was an +earlier partition scheme used in the first SCSI drives on the +MacPlus, but that was replaced by the current scheme in the Macintosh +II and subsequent machines and in subsequent operating system +releases. The current scheme is supported by Mac OS, A/UX, ProDos, +MkLinux, and "Rhapsody".</P> + +<H3>What is MkLinux?</H3> + +<P>Just in case you got pdisk not as part of an MkLinux release: +MkLinux is a version of the Linux operating system, converted to run +as a server process on top of the Mach microkernel. As with Linux, +all of the operating system source code is available for +<A HREF="http://www.mklinux.apple.com">download</A>, including the +Mach source. MkLinux runs on many of PowerPC based Macintosh +machines.</P> + +<H3>Which Macintosh machines does pdisk run on?</H3> + +<P>The Mac OS binary should run on any PowerPC based Macintosh. It +has been tested under System 7.6.1 and System 8, but should run on +older versions of the Mac OS as well. A Mac OS 68000 binary is also +distributed for those who may find it useful.</P> + +<H3>Why would I want to use pdisk on the Mac OS?</H3> + +<P>The main clients for the Mac OS version of pdisk are MkLinux +users. pdisk was originally developed for MkLinux. The command syntax +was originally identical to that for the 'fdisk' program. (fdisk is a +Linux program which edits the DOS/Windows disk partition format.) The +Mac OS version is a simple, crude port of the MkLinux version.</P> + +<P>The advantages of pdisk over the various Mac OS disk partitioning +programs (such as SilverLining, the FWB toolkit, Apple HD SC Setup, +DriveSetup, etc) are:</P> + +<UL> + <LI>unlike the Apple partitioners, it does not restrict the set of + drives it can operate on + + <LI>it allows partitions to be reordered (helpful, as MkLinux + depends on the order) + + <LI>it creates MkLinux partitions by default + + <LI>it allows the size of the partition map to be changed + + <LI>it allows the name of a partition to be changed + + <LI>it allows you to edit the partition map of your boot disk +</UL> + +<P>The disadvantages of pdisk are:</P> + +<UL> + <LI>it doesn't automatically initialize HFS partitions + + <LI>it can't install disk drivers + + <LI>it allows you to edit the partition map of your boot disk +</UL> + +<H3>Where can I get the source?</H3> + +<P>The main site for MkLinux is +<<A HREF="http://www.mklinux.apple.com">http://www.mklinux.apple.com</A>>. +As of the time this document was written you could find the pdisk +distributions at +<<A HREF="ftp://ftp.mklinux.apple.com/pub/Other_tools/pdisk/">ftp://ftp.mklinux.apple.com/pub/Other_tools/pdisk/</A>>. +This includes binary distributions for MkLinux and the Mac OS, as +well as a source distribution.</P> + +<H2>Description of the program (as of version 0.7)</H2> + +<P>Though pdisk is a Macintosh program its interface is very +un-Macintosh. pdisk is what is called a line-oriented program. In a +line-oriented program you do things by typing on the keyboard and the +program does not pay attention to the typing until the return key has +been typed.</P> + +<P>When you start up pdisk it brings up a window with some text in +it. The last line of this text should be something like " Top level +command (? for help): ". This is the prompt. If you type "?" followed +by a return character you should get a list like this:</P> + +<PRE>Notes: + Disk have fake names of the form /dev/scsi<bus>.<id> + For example, /dev/scsi0.1, /dev/scsi1.3, and so on. + MkLinux style names are also allowed (i.e /dev/sda or /dev/hda), + and these names follow the MkLinux DR3 conventions. + +Commands are: + h print help + v print the version number and release date + l list device's map + L list all devices' maps + e edit device's map + E (edit map with specified block size) + r toggle readonly flag + q quit the program</PRE> + +<P>Some of these commands need what are called arguments - for +example <B>l</B> (list) and <B>e</B> (edit) need a single argument, +the name of the device to list or edit. Commands which take arguments +prompt for each argument in turn. You can also type any number of the +arguments separated by spaces and those prompts will be skipped. +Commands are case insensitive (e.g. <B>h</B> and <B>H</B>) except +when the upper case letter does a variant form of the operation.</P> + +<DL> + <DT><B>h</B> + + <DD>Prints just the command help. The difference between <B>h</B> + and <B>?</B> is the latter prints some helpful notes as well. + + <DT><B>v</B> + + <DD>Prints a version number and release date. Matches the + version in the GetInfo window for the application. + + <DT><B>l</B> + + <DD>Prompts for the name of the device and then lists the + partition map on that device. + + <DT><B>L</B> + + <DD>Lists all the devices. + + <DT><B>e</B> + + <DD>Prompts for the name of the device and then opens the partition + map for editing. + + <DT><B>E</B> + + <DD>Same as <B>e</B>, except also prompts for block size. + + <DT><B>r</B> + + <DD>Toggles read-only setting. When read-only is on pdisk will not + write a partition map. + + <DT><B>q</B> + + <DD>Quit pdisk. +</DL> + +<H3>The form of the listing</H3> + +<P>This is a good point to show what the partition map listing looks +like.</P> + +<PRE>Partition map (with 512 byte blocks) on '/dev/scsi0.2' (/dev/sda) + #: type name length base ( size ) + 1: Apple_partition_map Apple 63 @ 1 + 2: Apple_Driver43*Macintosh 54 @ 64 + 3: Apple_Driver43*Macintosh 74 @ 118 + 4: Apple_Patches Patch Partition 512 @ 192 + 5: Apple_HFS untitled 2117430 @ 704 ( 1.0G) + 6: Apple_Free Extra 10 @ 2118134 + +Device block size=512, Number of Blocks=2118143 +DeviceType=0x0, DeviceId=0x0 +Drivers- +1: @ 64 for 20, type=0x1 +2: @ 118 for 32, type=0xffff</PRE> + +<P>The first line indicates what device this is and what size blocks +the partition map is using. Most partition maps will use 512-byte +blocks, but partition maps can use 1024-byte (1K) or 2048-byte (2K) +blocks instead. If we are able to deduce an MkLinux name different +from the name the MkLinux name is given in parentheses.</P> + +<P>Next is the partition list. Each partition (or piece) of the disk +takes one line of the list. The data describing the partition is +called the partition map entry. The entries are listed in order by +index. For each entry, the following information is displayed:</P> + +<UL> + <LI>index - where the partition entry is in the map. This does not + correspond the relative order of the partition contents and can + change when the partition map is edited. + + <LI>type - the sort of data expected to be in the partition. pdisk + doesn't put data into the contents of any partition except the + partition map partition. The type is a case-insensitive string. + + <LI>name - the name is for the user's information. + + <LI>length - the number of partition blocks the partition takes. + + <LI>base - the first block of the partition, measured in partition + blocks, starting from zero. + + <LI>size - this is the length in bytes. Only shown if the size is + at least one megabyte. +</UL> + +<P>Following the partition list is information from block zero of the +device which describes the location of drivers.</P> + +<H3>Editing Partition Tables</H3> + +<P>The <B>e</B> command at the top level menu opens a partition map +for editing. The prompt is then changed to "Command (? for help):". +If you type "?" followed by a return character you should get a list +like this:</P> + +<PRE>Notes: + Base and length fields are blocks, which vary in size between media. + The name of a partition is descriptive text. + +Commands are: + h help + p print the partition table + P (print ordered by base address) + i initialize partition map + s change size of partition map + c create new partition (standard MkLinux type) + C (create with type also specified) + n (re)name a partition + d delete a partition + r reorder partition entry in map + w write the partition table + q quit editing (don't save changes)</PRE> + +<P>Commands which take arguments prompt for each argument in turn. +You can also type any number of the arguments separated by spaces and +those prompts will be skipped. The only exception to typeahead are +the confirmation prompts on the <B>i</B> and <B>w</B> commands. +Commands can are case insensitive (e.g. <B>h</B> and <B>H</B>) except +when the upper case letter does a variant form of the operation.</P> + +<P>Partitions are always specified by their number, which the index +of the partition entry in the partition map. Many of the commands +will change the index numbers of other partitions besides the +affected partition. You are advised to print the table as frequently +as necessary.</P> + +<P>Creating more than fifteen partitions is not advised. There is +currently a bug in the some (all?) of the kernels which causes access +to the whole disk fail if more than fifteen partitions are in the +map.</P> + +<DL> + <DT><B>h</B> + + <DD>Prints just the command help. The difference between <B>h</B> + and <B>?</B> is the latter prints some helpful notes as well. + + <DT><B>p</B> + + <DD>Prints the partition table. The form is identical to the + listing described above. + + <DT><B>P</B> + + <DD>Identical to <B>p</B>, except the entries are listed in the + order of the partitions on the disk (i.e. by the increasing base + value) rather than in index order. + + <DT><B>i</B> + + <DD>Initializes the partition map (rarely used). This command + prompts for the size of the device. WARNING - if you write the map + after initializing it you will delete all the drivers on the device. + That makes the device invisible to the Mac OS. pdisk is not able + to install drivers. + + <DT><B>s</B> + + <DD>Change the size of the partition map partition. The partition + map's size must be less than or equal to the size of the partition + it is contained in. This is mostly useful when you want to do + tricky things like making a disk with multiple partitioning + schemes on it. + + <DT><B>c</B> + + <DD>Create a new partition takes three arguments.<BR> + + The first argument is the base address (in partition blocks) of + the partition. Besides a raw number, you can also specify a + partition number followed by the letter 'p' to indicate that the + first block of the new partition should be the same as the first + block of that existing free space partition.<BR> + + The second argument is the length of the partition in partition + blocks. This can be a raw number or can be a partition number + followed by the letter 'p' to use the size of that partition or + can be a number followed by 'k', 'm', or 'g' to indicate the size + in kilobytes, megabytes, or gigabytes respectively. (These are + powers of 1024, of course, not powers of 1000.)<BR> + + The last argument is the name of the partition. This can be a + single word without quotes, or a string surrounded by single or + double quotes.<BR> + + The type of the created partition is set to the correct type for + MkLinux ("Apple_UNIX_SVR2"). + + <DT><B>C</B> + + <DD>Identical to the <B>c</B> command, with the addition of a + prompt for the partition type after the other arguments. The type + can be a single word without quotes, or a string surrounded by + single or double quotes. + + <DT><B>n</B> + + <DD>Rename a partition. Do not change the name of any partition + whose type starts with "Apple_Driver". The MacOS looks at the + names of those partitions. All other partitions should be okay + to change. + + <DT><B>d</B> + + <DD>Delete a partition. When a partition is deleted it's type is + changed to free ("Apple_Free") and then it is combined with any + adjacent free space. + + <DT><B>r</B> + + <DD>Reorder takes the current index and the desired new index. If + you give a new index which is greater than the last index the + entry will be moved to the last index. + + <DT><B>w</B> + + <DD>Write does write the partition map out, but pdisk does not yet + flush the appropriate caches and unmount volumes so the partition + map is not reinterpreted. In order to use the new partition map + you must reboot your machine. Sorry. + + <DT><B>q</B> + + <DD>Quit out of editing. Returns to the top level prompt. If you + have modified the partition map you are NOT asked if you want to + save the changes, instead the changes are quietly thrown away. +</DL> + +<H3>Known problems</H3> + +<DL> + <DD>This is an awful Mac OS application, it should be rewritten + to look the way a Mac OS app should look. + + <DD>The code assumes a better understanding of the partitioning + scheme than most people care to acquire. + + <DD> + + <DD>Even more help should be available during user input. +</DL> + +<P> +<HR> +</P> + +<ADDRESS><A HREF="mailto:eryk@apple.com">eryk@apple.com</A> +</ADDRESS> +</BODY> +</HTML> diff --git a/sbin/pdisk/pdisk.mac.bin b/sbin/pdisk/pdisk.mac.bin Binary files differnew file mode 100644 index 00000000000..3bde0b6da82 --- /dev/null +++ b/sbin/pdisk/pdisk.mac.bin diff --git a/sbin/pdisk/pdisk.r b/sbin/pdisk/pdisk.r new file mode 100644 index 00000000000..090a678f11a --- /dev/null +++ b/sbin/pdisk/pdisk.r @@ -0,0 +1,234 @@ +/* + * pdisk.r + */ + +/* + * Copyright 1997 by Apple Computer, Inc. + * All Rights Reserved + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appears in all copies and + * that both the copyright notice and this permission notice appear in + * supporting documentation. + * + * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, + * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION + * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef SystemSevenOrLater +#define SystemSevenOrLater 1 +#endif +#include "Types.r" +#include "SysTypes.r" +#include "version.h" + + +resource 'vers' (1) { + kVersionMajor, + kVersionMinor*0x10 + kVersionBugFix, + kVersionStage, + kVersionDelta, + verUS, + VERSION, + $$format( + "%s - %4d%02d%02d " + "© 1992-%4d Apple Computer Inc. All Rights Reserved", + VERSION, $$year, $$month, $$day, + $$year + ), +}; + + +type 'PDSK' as 'STR '; +resource 'PDSK' (0, "Owner Resource", purgeable) { + $$format( + "pdisk\n© 1992-%4d Apple Computer Inc. All Rights Reserved.", + $$year + ) +}; + +resource 'BNDL' (128) { + 'PDSK', + 0, + { + 'FREF', { 0, 128 }, + 'ICN#', { 0, 128 } + } +}; + +resource 'FREF' (128) { + 'APPL', + 0, + "" +}; +resource 'icl8' (128) { + $"FFFF FFFF FFFF FFFF FFFF FFFF 0000 0000" + $"0000 FFFF FFFF FFFF 0000 0000 0000 0000" + $"FF2B 2B2B 2B2B 2B2B 2B2B 2BFF 0000 0000" + $"00FF 0808 0808 0808 FF00 0000 0000 0000" + $"FF2B 2B2B 2B2B 2B2B 2B2B FF00 0000 0000" + $"FF08 0808 0808 0808 08FF 0000 0000 0000" + $"FFFC FCFC FCFC FCFC FCFC FF00 0000 00FF" + $"0808 FFFF 0808 0808 0808 FF00 0000 0000" + $"FF00 0000 0000 0000 0000 FF00 0000 00FF" + $"FFFF 0000 FF08 0808 0808 08FF 0000 0000" + $"FF2B 2B2B 2B2B 2B2B 2B2B FF00 FFFF FF08" + $"08FF FFFF FFFF FFFF FF08 0808 FFFF FFFF" + $"FF2B 2B2B 2B2B 2B2B 2B2B FF00 0000 FF08" + $"0808 FFFF 0808 0808 0808 0808 08FF FFFF" + $"FFFF FFFF FFFF FFFF FFFF FF00 0000 00FF" + $"0808 0808 0808 0808 0808 0808 08FF FFFF" + $"00FF F7FC F7FC F7FC F7FF 0000 0000 0000" + $"FF08 0808 0808 0808 0808 0808 08FF FFFF" + $"00FF FFFF FBFB FBFF FFFF 0000 0000 0000" + $"00FF FF08 0808 0808 0808 0808 08FF FFFF" + $"0000 0000 FFFF FF00 0000 0000 0000 0000" + $"0000 00FF FFFF FFFF FFFF FF08 08FF FFFF" + $"0000 0000 0000 0000 0000 0000 0000 0000" + $"0000 0000 0000 0000 0000 00FF FFFF FFFF" + $"0000 0000 0000 0000 0000 0000 0000 0000" + $"0000 0000 0000 0000 0000 0000 00FF FFFF" + $"0000 0000 0000 0000 FFFF FFFF FFFF FFFF" + $"FFFF FFFF FFFF FF00 0000 0000 0000 0000" + $"0000 0000 0000 0000 FF2B 2B2B 2B2B 2B2B" + $"2B2B 2B2B 2B2B FF00 0000 0000 0000 0000" + $"0000 0000 0000 00FF 2B2B 2B2B 2B2B 2B2B" + $"2B2B 2B2B 2B2B FF00 0000 0000 0000 0000" + $"0000 0000 0000 00FF FCFC FCFC FCFC FCFC" + $"FCFC FCFC FCFC FF00 0000 0000 0000 0000" + $"0000 0000 0000 00FF 0000 0000 0000 0000" + $"0000 0000 0000 FF00 0000 0000 0000 0000" + $"0000 0000 0000 00FF 2B2B 2B2B 2B2B 2B2B" + $"2B2B 2B2B 2BFF 0000 0000 0000 0000 0000" + $"0000 0000 0000 00FF 2B2B 2B2B 2B2B 2B2B" + $"2B2B 2B2B FF00 0000 0000 0000 0000 0000" + $"0000 0000 0000 00FF FFFF FFFF FFFF FFFF" + $"FFFF FFFF FF00 0000 0000 0000 0000 0000" + $"0000 0000 0000 FFFC F7FC F7FC F7FC F7FC" + $"F7FC F7FC FF00 00FF FFFF FFFF FFFF FFFF" + $"0000 0000 0000 FFFF FFFF FFFF FFFF FFFF" + $"FFFF FFFF FF00 00FF 2B2B 2B2B 2B2B 2BFF" + $"0000 0000 0000 0000 0000 0000 0000 0000" + $"0000 0000 0000 00FF 2B2B 2B2B 2B2B 2BFF" + $"0000 0000 0000 0000 0000 0000 0000 0000" + $"0000 0000 0000 00FF FCFC E3E3 E3FC FCFF" + $"0000 0000 0000 0000 0000 0000 0000 0000" + $"0000 0000 0000 00FF 0000 0000 0000 00FF" + $"0000 0000 0000 0000 0000 0000 0000 0000" + $"0000 0000 0000 FF2B 2B2B 2B2B 2B2B 2BFF" + $"0000 0000 0000 0000 0000 0000 0000 0000" + $"0000 0000 00FF 2B2B 2B2B 2B2B 2B2B 2BFF" + $"0000 0000 0000 0000 0000 0000 0000 0000" + $"0000 0000 00FF FFFF FFFF FFFF FFFF FFFF" + $"0000 0000 0000 0000 0000 0000 0000 0000" + $"0000 0000 00FF F7FC F7FC F7FC F7FC FF00" + $"0000 0000 0000 0000 0000 0000 0000 0000" + $"0000 0000 00FF FFFF FFFB FBFB FFFF FF00" + $"0000 0000 0000 0000 0000 0000 0000 0000" + $"0000 0000 0000 0000 00FF FFFF" +}; + +resource 'icl4' (128) { + $"FFFF FFFF FFFF 0000 00FF FFFF 0000 0000" + $"FCCC CCCC CCCF 0000 0F02 0202 F000 0000" + $"FCCC CCCC CCF0 0000 F020 2020 2F00 0000" + $"FEEE EEEE EEF0 000F 02FF 0202 02F0 0000" + $"F000 0000 00F0 000F FF00 F020 202F 0000" + $"FCCC CCCC CCF0 FFF2 0FFF FFFF F202 FFFF" + $"FCCC CCCC CCF0 00F0 20FF 2020 2020 2FFF" + $"FFFF FFFF FFF0 000F 0202 0202 0202 0FFF" + $"0FCE CECE CF00 0000 F020 2020 2020 2FFF" + $"0FFF EEEF FF00 0000 0FF2 0202 0202 0FFF" + $"0000 FFF0 0000 0000 000F FFFF FFF0 2FFF" + $"0000 0000 0000 0000 0000 0000 000F FFFF" + $"0000 0000 0000 0000 0000 0000 0000 0FFF" + $"0000 0000 FFFF FFFF FFFF FFF0 0000 0000" + $"0000 0000 FCCC CCCC CCCC CCF0 0000 0000" + $"0000 000F CCCC CCCC CCCC CCF0 0000 0000" + $"0000 000F EEEE EEEE EEEE EEF0 0000 0000" + $"0000 000F 0000 0000 0000 00F0 0000 0000" + $"0000 000F CCCC CCCC CCCC CF00 0000 0000" + $"0000 000F CCCC CCCC CCCC F000 0000 0000" + $"0000 000F FFFF FFFF FFFF F000 0000 0000" + $"0000 00FE CECE CECE CECE F00F FFFF FFFF" + $"0000 00FF FFFF FFFF FFFF F00F CCCC CCCF" + $"0000 0000 0000 0000 0000 000F CCCC CCCF" + $"0000 0000 0000 0000 0000 000F EE88 8EEF" + $"0000 0000 0000 0000 0000 000F 0000 000F" + $"0000 0000 0000 0000 0000 00FC CCCC CCCF" + $"0000 0000 0000 0000 0000 0FCC CCCC CCCF" + $"0000 0000 0000 0000 0000 0FFF FFFF FFFF" + $"0000 0000 0000 0000 0000 0FCE CECE CEF0" + $"0000 0000 0000 0000 0000 0FFF FEEE FFF0" + $"0000 0000 0000 0000 0000 0000 0FFF" +}; + +resource 'ICN#' (128) { + { +/* 1 */ $"FFF0 3F00 8010 4080 8020 8040 FFE1 3020" + $"8021 C810 802E 7F8F 8022 3007 FFE1 0007" + $"5540 8007 7FC0 6007 0E00 1FE7 0000 001F" + $"0000 0007 00FF FE00 0080 0200 0100 0200" + $"01FF FE00 0100 0200 0100 0400 0100 0800" + $"01FF F800 0355 59FF 03FF F901 0000 0101" + $"0000 01FF 0000 0101 0000 0201 0000 0401" + $"0000 07FF 0000 0556 0000 07FE 0000 0070", + +/* 2 */ $"FFF0 3F00 FFF0 7F80 FFE0 FFC0 FFE1 FFE0" + $"FFE1 FFF0 FFEF FFFF FFE3 FFFF FFE1 FFFF" + $"7FC0 FFFF 7FC0 7FFF 0E00 1FFF 0000 001F" + $"0000 0007 00FF FE00 00FF FE00 01FF FE00" + $"01FF FE00 01FF FE00 01FF FC00 01FF F800" + $"01FF F800 03FF F9FF 03FF F9FF 0000 01FF" + $"0000 01FF 0000 01FF 0000 03FF 0000 07FF" + $"0000 07FF 0000 07FE 0000 07FE 0000 0070" + } +}; + +resource 'ics#' (128) { + { +/* 1 */ $"FC30 8448 B4A7 8B7B 7083 007F 0003 1FF0" + $"1010 1010 2020 3FDF 0011 0011 0021 003E", +/* 2 */ $"FC30 FC78 FCFF FBFF 70FF 007F 0003 1FF0" + $"1FF0 1FF0 3FE0 3FDF 001F 001F 003F 003E" + } +}; + +resource 'ics4' (128) { + $"FFFF FF00 00FF 0000 FCCC CF00 0F02 F000" + $"FC38 CF00 F0F0 2FFF FDDD F0FF 2FFF F2FF" + $"0FFF 0000 F020 20FF 0000 0000 0FFF FFFF" + $"0000 0000 0000 00FF 000F FFFF FFFF 0000" + $"000F CCCC CCCF 0000 000F CCCC CCCF 0000" + $"00FD DDDD DDF0 0000 00FF FFFF FF0F FFFF" + $"0000 0000 000F CCCF 0000 0000 000F CCCF" + $"0000 0000 00FD DDDF 0000 0000 00FF FFF0" +}; + +resource 'ics8' (128) { + $"FFFF FFFF FFFF 0000 0000 FFFF 0000 0000" + $"FF2B 2B2B 2BFF 0000 00FF 0808 FF00 0000" + $"FF2B D8E3 2BFF 0000 FF08 FF08 08FF FFFF" + $"FFF9 F9F9 FF00 FFFF 08FF FFFF FF08 FFFF" + $"00FF FFFF 0000 0000 FF08 0808 0808 FFFF" + $"0000 0000 0000 0000 00FF FFFF FFFF FFFF" + $"0000 0000 0000 0000 0000 0000 0000 FFFF" + $"0000 00FF FFFF FFFF FFFF FFFF 0000 0000" + $"0000 00FF 2B2B 2B2B 2B2B 2BFF 0000 0000" + $"0000 00FF 2B2B 2B2B 2B2B 2BFF 0000 0000" + $"0000 FFF9 F9F9 F9F9 F9F9 FF00 0000 0000" + $"0000 FFFF FFFF FFFF FFFF 00FF FFFF FFFF" + $"0000 0000 0000 0000 0000 00FF 2B2B 2BFF" + $"0000 0000 0000 0000 0000 00FF 2B2B 2BFF" + $"0000 0000 0000 0000 0000 FFF9 F9F9 F9FF" + $"0000 0000 0000 0000 0000 FFFF FFFF FF" +}; + diff --git a/sbin/pdisk/util.c b/sbin/pdisk/util.c new file mode 100644 index 00000000000..725c4cc7ba5 --- /dev/null +++ b/sbin/pdisk/util.c @@ -0,0 +1,164 @@ +/* + * util.c - + * + * Written by Eryk Vershen (eryk@apple.com) + */ + +/* + * Copyright 1997,1998 by Apple Computer, Inc. + * All Rights Reserved + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appears in all copies and + * that both the copyright notice and this permission notice appear in + * supporting documentation. + * + * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, + * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION + * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + + +// for sprintf() +#include <stdio.h> +// for tolower() +#include <ctype.h> + +#include "version.h" +#include "util.h" + + +/* + * Defines + */ +#define NumToolboxTraps() ( \ + (NGetTrapAddress(_InitGraf, ToolTrap) \ + == NGetTrapAddress(0xAA6E, ToolTrap)) \ + ? 0x200 : 0x400 \ + ) +#define GetTrapType(theTrap) ( \ + (((theTrap) & 0x800) != 0) ? ToolTrap : OSTrap \ + ) + + +/* + * Types + */ + + +/* + * Global Constants + */ + + +/* + * Global Variables + */ +static char dynamic_version[10]; + +/* + * Forward declarations + */ + + +/* + * Routines + */ +void +clear_memory(void *dataPtr, unsigned long size) +{ + char *ptr; + + ptr = (char *) dataPtr; + while (size > 0) { + *ptr++ = 0; + --size; + } +} + + +#if !defined(__linux__) && !defined(__unix__) +/* (see Inside Mac VI 3-8) */ +int +TrapAvailable(short theTrap) +{ + TrapType trapType; + + trapType = GetTrapType(theTrap); + + if (trapType == ToolTrap) { + theTrap &= 0x07FF; + if (theTrap >= NumToolboxTraps()) + theTrap = _Unimplemented; + } + + return ( + NGetTrapAddress(theTrap, trapType) + != NGetTrapAddress(_Unimplemented, ToolTrap) + ); +} +#endif + + +/* Ascii case-insensitive string comparison */ +int +istrncmp(const char *x, const char *y, long len) +{ + unsigned char *p = (unsigned char *)x; + unsigned char *q = (unsigned char *)y; + + while (len > 0) { + if (tolower(*p) != tolower(*q)) { + return (*p - *q); + } else if (*p == 0) { + break; + } + p++; + q++; + len--; + } + return (0); +} + + +const char * +get_version_string(void) +{ + int stage; + /* "copy" of stuff from SysTypes.r, since we can't include that*/ + enum {development = 0x20, alpha = 0x40, beta = 0x60, final = 0x80, /* or */ release = 0x80}; + + switch (kVersionStage) { + case development: stage = 'd'; break; + case alpha: stage = 'a'; break; + case beta: stage = 'b'; break; + case final: stage = 'f'; break; + default: stage = '?'; break; + } + + if (kVersionBugFix != 0) { + if (kVersionStage == final) { + sprintf(dynamic_version, "%d.%d.%d", + kVersionMajor, kVersionMinor, kVersionBugFix); + } else { + sprintf(dynamic_version, "%d.%d.%d%c%d", + kVersionMajor, kVersionMinor, kVersionBugFix, stage, kVersionDelta); + } + } else { + if (kVersionStage == final) { + sprintf(dynamic_version, "%d.%d", + kVersionMajor, kVersionMinor); + } else { + sprintf(dynamic_version, "%d.%d%c%d", + kVersionMajor, kVersionMinor, stage, kVersionDelta); + } + } + return dynamic_version; +} diff --git a/sbin/pdisk/util.h b/sbin/pdisk/util.h new file mode 100644 index 00000000000..77ce624a9c6 --- /dev/null +++ b/sbin/pdisk/util.h @@ -0,0 +1,62 @@ +/* + * util.h - + * + * Written by Eryk Vershen (eryk@apple.com) + */ + +/* + * Copyright 1997,1998 by Apple Computer, Inc. + * All Rights Reserved + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appears in all copies and + * that both the copyright notice and this permission notice appear in + * supporting documentation. + * + * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, + * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION + * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __util__ +#define __util__ + + +/* + * Defines + */ + + +/* + * Types + */ + + +/* + * Global Constants + */ + + +/* + * Global Variables + */ + + +/* + * Forward declarations + */ +void clear_memory(void *dataPtr, unsigned long size); +#if !defined(__linux__) && !defined(__unix__) +int TrapAvailable(short theTrap); +#endif +int istrncmp(const char *x, const char *y, long len); +const char *get_version_string(void); + +#endif /* __util__ */ diff --git a/sbin/pdisk/validate.c b/sbin/pdisk/validate.c new file mode 100644 index 00000000000..1c331383665 --- /dev/null +++ b/sbin/pdisk/validate.c @@ -0,0 +1,498 @@ +// +// validate.c - +// +// Written by Eryk Vershen (eryk@apple.com) +// + +/* + * Copyright 1997,1998 by Apple Computer, Inc. + * All Rights Reserved + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appears in all copies and + * that both the copyright notice and this permission notice appear in + * supporting documentation. + * + * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, + * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION + * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + + +// for *printf() +#include <stdio.h> +// for malloc(), free() +#ifndef __linux__ +#include <stdlib.h> +#else +#include <malloc.h> +#endif +// for O_RDONLY +#include <fcntl.h> +// for errno +#include <errno.h> + +#include "validate.h" +#include "deblock_media.h" +#include "pathname.h" +#include "convert.h" +#include "io.h" +#include "errors.h" + + +// +// Defines +// + + +// +// Types +// +enum range_state { + kUnallocated, + kAllocated, + kMultiplyAllocated +}; + +struct range_list { + struct range_list *next; + struct range_list *prev; + enum range_state state; + int valid; + u32 start; + u32 end; +}; +typedef struct range_list range_list; + + +// +// Global Constants +// + + +// +// Global Variables +// +static char *buffer; +static Block0 *b0; +static DPME *mb; +static partition_map_header *the_map; +static MEDIA the_media; +static int g; + + +// +// Forward declarations +// +int get_block_zero(void); +int get_block_n(int n); +range_list *new_range_list_item(enum range_state state, int valid, u32 low, u32 high); +void initialize_list(range_list **list); +void add_range(range_list **list, u32 base, u32 len, int allocate); +void print_range_list(range_list *list); +void delete_list(range_list *list); +void coalesce_list(range_list *list); + + +// +// Routines +// +int +get_block_zero(void) +{ + int rtn_value; + + if (the_map != NULL) { + b0 = the_map->misc; + rtn_value = 1; + } else { + if (read_media(the_media, (long long) 0, PBLOCK_SIZE, buffer) == 0) { + rtn_value = 0; + } else { + b0 = (Block0 *) buffer; + convert_block0(b0, 1); + rtn_value = 1; + } + } + return rtn_value; +} + + +int +get_block_n(int n) +{ + partition_map * entry; + int rtn_value; + + if (the_map != NULL) { + entry = find_entry_by_disk_address(n, the_map); + if (entry != 0) { + mb = entry->data; + rtn_value = 1; + } else { + rtn_value = 0; + } + } else { + if (read_media(the_media, ((long long) n) * g, PBLOCK_SIZE, (void *)buffer) == 0) { + rtn_value = 0; + } else { + mb = (DPME *) buffer; + convert_dpme(mb, 1); + rtn_value = 1; + } + } + return rtn_value; +} + + +range_list * +new_range_list_item(enum range_state state, int valid, u32 low, u32 high) +{ + range_list *item; + + item = (range_list *) malloc(sizeof(struct range_list)); + item->next = 0; + item->prev = 0; + item->state = state; + item->valid = valid; + item->start = low; + item->end = high; + return item; +} + + +void +initialize_list(range_list **list) +{ + range_list *item; + + item = new_range_list_item(kUnallocated, 0, 0, 0xFFFFFFFF); + *list = item; +} + + +void +delete_list(range_list *list) +{ + range_list *item; + range_list *cur; + + for (cur = list; cur != 0; ) { + item = cur; + cur = cur->next; + free(item); + } +} + + +void +add_range(range_list **list, u32 base, u32 len, int allocate) +{ + range_list *item; + range_list *cur; + u32 low; + u32 high; + + if (list == 0 || *list == 0) { + /* XXX initialized list will always have one element */ + return; + } + + low = base; + high = base + len - 1; + if (len == 0 || high < len - 1) { + /* XXX wrapped around */ + return; + } + + cur = *list; + while (low <= high) { + if (cur == 0) { + /* XXX should never occur */ + break; + } + if (low <= cur->end) { + if (cur->start < low) { + item = new_range_list_item(cur->state, cur->valid, cur->start, low-1); + /* insert before here */ + if (cur->prev == 0) { + item->prev = 0; + *list = item; + } else { + item->prev = cur->prev; + item->prev->next = item; + } + cur->prev = item; + item->next = cur; + + cur->start = low; + } + if (high < cur->end) { + item = new_range_list_item(cur->state, cur->valid, high+1, cur->end); + /* insert after here */ + if (cur->next == 0) { + item->next = 0; + } else { + item->next = cur->next; + item->next->prev = item; + } + cur->next = item; + item->prev = cur; + + cur->end = high; + } + + if (allocate) { + switch (cur->state) { + case kUnallocated: + cur->state = kAllocated; + break; + case kAllocated: + case kMultiplyAllocated: + cur->state = kMultiplyAllocated; + break; + } + } else { + cur->valid = 1; + } + low = cur->end + 1; + } + cur = cur->next; + } +} + + +void +coalesce_list(range_list *list) +{ + range_list *cur; + range_list *item; + + for (cur = list; cur != 0; ) { + item = cur->next; + if (item == 0) { + break; + } + if (cur->valid == item->valid + && cur->state == item->state) { + cur->end = item->end; + cur->next = item->next; + if (item->next != 0) { + item->next->prev = cur; + } + free(item); + } else { + cur = cur->next; + } + } +} + + +void +print_range_list(range_list *list) +{ + range_list *cur; + int printed; + char *s; + + if (list == 0) { + printf("Empty range list\n"); + return; + } + printf("Range list:\n"); + printed = 0; + for (cur = list; cur != 0; cur = cur->next) { + if (cur->valid) { + switch (cur->state) { + case kUnallocated: + s = "unallocated"; + break; + case kAllocated: + continue; + //s = "allocated"; + //break; + case kMultiplyAllocated: + s = "multiply allocated"; + break; + } + printed = 1; + printf("\t%lu:%lu %s\n", cur->start, cur->end, s); + } else { + switch (cur->state) { + case kUnallocated: + continue; + //s = "unallocated"; + //break; + case kAllocated: + s = "allocated"; + break; + case kMultiplyAllocated: + s = "multiply allocated"; + break; + } + printed = 1; + printf("\t%lu:%lu out of range, but %s\n", cur->start, cur->end, s); + } + } + if (printed == 0) { + printf("\tokay\n"); + } +} + + +void +validate_map(partition_map_header *map) +{ + range_list *list; + char *name; + int i; + u32 limit; + int printed; + + //printf("Validation not implemented yet.\n"); + + if (map == NULL) { + the_map = 0; + if (get_string_argument("Name of device: ", &name, 1) == 0) { + bad_input("Bad name"); + return; + } + the_media = open_pathname_as_media(name, O_RDONLY); + if (the_media == 0) { + error(errno, "can't open file '%s'", name); + free(name); + return; + } + g = media_granularity(the_media); + if (g < PBLOCK_SIZE) { + g = PBLOCK_SIZE; + } + the_media = open_deblock_media(PBLOCK_SIZE, the_media); + + buffer = malloc(PBLOCK_SIZE); + if (buffer == NULL) { + error(errno, "can't allocate memory for disk buffer"); + goto done; + } + + } else { + name = 0; + the_map = map; + g = map->logical_block; + } + + initialize_list(&list); + + // get block 0 + if (get_block_zero() == 0) { + printf("unable to read block 0\n"); + goto check_map; + } + // XXX signature valid + // XXX size & count match DeviceCapacity + // XXX number of descriptors matches array size + // XXX each descriptor wholly contained in a partition + add_range(&list, 1, b0->sbBlkCount-1, 0); /* subtract one since args are base & len */ + +check_map: + // compute size of map + if (map != NULL) { + limit = the_map->blocks_in_map; + } else { + if (get_block_n(1) == 0) { + printf("unable to get first block\n"); + goto done; + } else { + if (mb->dpme_signature != DPME_SIGNATURE) { + limit = -1; + } else { + limit = mb->dpme_map_entries; + } + } + } + + // for each entry + for (i = 1; ; i++) { + if (limit < 0) { + /* XXX what to use for end of list? */ + if (i > 5) { + break; + } + } else if (i > limit) { + break; + } + + printf("block %d:\n", i); + + // get entry + if (get_block_n(i) == 0) { + printf("\tunable to get\n"); + goto post_processing; + } + printed = 0; + + // signature matches + if (mb->dpme_signature != DPME_SIGNATURE) { + printed = 1; + printf("\tsignature is 0x%x, should be 0x%x\n", mb->dpme_signature, DPME_SIGNATURE); + } + // reserved1 == 0 + if (mb->dpme_reserved_1 != 0) { + printed = 1; + printf("\treserved word is 0x%x, should be 0\n", mb->dpme_reserved_1); + } + // entry count matches + if (limit < 0) { + printed = 1; + printf("\tentry count is 0x%lx, real value unknown\n", mb->dpme_map_entries); + } else if (mb->dpme_map_entries != limit) { + printed = 1; + printf("\tentry count is 0x%lx, should be %ld\n", mb->dpme_map_entries, limit); + } + // lblocks contained within physical + if (mb->dpme_lblock_start >= mb->dpme_pblocks + || mb->dpme_lblocks > mb->dpme_pblocks - mb->dpme_lblock_start) { + printed = 1; + printf("\tlogical blocks (%ld for %ld) not within physical size (%ld)\n", + mb->dpme_lblock_start, mb->dpme_lblocks, mb->dpme_pblocks); + } + // remember stuff for post processing + add_range(&list, mb->dpme_pblock_start, mb->dpme_pblocks, 1); + + // XXX type is known type? + // XXX no unknown flags? + // XXX boot blocks either within or outside of logical + // XXX checksum matches contents + // XXX other fields zero if boot_bytes is zero + // XXX processor id is known value? + // XXX no data in reserved3 + if (printed == 0) { + printf("\tokay\n"); + } + } + +post_processing: + // properties of whole map + + // every block on disk in one & only one partition + coalesce_list(list); + print_range_list(list); + // there is a partition for the map + // map fits within partition that contains it + + // try to detect 512/2048 mixed partition map? + +done: + if (map == NULL) { + close_media(the_media); + free(buffer); + free(name); + } +} diff --git a/sbin/pdisk/validate.h b/sbin/pdisk/validate.h new file mode 100644 index 00000000000..4ef6e737f7e --- /dev/null +++ b/sbin/pdisk/validate.h @@ -0,0 +1,59 @@ +// +// validate.h - +// +// Written by Eryk Vershen (eryk@apple.com) +// + +/* + * Copyright 1997,1998 by Apple Computer, Inc. + * All Rights Reserved + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appears in all copies and + * that both the copyright notice and this permission notice appear in + * supporting documentation. + * + * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, + * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION + * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef __validate__ +#define __validate__ + +#include "partition_map.h" + + +// +// Defines +// + + +// +// Types +// + + +// +// Global Constants +// + + +// +// Global Variables +// + + +// +// Forward declarations +// +void validate_map(partition_map_header *map); + +#endif /* __validate__ */ diff --git a/sbin/pdisk/version.h b/sbin/pdisk/version.h new file mode 100644 index 00000000000..378fb6dabee --- /dev/null +++ b/sbin/pdisk/version.h @@ -0,0 +1,82 @@ +/* + * version.h - version number for pdisk program + * + * Written by Eryk Vershen (eryk@apple.com) + */ + +/* + * Copyright 1997 by Apple Computer, Inc. + * All Rights Reserved + * + * Permission to use, copy, modify, and distribute this software and + * its documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appears in all copies and + * that both the copyright notice and this permission notice appear in + * supporting documentation. + * + * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE. + * + * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM + * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, + * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION + * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ +#ifndef __version__ +#define __version__ + + +/* + * Defines + */ +/* + * TO ADJUST THE VERSION - change the following six macros. + * + * A version is of the form: N.M{.X}{yZ} + * + * N is two digits indicating the major version + * M is a single digit indicating relative revision + * X is a single digit indicating a bug fix revision + * y is a character from the set [dab] indicating stage (dev,alpha,beta) + * Z is two digits indicating the delta within the stage + * + * Note that within the 'vers' resource all these fields end up + * comprising a four byte unsigned integer with the property that any later + * version will be be represented by a larger number. + */ + +#define VERSION "0.7a3" +#define RELEASE_DATE "18 February 1998" + +#define kVersionMajor 0x00 /* ie. N has two BCD digits */ +#define kVersionMinor 0x7 /* ie. M has a single BCD digit */ +#define kVersionBugFix 0x0 /* ie. X has a single BCD digit */ +#define kVersionStage alpha /* ie. y is one of the set - */ + /* {development,alpha,beta,final} + * also, release is a synonym for final + */ +#define kVersionDelta 0x03 /* ie. Z has two BCD digits */ + + +/* + * Types + */ + + +/* + * Global Constants + */ + + +/* + * Global Variables + */ + + +/* + * Forward declarations + */ + +#endif /* __version__ */ |