summaryrefslogtreecommitdiff
path: root/sbin
diff options
context:
space:
mode:
authorDale Rahn <drahn@cvs.openbsd.org>2001-03-24 00:14:39 +0000
committerDale Rahn <drahn@cvs.openbsd.org>2001-03-24 00:14:39 +0000
commitffb72f990c9933280de104024acf91acee02c1a5 (patch)
tree8312fd465c763b17886e6e1795ab48bde45c2381 /sbin
parentfa5275b22eb94a7d990e643d54768420845d618c (diff)
Import of pdisk from apple, BSD licensed code. Archive dated Feb 18 1998
This is a HFS partition editing tool.
Diffstat (limited to 'sbin')
-rw-r--r--sbin/pdisk/ATA_media.c1158
-rw-r--r--sbin/pdisk/ATA_media.h64
-rw-r--r--sbin/pdisk/DoSCSICommand.c649
-rw-r--r--sbin/pdisk/DoSCSICommand.h130
-rw-r--r--sbin/pdisk/HISTORY54
-rw-r--r--sbin/pdisk/MacSCSICommand.h420
-rw-r--r--sbin/pdisk/README144
-rw-r--r--sbin/pdisk/SCSI_media.c1091
-rw-r--r--sbin/pdisk/SCSI_media.h65
-rw-r--r--sbin/pdisk/bitfield.c101
-rw-r--r--sbin/pdisk/bitfield.h72
-rw-r--r--sbin/pdisk/convert.c203
-rw-r--r--sbin/pdisk/convert.h65
-rw-r--r--sbin/pdisk/deblock_media.c334
-rw-r--r--sbin/pdisk/deblock_media.h59
-rw-r--r--sbin/pdisk/dpme.h219
-rw-r--r--sbin/pdisk/dump.c804
-rw-r--r--sbin/pdisk/dump.h70
-rw-r--r--sbin/pdisk/errors.c169
-rw-r--r--sbin/pdisk/errors.h62
-rw-r--r--sbin/pdisk/file_media.c527
-rw-r--r--sbin/pdisk/file_media.h60
-rw-r--r--sbin/pdisk/io.c463
-rw-r--r--sbin/pdisk/io.h67
-rw-r--r--sbin/pdisk/layout_dump.c180
-rw-r--r--sbin/pdisk/layout_dump.h78
-rw-r--r--sbin/pdisk/makefile197
-rw-r--r--sbin/pdisk/media.c226
-rw-r--r--sbin/pdisk/media.h139
-rw-r--r--sbin/pdisk/partition_map.c1310
-rw-r--r--sbin/pdisk/partition_map.h107
-rw-r--r--sbin/pdisk/pathname.c229
-rw-r--r--sbin/pdisk/pathname.h62
-rw-r--r--sbin/pdisk/pdisk.8210
-rw-r--r--sbin/pdisk/pdisk.c1004
-rw-r--r--sbin/pdisk/pdisk.h57
-rw-r--r--sbin/pdisk/pdisk.html395
-rw-r--r--sbin/pdisk/pdisk.mac.binbin0 -> 55424 bytes
-rw-r--r--sbin/pdisk/pdisk.r234
-rw-r--r--sbin/pdisk/util.c164
-rw-r--r--sbin/pdisk/util.h62
-rw-r--r--sbin/pdisk/validate.c498
-rw-r--r--sbin/pdisk/validate.h59
-rw-r--r--sbin/pdisk/version.h82
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
+&lt;<A HREF="http://www.mklinux.apple.com">http://www.mklinux.apple.com</A>&gt;.
+As of the time this document was written you could find the pdisk
+distributions at
+&lt;<A HREF="ftp://ftp.mklinux.apple.com/pub/Other_tools/pdisk/">ftp://ftp.mklinux.apple.com/pub/Other_tools/pdisk/</A>&gt;.
+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&lt;bus&gt;.&lt;id&gt;
+ 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.
+&nbsp;
+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
+&nbsp;
+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.
+&nbsp;
+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>&nbsp;
+
+ <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
new file mode 100644
index 00000000000..3bde0b6da82
--- /dev/null
+++ b/sbin/pdisk/pdisk.mac.bin
Binary files differ
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__ */