--- /dev/null
+/*
+ * 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;
+}
+
+
+
--- /dev/null
+/*
+ * 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));
+}
--- /dev/null
+/*
+ * 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 <stdio.h>
+#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;
+}
+
+
+
--- /dev/null
+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)
--- /dev/null
+/*
+ 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__ */
--- /dev/null
+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
+
--- /dev/null
+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
--- /dev/null
+/*
+ * 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 <SCSI.h>
+
+#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__ */
--- /dev/null
+/*
+ * 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;
+ }
+}
--- /dev/null
+//
+// 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);
+}
--- /dev/null
+//
+// 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);
--- /dev/null
+//
+// 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 <stdio.h>
+
+#ifdef __linux__
+#include <endian.h>
+#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;
+}
--- /dev/null
+//
+// 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);
--- /dev/null
+//
+// 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
+//
--- /dev/null
+//
+// 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 <stdio.h>
+#ifndef __linux__
+#include <stdlib.h>
+#include <unistd.h>
+#endif
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#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");
+ }
+}
+
+
--- /dev/null
+//
+// 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);
--- /dev/null
+//
+// 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 <stdio.h>
+#ifndef __linux__
+#include <stdlib.h>
+#endif
+#include <string.h>
+#include <stdarg.h>
+
+#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
+}
--- /dev/null
+//
+// 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);
--- /dev/null
+/* 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 <quinlan@yggdrasil.com>), 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 <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <setjmp.h>
+#include <errno.h>
+#include <endian.h>
+
+#include <sys/ioctl.h>
+
+#include <linux/genhd.h>
+#include <linux/hdreg.h>
+#include <linux/fs.h>
+
+#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();
+ }
+ }
+}
--- /dev/null
+/*
+ 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);
--- /dev/null
+/*
+ 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 <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <ctype.h>
+#include <setjmp.h>
+#include <errno.h>
+
+#include <sys/ioctl.h>
+#include <sys/param.h>
+
+#include <linux/genhd.h>
+#include <linux/hdreg.h>
+#include <linux/fs.h>
+
+#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__ */
--- /dev/null
+/*
+ * 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 */
--- /dev/null
+//
+// 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 <stdio.h>
+#ifndef __linux__
+#include <stdlib.h>
+#include <fcntl.h>
+#include <SCSI.h>
+#endif
+#include <unistd.h>
+#include <string.h>
+#include <stdarg.h>
+#include <errno.h>
+
+#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);
+ }
+}
--- /dev/null
+//
+// 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);
--- /dev/null
+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
--- /dev/null
+//
+// 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 <stdio.h>
+#ifndef __linux__
+#include <stdlib.h>
+#include <unistd.h>
+#endif
+#include <string.h>
+#include <errno.h>
+
+#include <fcntl.h>
+#ifdef __linux__
+#include <sys/ioctl.h>
+#include <linux/fs.h>
+#include <linux/hdreg.h>
+#include <sys/stat.h>
+#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);
+}
--- /dev/null
+//
+// 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);
--- /dev/null
+.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)
--- /dev/null
+//
+// 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 <stdio.h>
+#ifdef __linux__
+#include <getopt.h>
+#else
+#include <stdlib.h>
+#include <unistd.h>
+#include <SIOUX.h>
+#endif
+#include <string.h>
+#include <errno.h>
+
+#ifdef __linux__
+#include <sys/ioctl.h>
+#include <linux/fs.h>
+#include <linux/hdreg.h>
+#endif
+
+#include "pdisk.h"
+#include "io.h"
+#include "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");
+}
--- /dev/null
+//
+// 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
+//
--- /dev/null
+/*
+ * 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"
+};
+
--- /dev/null
+/*
+ * 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
+ */