From: Michael McMaster Date: Tue, 10 Sep 2013 01:17:30 +0000 (+1000) Subject: Original version from ftp.mklinux.apple.com:/pub/Other_Tools/ X-Git-Tag: MKLINUX^0 X-Git-Url: http://git.codesrc.com/gitweb.cgi?a=commitdiff_plain;h=e78ccc1747f815dba33fd27c22dac24b17a1cce7;p=hfdisk.git Original version from ftp.mklinux.apple.com:/pub/Other_Tools/ --- e78ccc1747f815dba33fd27c22dac24b17a1cce7 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 + */