From e78ccc1747f815dba33fd27c22dac24b17a1cce7 Mon Sep 17 00:00:00 2001 From: Michael McMaster Date: Tue, 10 Sep 2013 11:17:30 +1000 Subject: [PATCH] Original version from ftp.mklinux.apple.com:/pub/Other_Tools/ --- DoReadWrite.c | 126 ++++ DoSCSICommandWithSense.c | 576 +++++++++++++++ DoTestUnitReady.c | 100 +++ HISTORY | 16 + MacSCSICommand.h | 420 +++++++++++ Makefile | 24 + README | 97 +++ SCSIStuff.h | 149 ++++ SCSI_misc.c | 39 + bitfield.c | 101 +++ bitfield.h | 67 ++ convert.c | 206 ++++++ convert.h | 58 ++ dpme.h | 209 ++++++ dump.c | 467 ++++++++++++ dump.h | 55 ++ errors.c | 155 ++++ errors.h | 56 ++ fdisk.c | 1508 ++++++++++++++++++++++++++++++++++++++ fdisk.h | 51 ++ fdisklabel.c | 803 ++++++++++++++++++++ fdisklabel.h | 239 ++++++ io.c | 529 +++++++++++++ io.h | 67 ++ list.src | 34 + partition_map.c | 1061 +++++++++++++++++++++++++++ partition_map.h | 92 +++ pdisk.8 | 182 +++++ pdisk.c | 711 ++++++++++++++++++ pdisk.h | 53 ++ pdisk.r | 234 ++++++ version.h | 78 ++ 32 files changed, 8563 insertions(+) create mode 100644 DoReadWrite.c create mode 100644 DoSCSICommandWithSense.c create mode 100644 DoTestUnitReady.c create mode 100644 HISTORY create mode 100644 MacSCSICommand.h create mode 100644 Makefile create mode 100644 README create mode 100644 SCSIStuff.h create mode 100644 SCSI_misc.c create mode 100644 bitfield.c create mode 100644 bitfield.h create mode 100644 convert.c create mode 100644 convert.h create mode 100644 dpme.h create mode 100644 dump.c create mode 100644 dump.h create mode 100644 errors.c create mode 100644 errors.h create mode 100644 fdisk.c create mode 100644 fdisk.h create mode 100644 fdisklabel.c create mode 100644 fdisklabel.h create mode 100644 io.c create mode 100644 io.h create mode 100644 list.src create mode 100644 partition_map.c create mode 100644 partition_map.h create mode 100644 pdisk.8 create mode 100644 pdisk.c create mode 100644 pdisk.h create mode 100644 pdisk.r create mode 100644 version.h diff --git a/DoReadWrite.c b/DoReadWrite.c new file mode 100644 index 0000000..d3a0c56 --- /dev/null +++ b/DoReadWrite.c @@ -0,0 +1,126 @@ +/* + * Copyright 1993-97 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 "SCSIStuff.h" +int DoRead(UInt8 targetID, UInt32 block, UInt16 count, char* addr); +int DoWrite(UInt8 targetID, UInt32 block, UInt16 count, char* addr); + +int +DoRead( + UInt8 targetID, + UInt32 block, + UInt16 count, + char * addr + ) +{ + 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; + + scsiDevice.diReserved = 0; + scsiDevice.bus = kOriginalSCSIBusAdaptor; + scsiDevice.targetID = targetID; + scsiDevice.LUN = 0; + + gReadCommand.lbn4 = (block >> 24) & 0xFF; + gReadCommand.lbn3 = (block >> 16) & 0xFF; + gReadCommand.lbn2 = (block >> 8) & 0xFF; + gReadCommand.lbn1 = block & 0xFF; + + gReadCommand.len2 = (count >> 8) & 0xFF; + gReadCommand.len1 = count & 0xFF; + + status = DoSCSICommand( + scsiDevice, + "\pRead", + (SCSI_CommandPtr) &gReadCommand, + (Ptr) addr, + count * 512, + scsiDirectionIn, + NULL, + &senseData, + errorText + ); + if (status == noErr) { + rtn_value = 1; + } else { + rtn_value = 0; + } + return rtn_value; +} + +int +DoWrite( + UInt8 targetID, + UInt32 block, + UInt16 count, + char * addr + ) +{ + 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; + + scsiDevice.diReserved = 0; + scsiDevice.bus = 0xff; + scsiDevice.targetID = targetID; + scsiDevice.LUN = 0; + + gWriteCommand.lbn4 = (block >> 24) & 0xFF; + gWriteCommand.lbn3 = (block >> 16) & 0xFF; + gWriteCommand.lbn2 = (block >> 8) & 0xFF; + gWriteCommand.lbn1 = block & 0xFF; + + gWriteCommand.len2 = (count >> 8) & 0xFF; + gWriteCommand.len1 = count & 0xFF; + + status = DoSCSICommand( + scsiDevice, + "\pWrite", + (SCSI_CommandPtr) &gWriteCommand, + (Ptr) addr, + count * 512, + scsiDirectionOut, + NULL, + &senseData, + errorText + ); + if (status == noErr) { + rtn_value = 1; + } else { + rtn_value = 0; + } + return rtn_value; +} + + + diff --git a/DoSCSICommandWithSense.c b/DoSCSICommandWithSense.c new file mode 100644 index 0000000..0a27e0f --- /dev/null +++ b/DoSCSICommandWithSense.c @@ -0,0 +1,576 @@ +/* + * 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 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 "SCSIStuff.h" + +OSErr OriginalSCSI( + DeviceIdent scsiDevice, + const SCSI_CommandPtr scsiCommand, + UInt8 scsiCommandLen, + Ptr dataBuffer, + ByteCount dataLength, + UInt32 scsiFlags, + ByteCount *actualTransferCount, + UInt8 *scsiStatusByte + ); +UInt16 GetCommandLength( + const SCSI_CommandPtr cmdPtr + ); +/* + * This is the maximum number of times we try to grab the SCSI Bus + */ +#define kMaxSCSIRetries 40 /* 10 seconds, 4 times/sec */ +#define kSCSICommandTimeout (5 * 1000L) /* Five seconds */ + +/* + * 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) +Boolean IsVirtualMemoryRunning(void); + +/* + * 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 +} + +OSErr +DoOriginalSCSICommand( + DeviceIdent scsiDevice, + const SCSI_CommandPtr theSCSICommand, + unsigned short cmdBlockLength, + Ptr dataBuffer, + ByteCount dataLength, + UInt32 scsiFlags, + ByteCount *actualTransferCount, + SCSI_Sense_Data *sensePtr + ); + +/* + * 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 { + ClearMemory(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)); +} diff --git a/DoTestUnitReady.c b/DoTestUnitReady.c new file mode 100644 index 0000000..b9b320b --- /dev/null +++ b/DoTestUnitReady.c @@ -0,0 +1,100 @@ +/* + * Copyright 1993-97 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 +#include "SCSIStuff.h" + +int +DoTestUnitReady( + UInt8 targetID + ) +{ + 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 = kOriginalSCSIBusAdaptor; + scsiDevice.targetID = targetID; + scsiDevice.LUN = 0; + + status = DoSCSICommand( + scsiDevice, + "\pTest Unit Ready", + (SCSI_CommandPtr) &gTestUnitReadyCommand, + NULL, + 0, + scsiDirectionNone, + NULL, + &senseData, + errorText + ); + if (status == scsiNonZeroStatus) { + msg = "Unknown problem"; + switch (senseData.senseKey & kScsiSenseKeyMask) { + case kScsiSenseIllegalReq: + msg = "Logical Unit Not Supported"; + break; + case kScsiSenseNotReady: + switch ((senseData.additionalSenseCode << 8) + | senseData.additionalSenseQualifier) { + case 0x0500: + msg = "Logical Unit does not respond to selection"; + break; + case 0x0401: + msg = "Logical Unit is becoming ready"; + break; + case 0x0400: + msg = "Logical Unit is not ready. No specific cause."; + break; + case 0x0402: + msg = "Logical Unit is not ready. Unit needs start command."; + break; + case 0x0403: + msg = "Logical Unit is not ready. Unit needs manual intervention."; + break; + case 0x0404: + msg = "Logical Unit is not ready. Format in progress"; + break; + case 0x2500: + msg = "Logical Unit is not supported"; + break; + } + } + rtn_value = -1; + } else if (status != noErr) { + msg = "Test Unit Ready failed"; + rtn_value = 0; + } else { + msg = "Okay - device is ready"; + rtn_value = 1; + } + //printf("%s\n", msg); + return rtn_value; +} + + + diff --git a/HISTORY b/HISTORY new file mode 100644 index 0000000..2e43b35 --- /dev/null +++ b/HISTORY @@ -0,0 +1,16 @@ +961108 Started work +961113 Released version 0.1 to MkLinux Team (vlb, lion, brett, gilbert) + Reads, initializes maps and add and delete partitions + +961127 Started work again + Tried to make it easier to use + Added reorder and resize commands + Little endian machine support + Fixed various bugs + Wrote man page +961218 Released version 0.2 to gilbert + +961219 Fixed bugs gilbert found +961220 Released version 0.3 to community + +970115 Released version 0.4 (with Macintosh app) diff --git a/MacSCSICommand.h b/MacSCSICommand.h new file mode 100644 index 0000000..b02b66f --- /dev/null +++ b/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/Makefile b/Makefile new file mode 100644 index 0000000..f26608f --- /dev/null +++ b/Makefile @@ -0,0 +1,24 @@ +all: pdisk fdisk + +pdisk: pdisk.o dump.o partition_map.o convert.o io.o errors.o bitfield.o + +fdisk: fdisk.o fdisklabel.o + +clean: + rm -f *.o pdisk fdisk + +distribution: + cd ..; tar cvf pdisk.src.tar.`date +%y%m%d` --files-from pdisk/list.src + tar cvf ../pdisk.bin.tar.`date +%y%m%d` pdisk fdisk pdisk.8 + cp pdisk.hqx ../pdisk.hqx.`date +%y%m%d` + +convert.o: convert.c partition_map.h convert.h +dump.o: dump.c io.h errors.h partition_map.h +errors.o: errors.c errors.h +io.o: io.c pdisk.h io.h errors.h +partition_map.o: partition_map.c partition_map.h pdisk.h convert.h io.h errors.h +pdisk.o: pdisk.c pdisk.h io.h errors.h partition_map.h version.h + +partition_map.h: dpme.h +dpme.h: bitfield.h + diff --git a/README b/README new file mode 100644 index 0000000..bfe57a0 --- /dev/null +++ b/README @@ -0,0 +1,97 @@ +README for pdisk (9 January 1997) +================ + +This file accompanies version 0.4 of pdisk. + +pdisk is a partition table editor for (Mk)Linux which understands the +Apple disk partitioning format. + +Version 0.4 is the second version of pdisk in general distribution. +(Version 0.3 was the first general distribution.) The author of pdisk +is Eryk Vershen (eryk@apple.com). Any questions, comments, suggestions, +etc. can be sent via email. I can't guarantee a response, but I'll try. + +Please read the man page. (man ./pdisk.8) + +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. + +I have also enclosed modified sources for fdisk, which do not have the +byte order problem. These are derived from the sparc patches (but contain +none of the sun disk label stuff) in the the latest package I found +util-linux-2.5-26.src.rpm, which I got from the RedHat 4.0 +distribution. + + +Building the macintosh application +---------------------------------- +I have only built this under Code Warrior 10. The project file is +included. The project stationery was 'MacOS:C/C++:ANSI Console PPC'. +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 +only 512 byte blocks are supported. 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. + +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 + software mechanic + eryk@apple.com diff --git a/SCSIStuff.h b/SCSIStuff.h new file mode 100644 index 0000000..2de563e --- /dev/null +++ b/SCSIStuff.h @@ -0,0 +1,149 @@ +/* + * Copyright 1993-97 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 __SCSIExplorer__ +#define __SCSIExplorer__ +#define DEBUG_INFOLIST 0 + +#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 + +/* + * Note: this must be SCSI.h from Universal Headers 2.0 - the current version + * of Think C headers still has the "old" header without SCSI Manager 4.3 support. + */ +#include + +#include "MacSCSICommand.h" + +#ifndef LOG +#define LOG(what) /* Nothing */ +#endif /* LOG */ + +/* + *** Common definitions + */ +#ifndef EXTERN +#define EXTERN extern +#endif +#ifndef TRUE +#define TRUE 1 +#define FALSE 0 +#endif +#ifndef NULL +#define NULL 0 +#endif + +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) +}; + +#define kOriginalSCSIBusAdaptor (0xFF) +#define kEndOfLine 0x0D /* Return */ + + +#define UNUSED(what) do { \ + what = what; \ + } while (0) + + +#define FourBytes(hiByteAddr) ( \ + ( (((UInt32) (((UInt8 *) &(hiByteAddr)))[0]) << 24) \ + | (((UInt32) (((UInt8 *) &(hiByteAddr)))[1]) << 16) \ + | (((UInt32) (((UInt8 *) &(hiByteAddr)))[2]) << 8) \ + | (((UInt32) (((UInt8 *) &(hiByteAddr)))[3]) << 0) \ + )) +#define ThreeBytes(hiByteAddr) ( \ + ( (((UInt32) (((UInt8 *) &(hiByteAddr)))[0]) << 16) \ + | (((UInt32) (((UInt8 *) &(hiByteAddr)))[1]) << 8) \ + | (((UInt32) (((UInt8 *) &(hiByteAddr)))[2]) << 0) \ + )) +#define TwoBytes(hiByteAddr) ( \ + ( (((UInt32) (((UInt8 *) &(hiByteAddr)))[0]) << 8) \ + | (((UInt32) (((UInt8 *) &(hiByteAddr)))[1]) << 0) \ + )) + +#define SameSCSIDevice(a, b) ((*((UInt32 *) &a)) == (*((UInt32 *) &b))) +int DoTestUnitReady(UInt8 targetID); + +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 + ); + +/* + * Cheap 'n dirty memory clear routine. + */ +#define CLEAR(dst) ClearMemory((void *) &dst, sizeof dst) +void ClearMemory( + void *dataArea, + ByteCount dataSize + ); + +/* + * Global values + */ +EXTERN SCSIExecIOPB *gSCSIExecIOPBPtr; +EXTERN UInt32 gSCSIExecIOPBPtrLen; + +#endif /* __SCSIExplorer__ */ diff --git a/SCSI_misc.c b/SCSI_misc.c new file mode 100644 index 0000000..08c25fb --- /dev/null +++ b/SCSI_misc.c @@ -0,0 +1,39 @@ +/* + * 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. + */ + +#include "SCSIStuff.h" + SCSIExecIOPB *gSCSIExecIOPBPtr; + UInt32 gSCSIExecIOPBPtrLen; + +void +ClearMemory( + void *dataPtr, + register unsigned long size + ) +{ + register char *ptr; + + ptr = (char *) dataPtr; + while (size > 0) { + *ptr++ = 0; + --size; + } +} diff --git a/bitfield.c b/bitfield.c new file mode 100644 index 0000000..687e8bd --- /dev/null +++ b/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; + int i; + + // 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; + int i; + + // 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/bitfield.h b/bitfield.h new file mode 100644 index 0000000..ff56759 --- /dev/null +++ b/bitfield.h @@ -0,0 +1,67 @@ +// +// 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 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. + */ + + +// +// 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); diff --git a/convert.c b/convert.c new file mode 100644 index 0000000..977ff9a --- /dev/null +++ b/convert.c @@ -0,0 +1,206 @@ +// +// convert.c - Little-endian conversion +// +// Written by Eryk Vershen (eryk@apple.com) +// +// See comments in convert.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 + +#ifdef __linux__ +#include +#else +#define LITTLE_ENDIAN 1234 +#define BIG_ENDIAN 4321 +#define BYTE_ORDER 4321 +#endif + +#include "partition_map.h" +#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/convert.h b/convert.h new file mode 100644 index 0000000..269e192 --- /dev/null +++ b/convert.h @@ -0,0 +1,58 @@ +// +// 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 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. + */ + + +// +// 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); diff --git a/dpme.h b/dpme.h new file mode 100644 index 0000000..2994266 --- /dev/null +++ b/dpme.h @@ -0,0 +1,209 @@ +// +// 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. + */ + +#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 */ + 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_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_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 +// diff --git a/dump.c b/dump.c new file mode 100644 index 0000000..61ad91b --- /dev/null +++ b/dump.c @@ -0,0 +1,467 @@ +// +// dump.c - 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. + */ + +#include +#ifndef __linux__ +#include +#include +#endif +#include +#include +#include + +#include "io.h" +#include "errors.h" +#include "partition_map.h" +#include "dump.h" + + +// +// Defines +// +#define ONE_KILOBYTE_IN_BLOCKS (1024.0/PBLOCK_SIZE) + + +// +// 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 +// + + +// +// Forward declarations +// +void dump_block_zero(partition_map_header *map); +void dump_partition_entry(partition_map *entry, int digits); + + +// +// Routines +// +void +dump(char *name) +{ + partition_map_header *map; + int junk; + + map = open_partition_map(name, &junk); + if (map == NULL) { + return; + } + + dump_partition_map(map, 1); + + close_partition_map(map); +} + + +void +dump_block_zero(partition_map_header *map) +{ + Block0 *p; + DDMap *m; + int i; + + p = map->misc; + if (p->sbSig != BLOCK0_SIGNATURE) { + return; + } + printf("\nBlock size=%u, Number of Blocks=%u\n", + p->sbBlkSize, p->sbBlkCount); + 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: @ %u for %u, type=0x%x\n", i+1, 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 j; + + if (map == NULL) { + bad_input("No partition map exists"); + return; + } + printf("%s\n", map->name); + + j = number_of_digits(map->media_size); + if (j < 7) { + j = 7; + } + printf(" #: type name " + "%*s %-*s ( size )\n", j, "length", j, "base"); + + if (disk_order) { + for (entry = map->disk_order; entry != NULL; + entry = entry->next_on_disk) { + + dump_partition_entry(entry, j); + } + } else { + for (entry = map->base_order; entry != NULL; + entry = entry->next_by_base) { + + dump_partition_entry(entry, j); + } + } + dump_block_zero(map); +} + + +void +dump_partition_entry(partition_map *entry, int digits) +{ + partition_map_header *map; + int j; + DPME *p; + BZB *bp; + char *s; + int aflag = 0; + int pflag = 1; + u32 size; + double bytes; + + map = entry->the_map; + p = entry->data; + 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("%4d: %.4s %-18.32s ", entry->disk_address, s, p->dpme_name); + } else { + printf("%4d: %20.32s %-18.32s ", + entry->disk_address, p->dpme_type, p->dpme_name); + } + + if (pflag) { + printf("%*u ", digits, p->dpme_pblocks); + size = p->dpme_pblocks; + } else if (p->dpme_lblocks + p->dpme_lblock_start != p->dpme_pblocks) { + printf("%*u+", digits, p->dpme_lblocks); + size = p->dpme_lblocks; + } else if (p->dpme_lblock_start != 0) { + printf("%*u ", digits, p->dpme_lblocks); + size = p->dpme_lblocks; + } else { + printf("%*u ", digits, p->dpme_pblocks); + size = p->dpme_pblocks; + } + if (pflag || p->dpme_lblock_start == 0) { + printf("@ %-*u", digits, p->dpme_pblock_start); + } else { + printf("@~%-*u", digits, p->dpme_pblock_start + p->dpme_lblock_start); + } + + bytes = size / ONE_KILOBYTE_IN_BLOCKS; + if (bytes >= 1024.0) { + bytes = bytes / 1024.0; + if (bytes < 1024.0) { + j = 'M'; + } else { + bytes = bytes / 1024.0; + j = 'G'; + } + 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() +{ + char name[20]; + int i; + int fd; + DPME * data; + long t; + + data = (DPME *) malloc(PBLOCK_SIZE); + if (data == NULL) { + error(errno, "can't allocate memory for try buffer"); + return; + } + for (i = 0; i < 7; i++) { + sprintf(name, "/dev/sd%c", 'a'+i); + if ((fd = open_device(name, O_RDONLY)) < 0) { +#ifdef __linux__ + if (errno == EACCES) { + error(errno, "can't open file '%s'", name); + } +#else + error(errno, "can't open file '%s'", name); +#endif + continue; + } + if (read_block(fd, 1, (char *)data, 1) == 0) { + close_device(fd); + continue; + } + close_device(fd); + + dump(name); + } + 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("fd=%d (%s)\n", map->fd, (map->regular_file)?"file":"device"); + printf("map %d blocks out of %d, media %u blocks\n", + map->blocks_in_map, map->maximum_in_map, map->media_size); + 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=%u\n", + zp->sbBlkSize, zp->sbBlkCount); + printf("DeviceType=0x%x, DeviceId=0x%x, sbData=0x%x\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: @ %u for %u, type=0x%x\n", i+1, 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("%2d: %20.32s ", + entry->disk_address, p->dpme_type); + printf("%7u @ %-7u ", p->dpme_pblocks, p->dpme_pblock_start); + printf("%c%c%c%c%c%c%c%c%c ", + (dpme_valid_get(p))?'V':'v', + (dpme_allocated_get(p))?'A':'a', + (dpme_in_use_get(p))?'I':'i', + (dpme_bootable_get(p))?'B':'b', + (dpme_readable_get(p))?'R':'r', + (dpme_writable_get(p))?'W':'w', + (dpme_os_pic_code_get(p))?'P':'p', + (dpme_os_specific_1_get(p))?'1':'.', + (dpme_os_specific_2_get(p))?'2':'.'); + if (p->dpme_lblock_start != 0 || p->dpme_pblocks != p->dpme_lblocks) { + printf("(%u @ %u)", 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("%2d: ", entry->disk_address); + printf("%7u ", p->dpme_boot_block); + printf("%7u ", p->dpme_boot_bytes); + printf("%8x ", p->dpme_load_addr); + printf("%8x ", p->dpme_load_addr_2); + printf("%8x ", p->dpme_goto_addr); + printf("%8x ", p->dpme_goto_addr_2); + printf("%8x ", p->dpme_checksum); + printf("%.32s", p->dpme_process_id); + printf("\n"); + } + printf("\n"); +/* +xx: cccc RU *dd s... +*/ + for (entry = map->disk_order; entry != NULL; entry = entry->next_on_disk) { + p = entry->data; + printf("%2d: ", 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(" %2d", 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"); + } +} + + diff --git a/dump.h b/dump.h new file mode 100644 index 0000000..bd25c6b --- /dev/null +++ b/dump.h @@ -0,0 +1,55 @@ +// +// 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. + */ + + +// +// Defines +// + + +// +// Types +// + + +// +// Global Constants +// + + +// +// Global Variables +// + + +// +// Forward declarations +// +void dump(char *name); +void dump_partition_map(partition_map_header *map, int disk_order); +void list_all_disks(); +void show_data_structures(partition_map_header *map); diff --git a/errors.c b/errors.c new file mode 100644 index 0000000..47c9c30 --- /dev/null +++ b/errors.c @@ -0,0 +1,155 @@ +// +// errors.c - error & help routines +// +// 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. + */ + +#include +#ifndef __linux__ +#include +#endif +#include +#include + +#include "errors.h" +#include "pdisk.h" + + +// +// Defines +// + + +// +// Types +// + + +// +// Global Constants +// + + +// +// Global Variables +// +char *program_name; + + +// +// 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 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); + +#ifdef __linux__ + if (value > 0 && value < sys_nerr) { + fprintf(stderr, " (%s)\n", sys_errlist[value]); + } else { + fprintf(stderr, "\n"); + } +#else + fprintf(stderr, "\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); + +#ifdef __linux__ + 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/errors.h b/errors.h new file mode 100644 index 0000000..b6de7fd --- /dev/null +++ b/errors.h @@ -0,0 +1,56 @@ +// +// 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. + */ + + +// +// Defines +// + + +// +// Types +// + + +// +// Global Constants +// + + +// +// Global Variables +// + + +// +// 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); diff --git a/fdisk.c b/fdisk.c new file mode 100644 index 0000000..11e92db --- /dev/null +++ b/fdisk.c @@ -0,0 +1,1508 @@ +/* fdisk.c -- Partition table manipulator for Linux. + * + * Copyright (C) 1992 A. V. Le Blanc (LeBlanc@mcc.ac.uk) + * + * This program is free software. You can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation: either version 1 or + * (at your option) any later version. + * + * Before Linux version 0.95c, this program requires a kernel patch. + * + * Modified, Tue Feb 2 18:46:49 1993, faith@cs.unc.edu to better support SCSI. + * Modified, Sat Feb 27 18:11:27 1993, faith@cs.unc.edu: added extfs support. + * Modified, Sat Mar 6 10:14:12 1993, faith@cs.unc.edu: added more comments. + * Modified, Sat Mar 6 12:25:45 1993, faith@cs.unc.edu: + * Added patches from Michael Bischoff (i1041905@ws.rz.tu-bs.de + * or mbi@mo.math.nat.tu-bs.de) to fix the following problems: + * 1) Incorrect mapping of head/sector/cylinder to absolute sector + * 2) Odd sector count causes one sector to be lost + * Modified, Sat Mar 6 12:25:52 1993, faith@cs.unc.edu: improved verification. + * Modified, Sat Apr 17 15:00:00 1993, LeBlanc@mcc.ac.uk: add -s, fix -l. + * Modified, Sat Apr 24 10:00:00 1993, LeBlanc@mcc.ac.uk: fix overlap bug. + * Modified, Wed May 5 21:30:00 1993, LeBlanc@mcc.ac.uk: errors to stderr. + * Modified, Mon Mar 21 20:00:00 1994, LeBlanc@mcc.ac.uk: + * more stderr for messages, avoid division by 0, and + * give reboot message only if ioctl(fd, BLKRRPART) fails. + * Modified, Mon Apr 25 01:01:05 1994, martin@cs.unc.edu: + * 1) Added support for DOS, OS/2, ... compatibility. We should be able + * use this fdisk to partition our drives for other operating systems. + * 2) Added a print the raw data in the partition table command. + * Modified, Wed Jun 22 21:05:30 1994, faith@cs.unc.edu: + * Added/changed a few partition type names to conform to cfdisk. + * (suggested by Sujal, smpatel@wam.umd.edu) + * Modified 3/5/95 leisner@sdsp.mc.xerox.com -- on -l only open + * devices RDONLY (instead of RDWR). This allows you to + * have the disks as rw-r----- with group disk (and if you + * want is safe to setguid fdisk to disk). + * Modified Sat Mar 11 10:02 1995 with more partition types, faith@cs.unc.edu + * Modified, Thu May 4 01:11:45 1995, esr@snark.thyrsus.com: + * It's user-interface cleanup time. + * Actual error messages for out-of-bounds values (what a concept!). + * Enable read-only access to partition table for learners. + * Smart defaults for most numeric prompts. + * Fixed a bug preventing a partition from crossing cylinder 8064, aeb, 950801. + * Read partition table twice to avoid kernel bug + * (from Daniel Quinlan ), Tue Sep 26 10:25:28 1995 + * Modified, Sat Jul 1 23:43:16 MET DST 1995, fasten@cs.bonn.edu: + * editor for NetBSD/i386 (and Linux/Alpha?) disklabels. + * Tue Sep 26 17:07:54 1995: More patches from aeb. Fix segfaults, all >4GB. + * Don't destroy random data if extd partition starts past 4GB, aeb, 950818. + * Don't segfault on bad partition created by previous fdisk. + * Modified, Fri Jul 14 11:13:35 MET DST 1996, jj@sunsite.mff.cuni.cz: + * editor for Sun disklabels. + * Modified, Wed Jul 3 10:14:17 MET DST 1996, jj@sunsite.mff.cuni.cz: + * support for sun floppies + * Modified, Fri Dec 20 15:05:56 PST 1996, eryk@apple.com: + * got rid of sun stuff, but kept byte order fixes + * + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include "fdisk.h" + +#define hex_val(c) ({ \ + char _c = (c); \ + isdigit(_c) ? _c - '0' : \ + tolower(_c) + 10 - 'a'; \ + }) + + +#define VERSION "2.1 (>4GB)" + +#define DEFAULT_DEVICE "/dev/hda" +#define ALTERNATE_DEVICE "/dev/sda" +#define LINE_LENGTH 80 +#define MAXIMUM_PARTS 60 +#define PART_TABLE_FLAG 0xaa55 +#define table_check(b) ((unsigned short *)((b) + 0x1fe)) +#define offset(b, n) ((struct partition *)((b) + 0x1be + \ + (n) * sizeof(struct partition))) +#define sector(s) ((s) & 0x3f) +#define cylinder(s, c) ((c) | (((s) & 0xc0) << 2)) + +#define calculate(h,s,c) (sector(s) - 1 + sectors * \ + ((h) + heads * cylinder(s,c))) +#define set_hsc(h,s,c,sector) { \ + s = sector % sectors + 1; \ + sector /= sectors; \ + h = sector % heads; \ + sector /= heads; \ + c = sector & 0xff; \ + s |= (sector >> 2) & 0xc0; \ + } + +#define ACTIVE_FLAG 0x80 +#define EXTENDED 5 + +#define LINUX_PARTITION 0x81 +#define LINUX_SWAP 0x82 +#define LINUX_NATIVE 0x83 + +/* normally O_RDWR, -l option gives O_RDONLY */ +static int type_open = O_RDWR; + +char *disk_device = DEFAULT_DEVICE, /* hda, unless specified */ + *line_ptr, /* interactive input */ + line_buffer[LINE_LENGTH], + changed[MAXIMUM_PARTS], /* marks changed buffers */ + buffer[SECTOR_SIZE], /* first four partitions */ + *buffers[MAXIMUM_PARTS] /* pointers to buffers */ + = {buffer, buffer, buffer, buffer}; + +int fd, /* the disk */ + ext_index, /* the prime extended partition */ + listing = 0, /* no aborts for fdisk -l */ + dos_compatible_flag = ~0, + partitions = 4; /* maximum partition + 1 */ + +uint heads, + sectors, + cylinders, + sector_offset = 1, + display_factor = 1, /* in units/sector */ + unit_flag = 1, + full_bits = 0, /* 1024 cylinders in sectors */ + extended_offset = 0, /* offset of link pointers */ + offsets[MAXIMUM_PARTS] = {0, 0, 0, 0}; + +struct partition *part_table[MAXIMUM_PARTS] /* partitions */ + = {offset(buffer, 0), offset(buffer, 1), + offset(buffer, 2), offset(buffer, 3)}, + *ext_pointers[MAXIMUM_PARTS] /* link pointers */ + = {NULL, NULL, NULL, NULL}; + +struct systypes sys_types[] = { /* struct systypes in fdisk.h *//* bf */ + {0, "Empty"}, + {1, "DOS 12-bit FAT"}, + {2, "XENIX root"}, + {3, "XENIX usr"}, + {4, "DOS 16-bit <32M"}, + {EXTENDED, "Extended"}, + {6, "DOS 16-bit >=32M"}, + {7, "OS/2 HPFS"}, /* or QNX? */ + {8, "AIX"}, + {9, "AIX bootable"}, + {10, "OS/2 Boot Manager"}, + {0x40, "Venix 80286"}, + {0x51, "Novell?"}, + {0x52, "Microport"}, /* or CPM? */ + {0x63, "GNU HURD"}, /* or System V/386? */ + {0x64, "Novell Netware 286"}, + {0x65, "Novell Netware 386"}, + {0x75, "PC/IX"}, + {0x80, "Old MINIX"}, /* Minix 1.4a and earlier */ + + {LINUX_PARTITION, "Linux/MINIX"}, /* Minix 1.4b and later */ + {LINUX_SWAP, "Linux swap"}, + {LINUX_NATIVE, "Linux native"}, + + {0x93, "Amoeba"}, + {0x94, "Amoeba BBT"}, /* (bad block table) */ + {0xa5, "BSD/386"}, + {0xb7, "BSDI fs"}, + {0xb8, "BSDI swap"}, + {0xc7, "Syrinx"}, + {0xdb, "CP/M"}, /* or Concurrent DOS? */ + {0xe1, "DOS access"}, + {0xe3, "DOS R/O"}, + {0xf2, "DOS secondary"}, + {0xff, "BBT"} /* (bad track table) */ + }; + +int nsys_types = sizeof (sys_types) / sizeof (struct systypes); /* bf */ + +uint read_int(uint low, uint dflt, uint high, enum offset base, char *mesg); +char read_char(char *mesg); + +jmp_buf listingbuf; + +inline unsigned short __swap16(unsigned short x) { + return (((__u16)(x) & 0xFF) << 8) | (((__u16)(x) & 0xFF00) >> 8); +} +inline __u32 __swap32(__u32 x) { + return (((__u32)(x) & 0xFF) << 24) | (((__u32)(x) & 0xFF00) << 8) | (((__u32)(x) & 0xFF0000) >> 8) | (((__u32)(x) & 0xFF000000) >> 24); +} + +void fatal(enum failure why) +{ + char error[LINE_LENGTH], + *message = error; + + if (listing) { + close(fd); + longjmp(listingbuf, 1); + } + + switch (why) { + case usage: message = + "Usage: fdisk [-l] [-v] [-s /dev/hdxn] [/dev/hdx]\n"; + break; + case unable_to_open: + sprintf(error, "Unable to open %s\n", disk_device); + break; + case unable_to_read: + sprintf(error, "Unable to read %s\n", disk_device); + break; + case unable_to_seek: + sprintf(error, "Unable to seek on %s\n", disk_device); + break; + case unable_to_write: + sprintf(error, "Unable to write %s\n", disk_device); + break; + case out_of_memory: + message = "Unable to allocate any more memory\n"; + break; + default: message = "Fatal error\n"; + } + + fputc('\n', stderr); + fputs(message, stderr); + exit(1); +} + +void menu(void) +{ + puts("Command action\n" + " a toggle a bootable flag\n" + " b edit bsd disklabel\n" /* bf */ + " c toggle the dos compatiblity flag\n" + " d delete a partition\n" + " l list known partition types\n" + " m print this menu\n" + " n add a new partition\n" + " p print the partition table\n" + " q quit without saving changes\n" + " t change a partition's system id\n" + " u change display/entry units\n" + " v verify the partition table\n" + " w write table to disk and exit\n" + " x extra functionality (experts only)" + ); +} + +void xmenu(void) +{ + puts("Command action\n" + " b move beginning of data in a partition\n" + " c change number of cylinders\n" + " d print the raw data in the partition table\n" + " e list extended partitions\n" + " h change number of heads\n" + " m print this menu\n" + " p print the partition table\n" + " q quit without saving changes\n" + " r return to main menu\n" + " s change number of sectors\n" + " v verify the partition table\n" + " w write table to disk and exit" + ); +} + +char *partition_type(unsigned char type) +{ + int high = sizeof(sys_types) / sizeof(struct systypes), + low = 0, mid; + uint tmp; + + while (high >= low) { + mid = (high + low) >> 1; + if ((tmp = sys_types[mid].index) == type) + return sys_types[mid].name; + else if (tmp < type) + low = mid + 1; + else high = mid - 1; + } + return NULL; +} + +/* added parameters to list_types() so fdisklabel + can pass another list of types. +*//* bf */ +void list_types(struct systypes *sys, int size) +{ + uint last[4], done = 0, next = 0; + int i; + + for (i = 3; i >= 0; i--) + last[3 - i] = done += (size + i - done) / (i + 1); + i = done = 0; + + do { + printf("%c%2x %-15.15s", i ? ' ' : '\n', + sys[next].index, sys[next].name); + next = last[i++] + done; + if (i > 3 || next >= last[i]) { + i = 0; + next = ++done; + } + } while (done < last[0]); + putchar('\n'); +} + +void clear_partition(struct partition *p) +{ + p->boot_ind = 0; + p->head = 0; + p->sector = 0; + p->cyl = 0; + p->sys_ind = 0; + p->end_head = 0; + p->end_sector = 0; + p->end_cyl = 0; + p->start_sect = 0; + p->nr_sects = 0; +} + +void set_partition(int i, struct partition *p, uint start, uint stop, + int sys, uint offset) +{ + p->boot_ind = 0; + p->sys_ind = sys; + p->start_sect = SWAP32(start - offset); + p->nr_sects = SWAP32(stop - start + 1); + if (dos_compatible_flag && (start/(sectors*heads) > 1023)) + start = heads*sectors*1024 - 1; + set_hsc(p->head, p->sector, p->cyl, start); + if (dos_compatible_flag && (stop/(sectors*heads) > 1023)) + stop = heads*sectors*1024 - 1; + set_hsc(p->end_head, p->end_sector, p->end_cyl, stop); + changed[i] = 1; +} + +int test_c(char **m, char *mesg) +{ + int val = 0; + if (!*m) + fprintf(stderr, "You must set"); + else { + fprintf(stderr, " %s", *m); + val = 1; + } + *m = mesg; + return val; +} + +int warn_geometry(void) +{ + char *m = NULL; + int prev = 0; + if (!heads) + prev = test_c(&m, "heads"); + if (!sectors) + prev = test_c(&m, "sectors"); + if (!cylinders) + prev = test_c(&m, "cylinders"); + if (!m) + return 0; + fprintf(stderr, + "%s%s.\nYou can do this from the extra functions menu.\n", + prev ? " and " : " ", m); + return 1; +} + +uint rounded(uint calcul, uint start) +{ + uint i; + if (!full_bits) + return calcul; + while ((i = calcul + full_bits) <= start) + calcul = i; + return calcul; +} + +void update_units(void) +{ + full_bits = 1024 * heads * sectors; + if (unit_flag && full_bits) + display_factor = full_bits >> 10; + else display_factor = 1; +} + +void warn_cylinders(void) +{ + update_units(); + if (cylinders > 1024) + fprintf(stderr, "The number of cylinders for this disk is " + "set to %d.\nThis is larger than 1024, and may cause " + "problems with:\n" + "1) software that runs at boot time (e.g., LILO)\n" + "2) booting and partitioning software form other OSs\n" + " (e.g., DOS FDISK, OS/2 FDISK)\n", + cylinders); +} + +void read_extended(struct partition *p) +{ + int i; + struct partition *q; + + ext_pointers[ext_index] = part_table[ext_index]; + if (!p->start_sect) + fprintf(stderr, "Bad offset in primary extended partition\n"); + else while (p->sys_ind == EXTENDED) { + if (partitions >= MAXIMUM_PARTS) { + fprintf(stderr, + "Warning: deleting partitions after %d\n", + partitions); + clear_partition(ext_pointers[partitions - 1]); + changed[partitions - 1] = 1; + return; + } + offsets[partitions] = extended_offset + SWAP32(p->start_sect); + if (!extended_offset) + extended_offset = SWAP32(p->start_sect); + if (llseek(fd, (loff_t)offsets[partitions] + * SECTOR_SIZE, SEEK_SET) < 0) + fatal(unable_to_seek); + if (!(buffers[partitions] = (char *) malloc(SECTOR_SIZE))) + fatal(out_of_memory); + if (SECTOR_SIZE != read(fd, buffers[partitions], SECTOR_SIZE)) + fatal(unable_to_read); + part_table[partitions] = ext_pointers[partitions] = NULL; + q = p = offset(buffers[partitions], 0); + for (i = 0; i < 4; i++, p++) { + if (p->sys_ind == EXTENDED) + if (ext_pointers[partitions]) + fprintf(stderr, "Warning: extra link " + "pointer in partition table " + "%d\n", partitions + 1); + else + ext_pointers[partitions] = p; + else if (p->sys_ind) + if (part_table[partitions]) + fprintf(stderr, + "Warning: ignoring extra data " + "in partition table %d\n", + partitions + 1); + else + part_table[partitions] = p; + } + if (!part_table[partitions]) + if (q != ext_pointers[partitions]) + part_table[partitions] = q; + else part_table[partitions] = q + 1; + if (!ext_pointers[partitions]) + if (q != part_table[partitions]) + ext_pointers[partitions] = q; + else ext_pointers[partitions] = q + 1; + p = ext_pointers[partitions++]; + } +} + +void get_boot(void) +{ + int i; + struct hd_geometry geometry; + + partitions = 4; + if ((fd = open(disk_device, type_open)) < 0) + { + if ((fd = open(disk_device, O_RDONLY)) < 0) + fatal(unable_to_open); + else + printf("You will not be able to write the partition table.\n"); + } + if (SECTOR_SIZE != read(fd, buffer, SECTOR_SIZE)) + fatal(unable_to_read); +#ifdef HDIO_REQ + if (!ioctl(fd, HDIO_REQ, &geometry)) { +#else + if (!ioctl(fd, HDIO_GETGEO, &geometry)) { +#endif + heads = geometry.heads; + sectors = geometry.sectors; + cylinders = geometry.cylinders; + if (dos_compatible_flag) + sector_offset = sectors; + warn_cylinders(); + } + else update_units(); + warn_geometry(); + + for (i = 0; i < 4; i++) + if(part_table[i]->sys_ind == EXTENDED) + if (partitions != 4) + fprintf(stderr, "Ignoring extra extended " + "partition %d\n", i + 1); + else read_extended(part_table[ext_index = i]); + + for (i = 3; i < partitions; i++) + if (SWAP16(*table_check(buffers[i])) != PART_TABLE_FLAG) { + fprintf(stderr, "Warning: invalid flag %04x of parti" + "tion table %d will be corrected by w(rite)\n", + SWAP16(*table_check(buffers[i])), i + 1); + changed[i] = 1; + } +} + +int read_line(void) +{ + if (!fgets(line_buffer, LINE_LENGTH, stdin)) + return 0; + line_ptr = line_buffer; + while (*line_ptr && !isgraph(*line_ptr)) + line_ptr++; + return *line_ptr; +} + +char read_char(char *mesg) +{ + do + fputs(mesg, stdout); + while (!read_line()); + return *line_ptr; +} + +char read_chars(char *mesg) +{ + fputs(mesg, stdout); + if (!read_line()) { + *line_ptr = '\n'; + return '\n'; + } else return *line_ptr; +} + +/* new function *//* bf */ +int read_hex(struct systypes *sys, int size) +{ + int hex; + + while (1) + { + read_char("Hex code (type L to list codes): "); + if (tolower(*line_ptr) == 'l') + list_types(sys, size); + else if (isxdigit (*line_ptr)) + { + hex = 0; + do + hex = hex << 4 | hex_val(*line_ptr++); + while (isxdigit(*line_ptr)); + return hex; + } + } +} + + +uint read_int(uint low, uint dflt, uint high, enum offset base, char *mesg) +{ + uint i, use_default = 1; + char ms[70]; + + switch(base) { + case lower: + sprintf(ms, "%s ([%d]-%d): ", mesg, low, high); + break; + case upper: + sprintf(ms, "%s (%d-[%d]): ", mesg, low, high); + break; + case deflt: + sprintf(ms, "%s (%d-[%d]-%d): ", mesg, low, dflt, high); + break; + default: + sprintf(ms, "%s (%d-%d): ", mesg, low, high); + break; + } + + while (1) { + if (base == deflt) { + while (read_chars(ms) != '\n' && !isdigit(*line_ptr) + && (*line_ptr != '-' && *line_ptr != '+')) + continue; + if (*line_ptr == '\n') + return dflt; + } else { + while (!isdigit(read_char(ms)) + && (*line_ptr != '-' && *line_ptr != '+')) + continue; + } + if (*line_ptr == '+' || *line_ptr == '-') { + if (*line_ptr == '+') + ++line_ptr; + i = atoi(line_ptr); + while (isdigit(*line_ptr)) + { + line_ptr++; + use_default = 0; + } + switch (*line_ptr) { + case 'c': + case 'C': if (!unit_flag) + i *= heads * sectors; + break; + case 'k': + case 'K': i *= 2; + i /= display_factor; + break; + case 'm': + case 'M': i *= 2048; + i /= display_factor; + break; + default: break; + } + switch(base) { + case lower: i += low; break; + case upper: i += high; break; + case deflt: i += dflt; break; + } + } + else + { + i = atoi(line_ptr); + while (isdigit(*line_ptr)) + { + line_ptr++; + use_default = 0; + } + } + if (use_default) + printf("Using default value %d\n", i = dflt); + if (i >= low && i <= high) + break; + else + printf("Value out of range.\n"); + } + return i; +} + +int get_partition(int warn, int max) +{ + /* + * try to pick a default least likely to do damage, + * in case luser just types a newline + */ + int i = read_int(1, max, max, ignore, "Partition number") - 1; + + if (warn && !part_table[i]->sys_ind) + fprintf(stderr, "Warning: partition %d has empty type\n", + i + 1); + return i; +} + +char *const str_units(void) +{ + return unit_flag ? "cylinder" : "sector"; +} + +void change_units(void) +{ + if ((unit_flag = !unit_flag)) + display_factor = 1; + else display_factor = heads * sectors; + update_units(); + printf("Changing display/entry units to %ss\n", + str_units()); +} + +void toggle_active(int i) +{ + struct partition *p = part_table[i]; + + if (p->sys_ind == EXTENDED && !p->boot_ind) + fprintf(stderr, + "WARNING: Partition %d is an extended partition\n", + i + 1); + if (p->boot_ind) + p->boot_ind = 0; + else p->boot_ind = ACTIVE_FLAG; + changed[i] = 1; +} + +void toggle_dos(void) +{ + dos_compatible_flag = ~dos_compatible_flag; + printf("DOS Compatibility flag is "); + if (dos_compatible_flag) + sector_offset = sectors; + else { + sector_offset = 1; + printf("not "); + } + printf("set\n"); +} + +void delete_partition(int i) +{ + struct partition *p = part_table[i], *q = ext_pointers[i]; + +/* Note that for the fifth partition (i == 4) we don't actually + * decrement partitions. + */ + + if (warn_geometry()) + return; + changed[i] = 1; + if (i < 4) { + if (p->sys_ind == EXTENDED && i == ext_index) { + while (partitions > 4) + free(buffers[--partitions]); + ext_pointers[ext_index] = NULL; + extended_offset = 0; + } + clear_partition(p); + } + else if (!q->sys_ind && i > 4) { + free(buffers[--partitions]); + clear_partition(ext_pointers[--i]); + } + else if (i > 3) { + if (i > 4) { + p = ext_pointers[i - 1]; + p->boot_ind = 0; + p->head = q->head; + p->sector = q->sector; + p->cyl = q->cyl; + p->sys_ind = EXTENDED; + p->end_head = q->end_head; + p->end_sector = q->end_sector; + p->end_cyl = q->end_cyl; + p->start_sect = q->start_sect; + p->nr_sects = q->nr_sects; + changed[i - 1] = 1; + } + else { + if(part_table[5]) /* prevent SEGFAULT */ + part_table[5]->start_sect = + SWAP32( + SWAP32(part_table[5]->start_sect) + + offsets[5] - extended_offset + ); + offsets[5] = extended_offset; + changed[5] = 1; + } + if (partitions > 5) { + partitions--; + free(buffers[i]); + while (i < partitions) { + changed[i] = changed[i + 1]; + buffers[i] = buffers[i + 1]; + offsets[i] = offsets[i + 1]; + part_table[i] = part_table[i + 1]; + ext_pointers[i] = ext_pointers[i + 1]; + i++; + } + } + else + clear_partition(part_table[i]); + } +} + +void change_sysid(void) +{ + char *temp; + int i = get_partition(0, partitions), sys, origsys; + struct partition *p = part_table[i]; + + sys = p->sys_ind; + origsys = sys; + if (sys == EXTENDED) + printf("Partition %d is extended. Delete it\n", i + 1); + else if (!sys) + printf("Partition %d does not exist yet!\n", i + 1); + else while (1) { +#if 0 + read_char("Hex code (type L to list codes): "); + if (tolower(*line_ptr) == 'l') + list_types(); + else if (isxdigit(*line_ptr)) { + sys = 0; + do + sys = sys << 4 | hex_val(*line_ptr++); + while (isxdigit(*line_ptr)); +#endif + /* The above code has been moved to read_hex () + to avoid having the same code in fdisklabel. + *//* bf */ + sys = read_hex (sys_types, nsys_types); /* bf */ + + if (!sys) { + delete_partition(i); + break; + } + else if (sys == EXTENDED) { + printf("You may not change a partition " + "to be an extended partition\n"); + break; + } + else if (sys < 256) { + if (sys == origsys) + break; + part_table[i]->sys_ind = sys; + printf ("Changed system type of partition %d " + "to %x (%s)\n", i + 1, sys, + (temp = partition_type(sys)) ? temp : + "Unknown"); + changed[i] = 1; + break; + } +#if 0 /* see above *//* bf */ + } +#endif + } +} + +/* check_consistency() and long2chs() added Sat Mar 6 12:28:16 1993, + * faith@cs.unc.edu, based on code fragments from pfdisk by Gordon W. Ross, + * Jan. 1990 (version 1.2.1 by Gordon W. Ross Aug. 1990; Modified by S. + * Lubkin Oct. 1991). */ + +static void long2chs(ulong ls, uint *c, uint *h, uint *s) +{ + int spc = heads * sectors; + + *c = ls / spc; + ls = ls % spc; + *h = ls / sectors; + *s = ls % sectors + 1; /* sectors count from 1 */ +} + +static void check_consistency(struct partition *p, int partition) +{ + uint pbc, pbh, pbs; /* physical beginning c, h, s */ + uint pec, peh, pes; /* physical ending c, h, s */ + uint lbc, lbh, lbs; /* logical beginning c, h, s */ + uint lec, leh, les; /* logical ending c, h, s */ + + if (!heads || !sectors || (partition >= 4)) + return; /* do not check extended partitions */ + +/* physical beginning c, h, s */ + pbc = p->cyl & 0xff | (p->sector << 2) & 0x300; + pbh = p->head; + pbs = p->sector & 0x3f; + +/* physical ending c, h, s */ + pec = p->end_cyl & 0xff | (p->end_sector << 2) & 0x300; + peh = p->end_head; + pes = p->end_sector & 0x3f; + +/* compute logical beginning (c, h, s) */ + long2chs(SWAP32(p->start_sect), &lbc, &lbh, &lbs); + +/* compute logical ending (c, h, s) */ + long2chs(SWAP32(p->start_sect) + SWAP32(p->nr_sects) - 1, &lec, &leh, &les); + +/* Same physical / logical beginning? */ + if (cylinders <= 1024 && (pbc != lbc || pbh != lbh || pbs != lbs)) { + printf("Partition %d has different physical/logical " + "beginnings (non-Linux?):\n", partition + 1); + printf(" phys=(%d, %d, %d) ", pbc, pbh, pbs); + printf("logical=(%d, %d, %d)\n",lbc, lbh, lbs); + } + +/* Same physical / logical ending? */ + if (cylinders <= 1024 && (pec != lec || peh != leh || pes != les)) { + printf("Partition %d has different physical/logical " + "endings:\n", partition + 1); + printf(" phys=(%d, %d, %d) ", pec, peh, pes); + printf("logical=(%d, %d, %d)\n",lec, leh, les); + } + +#if 0 +/* Beginning on cylinder boundary? */ + if (pbh != !pbc || pbs != 1) { + printf("Partition %i does not start on cylinder " + "boundary:\n", partition + 1); + printf(" phys=(%d, %d, %d) ", pbc, pbh, pbs); + printf("should be (%d, %d, 1)\n", pbc, !pbc); + } +#endif + +/* Ending on cylinder boundary? */ + if (peh != (heads - 1) || pes != sectors) { + printf("Partition %i does not end on cylinder boundary:\n", + partition + 1); + printf(" phys=(%d, %d, %d) ", pec, peh, pes); + printf("should be (%d, %d, %d)\n", + pec, heads - 1, sectors); + } +} + +void list_table(void) +{ + struct partition *p; + char *type; + int i, w = strlen(disk_device); + + printf("\nDisk %s: %d heads, %d sectors, %d cylinders\nUnits = " + "%ss of %d * 512 bytes\n\n", disk_device, heads, sectors, + cylinders, str_units(), display_factor); + if (w < 5) + w = 5; + printf("%*s Boot Begin Start End Blocks Id System\n", + w + 1, "Device"); + for (i = 0 ; i < partitions; i++) + if ((p = part_table[i])->sys_ind) { + printf("%*s%-2d %c%9d%9d%9d%9d%c %2x %s\n", w, +/* device */ disk_device, i + 1, +/* boot flag */ !p->boot_ind ? ' ' : p->boot_ind == ACTIVE_FLAG + ? '*' : '?', +/* begin */ cround(rounded( calculate(p->head, p->sector, p->cyl), + SWAP32(p->start_sect + offsets[i]))), +/* start */ cround(SWAP32(p->start_sect) + offsets[i]), +/* end */ cround(SWAP32(p->start_sect) + offsets[i] + SWAP32(p->nr_sects) + - (p->nr_sects ? 1: 0)), +/* odd flag on end */ SWAP32(p->nr_sects) / 2,SWAP32(p->nr_sects) & 1 ? '+' : ' ', +/* type id */ p->sys_ind, +/* type name */ (type = partition_type(p->sys_ind)) ? + type : "Unknown"); + check_consistency(p, i); + } + +} + +void x_list_table(int extend) +{ + struct partition *p, **q; + int i; + + if (extend) + q = ext_pointers; + else + q = part_table; + printf("\nDisk %s: %d heads, %d sectors, %d cylinders\n\n", + disk_device, heads, sectors, cylinders); + printf("Nr AF Hd Sec Cyl Hd Sec Cyl Start Size ID\n"); + for (i = 0 ; i < partitions; i++) + if (p = q[i]) { + printf("%2d %02x%4d%4d%5d%4d%4d%5d%8d%8d %02x\n", + i + 1, p->boot_ind, p->head, + sector(p->sector), + cylinder(p->sector, p->cyl), p->end_head, + sector(p->end_sector), + cylinder(p->end_sector, p->end_cyl), + SWAP32(p->start_sect), SWAP32(p->nr_sects), p->sys_ind); + if (p->sys_ind) + check_consistency(p, i); + } +} + +void check_bounds(uint *first, uint *last) +{ + int i; + uint max = 0xffffffff; /* used to be 256 * 63 * 1024 + but that made it impossible to add a + partition crossing cylinder 8064 */ + struct partition *p = part_table[0]; + + for (i = 0; i < partitions; p = part_table[++i]) + if (!p->sys_ind || p->sys_ind == EXTENDED) { + first[i] = max; + last[i] = 0; + } + else { + first[i] = rounded(calculate(p->head, p->sector, + p->cyl), SWAP32(p->start_sect) + offsets[i]); + last[i] = SWAP32(p->start_sect) + offsets[i] + SWAP32(p->nr_sects) - 1; + } +} + +void check(int n, uint h, uint s, uint c, uint start) +{ + uint total, real_s, real_c, i; + + real_s = sector(s) - 1; + real_c = cylinder(s, c); + total = (real_c * sectors + real_s) * heads + h; + if (full_bits) + while ((i = total + full_bits) <= start) { + real_c += 1024; + total = i; + } + if (!total) + fprintf(stderr, "Warning: partition %d contains sector 0\n", n); + if (h >= heads) + fprintf(stderr, + "Partition %d: head %d greater than maximum %d\n", + n, h + 1, heads); + if (real_s >= sectors) + fprintf(stderr, "Partition %d: sector %d greater than " + "maximum %d\n", n, s, sectors); + if (real_c >= cylinders) + fprintf(stderr, "Partitions %d: cylinder %d greater than " + "maximum %d\n", n, real_c + 1, cylinders); + if (cylinders <= 1024 && start != total) + fprintf(stderr, + "Partition %d: previous sectors %d disagrees with " + "total %d\n", n, start, total); +} + + +void verify(void) +{ + int i, j; + uint total = 1, + first[partitions], last[partitions]; + struct partition *p = part_table[0]; + + if (warn_geometry()) + return; + + check_bounds(first, last); + for (i = 0; i < partitions; p = part_table[++i]) + if (p->sys_ind && (p->sys_ind != EXTENDED)) { + check_consistency(p, i); + if (SWAP32(p->start_sect) + offsets[i] < first[i]) + printf("Warning: bad start-of-data in " + "partition %d\n", i + 1); + check(i + 1, p->end_head, p->end_sector, p->end_cyl, + last[i]); + total += last[i] + 1 - first[i]; + for (j = 0; j < i; j++) + if (first[i] >= first[j] && first[i] <= last[j] + || (last[i] <= last[j] && + last[i] >= first[j])) { + printf("Warning: partition %d overlaps " + "partition %d.\n", j + 1, i + 1); + total += first[i] >= first[j] ? + first[i] : first[j]; + total -= last[i] <= last[j] ? + last[i] : last[j]; + } + } + + if (extended_offset) { + uint e_last = SWAP32(part_table[ext_index]->start_sect) + + SWAP32(part_table[ext_index]->nr_sects) - 1; + + for (p = part_table[i = 4]; i < partitions; + p = part_table[++i]) { + total++; + if (!p->sys_ind) { + if (i != 4 || i + 1 < partitions) + printf("Warning: partition %d " + "is empty\n", i + 1); + } + else if (first[i] < extended_offset || + last[i] > e_last) + printf("Logical partition %d not entirely in " + "partition %d\n", i + 1, ext_index + 1); + } + } + + if (total > heads * sectors * cylinders) + printf("Total allocated sectors %d greater than the maximum " + "%d\n", total, heads * sectors * cylinders); + else if (total = heads * sectors * cylinders - total) + printf("%d unallocated sectors\n", total); +} + +void add_partition(int n, int sys) +{ + char mesg[48]; + int i, read = 0; + struct partition *p = part_table[n], *q = part_table[ext_index]; + uint start, stop = 0, limit, temp, + first[partitions], last[partitions]; + + if (p->sys_ind) { + printf("Partition %d is already defined. Delete " + "it before re-adding it.\n", n + 1); + return; + } + check_bounds(first, last); + if (n < 4) { + start = sector_offset; + limit = heads * sectors * cylinders - 1; + if (extended_offset) { + first[ext_index] = extended_offset; + last[ext_index] = SWAP32(q->start_sect) + SWAP32(q->nr_sects) - 1; + } + } + else { + start = extended_offset + sector_offset; + limit = SWAP32(q->start_sect) + SWAP32(q->nr_sects) - 1; + } + if (unit_flag) + for (i = 0; i < partitions; i++) + first[i] = (cround(first[i]) - 1) * display_factor; + + sprintf(mesg, "First %s", str_units()); + do { + temp = start; + for (i = 0; i < partitions; i++) { + if (start == offsets[i]) + start += sector_offset; + if (start >= first[i] && start <= last[i]) + if (n < 4) + start = last[i] + 1; + else + start = last[i] + sector_offset; + } + if (start > limit) + break; + if (start != temp && read) { + printf("Sector %d is already allocated\n", temp); + temp = start = stop; + read = 0; + } + if (!read && start == temp) { + uint i; + i = (stop = start) + (n > 4); + start = read_int(cround(i), cround(i), cround(limit), + ignore, mesg); + if (unit_flag) { + start = (start - 1) * display_factor; + if (start < i) start = i; + } + read = 1; + } + } while (start != temp || !read); + if (n > 4) /* NOT for fifth partition */ + offsets[n] = start - sector_offset; + + for (i = 0; i < partitions; i++) { + if (start < offsets[i] && limit >= offsets[i]) + limit = offsets[i] - 1; + if (start < first[i] && limit >= first[i]) + limit = first[i] - 1; + } + if (start > limit) { + printf("No free sectors available\n"); + if (n > 4) { + free(buffers[n]); + partitions--; + } + return; + } + if (cround(start) == cround(limit)) + stop = start; + else { + sprintf(mesg, "Last %s or +size or +sizeM or +sizeK", + str_units()); + stop = read_int(cround(start), cround(limit), cround(limit), + lower, mesg); + if (unit_flag) { + stop = stop * display_factor - 1; + if (stop >limit) + stop = limit; + } + } + + set_partition(n, p, start, stop, sys, offsets[n]); + + if (sys == EXTENDED) { + ext_index = n; + offsets[4] = extended_offset = start; + ext_pointers[n] = p; + if (!(buffers[4] = calloc(1, SECTOR_SIZE))) + fatal(out_of_memory); + part_table[4] = offset(buffers[4], 0); + ext_pointers[4] = part_table[4] + 1; + changed[4] = 1; + partitions = 5; + } + else { + if (n > 4) + set_partition(n - 1, ext_pointers[n - 1], + start - sector_offset, stop, EXTENDED, + extended_offset); +#if 0 + if ((limit = SWAP32(p->nr_sects)) & 1) + printf("Warning: partition %d has an odd " + "number of sectors.\n", n + 1); +#endif + } +} + +void add_logical(void) +{ + if (partitions > 5 || part_table[4]->sys_ind) { + if (!(buffers[partitions] = calloc(1, SECTOR_SIZE))) + fatal(out_of_memory); + part_table[partitions] = offset(buffers[partitions], 0); + ext_pointers[partitions] = part_table[partitions] + 1; + offsets[partitions] = 0; + partitions++; + } + add_partition(partitions - 1, LINUX_NATIVE); +} + +void new_partition(void) +{ + int i, free_primary = 0; + + if (warn_geometry()) + return; + if (partitions >= MAXIMUM_PARTS) { + printf("The maximum number of partitions has been created\n"); + return; + } + + for (i = 0; i < 4; i++) + free_primary += !part_table[i]->sys_ind; + if (!free_primary) + if (extended_offset) + add_logical(); + else + printf("You must delete some partition and add " + "an extended partition first\n"); + else { + char c, line[LINE_LENGTH]; + sprintf(line, "Command action\n %s\n p primary " + "partition (1-4)\n", extended_offset ? + "l logical (5 or over)" : "e extended"); + while (1) + if ((c = tolower(read_char(line))) == 'p') { + add_partition(get_partition(0, 4), + LINUX_NATIVE); + return; + } + else if (c == 'l' && extended_offset) { + add_logical(); + return; + } + else if (c == 'e' && !extended_offset) { + add_partition(get_partition(0, 4), + EXTENDED); + return; + } + else + printf("Invalid partition number " + "for type `%c'\n", c); + + } +} + +void write_table(void) +{ + int i, error = 0; + + changed[3] = changed[0] || changed[1] || changed[2] || changed[3]; + for (i = 3; i < partitions; i++) + if (changed[i]) { + *table_check(buffers[i]) = SWAP16(PART_TABLE_FLAG); + if (llseek(fd, (loff_t)offsets[i] + * SECTOR_SIZE, SEEK_SET) < 0) + fatal(unable_to_seek); + if (write(fd, buffers[i], SECTOR_SIZE) != SECTOR_SIZE) + fatal(unable_to_write); + } + + printf("The partition table has been altered!\n\n"); + + printf("Calling ioctl() to re-read partition table.\n" + "(Reboot to ensure the partition table has been updated.)\n"); + sync(); + sleep(2); + if (i = ioctl(fd, BLKRRPART)) { + error = 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(fd, BLKRRPART)) + error = errno; + } + + close(fd); + + printf("Syncing disks.\n"); + sync(); + sleep(4); /* for sync() */ + + if (i < 0) + printf("Re-read table failed with error %d: %s.\nReboot your " + "system to ensure the partition table is updated.\n", + error, strerror(error)); + + printf( "\nWARNING: If you have created or modified any DOS 6.x\n" + "partitions, please see the fdisk manual page for additional\n" + "information.\n" ); + + exit(0); +} + +#define MAX_PER_LINE 16 +void print_buffer(char buffer[]) +{ + int i, + l; + + for (i = 0, l = 0; i < SECTOR_SIZE; i++, l++) { + if (l == 0) + printf("0x%03X:", i); + printf(" %02X", (unsigned char) buffer[i]); + if (l == MAX_PER_LINE - 1) { + printf("\n"); + l = -1; + } + } + if (l > 0) + printf("\n"); + printf("\n"); +} + +void print_raw(void) +{ + int i; + + printf("Device: %s\n", disk_device); + for (i = 3; i < partitions; i++) + print_buffer(buffers[i]); +} + +void move_begin(int i) +{ + struct partition *p = part_table[i]; + uint new, first; + + if (warn_geometry()) + return; + if (!p->sys_ind || !p->nr_sects || p->sys_ind == EXTENDED) { + printf("Partition %d has no data area\n", i + 1); + return; + } + first = rounded(calculate(p->head, p->sector, p->cyl), SWAP32(p->start_sect) + + offsets[i]); + new = read_int(first, first, + SWAP32(p->start_sect) + SWAP32(p->nr_sects) + offsets[i] - 1, + lower, "New beginning of data") - offsets[i]; + + if (new != SWAP32(p->nr_sects)) { + first = SWAP32(p->nr_sects) + SWAP32(p->start_sect) - new; + p->nr_sects = SWAP32(first); + p->start_sect = SWAP32(new); + changed[i] = 1; + } +} + +void xselect(void) +{ + while(1) { + putchar('\n'); + switch (tolower(read_char("Expert command (m for help): "))) { + case 'b': move_begin(get_partition(0, partitions)); + break; + case 'c': cylinders = read_int(1, cylinders, 65535, + deflt, "Number of cylinders"); + warn_cylinders(); + break; + case 'd': print_raw(); + break; + case 'e': x_list_table(1); + break; + case 'h': heads = read_int(1, heads, 256, deflt, + "Number of heads"); + update_units(); + break; + case 'p': x_list_table(0); + break; + case 'q': close(fd); + exit(0); + case 'r': return; + case 's': sectors = read_int(1, sectors, 63, deflt, + "Number of sectors"); + if (dos_compatible_flag) { + sector_offset = sectors; + fprintf(stderr, "Warning: setting " + "sector offset for DOS " + "compatiblity\n"); + } + update_units(); + break; + case 'v': verify(); + break; + case 'w': write_table(); + default: xmenu(); + } + } +} + +void try(char *device) +{ + disk_device = device; + if (!setjmp(listingbuf)) + if ((fd = open(disk_device, type_open)) >= 0) { + close(fd); + get_boot(); + list_table(); + if (partitions > 4) + delete_partition(ext_index); + } else { + /* Ignore other errors, since we try IDE + and SCSI hard disks which may not be + installed on the system. */ + if(errno == EACCES) { + fprintf(stderr, "Cannot open %s\n", device); + exit(1); + } + } +} + +void main(int argc, char **argv) +{ + if (argc > 3) + fatal(usage); + if (argc > 1 && *argv[1] == '-') { + switch (*(argv[1] + 1)) { + case 'v': + printf("fdisk v" VERSION "\n"); + exit(0); + case 'l': + listing = 1; + type_open = O_RDONLY; + try("/dev/hda"); + try("/dev/hdb"); + try("/dev/hdc"); + try("/dev/hdd"); + try("/dev/sda"); + try("/dev/sdb"); + try("/dev/sdc"); + try("/dev/sdd"); + try("/dev/sde"); + try("/dev/sdf"); + try("/dev/sdg"); + try("/dev/sdh"); + exit(0); + case 's': { + int i; + if (argc < 3) + fatal(usage); + if (!(i = atoi(argv[2] + 8))) + fatal(usage); + disk_device = (char *) malloc(9); + strncpy(disk_device, argv[2], 8); + if ((fd = open(disk_device, O_RDWR)) >= 0) { + close(fd); + get_boot(); + if (i > partitions) exit(1); + if (part_table[--i]->sys_ind > 10) + printf("%d\n", + SWAP32(part_table[i]->nr_sects) / 2); + else exit(1); + exit(0); + } + } + default: + fatal(usage); + } + } + if (argc > 1) + disk_device = argv[argc - 1]; + else if ((fd = open(DEFAULT_DEVICE, O_RDWR)) < 0) + disk_device = ALTERNATE_DEVICE; + else close(fd); + + if (argc == 1) + printf("Using %s as default device!\n", disk_device); + get_boot(); + + while (1) { + putchar('\n'); + switch (tolower(read_char("Command (m for help): "))) { + case 'a': toggle_active(get_partition(1, partitions)); + break; +/* There should be a define which allows to turn off disklabel support so as + not to make fdisk larger than necessary on installation boot disks. +*/ +#if 1 /* #ifndef NO_DISKLABEL_SUPPORT */ + case 'b': bselect(); /* bf */ + break; +#endif + case 'c': + toggle_dos(); + break; + case 'd': delete_partition( + get_partition(1, partitions)); + break; + case 'l': list_types(sys_types, nsys_types); /* bf */ + break; + case 'n': new_partition(); + break; + case 'p': list_table(); + break; + case 'q': close(fd); + exit(0); + case 't': change_sysid(); + break; + case 'u': change_units(); + break; + case 'v': verify(); + break; + case 'w': write_table(); + case 'x': xselect(); + break; + default: menu(); + } + } +} diff --git a/fdisk.h b/fdisk.h new file mode 100644 index 0000000..2b6ddc8 --- /dev/null +++ b/fdisk.h @@ -0,0 +1,51 @@ +/* + fdisk.h +*/ + +#define SECTOR_SIZE 512 +#define NETBSD_PARTITION 0xa5 +#define cround(n) (((n) + display_factor * unit_flag) / display_factor) + +#if defined(__GNUC__) || defined(HAS_LONG_LONG) +typedef long long ext2_loff_t; +#else +typedef long ext2_loff_t; +#endif + +#if BYTE_ORDER == BIG_ENDIAN +#define SWAP16(x) __swap16(x) +#define SWAP32(x) __swap32(x) +#else +#define SWAP16(x) ((__u16)x) +#define SWAP32(x) ((__u32)x) +#endif + +enum failure {usage, unable_to_open, unable_to_read, unable_to_seek, + unable_to_write, out_of_memory}; + +enum offset {ignore, lower, deflt, upper}; + +struct systypes { + unsigned char index; + char *name; +}; + +/* prototypes for fdisk.c */ +extern char *disk_device, + *line_ptr; +extern int fd, + partitions; +extern uint unit_flag, + display_factor; +extern struct partition *part_table[]; +extern void fatal(enum failure why); +extern int get_partition(int warn, int max); +extern void list_types(struct systypes *sys, int size); +extern int read_line (void); +extern char read_char(char *mesg); +extern int read_hex(struct systypes *sys, int size); +uint read_int(uint low, uint dflt, uint high, enum offset base, char *mesg); +extern char *const str_units(void); + +/* prototypes for fdisklabel.c */ +extern void bselect(void); diff --git a/fdisklabel.c b/fdisklabel.c new file mode 100644 index 0000000..9344339 --- /dev/null +++ b/fdisklabel.c @@ -0,0 +1,803 @@ +/* + NetBSD disklabel editor for Linux fdisk + Written by Bernhard Fastenrath (fasten@informatik.uni-bonn.de) + with code from the NetBSD disklabel command: + + Copyright (c) 1987, 1988 Regents of the University of California. + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. All advertising materials mentioning features or use of this software + must display the following acknowledgement: + This product includes software developed by the University of + California, Berkeley and its contributors. + 4. Neither the name of the University nor the names of its contributors + may be used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + SUCH DAMAGE. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include "fdisk.h" +#define DKTYPENAMES +#include "fdisklabel.h" + +static void bsd_delete_part (void); +static void bsd_new_part (void); +static void bsd_print_disklabel (int show_all); +static void bsd_write_disklabel (void); +static int bsd_create_disklabel (void); +static void bsd_edit_disklabel (void); +static void bsd_write_bootstrap (void); +static void bsd_change_fstype (void); +static int bsd_get_part_index (int max); +static int bsd_check_new_partition (int *i); +static void bsd_list_types (void); +static u_short bsd_dkcksum (struct disklabel *lp); +static int bsd_initlabel (struct partition *p, struct disklabel *d, int pindex); +static int bsd_readlabel (struct partition *p, struct disklabel *d); +static int bsd_writelabel (struct partition *p, struct disklabel *d); +static void sync_disks (void); +#if defined (i386) +static int bsd_translate_fstype (int linux_type); +static void bsd_link_part (void); +#endif +#if defined (__alpha__) +void alpha_bootblock_checksum (char *boot); +#endif + +static struct disklabel bsd_dlabel; +static char buffer[BSD_BBSIZE]; +#if defined (i386) +static struct partition *bsd_part; +static int bsd_part_index; +#endif + +void +bmenu (void) +{ + puts ("Command action\n" + " d delete a BSD partition\n" + " e edit drive data\n" + " i install bootstrap\n" + " l list known filesystem types\n" + " m print this menu\n" + " n add a new BSD partition\n" + " p print BSD partition table\n" + " q quit without saving changes\n" +#if defined (i386) + " r return to main menu\n" +#endif + " s show complete disklabel\n" + " t change a partition's filesystem id\n" + " w write disklabel to disk\n" +#if defined (i386) + " x link BSD partition to non-BSD partition" +#endif + ); +} + +void +bselect (void) +{ +#if defined (i386) + int t; + + for (t=0; t<4; t++) + if (part_table[t] -> sys_ind == NETBSD_PARTITION) + { + bsd_part = part_table[t]; + bsd_part_index = t; + if (bsd_part -> start_sect == 0) + { + fprintf (stderr, "Partition %s%d has invalid starting sector 0.\n", + disk_device, t+1); + return; + } + printf ("Reading disklabel of %s%d at sector %d.\n", + disk_device, t+1, bsd_part -> start_sect + BSD_LABELSECTOR); + if (bsd_readlabel (bsd_part, &bsd_dlabel) == 0) + if (bsd_create_disklabel () == 0) + return; + break; + } + + if (t == 4) + { + printf ("There is no NetBSD partition on %s.\n", disk_device); + return; + } + +#elif defined (__alpha__) || defined (__powerpc__) + + if (bsd_readlabel (NULL, &bsd_dlabel) == 0) + if (bsd_create_disklabel () == 0) + exit ( EXIT_SUCCESS ); + +#endif + + while (1) + { + putchar ('\n'); + switch (tolower (read_char ("BSD disklabel command (m for help): "))) + { + case 'd': + bsd_delete_part (); + break; + case 'e': + bsd_edit_disklabel (); + break; + case 'i': + bsd_write_bootstrap (); + break; + case 'l': + bsd_list_types (); + break; + case 'n': + bsd_new_part (); + break; + case 'p': + bsd_print_disklabel (0); + break; + case 'q': + close (fd); + exit ( EXIT_SUCCESS ); + case 's': + bsd_print_disklabel (1); + break; + case 't': + bsd_change_fstype (); + break; + case 'w': + bsd_write_disklabel (); + break; +#if defined (i386) + case 'r': + return; + case 'x': + bsd_link_part (); + break; +#endif + default: + bmenu (); + break; + } + } +} + +static void +bsd_delete_part (void) +{ + int i; + + i = bsd_get_part_index (bsd_dlabel.d_npartitions); + bsd_dlabel.d_partitions[i].p_size = 0; + bsd_dlabel.d_partitions[i].p_offset = 0; + bsd_dlabel.d_partitions[i].p_fstype = BSD_FS_UNUSED; + if (bsd_dlabel.d_npartitions == i + 1) + while (bsd_dlabel.d_partitions[bsd_dlabel.d_npartitions-1].p_size == 0) + bsd_dlabel.d_npartitions--; +} + +static void +bsd_new_part (void) +{ + uint begin, end; + char mesg[48]; + int i; + + if (!bsd_check_new_partition (&i)) + return; + +#if defined (i386) + begin = bsd_part -> start_sect; + end = begin + bsd_part -> nr_sects - 1; +#elif defined (__alpha__) || defined (__powerpc__) + begin = 0; + end = bsd_dlabel.d_secperunit; +#endif + + sprintf (mesg, "First %s", str_units()); + begin = read_int (cround (begin), cround (begin), cround (end), ignore, mesg); + + sprintf (mesg, "Last %s or +size or +sizeM or +sizeK", str_units()); + end = read_int (cround (begin), cround (end), cround (end), ignore, mesg); + + if (unit_flag) + { + begin = (begin - 1) * display_factor; + end = end * display_factor - 1; + } + bsd_dlabel.d_partitions[i].p_size = end - begin + 1; + bsd_dlabel.d_partitions[i].p_offset = begin; + bsd_dlabel.d_partitions[i].p_fstype = BSD_FS_UNUSED; +} + +static void +bsd_print_disklabel (int show_all) +{ + struct disklabel *lp = &bsd_dlabel; + struct bsd_partition *pp; + FILE *f = stdout; + int i, j; + + if (show_all) + { +#if defined (i386) + fprintf(f, "# %s%d:\n", disk_device, bsd_part_index+1); +#elif defined (__alpha__) || defined (__powerpc__) + fprintf(f, "# %s:\n", disk_device); +#endif + if ((unsigned) lp->d_type < BSD_DKMAXTYPES) + fprintf(f, "type: %s\n", bsd_dktypenames[lp->d_type]); + else + fprintf(f, "type: %d\n", lp->d_type); + fprintf(f, "disk: %.*s\n", sizeof(lp->d_typename), lp->d_typename); + fprintf(f, "label: %.*s\n", sizeof(lp->d_packname), lp->d_packname); + fprintf(f, "flags:"); + if (lp->d_flags & BSD_D_REMOVABLE) + fprintf(f, " removable"); + if (lp->d_flags & BSD_D_ECC) + fprintf(f, " ecc"); + if (lp->d_flags & BSD_D_BADSECT) + fprintf(f, " badsect"); + fprintf(f, "\n"); + fprintf(f, "bytes/sector: %d\n", lp->d_secsize); + fprintf(f, "sectors/track: %d\n", lp->d_nsectors); + fprintf(f, "tracks/cylinder: %d\n", lp->d_ntracks); + fprintf(f, "sectors/cylinder: %d\n", lp->d_secpercyl); + fprintf(f, "cylinders: %d\n", lp->d_ncylinders); + fprintf(f, "rpm: %d\n", lp->d_rpm); + fprintf(f, "interleave: %d\n", lp->d_interleave); + fprintf(f, "trackskew: %d\n", lp->d_trackskew); + fprintf(f, "cylinderskew: %d\n", lp->d_cylskew); + fprintf(f, "headswitch: %d\t\t# milliseconds\n", lp->d_headswitch); + fprintf(f, "track-to-track seek: %d\t# milliseconds\n", lp->d_trkseek); + fprintf(f, "drivedata: "); + for (i = NDDATA - 1; i >= 0; i--) + if (lp->d_drivedata[i]) + break; + if (i < 0) + i = 0; + for (j = 0; j <= i; j++) + fprintf(f, "%d ", lp->d_drivedata[j]); + } + fprintf (f, "\n%d partitions:\n", lp->d_npartitions); + fprintf (f, "# size offset fstype [fsize bsize cpg]\n"); + pp = lp->d_partitions; + for (i = 0; i < lp->d_npartitions; i++, pp++) { + if (pp->p_size) { + fprintf(f, " %c: %8d %8d ", 'a' + i, + pp->p_size, pp->p_offset); + if ((unsigned) pp->p_fstype < BSD_FSMAXTYPES) + fprintf(f, "%8.8s", bsd_fstypes[pp->p_fstype].name); + else + fprintf(f, "%8x", pp->p_fstype); + switch (pp->p_fstype) + { + case BSD_FS_UNUSED: + fprintf(f, " %5d %5d %5.5s ", + pp->p_fsize, pp->p_fsize * pp->p_frag, ""); + break; + + case BSD_FS_BSDFFS: + fprintf(f, " %5d %5d %5d ", + pp->p_fsize, pp->p_fsize * pp->p_frag, + pp->p_cpg); + break; + + default: + fprintf(f, "%20.20s", ""); + break; + } + fprintf(f, "\t# (Cyl. %4d", +#if 0 + pp->p_offset / lp->d_secpercyl); /* differs from Linux fdisk */ +#else + pp->p_offset / lp->d_secpercyl + 1); +#endif + if (pp->p_offset % lp->d_secpercyl) + putc('*', f); + else + putc(' ', f); + fprintf(f, "- %d", + (pp->p_offset + + pp->p_size + lp->d_secpercyl - 1) / +#if 0 + lp->d_secpercyl - 1); /* differs from Linux fdisk */ +#else + lp->d_secpercyl); +#endif + if (pp->p_size % lp->d_secpercyl) + putc('*', f); + fprintf(f, ")\n"); + } + } +} + +static void +bsd_write_disklabel (void) +{ +#if defined (i386) + printf ("Writing disklabel to %s%d.\n", disk_device, bsd_part_index+1); + bsd_writelabel (bsd_part, &bsd_dlabel); +#elif defined (__alpha__) || defined (__powerpc__) + printf ("Writing disklabel to %s.\n", disk_device); + bsd_writelabel (NULL, &bsd_dlabel); +#endif +} + +static int +bsd_create_disklabel (void) +{ + char c; + +#if defined (i386) + fprintf (stderr, "%s%d contains no disklabel.\n", + disk_device, bsd_part_index+1); +#elif defined (__alpha__) || defined (__powerpc__) + fprintf (stderr, "%s contains no disklabel.\n", disk_device); +#endif + + while (1) + if ((c = tolower (read_char ("Do you want to create a disklabel? (y/n) "))) == 'y') + { +#if defined (i386) + if (bsd_initlabel (bsd_part, &bsd_dlabel, bsd_part_index) == 1) +#elif defined (__alpha__) || defined (__powerpc__) + if (bsd_initlabel (NULL, &bsd_dlabel, 0) == 1) +#endif + { + bsd_print_disklabel (1); + return 1; + } + else + return 0; + } + else if (c == 'n') + return 0; +} + +static int +edit_int (int def, char *mesg) +{ + do { + fputs (mesg, stdout); + printf (" (%d): ", def); + if (!read_line ()) + return def; + } + while (!isdigit (*line_ptr)); + return atoi (line_ptr); +} + +static void +bsd_edit_disklabel (void) +{ + struct disklabel *d; + + d = &bsd_dlabel; + +#if defined (__alpha__) || defined (__powerpc__) + d -> d_secsize = (u_long) edit_int ((u_long) d -> d_secsize ,"bytes/sector"); + d -> d_nsectors = (u_long) edit_int ((u_long) d -> d_nsectors ,"sectors/track"); + d -> d_ntracks = (u_long) edit_int ((u_long) d -> d_ntracks ,"tracks/cylinder"); + d -> d_ncylinders = (u_long) edit_int ((u_long) d -> d_ncylinders ,"cylinders"); +#endif + + /* d -> d_secpercyl can be != d -> d_nsectors * d -> d_ntracks */ + while (1) + { + d -> d_secpercyl = (u_long) edit_int ((u_long) d -> d_nsectors * d -> d_ntracks, + "sectors/cylinder"); + if (d -> d_secpercyl <= d -> d_nsectors * d -> d_ntracks) + break; + + printf ("Must be <= sectors/track * tracks/cylinder (default).\n"); + } + d -> d_rpm = (u_short) edit_int ((u_short) d -> d_rpm ,"rpm"); + d -> d_interleave = (u_short) edit_int ((u_short) d -> d_interleave,"interleave"); + d -> d_trackskew = (u_short) edit_int ((u_short) d -> d_trackskew ,"trackskew"); + d -> d_cylskew = (u_short) edit_int ((u_short) d -> d_cylskew ,"cylinderskew"); + d -> d_headswitch = (u_long) edit_int ((u_long) d -> d_headswitch ,"headswitch"); + d -> d_trkseek = (u_long) edit_int ((u_long) d -> d_trkseek ,"track-to-track seek"); + + d -> d_secperunit = d -> d_secpercyl * d -> d_ncylinders; +} + +static int +bsd_get_bootstrap (char *path, void *ptr, int size) +{ + int fd; + + if ((fd = open (path, O_RDONLY)) < 0) + { + perror (path); + return 0; + } + if (read (fd, ptr, size) < 0) + { + perror (path); + close (fd); + return 0; + } + printf (" ... %s\n", path); + close (fd); + return 1; +} + +static void +bsd_write_bootstrap (void) +{ + char *bootdir = BSD_LINUX_BOOTDIR; + char path[MAXPATHLEN]; + char *dkbasename; + struct disklabel dl; + char *d, *p, *e; + int sector; + + if (bsd_dlabel.d_type == BSD_DTYPE_SCSI) + dkbasename = "sd"; + else + dkbasename = "wd"; + + printf ("Bootstrap: %sboot -> boot%s (%s): ", dkbasename, dkbasename, dkbasename); + if (read_line ()) + { + line_ptr[strlen (line_ptr)-1] = '\0'; + dkbasename = line_ptr; + } + sprintf (path, "%s/%sboot", bootdir, dkbasename); + if (!bsd_get_bootstrap (path, buffer, (int) bsd_dlabel.d_secsize)) + return; + + /* We need a backup of the disklabel (bsd_dlabel might have changed). */ + d = &buffer[BSD_LABELSECTOR * SECTOR_SIZE]; + bcopy (d, &dl, sizeof (struct disklabel)); + + /* The disklabel will be overwritten by 0's from bootxx anyway */ + bzero (d, sizeof (struct disklabel)); + + sprintf (path, "%s/boot%s", bootdir, dkbasename); + if (!bsd_get_bootstrap (path, &buffer[bsd_dlabel.d_secsize], + (int) bsd_dlabel.d_bbsize - bsd_dlabel.d_secsize)) + return; + + e = d + sizeof (struct disklabel); + for (p=d; p < e; p++) + if (*p) + { + fprintf (stderr, "Bootstrap overlaps with disk label!\n"); + exit ( EXIT_FAILURE ); + } + + bcopy (&dl, d, sizeof (struct disklabel)); + +#if defined (i386) + sector = bsd_part -> start_sect; +#elif defined (__powerpc__) + sector = 0; +#elif defined (__alpha__) + sector = 0; + alpha_bootblock_checksum (buffer); +#endif + + if (llseek (fd, sector * SECTOR_SIZE, SEEK_SET) == -1) + fatal (unable_to_seek); + if (BSD_BBSIZE != write (fd, buffer, BSD_BBSIZE)) + fatal (unable_to_write); + +#if defined (i386) + printf ("Bootstrap installed on %s%d.\n", disk_device, bsd_part_index+1); +#elif defined (__alpha__) || defined (__powerpc__) + printf ("Bootstrap installed on %s.\n", disk_device); +#endif + + sync_disks (); +} + +static void +bsd_change_fstype (void) +{ + int i; + + i = bsd_get_part_index (bsd_dlabel.d_npartitions); + bsd_dlabel.d_partitions[i].p_fstype = read_hex (bsd_fstypes, BSD_FSMAXTYPES); +} + +static int +bsd_get_part_index (int max) +{ + char prompt[40]; + char l; + + sprintf (prompt, "Partition (a-%c): ", 'a' + max - 1); + do + l = tolower (read_char (prompt)); + while (l < 'a' || l > 'a' + max - 1); + return l - 'a'; +} + +static int +bsd_check_new_partition (int *i) +{ + int t; + + if (bsd_dlabel.d_npartitions == BSD_MAXPARTITIONS) + { + for (t=0; t < BSD_MAXPARTITIONS; t++) + if (bsd_dlabel.d_partitions[t].p_size == 0) + break; + + if (t == BSD_MAXPARTITIONS) + { + fprintf (stderr, "The maximum number of partitions has been created\n"); + return 0; + } + } + *i = bsd_get_part_index (BSD_MAXPARTITIONS); + + if (*i >= bsd_dlabel.d_npartitions) + bsd_dlabel.d_npartitions = (*i) + 1; + + if (bsd_dlabel.d_partitions[*i].p_size != 0) + { + fprintf (stderr, "This partition already exists.\n"); + return 0; + } + return 1; +} + +static void +bsd_list_types (void) +{ + list_types (bsd_fstypes, BSD_FSMAXTYPES); +} + +static u_short +bsd_dkcksum (struct disklabel *lp) +{ + register u_short *start, *end; + register u_short sum = 0; + + start = (u_short *)lp; + end = (u_short *)&lp->d_partitions[lp->d_npartitions]; + while (start < end) + sum ^= *start++; + return (sum); +} + +static int +bsd_initlabel (struct partition *p, struct disklabel *d, int pindex) +{ + struct hd_geometry geometry; + struct bsd_partition *pp; + + if (ioctl (fd, HDIO_GETGEO, &geometry) == -1) + { + perror ("ioctl"); + return 0; + } + bzero (d, sizeof (struct disklabel)); + + d -> d_magic = BSD_DISKMAGIC; + + if (strncmp (disk_device, "/dev/sd", 7) == 0) + d -> d_type = BSD_DTYPE_SCSI; + else + d -> d_type = BSD_DTYPE_ST506; + +#if 0 /* not used (at least not written to disk) by NetBSD/i386 1.0 */ + d -> d_subtype = BSD_DSTYPE_INDOSPART & pindex; +#endif + +#if defined (i386) + d -> d_flags = BSD_D_DOSPART; +#else + d -> d_flags = 0; +#endif + d -> d_secsize = SECTOR_SIZE; /* bytes/sector */ + d -> d_nsectors = geometry.sectors; /* sectors/track */ + d -> d_ntracks = geometry.heads; /* tracks/cylinder (heads) */ + d -> d_ncylinders = geometry.cylinders; + d -> d_secpercyl = geometry.sectors * geometry.heads; /* sectors/cylinder */ + d -> d_secperunit = d -> d_secpercyl * d -> d_ncylinders; + + d -> d_rpm = 3600; + d -> d_interleave = 1; + d -> d_trackskew = 0; + d -> d_cylskew = 0; + d -> d_headswitch = 0; + d -> d_trkseek = 0; + + d -> d_magic2 = BSD_DISKMAGIC; + d -> d_bbsize = BSD_BBSIZE; + d -> d_sbsize = BSD_SBSIZE; + +#if defined (i386) + d -> d_npartitions = 4; + pp = &d -> d_partitions[2]; /* Partition C should be the NetBSD partition */ + pp -> p_offset = p -> start_sect; + pp -> p_size = p -> nr_sects; + pp -> p_fstype = BSD_FS_UNUSED; + pp = &d -> d_partitions[3]; /* Partition D should be the whole disk */ + pp -> p_offset = 0; + pp -> p_size = d -> d_secperunit; + pp -> p_fstype = BSD_FS_UNUSED; +#elif defined (__alpha__) || defined (__powerpc__) + d -> d_npartitions = 3; + pp = &d -> d_partitions[2]; /* Partition C should be the whole disk */ + pp -> p_offset = 0; + pp -> p_size = d -> d_secperunit; + pp -> p_fstype = BSD_FS_UNUSED; +#endif + + return 1; +} + +static int +bsd_readlabel (struct partition *p, struct disklabel *d) +{ + int t, sector; + +#if defined (i386) + sector = p -> start_sect; +#elif defined (__alpha__) || defined (__powerpc__) + sector = 0; +#endif + + if (llseek (fd, sector * SECTOR_SIZE, SEEK_SET) == -1) + fatal (unable_to_seek); + if (BSD_BBSIZE != read (fd, buffer, BSD_BBSIZE)) + fatal (unable_to_read); + + bcopy (&buffer[BSD_LABELSECTOR * SECTOR_SIZE + BSD_LABELOFFSET], + d, sizeof (struct disklabel)); + + for (t = d -> d_npartitions; t < BSD_MAXPARTITIONS; t++) + { + d -> d_partitions[t].p_size = 0; + d -> d_partitions[t].p_offset = 0; + d -> d_partitions[t].p_fstype = BSD_FS_UNUSED; + } + if (d -> d_magic != BSD_DISKMAGIC || d -> d_magic2 != BSD_DISKMAGIC) + return 0; + + if (d -> d_npartitions > BSD_MAXPARTITIONS) + fprintf (stderr, "Warning: too many partitions (%d, maximum is %d).\n", + d -> d_npartitions, BSD_MAXPARTITIONS); + return 1; +} + +static int +bsd_writelabel (struct partition *p, struct disklabel *d) +{ + int sector; + +#if defined (i386) + sector = p -> start_sect + BSD_LABELSECTOR; +#elif defined (__alpha__) || defined (__powerpc__) + sector = BSD_LABELSECTOR; +#endif + + d -> d_checksum = 0; + d -> d_checksum = bsd_dkcksum (d); + + /* This is necessary if we want to write the bootstrap later, + otherwise we'd write the old disklabel with the bootstrap. + */ + bcopy (d, &buffer[BSD_LABELSECTOR * SECTOR_SIZE + BSD_LABELOFFSET], + sizeof (struct disklabel)); + +#if defined (__alpha__) && BSD_LABELSECTOR == 0 + alpha_bootblock_checksum (buffer); + if (llseek (fd, 0, SEEK_SET) == -1) + fatal (unable_to_seek); + if (BSD_BBSIZE != write (fd, buffer, BSD_BBSIZE)) + fatal (unable_to_write); +#else + if (llseek (fd, sector * SECTOR_SIZE + BSD_LABELOFFSET, SEEK_SET) == -1) + fatal (unable_to_seek); + if (sizeof (struct disklabel) != write (fd, d, sizeof (struct disklabel))) + fatal (unable_to_write); +#endif + + sync_disks (); + + return 1; +} + +static void +sync_disks (void) +{ + printf ("\nSyncing disks.\n"); + sync (); + sleep (4); +} + +#if defined (i386) +static int +bsd_translate_fstype (int linux_type) +{ + switch (linux_type) + { + case 0x01: /* DOS 12-bit FAT */ + case 0x04: /* DOS 16-bit <32M */ + case 0x06: /* DOS 16-bit >=32M */ + case 0xe1: /* DOS access */ + case 0xe3: /* DOS R/O */ + case 0xf2: /* DOS secondary */ + return BSD_FS_MSDOS; + case 0x07: /* OS/2 HPFS */ + return BSD_FS_HPFS; + default: + return BSD_FS_OTHER; + } +} + +static void +bsd_link_part (void) +{ + int k, i; + + k = get_partition (1, partitions); + + if (!bsd_check_new_partition (&i)) + return; + + bsd_dlabel.d_partitions[i].p_size = part_table[k] -> nr_sects; + bsd_dlabel.d_partitions[i].p_offset = part_table[k] -> start_sect; + bsd_dlabel.d_partitions[i].p_fstype = + bsd_translate_fstype (part_table[k] -> sys_ind); +} +#endif + +#if defined (__alpha__) +typedef unsigned long long u_int64_t; + +void +alpha_bootblock_checksum (char *boot) +{ + u_int64_t *dp, sum; + int i; + + dp = (u_int64_t *)boot; + sum = 0; + for (i = 0; i < 63; i++) + sum += dp[i]; + dp[63] = sum; +} +#endif /* __alpha__ */ diff --git a/fdisklabel.h b/fdisklabel.h new file mode 100644 index 0000000..0b5227c --- /dev/null +++ b/fdisklabel.h @@ -0,0 +1,239 @@ +/* + * Copyright (c) 1987, 1988 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by the University of + * California, Berkeley and its contributors. + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#define BSD_DISKMAGIC ((u_long) 0x82564557) +#define BSD_MAXPARTITIONS 8 +#define BSD_LINUX_BOOTDIR "/usr/ucb/mdec" + +#if defined (i386) +#define BSD_LABELSECTOR 1 +#define BSD_LABELOFFSET 0 +#define BSD_BBSIZE 8192 /* size of boot area, with label */ +#define BSD_SBSIZE 8192 /* max size of fs superblock */ +#elif defined (__alpha__) +#error LABELSECTOR, LABELOFFSET, BBSIZE & SBSIZE are undefined for __alpha__ +#define BSD_LABELSECTOR 0 +#define BSD_LABELOFFSET 0 +#define BSD_BBSIZE 0 +#define BSD_SBSIZE 0 +#elif defined (__powerpc__) +/* LABELSECTOR, LABELOFFSET, BBSIZE & SBSIZE are undefined for __powerpc__ */ +#define BSD_LABELSECTOR 0 +#define BSD_LABELOFFSET 0 +#define BSD_BBSIZE 0 +#define BSD_SBSIZE 0 +#else +#error unknown architecture +#endif + +struct disklabel { + u_long d_magic; /* the magic number */ + short d_type; /* drive type */ + short d_subtype; /* controller/d_type specific */ + char d_typename[16]; /* type name, e.g. "eagle" */ + /* + * d_packname contains the pack identifier and is returned when + * the disklabel is read off the disk or in-core copy. + * d_boot0 and d_boot1 are the (optional) names of the + * primary (block 0) and secondary (block 1-15) bootstraps + * as found in /usr/mdec. These are returned when using + * getdiskbyname(3) to retrieve the values from /etc/disktab. + */ +#if defined(KERNEL) || defined(STANDALONE) + char d_packname[16]; /* pack identifier */ +#else + union { + char un_d_packname[16]; /* pack identifier */ + struct { + char *un_d_boot0; /* primary bootstrap name */ + char *un_d_boot1; /* secondary bootstrap name */ + } un_b; + } d_un; +#define d_packname d_un.un_d_packname +#define d_boot0 d_un.un_b.un_d_boot0 +#define d_boot1 d_un.un_b.un_d_boot1 +#endif /* ! KERNEL or STANDALONE */ + /* disk geometry: */ + u_long d_secsize; /* # of bytes per sector */ + u_long d_nsectors; /* # of data sectors per track */ + u_long d_ntracks; /* # of tracks per cylinder */ + u_long d_ncylinders; /* # of data cylinders per unit */ + u_long d_secpercyl; /* # of data sectors per cylinder */ + u_long d_secperunit; /* # of data sectors per unit */ + /* + * Spares (bad sector replacements) below + * are not counted in d_nsectors or d_secpercyl. + * Spare sectors are assumed to be physical sectors + * which occupy space at the end of each track and/or cylinder. + */ + u_short d_sparespertrack; /* # of spare sectors per track */ + u_short d_sparespercyl; /* # of spare sectors per cylinder */ + /* + * Alternate cylinders include maintenance, replacement, + * configuration description areas, etc. + */ + u_long d_acylinders; /* # of alt. cylinders per unit */ + + /* hardware characteristics: */ + /* + * d_interleave, d_trackskew and d_cylskew describe perturbations + * in the media format used to compensate for a slow controller. + * Interleave is physical sector interleave, set up by the formatter + * or controller when formatting. When interleaving is in use, + * logically adjacent sectors are not physically contiguous, + * but instead are separated by some number of sectors. + * It is specified as the ratio of physical sectors traversed + * per logical sector. Thus an interleave of 1:1 implies contiguous + * layout, while 2:1 implies that logical sector 0 is separated + * by one sector from logical sector 1. + * d_trackskew is the offset of sector 0 on track N + * relative to sector 0 on track N-1 on the same cylinder. + * Finally, d_cylskew is the offset of sector 0 on cylinder N + * relative to sector 0 on cylinder N-1. + */ + u_short d_rpm; /* rotational speed */ + u_short d_interleave; /* hardware sector interleave */ + u_short d_trackskew; /* sector 0 skew, per track */ + u_short d_cylskew; /* sector 0 skew, per cylinder */ + u_long d_headswitch; /* head switch time, usec */ + u_long d_trkseek; /* track-to-track seek, usec */ + u_long d_flags; /* generic flags */ +#define NDDATA 5 + u_long d_drivedata[NDDATA]; /* drive-type specific information */ +#define NSPARE 5 + u_long d_spare[NSPARE]; /* reserved for future use */ + u_long d_magic2; /* the magic number (again) */ + u_short d_checksum; /* xor of data incl. partitions */ + /* filesystem and partition information: */ + u_short d_npartitions; /* number of partitions in following */ + u_long d_bbsize; /* size of boot area at sn0, bytes */ + u_long d_sbsize; /* max size of fs superblock, bytes */ + struct bsd_partition { /* the partition table */ + u_long p_size; /* number of sectors in partition */ + u_long p_offset; /* starting sector */ + u_long p_fsize; /* filesystem basic fragment size */ + u_char p_fstype; /* filesystem type, see below */ + u_char p_frag; /* filesystem fragments per block */ + u_short p_cpg; /* filesystem cylinders per group */ + } d_partitions[BSD_MAXPARTITIONS]; /* actually may be more */ +}; + +/* d_type values: */ +#define BSD_DTYPE_SMD 1 /* SMD, XSMD; VAX hp/up */ +#define BSD_DTYPE_MSCP 2 /* MSCP */ +#define BSD_DTYPE_DEC 3 /* other DEC (rk, rl) */ +#define BSD_DTYPE_SCSI 4 /* SCSI */ +#define BSD_DTYPE_ESDI 5 /* ESDI interface */ +#define BSD_DTYPE_ST506 6 /* ST506 etc. */ +#define BSD_DTYPE_HPIB 7 /* CS/80 on HP-IB */ +#define BSD_DTYPE_HPFL 8 /* HP Fiber-link */ +#define BSD_DTYPE_FLOPPY 10 /* floppy */ + +/* d_subtype values: */ +#define BSD_DSTYPE_INDOSPART 0x8 /* is inside dos partition */ +#define BSD_DSTYPE_DOSPART(s) ((s) & 3) /* dos partition number */ +#define BSD_DSTYPE_GEOMETRY 0x10 /* drive params in label */ + +#ifdef DKTYPENAMES +static char *bsd_dktypenames[] = { + "unknown", + "SMD", + "MSCP", + "old DEC", + "SCSI", + "ESDI", + "ST506", + "HP-IB", + "HP-FL", + "type 9", + "floppy", + 0 +}; +#define BSD_DKMAXTYPES (sizeof(bsd_dktypenames) / sizeof(bsd_dktypenames[0]) - 1) +#endif + +/* + * Filesystem type and version. + * Used to interpret other filesystem-specific + * per-partition information. + */ +#define BSD_FS_UNUSED 0 /* unused */ +#define BSD_FS_SWAP 1 /* swap */ +#define BSD_FS_V6 2 /* Sixth Edition */ +#define BSD_FS_V7 3 /* Seventh Edition */ +#define BSD_FS_SYSV 4 /* System V */ +#define BSD_FS_V71K 5 /* V7 with 1K blocks (4.1, 2.9) */ +#define BSD_FS_V8 6 /* Eighth Edition, 4K blocks */ +#define BSD_FS_BSDFFS 7 /* 4.2BSD fast file system */ +#define BSD_FS_MSDOS 8 /* MS-DOS file system */ +#define BSD_FS_BSDLFS 9 /* 4.4BSD log-structured file system */ +#define BSD_FS_OTHER 10 /* in use, but unknown/unsupported */ +#define BSD_FS_HPFS 11 /* OS/2 high-performance file system */ +#define BSD_FS_ISO9660 12 /* ISO-9660 filesystem (cdrom) */ +#define BSD_FS_ISOFS BSD_FS_ISO9660 +#define BSD_FS_BOOT 13 /* partition contains bootstrap */ +#define BSD_FS_ADOS 14 /* AmigaDOS fast file system */ +#define BSD_FS_HFS 15 /* Macintosh HFS */ + +#ifdef DKTYPENAMES +static struct systypes bsd_fstypes[] = { + {BSD_FS_UNUSED, "unused"}, + {BSD_FS_SWAP, "swap"}, + {BSD_FS_V6, "Version 6"}, + {BSD_FS_V7, "Version 7"}, + {BSD_FS_SYSV, "System V"}, + {BSD_FS_V71K, "4.1BSD"}, + {BSD_FS_V8, "Eighth Edition"}, + {BSD_FS_BSDFFS, "4.2BSD"}, + {BSD_FS_MSDOS, "MS-DOS"}, + {BSD_FS_BSDLFS, "4.4LFS"}, + {BSD_FS_OTHER, "unknown"}, + {BSD_FS_HPFS, "HPFS"}, + {BSD_FS_ISO9660,"ISO-9660"}, + {BSD_FS_BOOT, "boot"}, + {BSD_FS_ADOS, "ADOS"}, + {BSD_FS_HFS, "HFS"} +}; + +#define BSD_FSMAXTYPES (sizeof(bsd_fstypes) / sizeof(struct systypes)) +#endif + +/* + * flags shared by various drives: + */ +#define BSD_D_REMOVABLE 0x01 /* removable media */ +#define BSD_D_ECC 0x02 /* supports ECC */ +#define BSD_D_BADSECT 0x04 /* supports bad sector forw. */ +#define BSD_D_RAMDISK 0x08 /* disk emulator */ +#define BSD_D_CHAIN 0x10 /* can do back-back transfers */ +#define BSD_D_DOSPART 0x20 /* within MSDOS partition */ diff --git a/io.c b/io.c new file mode 100644 index 0000000..0c99d94 --- /dev/null +++ b/io.c @@ -0,0 +1,529 @@ +// +// io.c - simple io and input parsing routines +// +// 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. + */ + +#include +#ifndef __linux__ +#include +#include +#include +#endif +#include +#include +#include +#include + +#include "pdisk.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__ +#define SCSI_FD 8 +#define loff_t long +#define llseek lseek +#endif + + +// +// Types +// + + +// +// Global Constants +// +const long kDefault = -1; + + +// +// Global Variables +// +short unget_buf[UNGET_MAX_COUNT+1]; +int unget_count; + + +// +// Forward declarations +// +long get_number(int first_char); +char* get_string(int eos); +#ifndef __linux__ +int DoTestUnitReady(UInt8 targetID); +int DoRead(UInt8 targetID, UInt32 block, UInt16 count, char* addr); +int DoWrite(UInt8 targetID, UInt32 block, UInt16 count, char* addr); +#endif + + +// +// Routines +// +int +getch() +{ + if (unget_count > 0) { + return (unget_buf[--unget_count]); + } else { + return (getc(stdin)); + } +} + + +void +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 ungetch()."); + } +} + + +void +flush_to_newline(int keep_newline) +{ + int c; + + for (;;) { + c = getch(); + + if (c <= 0) { + break; + } else if (c == '\n') { + if (keep_newline) { + ungetch(c); + } + break; + } else { + // skip + } + } + return; +} + + +int +get_okay(char *prompt, int default_value) +{ + int c; + + flush_to_newline(0); + printf(prompt); + + for (;;) { + c = getch(); + + if (c <= 0) { + break; + } else if (c == ' ' || c == '\t') { + // skip blanks and tabs + } else if (c == '\n') { + 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 = 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 = getch(); + + if (c <= 0) { + break; + } else if (c == ' ' || c == '\t') { + // skip blanks and tabs + } else if (c == '\n') { + if (default_value < 0) { + printf(prompt); + } else { + ungetch(c); + *number = default_value; + result = 1; + break; + } + } else if ('0' <= c && c <= '9') { + *number = get_number(c); + result = 1; + break; + } else { + 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=getch()) == 'x' || c == 'X') { + c = getch(); + base = 16; + digit = BAD_DIGIT; + } else { + c = first_char; + base = 8; + digit = 0; + } + ret_value = 0; + for (ret_value = 0; ; c = 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; + } + ungetch(c); + return(ret_value); +} + + +int +get_string_argument(char *prompt, char **string, int reprompt) +{ + int c; + int result = 0; + + for (;;) { + c = getch(); + + if (c <= 0) { + break; + } else if (c == ' ' || c == '\t') { + // skip blanks and tabs + } else if (c == '\n') { + if (reprompt) { + printf(prompt); + } else { + 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 == '/')) { + ungetch(c); + *string = get_string(' '); + result = 1; + break; + } else { + 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 = getch(); + for (s = ret_value; ; c = 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; + ungetch(c); + break; + } else { + *s++ = c; + } + } + return(ret_value); +} + + +long +get_multiplier(long divisor) +{ + int c; + int result; + + c = getch(); + + if (c <= 0 || divisor <= 0) { + result = 0; + } 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 { + ungetch(c); + result = 1; + } + if (result > 1) { + if (result >= divisor) { + result /= divisor; + } else { + result = 1; + } + } + 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); +} + + +int +read_block(int fd, unsigned long num, char *buf, int quiet) +{ + loff_t x; + long t; + +#ifndef __linux__ + if (fd <= SCSI_FD) { + //printf("Read block %d of scsi device %d\n", num, fd); + return DoRead(fd, num, 1, buf); + } else { +#else + { +#endif + x = num * PBLOCK_SIZE; + if ((x = llseek(fd, x, 0)) < 0) { + if (quiet == 0) { + error(errno, "Can't seek on file"); + } + return 0; + } + if ((t = read(fd, buf, PBLOCK_SIZE)) != PBLOCK_SIZE) { + if (quiet == 0) { + error((t<0?errno:0), "Can't read block %u from file", num); + } + return 0; + } + return 1; + } +} + + +int +write_block(int fd, unsigned long num, char *buf) +{ + loff_t x; + long t; + + if (rflag) { + printf("Can't write block %u to file", num); + return 0; + } +#ifndef __linux__ + if (fd <= SCSI_FD) { + //printf("Write block %d of scsi device %d\n", num, fd); + return DoWrite(fd, num, 1, buf); + } else { +#else + { +#endif + x = num * PBLOCK_SIZE; + if ((x = lseek(fd, x, 0)) < 0) { + error(errno, "Can't seek on file"); + return 0; + } + if ((t = write(fd, buf, PBLOCK_SIZE)) != PBLOCK_SIZE) { + error((t<0?errno:0), "Can't write block %u to file", num); + return 0; + } + return 1; + } +} + + +int +close_device(int fildes) +{ +#ifndef __linux__ + if (fildes <= SCSI_FD) { + //printf("Close of scsi device %d\n", fildes); + return 1; + } else { +#else + { +#endif + return close(fildes); + } +} + + +int +open_device(const char *path, int oflag) +{ +#ifndef __linux__ + int id; + int fd; + DeviceIdent scsiDevice; + + if (strncmp("/dev/sd", path, 7) == 0 + && path[7] >= 'a' && path[7] <= 'g' + && path[8] == 0) { + id = path[7] - 'a'; + //printf("Open scsi device %d\n", id); + + if (DoTestUnitReady(id) > 0) { + return id; + } else { + return -1; + } + } else { +#else + { +#endif + return open(path, oflag); + } +} diff --git a/io.h b/io.h new file mode 100644 index 0000000..9561b34 --- /dev/null +++ b/io.h @@ -0,0 +1,67 @@ +// +// io.h - simple io and input parsing routines +// +// 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. + */ + + +// +// Defines +// +#define PBLOCK_SIZE 512 + + +// +// Types +// + + +// +// Global Constants +// +extern const long kDefault; + + +// +// Global Variables +// + + +// +// Forward declarations +// +void bad_input(char *fmt, ...); +int close_device(int fildes); +void flush_to_newline(int keep_newline); +int get_command(char *prompt, int promptBeforeGet, int *command); +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_string_argument(char *prompt, char **string, int reprompt); +int getch(); +int number_of_digits(unsigned long value); +int open_device(const char *path, int oflag); +int read_block(int fd, unsigned long num, char *buf, int quiet); +void ungetch(int c); +int write_block(int fd, unsigned long num, char *buf); diff --git a/list.src b/list.src new file mode 100644 index 0000000..63288c5 --- /dev/null +++ b/list.src @@ -0,0 +1,34 @@ +pdisk/DoReadWrite.c +pdisk/DoSCSICommandWithSense.c +pdisk/DoTestUnitReady.c +pdisk/HISTORY +pdisk/MacSCSICommand.h +pdisk/README +pdisk/SCSIStuff.h +pdisk/SCSI_misc.c +pdisk/bitfield.c +pdisk/bitfield.h +pdisk/convert.c +pdisk/convert.h +pdisk/dpme.h +pdisk/dump.c +pdisk/dump.h +pdisk/errors.c +pdisk/errors.h +pdisk/io.c +pdisk/io.h +pdisk/list.src +pdisk/makefile +pdisk/partition_map.c +pdisk/partition_map.h +pdisk/pdisk.8 +pdisk/pdisk.c +pdisk/pdisk.h +pdisk/pdisk.r +pdisk/version.h +pdisk/pdisk.mac.bin + +pdisk/fdisk.c +pdisk/fdisk.h +pdisk/fdisklabel.c +pdisk/fdisklabel.h diff --git a/partition_map.c b/partition_map.c new file mode 100644 index 0000000..113f66b --- /dev/null +++ b/partition_map.c @@ -0,0 +1,1061 @@ +// +// partition_map.c - partition map routines +// +// 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. + */ + +#include +#ifndef __linux__ +#include +#include +#endif +#include +#include + +#include +#ifdef __linux__ +#include +#include +#include +#include +#endif + +#include "partition_map.h" +#include "pdisk.h" +#include "convert.h" +#include "io.h" +#include "errors.h" + + +// +// Defines +// +// #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 * kFreeName = "Extra"; + +enum add_action { + kReplace = 0, + kAdd = 1, + kSplit = 2 +}; + +// +// Global Variables +// + + +// +// Forward declarations +// +int add_data_to_map(struct dpme *data, long index, partition_map_header *map); +void coerce_block0(partition_map_header *map); +int contains_driver(partition_map *entry); +void combine_entry(partition_map *entry); +long compute_device_size(int fd); +DPME* create_data(const char *name, const char *dptype, u32 base, u32 length); +partition_map_header* create_partition_map(char *name); +void delete_entry(partition_map *entry); +void insert_in_base_order(partition_map *entry); +void insert_in_disk_order(partition_map *entry); +int read_partition_map(partition_map_header *map); +void remove_from_disk_order(partition_map *entry); +void renumber_disk_addresses(partition_map_header *map); + + +// +// Routines +// +partition_map_header * +open_partition_map(char *name, int *valid_file) +{ + int fd; + partition_map_header * map; + int writeable; + unsigned long length; +#ifdef __linux__ + struct stat info; +#endif + + fd = open_device(name, (rflag)?O_RDONLY:O_RDWR); + if (fd < 0) { + fd = open_device(name, O_RDONLY); + if (fd < 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_device(fd); + return NULL; + } + map->fd = fd; + map->name = name; + map->writeable = (rflag)?0:writeable; + map->changed = 0; + map->disk_order = NULL; + map->base_order = NULL; + map->blocks_in_map = 0; + map->maximum_in_map = -1; + map->media_size = compute_device_size(fd); + +#ifdef __linux__ + if (fstat(fd, &info) < 0) { + error(errno, "can't stat file '%s'", name); + map->regular_file = 0; + } else { + map->regular_file = S_ISREG(info.st_mode); + } +#else + map->regular_file = 0; +#endif + + map->misc = (Block0 *) malloc(PBLOCK_SIZE); + if (map->misc == NULL) { + error(errno, "can't allocate memory for block zero buffer"); + } else if (read_block(fd, 0, (char *)map->misc, 0) == 0 + || convert_block0(map->misc, 1)) { + // if I can't read block 0 I might as well give up + } else if (read_partition_map(map) < 0) { + // some sort of failure reading the map + } else { + // got it! + coerce_block0(map); + 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_device(map->fd); + free(map); +} + + +int +read_partition_map(partition_map_header *map) +{ + DPME *data; + u32 limit; + int index; + + data = (DPME *) malloc(PBLOCK_SIZE); + if (data == NULL) { + error(errno, "can't allocate memory for disk buffers"); + return -1; + } + + if (read_block(map->fd, 1, (char *)data, 0) == 0) { + free(data); + return -1; + } else if (convert_dpme(data, 1) + || data->dpme_signature != DPME_SIGNATURE) { + free(data); + return -1; + } else { + 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->fd, index, (char *)data, 0) == 0) { + free(data); + return -1; + } else if (convert_dpme(data, 1) + || data->dpme_signature != DPME_SIGNATURE + || data->dpme_map_entries != limit) { + free(data); + return -1; + } + } + } + return 0; +} + + +void +write_partition_map(partition_map_header *map) +{ + int fd; + char *block; + partition_map * entry; + int i; + int saved_errno; + + fd = map->fd; + if (map->misc != NULL) { + convert_block0(map->misc, 0); + write_block(fd, 0, (char *)map->misc); + convert_block0(map->misc, 1); + } else { + block = (char *) calloc(1, PBLOCK_SIZE); + if (block != NULL) { + write_block(fd, 0, block); + free(block); + } + } + for (entry = map->disk_order; entry != NULL; entry = entry->next_on_disk) { + convert_dpme(entry->data, 0); + write_block(fd, entry->disk_address, (char *)entry->data); + convert_dpme(entry->data, 1); + i = entry->disk_address; + } + // 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(fd, i, block, 1)) { + block[0] = 0; + write_block(fd, i, block); + } + free(block); + } + } + printf("The partition table has been altered!\n\n"); + +#ifdef __linux__ + if (map->regular_file) { + close_device(map->fd); + } else { + // printf("Calling ioctl() to re-read partition table.\n" + // "(Reboot to ensure the partition table has been updated.)\n"); + sync(); + sleep(2); + if ((i = ioctl(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(fd, BLKRRPART)) != 0) { + saved_errno = errno; + } + } + close_device(map->fd); + + // 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"); + } + } +#else + close_device(map->fd); +#endif + map->fd = open_device(map->name, (map->writeable)?O_RDWR:O_RDONLY); + if (map->fd < 0) { + fatal(errno, "can't re-open file '%s' for %sing", map->name, + (rflag)?"read":"writ"); + } + +} + + +int +add_data_to_map(struct dpme *data, long index, partition_map_header *map) +{ + partition_map *entry; + + 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; + + insert_in_disk_order(entry); + insert_in_base_order(entry); + + map->blocks_in_map++; + if (map->maximum_in_map < 0) { + if (strncmp(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); + 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) +{ + int fd; + partition_map_header * map; + unsigned long length; + DPME *data; + int ok; + unsigned long number; +#ifdef __linux__ + struct stat info; +#endif + + fd = open_device(name, (rflag)?O_RDONLY:O_RDWR); + if (fd < 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_device(fd); + return NULL; + } + map->fd = fd; + map->name = name; + map->writeable = (rflag)?0:1; + map->changed = 0; + map->disk_order = NULL; + map->base_order = NULL; + map->blocks_in_map = 0; + map->maximum_in_map = -1; + + number = compute_device_size(fd); + printf("size of 'device' is %u blocks: ", number); + flush_to_newline(0); + get_number_argument("what should be the size? ", (long *)&number, number); + if (number < 4) { + number = 4; + } + printf("new size of 'device' is %u blocks\n", number); + map->media_size = number; + +#ifdef __linux__ + if (fstat(fd, &info) < 0) { + error(errno, "can't stat file '%s'", name); + map->regular_file = 0; + } else { + map->regular_file = S_ISREG(info.st_mode); + } +#else + map->regular_file = 0; +#endif + + map->misc = (Block0 *) malloc(PBLOCK_SIZE); + if (map->misc == NULL) { + error(errno, "can't allocate memory for block zero buffer"); + } else { + // got it! + 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 { + map->changed = 1; + coerce_block0(map); + return map; + } + } + } + close_partition_map(map); + return NULL; +} + + +void +coerce_block0(partition_map_header *map) +{ + Block0 *p; + + p = map->misc; + if (p == NULL) { + return; + } + if (p->sbSig != BLOCK0_SIGNATURE) { + p->sbSig = BLOCK0_SIGNATURE; + p->sbBlkSize = 512; + p->sbBlkCount = map->media_size; + p->sbDevType = 0; + p->sbDevId = 0; + p->sbData = 0; + p->sbDrvrCount = 0; + } +} + + +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; + u32 adjusted_length; + u32 new_base; + u32 new_length; + + // 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 + || strncmp(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; + 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(int fd) +{ +#ifdef TEST_COMPUTE + unsigned long length; + struct hd_geometry geometry; + struct stat info; + loff_t pos; +#endif + char* data; + unsigned long l, r, x; + int valid; + +#ifdef TEST_COMPUTE + 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/PBLOCK_SIZE); + } + + 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, 0, SEEK_END)) < 0) { + printf("llseek to end of device failed\n"); + } else if ((pos = llseek(fd, 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/PBLOCK_SIZE); + } +#endif + + 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(fd, r, data, 1) != 0) { + l = r; + if (r <= 1024) { + r = r * 1024; + } else { + r = r * 2; + } + if (r >= (1024*1024*1024)) { + break; + } + } + // binary search for end + while (l <= r) { + x = (l + r) / 2; + if ((valid = read_block(fd, x, data, 1)) != 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 +delete_partition_from_map(partition_map *entry) +{ + partition_map_header *map; + DPME *data; + + if (strncmp(entry->data->dpme_type, kMapType, DPISTRLEN) == 0) { + printf("Can't delete entry for the map itself\n"); + return; + } + if (contains_driver(entry)) { + printf("Can't delete entry for a driver (yet).\n"); + return; + } + data = create_data(kFreeName, kFreeType, + entry->data->dpme_pblock_start, entry->data->dpme_pblocks); + if (data == NULL) { + return; + } + 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; + + map = entry->the_map; + p = map->misc; + if (p == NULL) { + return 0; + } + if (p->sbSig != BLOCK0_SIGNATURE) { + return 0; + } + if (p->sbDrvrCount > 0) { + m = (DDMap *) p->sbMap; + for (i = 0; i < p->sbDrvrCount; i++) { + if (entry->data->dpme_pblock_start <= m[i].ddBlock + && (m[i].ddBlock + 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; + + if (entry == NULL + || strncmp(entry->data->dpme_type, kFreeType, DPISTRLEN) != 0) { + return; + } + if (entry->next_by_base != NULL) { + p = entry->next_by_base; + if (strncmp(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) + } 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 (strncmp(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) + } 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); + } + } +} + + +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; +} + + +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 = map->base_order; + while (entry != NULL) { + if (strncmp(entry->data->dpme_type, kMapType, DPISTRLEN) == 0) { + break; + } + entry = entry->next_by_base; + } + 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 + || strncmp(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; + } + entry->data->dpme_type[0] = 0; + delete_partition_from_map(entry); + add_partition_to_map("Apple", kMapType, 1, new_size, map); + return; + } + + // make it larger + if (next == NULL + || strncmp(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; + } + entry->data->dpme_type[0] = 0; + delete_partition_from_map(entry); + add_partition_to_map("Apple", kMapType, 1, new_size, map); +} diff --git a/partition_map.h b/partition_map.h new file mode 100644 index 0000000..90f2210 --- /dev/null +++ b/partition_map.h @@ -0,0 +1,92 @@ +// +// partition_map.h - partition map 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. + */ + +#include "dpme.h" + + +// +// Defines +// + + +// +// Types +// +struct partition_map_header { + int fd; + char *name; + struct partition_map * disk_order; + struct partition_map * base_order; + Block0 *misc; + int writeable; + int changed; + int regular_file; + int blocks_in_map; + int maximum_in_map; + unsigned long media_size; +}; +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; + 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 * kFreeName; + + +// +// Global Variables +// + + +// +// 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); +void delete_partition_from_map(partition_map *entry); +partition_map* find_entry_by_disk_address(long index, 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); +void resize_map(long new_size, partition_map_header *map); +void write_partition_map(partition_map_header *map); diff --git a/pdisk.8 b/pdisk.8 new file mode 100644 index 0000000..01eaa81 --- /dev/null +++ b/pdisk.8 @@ -0,0 +1,182 @@ +.TH PDISK 8 "20 December 1996" "MkLinux DR2" "Linux Programmer's Manual" +.SH NAME +pdisk \- Apple partition table editor for Linux +.SH SYNOPSIS +.B pdisk +.B "[\-h|\--help] [\-v|\--version] [\-l|\--list [name ...]]" +.br +.B pdisk +.B "[\-r|\--readonly]" +device ... +.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 \-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. +.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 +C (create with type also specified) +d delete a partition +r reorder partition entry in map +w write the partition table +q quit without saving 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 +.B C +command is identical to the +.B c +command, with the addition of a partition type argument after the +other arguments. + +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/pdisk.c b/pdisk.c new file mode 100644 index 0000000..52f98c7 --- /dev/null +++ b/pdisk.c @@ -0,0 +1,711 @@ +// +// pdisk - an editor for Apple format partition tables +// +// Written by Eryk Vershen (eryk@apple.com) +// +// Still under development (as of 20 Dec 1996) +// + +/* + * 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 +#ifdef __linux__ +#include +#else +#include +#include +#include +#endif +#include +#include + +#ifdef __linux__ +#include +#include +#include +#endif + +#include "pdisk.h" +#include "io.h" +#include "errors.h" +#include "partition_map.h" +#include "dump.h" +#include "version.h" + + +// +// Defines +// +#define ARGV_CHUNK 5 +#ifdef __linux__ +#define std_main main +#endif + + +// +// Types +// + + +// +// Global Constants +// +enum getopt_values { + kLongOption = 0, + kBadOption = '?', + kOptionArg = 1000, + kListOption = 1001 +}; + + +// +// Global Variables +// +int lflag; +char *lfile; +int vflag; +int hflag; +int dflag; +int rflag; + + +// +// Forward declarations +// +void do_add_intel_partition(partition_map_header *map); +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); +int do_expert(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 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 print_notes(); + + +// +// Routines +// +#ifdef __linux__ +int +main(int argc, char **argv) +{ + int name_index; + + 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); + } + + name_index = get_options(argc, argv); + + if (vflag) { + printf("version " VERSION " (" RELEASE_DATE ")\n"); + } + if (hflag) { + do_help(); + } 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++]); + } + } else if (!vflag) { + usage("no device argument"); + do_help(); + } +} +#else +main() +{ + char *name; + int command; + int first = 1; + + printf("This app uses the SIOUX console library\n"); + printf("Choose 'Quit' from the file menu to quit.\n\n"); + printf("Use MkLinux style disk names (i.e. /dev/sda, /dev/sdb, 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 ... */ + + 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); + } + init_program_name(NULL); + + while (get_command("Top level command (? for help): ", first, &command)) { + first = 0; + + switch (command) { + case '?': + print_notes(); + 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(" r toggle readonly flag\n"); + printf(" q quit the program\n"); + break; + case 'Q': + case 'q': + goto finis; + 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); + break; + case 'E': + case 'e': + if (get_string_argument("Name of device: ", &name, 1) == 0) { + bad_input("Bad name"); + break; + } + edit(name); + break; + case 'R': + case 'r': + if (rflag) { + rflag = 0; + } else { + rflag = 1; + } + printf("Now in %s mode.\n", (rflag)?"readonly":"read/write"); + break; + default: + bad_input("No such command (%c)", command); + break; + } + } +finis: + + printf("Processing stopped: Choose 'Quit' from the file menu to quit.\n\n"); +} +#endif + + +#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'}, + {0, 0, 0, 0} + }; + int option_index = 0; + extern int optind; + extern char *optarg; + int flag = 0; + + init_program_name(argv); + + lflag = 0; + lfile = NULL; + vflag = 0; + hflag = 0; + dflag = 0; + rflag = 0; + + optind = 0; // reset option scanner logic + while ((c = getopt_long(argc, argv, "hlvdr", long_options, + &option_index)) >= 0) { + switch (c) { + case kLongOption: + // option_index would be used here + break; + case 'h': + hflag = 1; + break; + case kListOption: + if (optarg != NULL) { + lfile = optarg; + } + // fall through + case 'l': + lflag = 1; + break; + case 'v': + vflag = 1; + break; + case 'd': + dflag = 1; + break; + case 'r': + rflag = 1; + break; + case kBadOption: + default: + flag = 1; + break; + } + } + if (flag) { + usage("bad arguments"); + } + return optind; +} +#endif + +// +// Edit the file +// +void +edit(char *name) +{ + partition_map_header *map; + int command; +#ifdef __linux__ + int first = 1; +#else + int first = 0; +#endif + int order; + int get_type; + int valid_file; + + map = open_partition_map(name, &valid_file); + if (!valid_file) { + return; + } + + printf("%s\n", name); + + while (get_command("Command (? for help): ", first, &command)) { + first = 0; + order = 1; + get_type = 0; + + switch (command) { + case '?': + print_notes(); + 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\n"); + printf(" C (create with type also specified)\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 '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)) { + flush_to_newline(0); + goto finis; + } + break; + case 'W': + case 'w': + if (!rflag) { + do_write_partition_map(map); + 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; + long mult; + 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); + + } else if (get_string_argument("Type of partition: ", &type_name, 1) == 0) { + bad_input("Bad type"); + return; + } else { + if (strncmp(type_name, kFreeType, DPISTRLEN) == 0) { + bad_input("Can't create a partition with the Free type"); + return; + } + if (strncmp(type_name, kMapType, DPISTRLEN) == 0) { + bad_input("Can't create a partition with the Map type"); + return; + } + add_partition_to_map(name, type_name, base, length, map); + } +} + + +int +get_base_argument(long *number, partition_map_header *map) +{ + partition_map * entry; + int c; + int result = 0; + + if (get_number_argument("First block: ", number, kDefault) == 0) { + bad_input("Bad block number"); + } else { + result = 1; + c = getch(); + + if (c == 'p' || c == 'P') { + 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; + } + } else if (c > 0) { + ungetch(c); + } + } + return result; +} + + +int +get_size_argument(long *number, partition_map_header *map) +{ + partition_map * entry; + int c; + int result = 0; + long multiple; + + if (get_number_argument("Length in blocks: ", number, kDefault) == 0) { + bad_input("Bad length"); + } else { + result = 1; + multiple = get_multiplier(PBLOCK_SIZE); + if (multiple != 1) { + *number *= multiple; + } else { + c = getch(); + + if (c == 'p' || c == 'P') { + entry = find_entry_by_disk_address(*number, map); + if (entry == NULL) { + bad_input("Bad partition number"); + result = 0; + } else { + *number = entry->data->dpme_pblocks; + } + } else if (c > 0) { + ungetch(c); + } + } + } + return result; +} + + +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) +{ + partition_map * cur; + 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); +} + +int +do_expert(partition_map_header *map) +{ + int command; + int first = 0; + int quit = 0; + + while (get_command("Expert command (? for help): ", first, &command)) { + first = 0; + + switch (command) { + case '?': + print_notes(); + case 'H': + case 'h': + printf("Commands are:\n"); + printf(" h print help\n"); + printf(" x return to main menu\n"); + printf(" p print the partition table\n"); + if (dflag) { + printf(" P (show data structures - debugging)\n"); + } + printf(" s change size of partition map\n"); + if (!rflag) { + printf(" w write the partition table\n"); + } + printf(" q quit without saving changes\n"); + break; + case 'X': + case 'x': + flush_to_newline(1); + goto finis; + break; + case 'Q': + case 'q': + quit = 1; + goto finis; + break; + case 'S': + case 's': + do_change_map_size(map); + break; + case 'P': + if (dflag) { + show_data_structures(map); + break; + } + // fall through + case 'p': + dump_partition_map(map, 1); + break; + case 'W': + case 'w': + if (!rflag) { + do_write_partition_map(map); + break; + } + default: + 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 +print_notes() +{ + printf("Notes:\n"); + printf(" Base and length fields are blocks, which are 512 bytes long.\n"); + printf(" The name of a partition is descriptive text.\n"); + printf("\n"); +} diff --git a/pdisk.h b/pdisk.h new file mode 100644 index 0000000..b1f9e3b --- /dev/null +++ b/pdisk.h @@ -0,0 +1,53 @@ +// +// 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. + */ + + +// +// Defines +// + + +// +// Types +// + + +// +// Global Constants +// + + +// +// Global Variables +// +extern int rflag; +extern int hflag; + + +// +// Forward declarations +// diff --git a/pdisk.r b/pdisk.r new file mode 100644 index 0000000..1e42dbb --- /dev/null +++ b/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 (%02d%02d%02d)\n" + "© 1992-%4d Apple Computer Inc. All Rights Reserved", + VERSION, $$year % 100, $$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/version.h b/version.h new file mode 100644 index 0000000..c461831 --- /dev/null +++ b/version.h @@ -0,0 +1,78 @@ +/* + * 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. + */ + + +/* + * 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.4a2" +#define RELEASE_DATE "15 January 1997" + +#define kVersionMajor 0x00 /* ie. N has two BCD digits */ +#define kVersionMinor 0x4 /* 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 0x02 /* ie. Z has two BCD digits */ + + +/* + * Types + */ + + +/* + * Global Constants + */ + + +/* + * Global Variables + */ + + +/* + * Forward declarations + */ -- 2.38.5