]> localhost Git - hfdisk.git/commitdiff
Original version from ftp.mklinux.apple.com:/pub/Other_Tools/ MKLINUX
authorMichael McMaster <michael@codesrc.com>
Tue, 10 Sep 2013 01:17:30 +0000 (11:17 +1000)
committerMichael McMaster <michael@codesrc.com>
Tue, 10 Sep 2013 01:17:30 +0000 (11:17 +1000)
32 files changed:
DoReadWrite.c [new file with mode: 0644]
DoSCSICommandWithSense.c [new file with mode: 0644]
DoTestUnitReady.c [new file with mode: 0644]
HISTORY [new file with mode: 0644]
MacSCSICommand.h [new file with mode: 0644]
Makefile [new file with mode: 0644]
README [new file with mode: 0644]
SCSIStuff.h [new file with mode: 0644]
SCSI_misc.c [new file with mode: 0644]
bitfield.c [new file with mode: 0644]
bitfield.h [new file with mode: 0644]
convert.c [new file with mode: 0644]
convert.h [new file with mode: 0644]
dpme.h [new file with mode: 0644]
dump.c [new file with mode: 0644]
dump.h [new file with mode: 0644]
errors.c [new file with mode: 0644]
errors.h [new file with mode: 0644]
fdisk.c [new file with mode: 0644]
fdisk.h [new file with mode: 0644]
fdisklabel.c [new file with mode: 0644]
fdisklabel.h [new file with mode: 0644]
io.c [new file with mode: 0644]
io.h [new file with mode: 0644]
list.src [new file with mode: 0644]
partition_map.c [new file with mode: 0644]
partition_map.h [new file with mode: 0644]
pdisk.8 [new file with mode: 0644]
pdisk.c [new file with mode: 0644]
pdisk.h [new file with mode: 0644]
pdisk.r [new file with mode: 0644]
version.h [new file with mode: 0644]

diff --git a/DoReadWrite.c b/DoReadWrite.c
new file mode 100644 (file)
index 0000000..d3a0c56
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ * Copyright 1993-97 by Apple Computer, Inc.
+ *              All Rights Reserved 
+ *  
+ * Permission to use, copy, modify, and distribute this software and 
+ * its documentation for any purpose and without fee is hereby granted, 
+ * provided that the above copyright notice appears in all copies and 
+ * that both the copyright notice and this permission notice appear in 
+ * supporting documentation. 
+ *  
+ * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE 
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
+ * FOR A PARTICULAR PURPOSE. 
+ *  
+ * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR 
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, 
+ * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION 
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 
+ */
+#include "SCSIStuff.h"
+int DoRead(UInt8 targetID, UInt32 block, UInt16 count, char* addr);
+int DoWrite(UInt8 targetID, UInt32 block, UInt16 count, char* addr);
+
+int
+DoRead(
+       UInt8               targetID,
+       UInt32              block,
+       UInt16              count,
+       char *              addr
+    )
+{
+    OSErr                   status;
+    Str255                  errorText;
+    char*       msg;
+    static SCSI_10_Byte_Command gReadCommand = {
+       kScsiCmdRead10, 0, 0, 0, 0, 0, 0, 0, 0, 0
+    };
+    SCSI_Sense_Data         senseData;
+    DeviceIdent scsiDevice;
+    int rtn_value;
+
+    scsiDevice.diReserved = 0;
+    scsiDevice.bus = kOriginalSCSIBusAdaptor;
+    scsiDevice.targetID = targetID;
+    scsiDevice.LUN = 0;
+
+    gReadCommand.lbn4 = (block >> 24) & 0xFF;
+    gReadCommand.lbn3 = (block >> 16) & 0xFF;
+    gReadCommand.lbn2 = (block >> 8) & 0xFF;
+    gReadCommand.lbn1 = block & 0xFF;
+
+    gReadCommand.len2 = (count >> 8) & 0xFF;
+    gReadCommand.len1 = count & 0xFF;
+
+    status = DoSCSICommand(
+                           scsiDevice,
+                           "\pRead",
+                           (SCSI_CommandPtr) &gReadCommand,
+                           (Ptr) addr,
+                           count * 512,
+                           scsiDirectionIn,
+                           NULL,
+                           &senseData,
+                           errorText
+           );
+    if (status == noErr) {
+       rtn_value = 1;
+    } else {
+       rtn_value = 0;
+    }
+    return rtn_value;
+}
+
+int
+DoWrite(
+       UInt8               targetID,
+       UInt32              block,
+       UInt16              count,
+       char *              addr
+    )
+{
+    OSErr                   status;
+    Str255                  errorText;
+    char*       msg;
+    static SCSI_10_Byte_Command gWriteCommand = {
+       kScsiCmdWrite10, 0, 0, 0, 0, 0, 0, 0, 0, 0
+    };
+    SCSI_Sense_Data         senseData;
+    DeviceIdent scsiDevice;
+    int rtn_value;
+
+    scsiDevice.diReserved = 0;
+    scsiDevice.bus = 0xff;
+    scsiDevice.targetID = targetID;
+    scsiDevice.LUN = 0;
+
+    gWriteCommand.lbn4 = (block >> 24) & 0xFF;
+    gWriteCommand.lbn3 = (block >> 16) & 0xFF;
+    gWriteCommand.lbn2 = (block >> 8) & 0xFF;
+    gWriteCommand.lbn1 = block & 0xFF;
+
+    gWriteCommand.len2 = (count >> 8) & 0xFF;
+    gWriteCommand.len1 = count & 0xFF;
+
+    status = DoSCSICommand(
+                           scsiDevice,
+                           "\pWrite",
+                           (SCSI_CommandPtr) &gWriteCommand,
+                           (Ptr) addr,
+                           count * 512,
+                           scsiDirectionOut,
+                           NULL,
+                           &senseData,
+                           errorText
+           );
+    if (status == noErr) {
+       rtn_value = 1;
+    } else {
+       rtn_value = 0;
+    }
+    return rtn_value;
+}
+
+
+
diff --git a/DoSCSICommandWithSense.c b/DoSCSICommandWithSense.c
new file mode 100644 (file)
index 0000000..0a27e0f
--- /dev/null
@@ -0,0 +1,576 @@
+/*
+ * DoScsiCommand.c
+ *
+ * This is the common entry to the original and asynchronous SCSI Manager calls:
+ * if the asynchronous SCSI Manager is requested, it calls it. Otherwise, it
+ * calls the original SCSI Manager and executes Request Sense if necessary.
+ *
+ * This function returns "autosense" in the SCSI_Sense_Data area. This will
+ * be formatted in the senseMessage string.
+ */
+
+/*
+ * Copyright 1992, 1993, 1997 by Apple Computer, Inc.
+ *              All Rights Reserved 
+ *  
+ * Permission to use, copy, modify, and distribute this software and 
+ * its documentation for any purpose and without fee is hereby granted, 
+ * provided that the above copyright notice appears in all copies and 
+ * that both the copyright notice and this permission notice appear in 
+ * supporting documentation. 
+ *  
+ * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE 
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
+ * FOR A PARTICULAR PURPOSE. 
+ *  
+ * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR 
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, 
+ * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION 
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 
+ */
+#include "SCSIStuff.h"
+
+OSErr                       OriginalSCSI(
+       DeviceIdent             scsiDevice,
+       const SCSI_CommandPtr   scsiCommand,
+       UInt8                   scsiCommandLen,
+       Ptr                     dataBuffer,
+       ByteCount               dataLength,
+       UInt32                  scsiFlags,
+       ByteCount               *actualTransferCount,
+       UInt8                   *scsiStatusByte
+    );
+UInt16                      GetCommandLength(
+       const SCSI_CommandPtr   cmdPtr
+    );
+/*
+ * This is the maximum number of times we try to grab the SCSI Bus
+ */
+#define kMaxSCSIRetries         40                  /* 10 seconds, 4 times/sec  */
+#define kSCSICommandTimeout     (5 * 1000L)         /* Five seconds             */
+
+/*
+ * This test is TRUE if the SCSI bus status indicates "busy" (which is the case
+ * if either the BSY or SEL bit is set).
+ */
+#ifndef kScsiStatBSY
+#define kScsiStatBSY            (1 << 6)
+#endif
+#ifndef kScsiStatSEL
+#define kScsiStatSEL            (1 << 1)
+#endif
+#define ScsiBusBusy()       ((SCSIStat() & (kScsiStatBSY | kScsiStatSEL)) != 0)
+Boolean                     IsVirtualMemoryRunning(void);
+
+/*
+ * This returns TRUE if the command failed with "Illegal Request." We need this
+ * so we can ignore LogSense or ReadDefectData if the device doesn't support
+ * these functions.
+ */
+Boolean
+IsIllegalRequest(
+       OSErr                   scsiStatus,
+       const SCSI_Sense_Data   *senseDataPtr
+    )
+{
+       Boolean                 result;
+#define SENSE   (*senseDataPtr)
+
+       result = FALSE;
+       if (scsiStatus == scsiNonZeroStatus
+        && (SENSE.senseKey & kScsiSenseKeyMask) == kScsiSenseIllegalReq
+        && SENSE.additionalSenseLength >= 4) {
+           switch ((SENSE.additionalSenseCode << 8) | SENSE.additionalSenseQualifier) {
+           case 0x0000:
+           case 0x2000:
+           case 0x2022:    /* Obsolete */
+               result = TRUE;
+               break;
+           default:
+               break;
+           }
+       }
+       return (result);
+#undef SENSE
+}
+
+/*
+ * This returns TRUE if the command failed with Device Not Ready (No Media Present)
+ */
+Boolean
+IsNoMedia(
+       OSErr                   scsiStatus,
+       const SCSI_Sense_Data   *senseDataPtr
+    )
+{
+       Boolean                 result;
+#define SENSE   (*senseDataPtr)
+
+       result = FALSE;
+       if (scsiStatus == scsiNonZeroStatus
+        && (SENSE.senseKey & kScsiSenseKeyMask) == kScsiSenseNotReady
+        && SENSE.additionalSenseLength >= 4) {
+           switch ((SENSE.additionalSenseCode << 8) | SENSE.additionalSenseQualifier) {
+           case 0x0000:
+           case 0x3A00:
+               result = TRUE;
+               break;
+           default:
+               break;
+           }
+       }
+       return (result);
+#undef SENSE
+}
+
+OSErr
+DoOriginalSCSICommand(
+       DeviceIdent             scsiDevice,
+       const SCSI_CommandPtr   theSCSICommand,
+       unsigned short          cmdBlockLength,
+       Ptr                     dataBuffer,
+       ByteCount               dataLength,
+       UInt32                  scsiFlags,
+       ByteCount               *actualTransferCount,
+       SCSI_Sense_Data         *sensePtr
+    );
+
+/*
+ * Do one SCSI Command. If the device returns Check Condition, issue Request Sense
+ * (original SCSI Manager only) and interpret the sense data. The original SCSI
+ * command status is in SCB.status. If it is statusErr or scsiNonZeroStatus,
+ * the sense data is in SCB.sense and the Request Sense status is in
+ * SCB.requestSenseStatus.
+ *
+ * If sensePtr[0] is non-zero, there is a message.
+ */
+OSErr
+DoSCSICommand(
+       DeviceIdent             scsiDevice,
+       ConstStr255Param        currentAction,
+       const SCSI_CommandPtr   callerSCSICommand,
+       Ptr                     dataBuffer,
+       ByteCount               dataLength,
+       UInt32                  scsiFlags,
+       ByteCount               *actualTransferCount,
+       SCSI_Sense_Data         *sensePtr,
+       StringPtr               senseMessage
+    )
+{
+       OSErr                   status;
+       SCSI_Command            theSCSICommand;
+       unsigned short          cmdBlockLength;
+               
+//      SpinSpinner(&gCurrentInfoPtr->spinnerRecord);
+//      ShowProgressAction(currentAction);
+       /*
+        * Store the LUN information in the command block - this is needed
+        * for devices that only examine the command block for LUN values.
+        * (On SCSI-II, the asynchronous SCSI Manager also includes the
+        * LUN in the identify message).
+        */
+       theSCSICommand = *callerSCSICommand;
+       theSCSICommand.scsi[1] &= ~0xE0;
+       theSCSICommand.scsi[1] |= (scsiDevice.LUN & 0x03) << 5;
+       cmdBlockLength = GetCommandLength(&theSCSICommand);
+       if (senseMessage != NULL)
+           senseMessage[0] = 0;
+       if (sensePtr != NULL)
+           sensePtr->errorCode = 0;
+       if (scsiDevice.bus == kOriginalSCSIBusAdaptor) {
+           status = DoOriginalSCSICommand(
+                       scsiDevice,
+                       &theSCSICommand,
+                       cmdBlockLength,
+                       dataBuffer,
+                       dataLength,
+                       scsiFlags,
+                       actualTransferCount,
+                       sensePtr
+                   );
+       }
+       else {
+           ClearMemory(gSCSIExecIOPBPtr, gSCSIExecIOPBPtrLen);
+#define PB  (*gSCSIExecIOPBPtr)
+           PB.scsiPBLength = gSCSIExecIOPBPtrLen;
+           PB.scsiFunctionCode = SCSIExecIO;
+           PB.scsiDevice = scsiDevice;
+           PB.scsiTimeout = kSCSICommandTimeout;
+           /*
+            * Fiddle the flags so they're the least disruptive possible.
+            */
+           PB.scsiFlags = scsiFlags | (scsiSIMQNoFreeze | scsiDontDisconnect);
+           if (sensePtr != NULL) {
+               PB.scsiSensePtr = (UInt8 *) sensePtr;
+               PB.scsiSenseLength = sizeof *sensePtr;
+           }
+           BlockMoveData(&theSCSICommand, &PB.scsiCDB.cdbBytes[0], cmdBlockLength);
+           PB.scsiCDBLength = cmdBlockLength;
+           if (dataBuffer != NULL) {
+               PB.scsiDataPtr = (UInt8 *) dataBuffer;
+               PB.scsiDataLength = dataLength;
+               PB.scsiDataType = scsiDataBuffer;
+               PB.scsiTransferType = scsiTransferPolled;
+           }
+           status = SCSIAction((SCSI_PB *) &PB);
+           if (status == noErr)
+               status = PB.scsiResult;
+           if (status == scsiSelectTimeout)
+               status = scsiDeviceNotThere;
+           if (actualTransferCount != NULL) {
+               /*
+                * Make sure that the actual transfer count does not exceed
+                * the allocation count (some devices spit extra data at us!)
+                */
+               *actualTransferCount = dataLength - PB.scsiDataResidual;
+               if (*actualTransferCount > dataLength)
+                   *actualTransferCount = dataLength;
+           }
+#undef PB
+       }
+       if (status == scsiNonZeroStatus
+        && sensePtr != NULL
+        && sensePtr->errorCode != 0
+        && senseMessage != NULL) {
+//          FormatSenseMessage(sensePtr, senseMessage);
+//          ShowProgressAction(senseMessage);
+       }
+       return (status);
+}
+
+/*
+ * Do a command with autosense using the original SCSI manager.
+ */
+OSErr
+DoOriginalSCSICommand(
+       DeviceIdent             scsiDevice,
+       const SCSI_CommandPtr   theSCSICommand,
+       unsigned short          cmdBlockLength,
+       Ptr                     dataBuffer,
+       ByteCount               dataLength,
+       UInt32                  scsiFlags,
+       ByteCount               *actualTransferCount,
+       SCSI_Sense_Data         *sensePtr
+    )
+{
+       OSErr                   status;
+       UInt8                   scsiStatusByte;
+       SCSI_Command            scsiStatusCommand;
+
+       status = OriginalSCSI(
+                   scsiDevice,
+                   theSCSICommand,
+                   cmdBlockLength,
+                   dataBuffer,
+                   dataLength,
+                   scsiFlags,
+                   actualTransferCount,
+                   &scsiStatusByte
+           );
+       if (status == scsiNonZeroStatus
+        && scsiStatusByte == kScsiStatusCheckCondition
+        && sensePtr != NULL) {
+           CLEAR(scsiStatusCommand);
+           CLEAR(*sensePtr);
+           scsiStatusCommand.scsi6.opcode = kScsiCmdRequestSense;
+           scsiStatusCommand.scsi[1] |= (scsiDevice.LUN & 0x03) << 5;
+           scsiStatusCommand.scsi6.len = sizeof *sensePtr;
+           status = OriginalSCSI(
+                       scsiDevice,
+                       &scsiStatusCommand,
+                       sizeof scsiStatusCommand.scsi6,
+                       (Ptr) sensePtr,
+                       sizeof *sensePtr,
+                       scsiDirectionIn,
+                       NULL,
+                       &scsiStatusByte
+                   );
+           if (status != noErr && status != scsiDataRunError) {
+#ifdef notdef
+               if (gDebugOnError && scsiStatusByte != kScsiStatusCheckCondition) {
+                   Str255          work;
+
+                   pstrcpy(work, "\pAutosense failed ");
+                   AppendSigned(work, status);
+                   AppendChar(work, ' ');
+                   AppendHexLeadingZeros(work, scsiStatusByte, 2);
+                   DebugStr(work);
+               }
+#endif
+               sensePtr->errorCode = 0;
+               status = scsiAutosenseFailed;
+           }
+           else {
+               status = scsiNonZeroStatus;
+           }
+       }
+       return (status);
+}
+
+OSErr
+OriginalSCSI(
+       DeviceIdent             scsiDevice,
+       const SCSI_CommandPtr   scsiCommand,
+       UInt8                   scsiCommandLen,
+       Ptr                     dataBuffer,
+       ByteCount               dataLength,
+       UInt32                  scsiFlags,
+       ByteCount               *actualTransferCount,
+       UInt8                   *scsiStatusBytePtr
+    )
+{
+       OSErr                   status;             /* Final status             */
+       OSErr                   completionStatus;   /* Status from ScsiComplete */
+       short                   totalTries;         /* Get/Select retries       */
+       short                   getTries;           /* Get retries              */
+       short                   iCount;             /* Bus free counter         */
+       unsigned long           watchdog;           /* Timeout after this       */
+       unsigned long           myTransferCount;    /* Gets TIB loop counter    */
+       short                   scsiStatusByte;     /* Gets SCSIComplete result */
+       short                   scsiMsgByte;        /* Gets SCSIComplete result */
+       Boolean                 bufferHoldFlag;
+       /*
+        * The TIB has the following format:
+        *  [0] scInc   user buffer         transferQuantum or transferSize
+        *  [1] scAdd   &theTransferCount   1
+        *  [2] scLoop  -> tib[0]           transferSize / transferQuantum
+        *  [3] scStop
+        * The intent of this is to return, in actualTransferCount, the number
+        * of times we cycled through the tib[] loop. This will be the actual
+        * transfer count if transferQuantum equals one, or the number of
+        * "blocks" if transferQuantum is the length of one sector.
+        */
+       SCSIInstr               tib[4];             /* Current TIB              */
+
+       status = noErr;
+       bufferHoldFlag = FALSE;
+       scsiStatusByte = 0xFF;
+       scsiMsgByte = 0xFF;
+       myTransferCount = 0;
+       /*
+        * If there is a data transfer, setup the tib.
+        */
+       if (dataBuffer != NULL) {
+           tib[0].scOpcode = scInc;
+           tib[0].scParam1 = (unsigned long) dataBuffer;
+           tib[0].scParam2 = 1;
+           tib[1].scOpcode = scAdd;
+           tib[1].scParam1 = (unsigned long) &myTransferCount;
+           tib[1].scParam2 = 1;
+           tib[2].scOpcode = scLoop;
+           tib[2].scParam1 = (-2 * sizeof (SCSIInstr));
+           tib[2].scParam2 = dataLength / tib[0].scParam2;
+           tib[3].scOpcode = scStop;
+           tib[3].scParam1 = 0;
+           tib[3].scParam2 = 0;
+       }
+       if (IsVirtualMemoryRunning() && dataBuffer != NULL) {
+           /*
+            * Lock down the user buffer, if any. In a real-world application
+            * or driver, this would be done before calling the SCSI interface.
+            */
+#ifdef notdef
+           FailOSErr(
+               HoldMemory(dataBuffer, dataLength),
+               "\pCan't lock data buffer in physical memory"
+           );
+#else
+       HoldMemory(dataBuffer, dataLength);
+#endif
+           bufferHoldFlag = TRUE;
+       }
+       /*
+        * Arbitrate for the scsi bus.  This will fail if some other device is
+        * accessing the bus at this time (which is unlikely).
+        *
+        *** Do not set breakpoints or call any functions that may require device
+        *** I/O (such as display code that accesses font resources between
+        *** SCSIGet and SCSIComplete,
+        *
+        */
+       for (totalTries = 0; totalTries < kMaxSCSIRetries; totalTries++) {
+           for (getTries = 0; getTries < 4; getTries++) {
+               /*
+                * Wait for the bus to go free.
+                */
+               watchdog = TickCount() + 300;       /* 5 second timeout         */
+               while (ScsiBusBusy()) {
+                   if (/*gStopNow || StopNow() ||*/ TickCount() > watchdog) {
+                       status = scsiBusy;
+                       goto exit;
+                   }
+               }
+               /*
+                * The bus is free, try to grab it
+                */
+               for (iCount = 0; iCount < 4; iCount++) {
+                   if ((status = SCSIGet()) == noErr)
+                       break;
+               }
+               if (status == noErr)
+                   break;                          /* Success: we have the bus */
+               /*
+                * The bus became busy again. Try to wait for it to go free.
+                */
+               for (iCount = 0;
+                       /*gStopNow == FALSE && StopNow() == FALSE &&*/ iCount < 100 && ScsiBusBusy();
+                       iCount++)
+                   ;
+           } /* The getTries loop */
+           if (status != noErr) {
+               /*
+                * The SCSI Manager thinks the bus is not busy and not selected,
+                * but "someone" has set its internal semaphore that signals
+                * that the SCSI Manager itself is busy. The application will have
+                * to handle this problem. (We tried getTries * 4 times).
+                */
+               status = scsiBusy;
+               goto exit;
+           }
+           /*
+            * We now own the SCSI bus. Try to select the device.
+            */
+           if ((status = SCSISelect(scsiDevice.targetID)) != noErr) {
+               switch (status) {
+               /*
+                * We get scBadParmsErr if we try to arbitrate for the initiator.
+                */
+               case scBadParmsErr: status = scsiTIDInvalid;        break;
+               case scCommErr:     status = scsiDeviceNotThere;    break;
+               case scArbNBErr:    status = scsiBusy;              break;
+               case scSequenceErr: status = scsiRequestInvalid;    break;
+               }
+               goto exit;
+           }
+           /*
+            * From this point on, we must exit through SCSIComplete() even if an
+            * error is detected. Send a command to the selected device. There are
+            * several failure modes, including an illegal command (such as a
+            * write to a read-only device). If the command failed because of
+            * "device busy", we will try it again.
+            */
+           status = SCSICmd((Ptr) scsiCommand, scsiCommandLen);
+           if (status != noErr) {
+               switch (status) {
+               case scCommErr:     status = scsiCommandTimeout;    break;
+               case scPhaseErr:    status = scsiSequenceFailed;    break;
+               }
+           }
+           if (status == noErr && dataBuffer != NULL) {
+               /*
+                * This command requires a data transfer.
+                */
+               if (scsiFlags == scsiDirectionOut)
+                   status = SCSIWrite((Ptr) tib);
+               else {
+                   status = SCSIRead((Ptr) tib);
+               }
+               switch (status) {
+               case scCommErr:     status = scsiCommandTimeout;        break;
+               case scBadParmsErr: status = scsiRequestInvalid;        break;
+               case scPhaseErr:    status = noErr; /* Don't care */    break;
+               case scCompareErr:                  /* Can't happen */  break;
+               }
+           }
+           /*
+            * SCSIComplete "runs" the bus-phase algorithm until the bitter end,
+            * returning the status and command-completion message bytes..
+            */
+           completionStatus = SCSIComplete(
+                       &scsiStatusByte,
+                       &scsiMsgByte,
+                       5 * 60L
+                   );
+           if (status == noErr && completionStatus != noErr) {
+               switch (completionStatus) {
+               case scCommErr:         status = scsiCommandTimeout;    break;
+               case scPhaseErr:        status = scsiSequenceFailed;    break;
+               case scComplPhaseErr:   status = scsiSequenceFailed;    break;
+               }
+           }
+           if (completionStatus == noErr && scsiStatusByte == kScsiStatusBusy) {
+               /*
+                * ScsiComplete is happy. If the device is busy,
+                * pause for 1/4 second and try again.
+                */
+               watchdog = TickCount() + 15;
+               while (TickCount() < watchdog)
+                   ;
+               continue;               /* Do next totalTries attempt       */
+           }
+           /*
+            * This is the normal exit (success) or final failure exit.
+            */
+           break;
+       } /* totalTries loop */
+exit:   if (bufferHoldFlag)
+           (void) UnholdMemory(dataBuffer, dataLength);
+       /*
+        * Return the number of bytes transferred to the caller. If the caller
+        * supplied an actual count and the count is no greater than the maximum,
+        * ignore any phase errors.
+        */
+       if (actualTransferCount != NULL) {
+           *actualTransferCount = myTransferCount;
+           if (*actualTransferCount > dataLength)
+               *actualTransferCount = dataLength;
+       }
+       /*
+        * Also, there is a bug in the combination of System 7.0.1 and the 53C96
+        * that may cause the real SCSI Status Byte to be in the Message byte.
+        */
+       if (scsiStatusByte == kScsiStatusGood
+        && scsiMsgByte == kScsiStatusCheckCondition)
+           scsiStatusByte = kScsiStatusCheckCondition;
+       if (status == noErr) {
+           switch (scsiStatusByte) {
+           case kScsiStatusGood:                               break;
+           case kScsiStatusBusy:   status = scsiBusy;          break;
+           case 0xFF:              status = scsiProvideFail;   break;
+           default:                status = scsiNonZeroStatus; break;
+           }
+       }
+       if (status == noErr
+        && (scsiFlags & scsiDirectionMask) != scsiDirectionNone
+        && myTransferCount != dataLength)
+           status = scsiDataRunError;          
+       if (scsiStatusBytePtr != NULL)
+           *scsiStatusBytePtr = scsiStatusByte;
+       return (status);
+}
+
+UInt16
+GetCommandLength(
+       const SCSI_CommandPtr   cmdPtr
+    )
+{
+       unsigned short          result;
+       /*
+        * Look at the "group code" in the command operation. Return zero
+        * error for the reserved (3, 4) and vendor-specific command (6, 7)
+        * command groups. Otherwise, set the command length from the group code
+        * value as specified in the SCSI-II spec.
+        */
+       switch (cmdPtr->scsi6.opcode & 0xE0) {
+       case (0 << 5):  result = 6;     break;
+       case (1 << 5):
+       case (2 << 5):  result = 10;    break;
+       case (5 << 5):  result = 12;    break;
+       default:        result = 0;     break;
+       }
+       return (result);
+}
+
+Boolean
+IsVirtualMemoryRunning(void)
+{
+       OSErr                       status;
+       long                        response;
+       
+       status = Gestalt(gestaltVMAttr, &response);
+       /*
+        * VM is active iff Gestalt succeeded and the response is appropriate.
+        */
+       return (status == noErr && ((response & (1 << gestaltVMPresent)) != 0));
+}
diff --git a/DoTestUnitReady.c b/DoTestUnitReady.c
new file mode 100644 (file)
index 0000000..b9b320b
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * Copyright 1993-97 by Apple Computer, Inc.
+ *              All Rights Reserved 
+ *  
+ * Permission to use, copy, modify, and distribute this software and 
+ * its documentation for any purpose and without fee is hereby granted, 
+ * provided that the above copyright notice appears in all copies and 
+ * that both the copyright notice and this permission notice appear in 
+ * supporting documentation. 
+ *  
+ * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE 
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
+ * FOR A PARTICULAR PURPOSE. 
+ *  
+ * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR 
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, 
+ * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION 
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 
+ */
+#include <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;
+}
+
+
+
diff --git a/HISTORY b/HISTORY
new file mode 100644 (file)
index 0000000..2e43b35
--- /dev/null
+++ b/HISTORY
@@ -0,0 +1,16 @@
+961108 Started work
+961113 Released version 0.1 to MkLinux Team (vlb, lion, brett, gilbert)
+       Reads, initializes maps and add and delete partitions
+
+961127 Started work again
+       Tried to make it easier to use
+       Added reorder and resize commands
+       Little endian machine support
+       Fixed various bugs
+       Wrote man page
+961218 Released version 0.2 to gilbert
+
+961219 Fixed bugs gilbert found
+961220 Released version 0.3 to community
+
+970115 Released version 0.4 (with Macintosh app)
diff --git a/MacSCSICommand.h b/MacSCSICommand.h
new file mode 100644 (file)
index 0000000..b02b66f
--- /dev/null
@@ -0,0 +1,420 @@
+/*
+    File:       MacSCSICommand.h
+
+    Contains:   SCSI specific definitions.
+
+    Written by: Martin Minow
+
+*/
+
+/*
+ * Copyright 1995, 1997 by Apple Computer, Inc.
+ *              All Rights Reserved 
+ *  
+ * Permission to use, copy, modify, and distribute this software and 
+ * its documentation for any purpose and without fee is hereby granted, 
+ * provided that the above copyright notice appears in all copies and 
+ * that both the copyright notice and this permission notice appear in 
+ * supporting documentation. 
+ *  
+ * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE 
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
+ * FOR A PARTICULAR PURPOSE. 
+ *  
+ * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR 
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, 
+ * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION 
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 
+ */
+
+/*
+ * Scsi-specific definitions.
+ */
+#ifndef __MacSCSICommand__
+#define __MacSCSICommand__
+
+/*
+ * The 6-byte commands are used for most simple
+ * I/O requests.
+ */
+struct SCSI_6_Byte_Command {                /* Six-byte command         */
+    unsigned char       opcode;             /*  0                       */
+    unsigned char       lbn3;               /*  1 lbn in low 5          */
+    unsigned char       lbn2;               /*  2                       */
+    unsigned char       lbn1;               /*  3                       */
+    unsigned char       len;                /*  4                       */
+    unsigned char       ctrl;               /*  5                       */
+};
+typedef struct SCSI_6_Byte_Command SCSI_6_Byte_Command;
+
+struct SCSI_10_Byte_Command {               /* Ten-byte command         */
+    unsigned char       opcode;             /*  0                       */
+    unsigned char       lun;                /*  1                       */
+    unsigned char       lbn4;               /*  2                       */
+    unsigned char       lbn3;               /*  3                       */
+    unsigned char       lbn2;               /*  4                       */
+    unsigned char       lbn1;               /*  5                       */
+    unsigned char       pad;                /*  6                       */
+    unsigned char       len2;               /*  7                       */
+    unsigned char       len1;               /*  8                       */
+    unsigned char       ctrl;               /*  9                       */
+};
+typedef struct SCSI_10_Byte_Command SCSI_10_Byte_Command;
+
+struct SCSI_12_Byte_Command {               /* Twelve-byte command      */
+    unsigned char       opcode;             /*  0                       */
+    unsigned char       lun;                /*  1                       */
+    unsigned char       lbn4;               /*  2                       */
+    unsigned char       lbn3;               /*  3                       */
+    unsigned char       lbn2;               /*  4                       */
+    unsigned char       lbn1;               /*  5                       */
+    unsigned char       len4;               /*  6                       */
+    unsigned char       len3;               /*  7                       */
+    unsigned char       len2;               /*  8                       */
+    unsigned char       len1;               /*  9                       */
+    unsigned char       pad;                /* 10                       */
+    unsigned char       ctrl;               /* 11                       */
+};
+typedef struct SCSI_12_Byte_Command SCSI_12_Byte_Command;
+
+/*
+ * This union defines all scsi commands.
+ */
+union SCSI_Command {
+    SCSI_6_Byte_Command     scsi6;
+    SCSI_10_Byte_Command    scsi10;
+    SCSI_12_Byte_Command    scsi12;
+    unsigned char           scsi[12];
+};
+typedef union SCSI_Command SCSI_Command, *SCSI_CommandPtr;
+
+/*
+ * Returned by a read-capacity command.
+ */
+struct SCSI_Capacity_Data {
+    unsigned char       lbn4;               /* Number                   */
+    unsigned char       lbn3;               /*  of                      */
+    unsigned char       lbn2;               /*   logical                */
+    unsigned char       lbn1;               /*    blocks                */
+    unsigned char       len4;               /* Length                   */
+    unsigned char       len3;               /*  of each                 */
+    unsigned char       len2;               /*   logical block          */
+    unsigned char       len1;               /*    in bytes              */
+};
+typedef struct SCSI_Capacity_Data SCSI_Capacity_Data;
+
+struct SCSI_Inquiry_Data {                  /* Inquiry returns this     */
+    unsigned char       devType;            /*  0 Device type,          */
+    unsigned char       devTypeMod;         /*  1 Device type modifier  */
+    unsigned char       version;            /*  2 ISO/ECMA/ANSI version */
+    unsigned char       format;             /*  3 Response data format  */
+    unsigned char       length;             /*  4 Additional Length     */
+    unsigned char       reserved5;          /*  5 Reserved              */
+    unsigned char       reserved6;          /*  6 Reserved              */
+    unsigned char       flags;              /*  7 Capability flags      */
+    unsigned char       vendor[8];          /*  8-15 Vendor-specific    */
+    unsigned char       product[16];        /* 16-31 Product id         */
+    unsigned char       revision[4];        /* 32-35 Product revision   */
+    unsigned char       vendorSpecific[20]; /* 36-55 Vendor stuff       */
+    unsigned char       moreReserved[40];   /* 56-95 Reserved           */
+};
+typedef struct SCSI_Inquiry_Data SCSI_Inquiry_Data;
+
+/*
+ * This bit may be set in SCSI_Inquiry_Data.devTypeMod
+ */
+enum {
+    kScsiInquiryRMB = 0x80                  /* Removable medium if set  */
+};
+/*
+ * These bits may be set in SCSI_Inquiry_Data.flags
+ */
+enum {
+    kScsiInquiryRelAdr  = 0x80,             /* Has relative addressing  */
+    kScsiInquiryWBus32  = 0x40,             /* Wide (32-bit) transfers  */
+    kScsiInquiryWBus16  = 0x20,             /* Wide (16-bit) transfers  */
+    kScsiInquirySync    = 0x10,             /* Synchronous transfers    */
+    kScsiInquiryLinked  = 0x08,             /* Linked commands ok       */
+    kScsiInquiryReserved = 0x04,
+    kScsiInquiryCmdQue  = 0x02,             /* Tagged cmd queuing ok    */
+    kScsiInquirySftRe   = 0x01              /* Soft reset alternative   */
+};
+
+/*
+ * These bits may be set in SCSI_Inquiry_Data.devType
+ */
+enum {
+    kScsiDevTypeDirect                  = 0,
+    kScsiDevTypeSequential,
+    kScsiDevTypePrinter,
+    kScsiDevTypeProcessor,
+    kScsiDevTypeWorm,                       /* Write-once, read mult    */
+    kScsiDevTypeCDROM,
+    kScsiDevTypeScanner,
+    kScsiDevTypeOptical,
+    kScsiDevTypeChanger,
+    kScsiDevTypeComm,
+    kScsiDevTypeGraphicArts0A,
+    kScsiDevTypeGraphicArts0B,
+    kScsiDevTypeFirstReserved,              /* Reserved sequence start  */
+    kScsiDevTypeUnknownOrMissing        = 0x1F,
+    kScsiDevTypeMask                    = 0x1F
+};
+/*
+ * These are device type qualifiers. We need them to distinguish between "unknown"
+ * and "missing" devices.
+ */
+enum {
+    kScsiDevTypeQualifierConnected      = 0x00, /* Exists and is connected      */
+    kScsiDevTypeQualifierNotConnected   = 0x20, /* Logical unit exists          */
+    kScsiDevTypeQualifierReserved       = 0x40,
+    kScsiDevTypeQualifierMissing        = 0x60, /* No such logical unit         */
+    kScsiDevTypeQualifierVendorSpecific = 0x80, /* Other bits are unspecified   */
+    kScsiDevTypeQualifierMask           = 0xE0
+};
+#define kScsiDevTypeMissing \
+    (kScsiDevTypeUnknownOrMissing | kScsiDevTypeQualifierMissing)
+
+/*
+ * This is the data that is returned after a GetExtendedStatus
+ * request. The errorCode gives a general indication of the error,
+ * which may be qualified by the additionalSenseCode and
+ * additionalSenseQualifier fields. These may be device (vendor)
+ * specific values, however. The info[] field contains additional
+ * information. For a media error, it contains the failing
+ * logical block number (most-significant byte first).
+ */
+struct SCSI_Sense_Data {                /* Request Sense result         */
+    unsigned char       errorCode;      /*  0   Class code, valid lbn   */
+    unsigned char       segmentNumber;  /*  1   Segment number          */
+    unsigned char       senseKey;       /*  2   Sense key and flags     */
+    unsigned char       info[4];
+    unsigned char       additionalSenseLength;
+    unsigned char       reservedForCopy[4];
+    unsigned char       additionalSenseCode;
+    unsigned char       additionalSenseQualifier;   
+    unsigned char       fruCode;        /* Field replacable unit code   */
+    unsigned char       senseKeySpecific[2];
+    unsigned char       additional[101];
+};
+typedef struct SCSI_Sense_Data SCSI_Sense_Data;
+/*
+ * The high-bit of errorCode signals whether there is a logical
+ * block. The low value signals whether there is a valid sense
+ */
+#define kScsiSenseHasLBN            0x80    /* Logical block number set */
+#define kScsiSenseInfoValid         0x70    /* Is sense key valid?      */
+#define kScsiSenseInfoMask          0x70    /* Mask for sense info      */
+/*
+ * These bits may be set in the sense key
+ */
+#define kScsiSenseKeyMask           0x0F
+#define kScsiSenseILI               0x20    /* Illegal logical Length   */
+#define kScsiSenseEOM               0x40    /* End of media             */
+#define kScsiSenseFileMark          0x80    /* End of file mark         */
+
+/*
+ * SCSI sense codes. (Returned after request sense).
+ */
+#define  kScsiSenseNone             0x00    /* No error                 */
+#define  kScsiSenseRecoveredErr     0x01    /* Warning                  */
+#define  kScsiSenseNotReady         0x02    /* Device not ready         */
+#define  kScsiSenseMediumErr        0x03    /* Device medium error      */
+#define  kScsiSenseHardwareErr      0x04    /* Device hardware error    */
+#define  kScsiSenseIllegalReq       0x05    /* Illegal request for dev. */
+#define  kScsiSenseUnitAtn          0x06    /* Unit attention (not err) */
+#define  kScsiSenseDataProtect      0x07    /* Data protection          */
+#define  kScsiSenseBlankCheck       0x08    /* Tape-specific error      */
+#define  kScsiSenseVendorSpecific   0x09    /* Vendor-specific error    */
+#define  kScsiSenseCopyAborted      0x0a    /* Copy request cancelled   */
+#define  kScsiSenseAbortedCmd       0x0b    /* Initiator aborted cmd.   */
+#define  kScsiSenseEqual            0x0c    /* Comparison equal         */
+#define  kScsiSenseVolumeOverflow   0x0d    /* Write past end mark      */
+#define  kScsiSenseMiscompare       0x0e    /* Comparison failed        */
+#define  kScsiSenseCurrentErr       0x70
+#define  kScsiSenseDeferredErr      0x71
+
+/*
+ * Mode sense parameter header
+ */
+struct SCSI_ModeParamHeader {
+    unsigned char       modeDataLength;
+    unsigned char       mediumType;
+    unsigned char       deviceSpecific;
+    unsigned char       blockDescriptorLength;
+};
+typedef struct SCSI_ModeParamHeader SCSI_ModeParamHeader;
+
+struct SCSI_ModeParamBlockDescriptor {
+    unsigned char       densityCode;
+    unsigned char       numberOfBlocks[3];
+    unsigned char       reserved;
+    unsigned char       blockLength[3];
+};
+typedef struct SCSI_ModeParamBlockDescriptor SCSI_ModeParamBlockDescriptor;
+
+union SCSI_ModeParamPage {
+    unsigned char       data[1];
+    struct {
+       unsigned char   code;
+       unsigned char   length;
+    } page;
+};
+typedef union SCSI_ModeParamPage SCSI_ModeParamPage;
+
+/*
+ * LogSense parameter header
+ */
+struct SCSI_LogSenseParamHeader {
+    unsigned char       pageCode;
+    unsigned char       reserved;
+    unsigned char       pageLength[2];
+};
+typedef struct SCSI_LogSenseParamHeader SCSI_LogSenseParamHeader;
+
+/*
+ * Log parameter pages are variable-length with a fixed length header.
+ */
+union SCSI_LogSenseParamPage {
+    unsigned char       data[1];
+    struct {
+       unsigned char   parameterCode[2];
+       unsigned char   flags;
+       unsigned char   parameterLength;
+    } page;
+};
+typedef union SCSI_LogSenseParamPage SCSI_LogSenseParamPage;
+
+/*
+ * SCSI command status (from status phase)
+ */
+#define  kScsiStatusGood            0x00    /* Normal completion        */
+#define  kScsiStatusCheckCondition  0x02    /* Need GetExtendedStatus   */
+#define  kScsiStatusConditionMet    0x04
+#define  kScsiStatusBusy            0x08    /* Device busy (self-test?) */
+#define  kScsiStatusIntermediate    0x10    /* Intermediate status      */
+#define  kScsiStatusResConflict     0x18    /* Reservation conflict     */
+#define  kScsiStatusQueueFull       0x28    /* Target can't do command  */
+#define  kScsiStatusReservedMask    0x3e    /* Vendor specific?         */
+
+/*
+ * SCSI command codes. Commands defined as ...6, ...10, ...12, are
+ * six-byte, ten-byte, and twelve-byte variants of the indicated command.
+ */
+/*
+ * These commands are supported for all devices.
+ */
+#define kScsiCmdChangeDefinition    0x40
+#define kScsiCmdCompare             0x39
+#define kScsiCmdCopy                0x18
+#define kScsiCmdCopyAndVerify       0x3a
+#define kScsiCmdInquiry             0x12
+#define kScsiCmdLogSelect           0x4c
+#define kScsiCmdLogSense            0x4d
+#define kScsiCmdModeSelect10        0x55
+#define kScsiCmdModeSelect6         0x15
+#define kScsiCmdModeSense10         0x5a
+#define kScsiCmdModeSense6          0x1a
+#define kScsiCmdReadBuffer          0x3c
+#define kScsiCmdRecvDiagResult      0x1c
+#define kScsiCmdRequestSense        0x03
+#define kScsiCmdSendDiagnostic      0x1d
+#define kScsiCmdTestUnitReady       0x00
+#define kScsiCmdWriteBuffer         0x3b
+
+/*
+ * These commands are supported by direct-access devices only.
+ */
+#define kScsiCmdFormatUnit          0x04
+#define kSCSICmdCopy                0x18
+#define kSCSICmdCopyAndVerify       0x3a
+#define kScsiCmdLockUnlockCache     0x36
+#define kScsiCmdPrefetch            0x34
+#define kScsiCmdPreventAllowRemoval 0x1e
+#define kScsiCmdRead6               0x08
+#define kScsiCmdRead10              0x28
+#define kScsiCmdReadCapacity        0x25
+#define kScsiCmdReadDefectData      0x37
+#define kScsiCmdReadLong            0x3e
+#define kScsiCmdReassignBlocks      0x07
+#define kScsiCmdRelease             0x17
+#define kScsiCmdReserve             0x16
+#define kScsiCmdRezeroUnit          0x01
+#define kScsiCmdSearchDataEql       0x31
+#define kScsiCmdSearchDataHigh      0x30
+#define kScsiCmdSearchDataLow       0x32
+#define kScsiCmdSeek6               0x0b
+#define kScsiCmdSeek10              0x2b
+#define kScsiCmdSetLimits           0x33
+#define kScsiCmdStartStopUnit       0x1b
+#define kScsiCmdSynchronizeCache    0x35
+#define kScsiCmdVerify              0x2f
+#define kScsiCmdWrite6              0x0a
+#define kScsiCmdWrite10             0x2a
+#define kScsiCmdWriteAndVerify      0x2e
+#define kScsiCmdWriteLong           0x3f
+#define kScsiCmdWriteSame           0x41
+
+/*
+ * These commands are supported by sequential devices.
+ */
+#define kScsiCmdRewind              0x01
+#define kScsiCmdWriteFilemarks      0x10
+#define kScsiCmdSpace               0x11
+#define kScsiCmdLoadUnload          0x1B
+/*
+ * ANSI SCSI-II for CD-ROM devices.
+ */
+#define kScsiCmdReadCDTableOfContents   0x43
+
+/*
+ * Message codes (for Msg In and Msg Out phases).
+ */
+#define kScsiMsgAbort               0x06
+#define kScsiMsgAbortTag            0x0d
+#define kScsiMsgBusDeviceReset      0x0c
+#define kScsiMsgClearQueue          0x0e
+#define kScsiMsgCmdComplete         0x00
+#define kScsiMsgDisconnect          0x04
+#define kScsiMsgIdentify            0x80
+#define kScsiMsgIgnoreWideResdue    0x23
+#define kScsiMsgInitiateRecovery    0x0f
+#define kScsiMsgInitiatorDetectedErr 0x05
+#define kScsiMsgLinkedCmdComplete   0x0a
+#define kScsiMsgLinkedCmdCompleteFlag 0x0b
+#define kScsiMsgParityErr           0x09
+#define kScsiMsgRejectMsg           0x07
+#define kScsiMsgModifyDataPtr       0x00 /* Extended msg        */
+#define kScsiMsgNop                 0x08
+#define kScsiMsgHeadOfQueueTag      0x21 /* Two byte msg        */
+#define kScsiMsgOrderedQueueTag     0x22 /* Two byte msg        */
+#define kScsiMsgSimpleQueueTag      0x20 /* Two byte msg        */
+#define kScsiMsgReleaseRecovery     0x10
+#define kScsiMsgRestorePointers     0x03
+#define kScsiMsgSaveDataPointers    0x02
+#define kScsiMsgSyncXferReq         0x01 /* Extended msg        */
+#define kScsiMsgWideDataXferReq     0x03 /* Extended msg        */
+#define kScsiMsgTerminateIOP        0x11
+#define kScsiMsgExtended            0x01
+#define kScsiMsgEnableDisconnectMask 0x40
+
+#define kScsiMsgTwoByte             0x20
+#define kScsiMsgTwoByteMin          0x20
+#define kScsiMsgTwoByteMax          0x2f
+
+/*
+ * Default timeout times for SCSI commands (times are in Msec).
+ */
+#define kScsiNormalCompletionTime   (500L)          /* 1/2 second               */
+/*
+ * Dratted DAT tape.
+ */
+#define kScsiDATCompletionTime      (60L * 1000L);  /* One minute               */
+/*
+ * Yes, we do allow 90 seconds for spin-up of those dratted tape drives.
+ */
+#define kScsiSpinUpCompletionTime   (90L * 1000L)
+
+
+#endif /* __MacSCSICommand__ */
diff --git a/Makefile b/Makefile
new file mode 100644 (file)
index 0000000..f26608f
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,24 @@
+all: pdisk fdisk
+
+pdisk: pdisk.o dump.o partition_map.o convert.o io.o errors.o bitfield.o
+
+fdisk: fdisk.o fdisklabel.o
+
+clean:
+       rm -f *.o pdisk fdisk
+
+distribution:
+       cd ..; tar cvf pdisk.src.tar.`date +%y%m%d` --files-from pdisk/list.src
+       tar cvf ../pdisk.bin.tar.`date +%y%m%d` pdisk fdisk pdisk.8
+       cp pdisk.hqx ../pdisk.hqx.`date +%y%m%d`
+
+convert.o: convert.c partition_map.h convert.h
+dump.o: dump.c io.h errors.h partition_map.h
+errors.o: errors.c errors.h
+io.o: io.c pdisk.h io.h errors.h
+partition_map.o: partition_map.c partition_map.h pdisk.h convert.h io.h errors.h
+pdisk.o: pdisk.c pdisk.h io.h errors.h partition_map.h version.h
+
+partition_map.h: dpme.h
+dpme.h: bitfield.h
+
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..bfe57a0
--- /dev/null
+++ b/README
@@ -0,0 +1,97 @@
+README for pdisk       (9 January 1997)
+================
+
+This file accompanies version 0.4 of pdisk.
+
+pdisk is a partition table editor for (Mk)Linux which understands the
+Apple disk partitioning format.
+
+Version 0.4 is the second version of pdisk in general distribution.
+(Version 0.3 was the first general distribution.) The author of pdisk
+is Eryk Vershen (eryk@apple.com).  Any questions, comments, suggestions,
+etc. can be sent via email.  I can't guarantee a response, but I'll try.
+
+Please read the man page.  (man ./pdisk.8)
+
+The best curently available documentation on the Apple disk partitioning scheme
+is "Inside Macintosh: Devices" pages 3-12 to 3-15 combined with the info
+in "Inside Macintosh - Volume V" pages V-576 to V-582.  This, unfortunately,
+does not cover everything.
+
+I have also enclosed modified sources for fdisk, which do not have the
+byte order problem.  These are derived from the sparc patches (but contain
+none of the sun disk label stuff) in the the latest package I found
+util-linux-2.5-26.src.rpm, which I got from the RedHat 4.0
+distribution.
+
+
+Building the macintosh application
+----------------------------------
+I have only built this under Code Warrior 10.  The project file is
+included.  The project stationery was 'MacOS:C/C++:ANSI Console PPC'.
+Thanks to Martin Minow for the SCSI support code.
+
+
+Some notes on the apple partitioning
+------------------------------------
+The apple disk partitioning scheme was developed in 1986. It attempted to
+be forward thinking as it was intended to handle drives of sizes up to several
+hundred megabytes.  There was a design document, but like most such documents
+it was neither complete nor unambiguous.
+
+While the original intent was to handle various block sizes, in practice
+only 512 byte blocks are supported.  Since the various address fields are
+32 bits unsigned this means the format can handle disks up to 2 Terabytes
+in size.  (32bits + 9 bits = 41 bits)
+Because the format was designed around SCSI, there is no knowledge of
+cylinders or heads, all block address are in absolute sector form.
+A correct map should describe every block on the disk except for block zero.
+
+An aside on CDROMs.  Most old apple CDROMs have incorrect data in block zero.
+Since the HFS file-system could only handle 512 byte blocks, apple drives had
+a special mode where they would do deblocking (i.e. converting 2k blocks
+into four 512byte blocks and accepting 512byte block addresses.)  The partition
+maps laid down on these disks are for the deblocked form.  In many cases the
+partition maps they contain have only the minimum number of fields correct.
+At least one CDROM I have seen doesn't even contain a partition map at all,
+but is simply an HFS volume.
+
+The documentation in Inside Macintosh is only partially correct.
+The boot-arguments field was left out.  A/UX used the boot arguments field
+for something that was called the bzb (block zero block - don't ask me why).
+This structure evolved over the course of A/UX.  I have recapitulated this
+in the dpme.h header file.
+
+
+Making a disk with Apple & Intel partitioning
+---------------------------------------------
+Don't cringe. I know it is an awful hack, but sometimes...
+While I don't recommend doing this, it can be useful.
+The procedure below is what we did.
+
+The intel map can contain NO MORE THAN FOUR PRIMARY PARTITIONS.
+You can't have any extended or logical partitions.  (Well, you might get it
+to work but I wouldn't want to try it.)  The disk will NOT BE INTEL BOOTABLE.
+
+1) Use pdisk to initialize an apple partition map.  Don't add any partitions
+   yet, just write the map out and quit.
+
+2) Use fdisk to create the primary partitions.  Go into the expert 'x' menu
+   in fdisk and print out the table with the sector addresses.  Write the
+   start and lengths down some where.  Write the table out.
+
+3) Use pdisk again.  Shrink the partition map down, if necessary, so it
+   does not overlap any intel partition.  Create an apple partition for each
+   intel partition using the start and length value you got from fdisk.
+   Write out the map and quit.
+
+At present file systems are not compatible between Linux & MkLinux, but you
+can tar stuff into these partitions and tar them out on another machine.
+
+
+
+Good luck,
+
+-eryk
+ software mechanic
+ eryk@apple.com
diff --git a/SCSIStuff.h b/SCSIStuff.h
new file mode 100644 (file)
index 0000000..2de563e
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+ * Copyright 1993-97 by Apple Computer, Inc.
+ *              All Rights Reserved 
+ *  
+ * Permission to use, copy, modify, and distribute this software and 
+ * its documentation for any purpose and without fee is hereby granted, 
+ * provided that the above copyright notice appears in all copies and 
+ * that both the copyright notice and this permission notice appear in 
+ * supporting documentation. 
+ *  
+ * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE 
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
+ * FOR A PARTICULAR PURPOSE. 
+ *  
+ * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR 
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, 
+ * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION 
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 
+ */
+
+#ifndef __SCSIExplorer__
+#define __SCSIExplorer__
+#define DEBUG_INFOLIST          0
+
+#if !defined(__NewTypesDefined__)
+#define __NewTypesDefined__
+typedef signed char     SInt8;
+typedef signed short    SInt16;
+typedef signed long     SInt32;
+typedef unsigned char   UInt8;
+typedef unsigned short  UInt16;
+typedef unsigned long   UInt32;
+typedef unsigned long   ItemCount;
+typedef unsigned long   ByteCount;
+#endif
+
+/*
+ * Note: this must be SCSI.h from Universal Headers 2.0 - the current version
+ * of Think C headers still has the "old" header without SCSI Manager 4.3 support.
+ */
+#include <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__ */
diff --git a/SCSI_misc.c b/SCSI_misc.c
new file mode 100644 (file)
index 0000000..08c25fb
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * Copyright 1997 by Apple Computer, Inc.
+ *              All Rights Reserved 
+ *  
+ * Permission to use, copy, modify, and distribute this software and 
+ * its documentation for any purpose and without fee is hereby granted, 
+ * provided that the above copyright notice appears in all copies and 
+ * that both the copyright notice and this permission notice appear in 
+ * supporting documentation. 
+ *  
+ * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE 
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
+ * FOR A PARTICULAR PURPOSE. 
+ *  
+ * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR 
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, 
+ * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION 
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 
+ */
+
+#include "SCSIStuff.h"
+ SCSIExecIOPB       *gSCSIExecIOPBPtr;
+ UInt32         gSCSIExecIOPBPtrLen;
+
+void
+ClearMemory(
+       void                    *dataPtr,
+       register unsigned long          size
+    )
+{
+       register char           *ptr;
+
+       ptr = (char *) dataPtr;
+       while (size > 0) {
+           *ptr++ = 0;
+           --size;
+       }
+}
diff --git a/bitfield.c b/bitfield.c
new file mode 100644 (file)
index 0000000..687e8bd
--- /dev/null
@@ -0,0 +1,101 @@
+//
+// bitfield.c - extract and set bit fields
+//
+// Written by Eryk Vershen (eryk@apple.com)
+//
+// See comments in bitfield.h
+//
+
+/*
+ * Copyright 1996, 1997 by Apple Computer, Inc.
+ *              All Rights Reserved 
+ *  
+ * Permission to use, copy, modify, and distribute this software and 
+ * its documentation for any purpose and without fee is hereby granted, 
+ * provided that the above copyright notice appears in all copies and 
+ * that both the copyright notice and this permission notice appear in 
+ * supporting documentation. 
+ *  
+ * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE 
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
+ * FOR A PARTICULAR PURPOSE. 
+ *  
+ * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR 
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, 
+ * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION 
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 
+ */
+
+#include "bitfield.h"
+
+//
+// Defines
+//
+
+
+//
+// Types
+//
+
+
+//
+// Global Constants
+//
+const unsigned long masks[] = {
+    0x00000000,
+    0x00000001, 0x00000003, 0x00000007, 0x0000000F,
+    0x0000001F, 0x0000003F, 0x0000007F, 0x000000FF,
+    0x000001FF, 0x000003FF, 0x000007FF, 0x00000FFF,
+    0x00001FFF, 0x00003FFF, 0x00007FFF, 0x0000FFFF,
+    0x0001FFFF, 0x0003FFFF, 0x0007FFFF, 0x000FFFFF,
+    0x001FFFFF, 0x003FFFFF, 0x007FFFFF, 0x00FFFFFF,
+    0x01FFFFFF, 0x03FFFFFF, 0x07FFFFFF, 0x0FFFFFFF,
+    0x1FFFFFFF, 0x3FFFFFFF, 0x7FFFFFFF, 0xFFFFFFFF
+};
+
+//
+// Global Variables
+//
+
+
+//
+// Forward declarations
+//
+
+
+//
+// Routines
+//
+unsigned long
+bitfield_set(unsigned long *bf, int base, int length, unsigned long value)
+{
+    unsigned long t;
+    unsigned long m;
+    int s;
+    int i;
+
+    // compute shift & mask, coerce value to correct number of bits,
+    // zap the old bits and stuff the new value
+    // return the masked value in case someone wants it.
+    s = (base + 1) - length;
+    m = masks[length];
+    t = value & m;
+    *bf = (*bf & ~(m << s)) | (t << s);
+    return t;
+}
+
+
+unsigned long
+bitfield_get(unsigned long bf, int base, int length)
+{
+    unsigned long m;
+    int s;
+    int i;
+
+    // compute shift & mask
+    // return the correct number of bits (shifted to low end)
+    s = (base + 1) - length;
+    m = masks[length];
+    return ((bf >> s) & m);
+}
diff --git a/bitfield.h b/bitfield.h
new file mode 100644 (file)
index 0000000..ff56759
--- /dev/null
@@ -0,0 +1,67 @@
+//
+// bitfield.h - extract and set bit fields
+//
+// Written by Eryk Vershen (eryk@apple.com)
+//
+// Bitfields are not particularly transportable between big and little
+// endian machines.  Big endian machines lay out bitfields starting
+// from the most significant bit of the (one, two or four byte) number,
+// whereas little endian machines lay out bitfields starting from the
+// least signifcant bit.
+//
+// These routines were written to support some bitfields in a disk
+// data structure (partition map) whose original definition was on
+// a big-endian machine.
+//
+// They only work on 32-bit values because I didn't need 16-bit support.
+// The bits in the long word are numbered from 0 (least significant) to
+// 31 (most significant).
+//
+
+/*
+ * Copyright 1996 by Apple Computer, Inc.
+ *              All Rights Reserved 
+ *  
+ * Permission to use, copy, modify, and distribute this software and 
+ * its documentation for any purpose and without fee is hereby granted, 
+ * provided that the above copyright notice appears in all copies and 
+ * that both the copyright notice and this permission notice appear in 
+ * supporting documentation. 
+ *  
+ * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE 
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
+ * FOR A PARTICULAR PURPOSE. 
+ *  
+ * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR 
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, 
+ * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION 
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 
+ */
+
+
+//
+// Defines
+//
+
+
+//
+// Types
+//
+
+
+//
+// Global Constants
+//
+
+
+//
+// Global Variables
+//
+
+
+//
+// Forward declarations
+//
+unsigned long bitfield_set(unsigned long *bf, int base, int length, unsigned long value);
+unsigned long bitfield_get(unsigned long bf, int base, int length);
diff --git a/convert.c b/convert.c
new file mode 100644 (file)
index 0000000..977ff9a
--- /dev/null
+++ b/convert.c
@@ -0,0 +1,206 @@
+//
+// convert.c - Little-endian conversion
+//
+// Written by Eryk Vershen (eryk@apple.com)
+//
+// See comments in convert.h
+//
+
+/*
+ * Copyright 1996,1997 by Apple Computer, Inc.
+ *              All Rights Reserved 
+ *  
+ * Permission to use, copy, modify, and distribute this software and 
+ * its documentation for any purpose and without fee is hereby granted, 
+ * provided that the above copyright notice appears in all copies and 
+ * that both the copyright notice and this permission notice appear in 
+ * supporting documentation. 
+ *  
+ * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE 
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
+ * FOR A PARTICULAR PURPOSE. 
+ *  
+ * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR 
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, 
+ * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION 
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 
+ */
+
+#include <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;
+}
diff --git a/convert.h b/convert.h
new file mode 100644 (file)
index 0000000..269e192
--- /dev/null
+++ b/convert.h
@@ -0,0 +1,58 @@
+//
+// convert.h - Little-endian conversion
+//
+// Written by Eryk Vershen (eryk@apple.com)
+//
+// The approach taken to conversion is fairly simply.
+// Keep the in-memory copy in the machine's normal form and
+// Convert as necessary when reading and writing.
+//
+
+/*
+ * Copyright 1996 by Apple Computer, Inc.
+ *              All Rights Reserved 
+ *  
+ * Permission to use, copy, modify, and distribute this software and 
+ * its documentation for any purpose and without fee is hereby granted, 
+ * provided that the above copyright notice appears in all copies and 
+ * that both the copyright notice and this permission notice appear in 
+ * supporting documentation. 
+ *  
+ * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE 
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
+ * FOR A PARTICULAR PURPOSE. 
+ *  
+ * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR 
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, 
+ * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION 
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 
+ */
+
+
+//
+// Defines
+//
+
+
+//
+// Types
+//
+
+
+//
+// Global Constants
+//
+
+
+//
+// Global Variables
+//
+
+
+//
+// Forward declarations
+//
+int convert_block0(Block0 *data, int to_cpu_form);
+int convert_bzb(BZB *data, int to_cpu_form);
+int convert_dpme(DPME *data, int to_cpu_form);
diff --git a/dpme.h b/dpme.h
new file mode 100644 (file)
index 0000000..2994266
--- /dev/null
+++ b/dpme.h
@@ -0,0 +1,209 @@
+//
+// dpme.h - Disk Partition Map Entry (dpme)
+//
+// Written by Eryk Vershen (eryk@apple.com)
+//
+// This file describes structures and values related to the standard
+// Apple SCSI disk partitioning scheme.
+//
+// Each entry is (and shall remain) 512 bytes long.
+//
+// For more information see:
+//     "Inside Macintosh: Devices" pages 3-12 to 3-15.
+//     "Inside Macintosh - Volume V" pages V-576 to V-582
+//     "Inside Macintosh - Volume IV" page IV-292
+//
+// There is a kernel file with much of the same info (under different names):
+//     /usr/src/mklinux-1.0DR2/osfmk/src/mach_kernel/ppc/POWERMAC/mac_label.h
+//
+
+/*
+ * Copyright 1996 by Apple Computer, Inc.
+ *              All Rights Reserved 
+ *  
+ * Permission to use, copy, modify, and distribute this software and 
+ * its documentation for any purpose and without fee is hereby granted, 
+ * provided that the above copyright notice appears in all copies and 
+ * that both the copyright notice and this permission notice appear in 
+ * supporting documentation. 
+ *  
+ * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE 
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
+ * FOR A PARTICULAR PURPOSE. 
+ *  
+ * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR 
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, 
+ * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION 
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 
+ */
+
+#include "bitfield.h"
+
+//
+// Defines
+//
+#define        BLOCK0_SIGNATURE        0x4552  /* Signature value.         */
+
+#define        DPISTRLEN       32
+#define        DPME_SIGNATURE  0x504D
+
+// A/UX only stuff (tradition!)
+#define        dpme_bzb        dpme_boot_args
+#define        BZBMAGIC 0xABADBABE     /* BZB magic number */
+#define        FST     ((u8) 0x1)      /* standard UNIX FS */
+#define        FSTEFS  ((u8) 0x2)      /* Autorecovery FS */
+#define        FSTSFS  ((u8) 0x3)      /* Swap FS */
+
+
+//
+// Types
+//
+typedef        unsigned char   u8;
+typedef        unsigned short  u16;
+typedef        unsigned long   u32;
+
+
+// Physical block zero of the disk has this format
+struct Block0 {
+    u16        sbSig;          /* unique value for SCSI block 0 */
+    u16        sbBlkSize;      /* block size of device */
+    u32        sbBlkCount;     /* number of blocks on device */
+    u16        sbDevType;      /* device type */
+    u16        sbDevId;        /* device id */
+    u32        sbData;         /* not used */
+    u16        sbDrvrCount;    /* driver descriptor count */
+    u16        sbMap[247];     /* descriptor map */
+};
+typedef struct Block0 Block0;
+
+// Where &sbMap[0] is actually an array DDMap[sbDrvrCount]
+// kludge to get around alignment junk
+struct DDMap {
+    u32        ddBlock;        /* 1st driver's starting block */
+    u16        ddSize;         /* size of 1st driver (512-byte blks) */
+    u16        ddType;         /* system type (1 for Mac+) */
+};
+typedef struct DDMap DDMap;
+
+
+// Each partition map entry (blocks 1 through n) has this format
+struct dpme {
+    u16     dpme_signature          ;
+    u16     dpme_reserved_1         ;
+    u32     dpme_map_entries        ;
+    u32     dpme_pblock_start       ;
+    u32     dpme_pblocks            ;
+    char    dpme_name[DPISTRLEN]    ;  /* name of partition */
+    char    dpme_type[DPISTRLEN]    ;  /* type of partition */
+    u32     dpme_lblock_start       ;
+    u32     dpme_lblocks            ;
+    u32     dpme_flags;
+#if 0
+    u32     dpme_reserved_2    : 23 ;  /* Bit 9 through 31.        */
+    u32     dpme_os_specific_1 :  1 ;  /* Bit 8.                   */
+    u32     dpme_os_specific_2 :  1 ;  /* Bit 7.                   */
+    u32     dpme_os_pic_code   :  1 ;  /* Bit 6.                   */
+    u32     dpme_writable      :  1 ;  /* Bit 5.                   */
+    u32     dpme_readable      :  1 ;  /* Bit 4.                   */
+    u32     dpme_bootable      :  1 ;  /* Bit 3.                   */
+    u32     dpme_in_use        :  1 ;  /* Bit 2.                   */
+    u32     dpme_allocated     :  1 ;  /* Bit 1.                   */
+    u32     dpme_valid         :  1 ;  /* Bit 0.                   */
+#endif
+    u32     dpme_boot_block         ;
+    u32     dpme_boot_bytes         ;
+    u8     *dpme_load_addr          ;
+    u8     *dpme_load_addr_2        ;
+    u8     *dpme_goto_addr          ;
+    u8     *dpme_goto_addr_2        ;
+    u32     dpme_checksum           ;
+    char    dpme_process_id[16]     ;
+    u32     dpme_boot_args[32]      ;
+    u32     dpme_reserved_3[62]     ;
+};
+typedef struct dpme DPME;
+
+#define        dpme_os_specific_1_set(p, v)    bitfield_set(&p->dpme_flags, 8, 1, v)
+#define        dpme_os_specific_2_set(p, v)    bitfield_set(&p->dpme_flags, 7, 1, v)
+#define        dpme_os_pic_code_set(p, v)      bitfield_set(&p->dpme_flags, 6, 1, v)
+#define        dpme_writable_set(p, v)         bitfield_set(&p->dpme_flags, 5, 1, v)
+#define        dpme_readable_set(p, v)         bitfield_set(&p->dpme_flags, 4, 1, v)
+#define        dpme_bootable_set(p, v)         bitfield_set(&p->dpme_flags, 3, 1, v)
+#define        dpme_in_use_set(p, v)           bitfield_set(&p->dpme_flags, 2, 1, v)
+#define        dpme_allocated_set(p, v)        bitfield_set(&p->dpme_flags, 1, 1, v)
+#define        dpme_valid_set(p, v)            bitfield_set(&p->dpme_flags, 0, 1, v)
+
+#define        dpme_os_specific_1_get(p)       bitfield_get(p->dpme_flags, 8, 1)
+#define        dpme_os_specific_2_get(p)       bitfield_get(p->dpme_flags, 7, 1)
+#define        dpme_os_pic_code_get(p)         bitfield_get(p->dpme_flags, 6, 1)
+#define        dpme_writable_get(p)            bitfield_get(p->dpme_flags, 5, 1)
+#define        dpme_readable_get(p)            bitfield_get(p->dpme_flags, 4, 1)
+#define        dpme_bootable_get(p)            bitfield_get(p->dpme_flags, 3, 1)
+#define        dpme_in_use_get(p)              bitfield_get(p->dpme_flags, 2, 1)
+#define        dpme_allocated_get(p)           bitfield_get(p->dpme_flags, 1, 1)
+#define        dpme_valid_get(p)               bitfield_get(p->dpme_flags, 0, 1)
+
+
+// A/UX only data structures (sentimental reasons?)
+
+// Alternate block map (aka bad block remaping) [Never really used]
+struct abm             /* altblk map info stored in bzb */
+{
+    u32  abm_size;     /* size of map in bytes */
+    u32  abm_ents;     /* number of used entries */
+    u32  abm_start;    /* start of altblk map */
+};
+typedef        struct abm ABM;
+
+// BZB (Block Zero Block, but I can't remember the etymology)
+// Where &dpme_boot_args[0] is actually the address of a struct bzb
+// kludge to get around alignment junk
+struct bzb                     /* block zero block format */
+{
+    u32  bzb_magic;            /* magic number */
+    u8   bzb_cluster;          /* Autorecovery cluster grouping */
+    u8   bzb_type;             /* FS type */
+    u16  bzb_inode;            /* bad block inode number */
+    u32  bzb_flags;
+#if 0
+    u16  bzb_root:1,           /* FS is a root FS */
+        bzb_usr:1,             /* FS is a usr FS */
+        bzb_crit:1,            /* FS is a critical FS */
+        bzb_rsrvd:8,           /* reserved for later use */
+        bzb_slice:5;           /* slice number to associate with plus one */
+    u16  bzb_filler;           /* pad bitfield to 32 bits */
+#endif
+    u32  bzb_tmade;            /* time of FS creation */
+    u32  bzb_tmount;           /* time of last mount */
+    u32  bzb_tumount;          /* time of last umount */
+    ABM  bzb_abm;              /* altblk map info */
+    u32  bzb_fill2[7];         /* for expansion of ABM (ha!ha!) */
+    u8   bzb_mount_point[64];  /* default mount point name */
+};
+typedef        struct bzb      BZB;
+
+#define        bzb_root_set(p, v)              bitfield_set(&p->bzb_flags, 31, 1, v)
+#define        bzb_usr_set(p, v)               bitfield_set(&p->bzb_flags, 30, 1, v)
+#define        bzb_crit_set(p, v)              bitfield_set(&p->bzb_flags, 29, 1, v)
+#define        bzb_slice_set(p, v)             bitfield_set(&p->bzb_flags, 20, 5, v)
+
+#define        bzb_root_get(p)                 bitfield_get(p->bzb_flags, 31, 1)
+#define        bzb_usr_get(p)                  bitfield_get(p->bzb_flags, 30, 1)
+#define        bzb_crit_get(p)                 bitfield_get(p->bzb_flags, 29, 1)
+#define        bzb_slice_get(p)                bitfield_get(p->bzb_flags, 20, 5)
+
+
+//
+// Global Constants
+//
+
+
+//
+// Global Variables
+//
+
+
+//
+// Forward declarations
+//
diff --git a/dump.c b/dump.c
new file mode 100644 (file)
index 0000000..61ad91b
--- /dev/null
+++ b/dump.c
@@ -0,0 +1,467 @@
+//
+// dump.c - dumping partition maps
+//
+// Written by Eryk Vershen (eryk@apple.com)
+//
+
+/*
+ * Copyright 1996,1997 by Apple Computer, Inc.
+ *              All Rights Reserved 
+ *  
+ * Permission to use, copy, modify, and distribute this software and 
+ * its documentation for any purpose and without fee is hereby granted, 
+ * provided that the above copyright notice appears in all copies and 
+ * that both the copyright notice and this permission notice appear in 
+ * supporting documentation. 
+ *  
+ * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE 
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
+ * FOR A PARTICULAR PURPOSE. 
+ *  
+ * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR 
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, 
+ * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION 
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 
+ */
+
+#include <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");
+    }
+}
+
+
diff --git a/dump.h b/dump.h
new file mode 100644 (file)
index 0000000..bd25c6b
--- /dev/null
+++ b/dump.h
@@ -0,0 +1,55 @@
+//
+// dump.h - dumping partition maps
+//
+// Written by Eryk Vershen (eryk@apple.com)
+//
+
+/*
+ * Copyright 1996,1997 by Apple Computer, Inc.
+ *              All Rights Reserved 
+ *  
+ * Permission to use, copy, modify, and distribute this software and 
+ * its documentation for any purpose and without fee is hereby granted, 
+ * provided that the above copyright notice appears in all copies and 
+ * that both the copyright notice and this permission notice appear in 
+ * supporting documentation. 
+ *  
+ * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE 
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
+ * FOR A PARTICULAR PURPOSE. 
+ *  
+ * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR 
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, 
+ * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION 
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 
+ */
+
+
+//
+// Defines
+//
+
+
+//
+// Types
+//
+
+
+//
+// Global Constants
+//
+
+
+//
+// Global Variables
+//
+
+
+//
+// Forward declarations
+//
+void dump(char *name);
+void dump_partition_map(partition_map_header *map, int disk_order);
+void list_all_disks();
+void show_data_structures(partition_map_header *map);
diff --git a/errors.c b/errors.c
new file mode 100644 (file)
index 0000000..47c9c30
--- /dev/null
+++ b/errors.c
@@ -0,0 +1,155 @@
+//
+// errors.c - error & help routines
+//
+// Written by Eryk Vershen (eryk@apple.com)
+//
+
+/*
+ * Copyright 1996,1997 by Apple Computer, Inc.
+ *              All Rights Reserved 
+ *  
+ * Permission to use, copy, modify, and distribute this software and 
+ * its documentation for any purpose and without fee is hereby granted, 
+ * provided that the above copyright notice appears in all copies and 
+ * that both the copyright notice and this permission notice appear in 
+ * supporting documentation. 
+ *  
+ * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE 
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
+ * FOR A PARTICULAR PURPOSE. 
+ *  
+ * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR 
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, 
+ * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION 
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 
+ */
+
+#include <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
+}
diff --git a/errors.h b/errors.h
new file mode 100644 (file)
index 0000000..b6de7fd
--- /dev/null
+++ b/errors.h
@@ -0,0 +1,56 @@
+//
+// errors.h - error & help routines
+//
+// Written by Eryk Vershen (eryk@apple.com)
+//
+
+/*
+ * Copyright 1996 by Apple Computer, Inc.
+ *              All Rights Reserved 
+ *  
+ * Permission to use, copy, modify, and distribute this software and 
+ * its documentation for any purpose and without fee is hereby granted, 
+ * provided that the above copyright notice appears in all copies and 
+ * that both the copyright notice and this permission notice appear in 
+ * supporting documentation. 
+ *  
+ * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE 
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
+ * FOR A PARTICULAR PURPOSE. 
+ *  
+ * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR 
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, 
+ * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION 
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 
+ */
+
+
+//
+// Defines
+//
+
+
+//
+// Types
+//
+
+
+//
+// Global Constants
+//
+
+
+//
+// Global Variables
+//
+
+
+//
+// Forward declarations
+//
+void do_help();
+void init_program_name(char **argv);
+void error(int value, char *fmt, ...);
+void fatal(int value, char *fmt, ...);
+void usage(char *kind);
diff --git a/fdisk.c b/fdisk.c
new file mode 100644 (file)
index 0000000..11e92db
--- /dev/null
+++ b/fdisk.c
@@ -0,0 +1,1508 @@
+/* fdisk.c -- Partition table manipulator for Linux.
+ *
+ * Copyright (C) 1992  A. V. Le Blanc (LeBlanc@mcc.ac.uk)
+ *
+ * This program is free software.  You can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation: either version 1 or
+ * (at your option) any later version.
+ *
+ * Before Linux version 0.95c, this program requires a kernel patch.
+ *
+ * Modified, Tue Feb  2 18:46:49 1993, faith@cs.unc.edu to better support SCSI.
+ * Modified, Sat Feb 27 18:11:27 1993, faith@cs.unc.edu: added extfs support.
+ * Modified, Sat Mar  6 10:14:12 1993, faith@cs.unc.edu: added more comments.
+ * Modified, Sat Mar  6 12:25:45 1993, faith@cs.unc.edu:
+ *     Added patches from Michael Bischoff (i1041905@ws.rz.tu-bs.de
+ *     or mbi@mo.math.nat.tu-bs.de) to fix the following problems:
+ *     1) Incorrect mapping of head/sector/cylinder to absolute sector
+ *     2) Odd sector count causes one sector to be lost
+ * Modified, Sat Mar  6 12:25:52 1993, faith@cs.unc.edu: improved verification.
+ * Modified, Sat Apr 17 15:00:00 1993, LeBlanc@mcc.ac.uk: add -s, fix -l.
+ * Modified, Sat Apr 24 10:00:00 1993, LeBlanc@mcc.ac.uk: fix overlap bug.
+ * Modified, Wed May  5 21:30:00 1993, LeBlanc@mcc.ac.uk: errors to stderr.
+ * Modified, Mon Mar 21 20:00:00 1994, LeBlanc@mcc.ac.uk:
+ *     more stderr for messages, avoid division by 0, and
+ *     give reboot message only if ioctl(fd, BLKRRPART) fails.
+ * Modified, Mon Apr 25 01:01:05 1994, martin@cs.unc.edu:
+ *    1) Added support for DOS, OS/2, ... compatibility.  We should be able
+ *       use this fdisk to partition our drives for other operating systems.
+ *    2) Added a print the raw data in the partition table command.
+ * Modified, Wed Jun 22 21:05:30 1994, faith@cs.unc.edu:
+ *    Added/changed a few partition type names to conform to cfdisk.
+ *    (suggested by Sujal, smpatel@wam.umd.edu)
+ * Modified 3/5/95 leisner@sdsp.mc.xerox.com -- on -l only open
+ *    devices RDONLY (instead of RDWR).  This allows you to
+ *    have the disks as rw-r----- with group disk (and if you
+ *    want is safe to setguid fdisk to disk).
+ * Modified Sat Mar 11 10:02 1995 with more partition types, faith@cs.unc.edu
+ * Modified, Thu May  4 01:11:45 1995, esr@snark.thyrsus.com:
+ *     It's user-interface cleanup time.
+ *     Actual error messages for out-of-bounds values (what a concept!).
+ *     Enable read-only access to partition table for learners.
+ *     Smart defaults for most numeric prompts.
+ * Fixed a bug preventing a partition from crossing cylinder 8064, aeb, 950801.
+ * Read partition table twice to avoid kernel bug
+ *     (from Daniel Quinlan <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();
+               }
+       }
+}
diff --git a/fdisk.h b/fdisk.h
new file mode 100644 (file)
index 0000000..2b6ddc8
--- /dev/null
+++ b/fdisk.h
@@ -0,0 +1,51 @@
+/*
+   fdisk.h
+*/
+
+#define SECTOR_SIZE    512
+#define NETBSD_PARTITION 0xa5
+#define cround(n)      (((n) + display_factor * unit_flag) / display_factor)
+
+#if defined(__GNUC__) || defined(HAS_LONG_LONG)
+typedef long long ext2_loff_t;
+#else
+typedef long      ext2_loff_t;
+#endif
+
+#if BYTE_ORDER == BIG_ENDIAN
+#define SWAP16(x) __swap16(x)
+#define SWAP32(x) __swap32(x)
+#else
+#define SWAP16(x) ((__u16)x)
+#define SWAP32(x) ((__u32)x)
+#endif
+
+enum failure {usage, unable_to_open, unable_to_read, unable_to_seek,
+       unable_to_write, out_of_memory};
+
+enum offset {ignore, lower, deflt, upper};
+
+struct systypes {
+  unsigned char index;
+  char *name;
+};
+
+/* prototypes for fdisk.c */
+extern char *disk_device,
+            *line_ptr;
+extern int fd,
+           partitions;
+extern uint unit_flag,
+            display_factor;
+extern struct partition *part_table[];
+extern void fatal(enum failure why);
+extern int  get_partition(int warn, int max);
+extern void list_types(struct systypes *sys, int size);
+extern int read_line (void);
+extern char read_char(char *mesg);
+extern int read_hex(struct systypes *sys, int size);
+uint read_int(uint low, uint dflt, uint high, enum offset base, char *mesg);
+extern char *const str_units(void);
+
+/* prototypes for fdisklabel.c */
+extern void bselect(void);
diff --git a/fdisklabel.c b/fdisklabel.c
new file mode 100644 (file)
index 0000000..9344339
--- /dev/null
@@ -0,0 +1,803 @@
+/*
+   NetBSD disklabel editor for Linux fdisk
+   Written by Bernhard Fastenrath (fasten@informatik.uni-bonn.de)
+   with code from the NetBSD disklabel command:
+  
+   Copyright (c) 1987, 1988 Regents of the University of California.
+   All rights reserved.
+  
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+   1. Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+   2. Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+   3. All advertising materials mentioning features or use of this software
+      must display the following acknowledgement:
+       This product includes software developed by the University of
+       California, Berkeley and its contributors.
+   4. Neither the name of the University nor the names of its contributors
+      may be used to endorse or promote products derived from this software
+      without specific prior written permission.
+  
+   THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+   ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+   IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+   ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+   FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+   DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+   OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+   HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+   LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+   OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+   SUCH DAMAGE.
+*/
+
+#include <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__ */
diff --git a/fdisklabel.h b/fdisklabel.h
new file mode 100644 (file)
index 0000000..0b5227c
--- /dev/null
@@ -0,0 +1,239 @@
+/*
+ * Copyright (c) 1987, 1988 Regents of the University of California.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#define BSD_DISKMAGIC     ((u_long) 0x82564557)
+#define        BSD_MAXPARTITIONS 8
+#define BSD_LINUX_BOOTDIR "/usr/ucb/mdec"
+
+#if defined (i386)
+#define BSD_LABELSECTOR   1
+#define BSD_LABELOFFSET   0
+#define        BSD_BBSIZE        8192          /* size of boot area, with label */
+#define        BSD_SBSIZE        8192          /* max size of fs superblock */
+#elif defined (__alpha__)
+#error LABELSECTOR, LABELOFFSET, BBSIZE & SBSIZE are undefined for __alpha__
+#define BSD_LABELSECTOR   0
+#define BSD_LABELOFFSET   0
+#define        BSD_BBSIZE        0
+#define        BSD_SBSIZE        0
+#elif defined (__powerpc__)
+/* LABELSECTOR, LABELOFFSET, BBSIZE & SBSIZE are undefined for __powerpc__ */
+#define BSD_LABELSECTOR   0
+#define BSD_LABELOFFSET   0
+#define        BSD_BBSIZE        0
+#define        BSD_SBSIZE        0
+#else
+#error unknown architecture
+#endif
+
+struct disklabel {
+       u_long  d_magic;                /* the magic number */
+       short   d_type;                 /* drive type */
+       short   d_subtype;              /* controller/d_type specific */
+       char    d_typename[16];         /* type name, e.g. "eagle" */
+       /* 
+        * d_packname contains the pack identifier and is returned when
+        * the disklabel is read off the disk or in-core copy.
+        * d_boot0 and d_boot1 are the (optional) names of the
+        * primary (block 0) and secondary (block 1-15) bootstraps
+        * as found in /usr/mdec.  These are returned when using
+        * getdiskbyname(3) to retrieve the values from /etc/disktab.
+        */
+#if defined(KERNEL) || defined(STANDALONE)
+       char    d_packname[16];                 /* pack identifier */ 
+#else
+       union {
+               char    un_d_packname[16];      /* pack identifier */ 
+               struct {
+                       char *un_d_boot0;       /* primary bootstrap name */
+                       char *un_d_boot1;       /* secondary bootstrap name */
+               } un_b; 
+       } d_un; 
+#define d_packname     d_un.un_d_packname
+#define d_boot0                d_un.un_b.un_d_boot0
+#define d_boot1                d_un.un_b.un_d_boot1
+#endif /* ! KERNEL or STANDALONE */
+                       /* disk geometry: */
+       u_long  d_secsize;              /* # of bytes per sector */
+       u_long  d_nsectors;             /* # of data sectors per track */
+       u_long  d_ntracks;              /* # of tracks per cylinder */
+       u_long  d_ncylinders;           /* # of data cylinders per unit */
+       u_long  d_secpercyl;            /* # of data sectors per cylinder */
+       u_long  d_secperunit;           /* # of data sectors per unit */
+       /*
+        * Spares (bad sector replacements) below
+        * are not counted in d_nsectors or d_secpercyl.
+        * Spare sectors are assumed to be physical sectors
+        * which occupy space at the end of each track and/or cylinder.
+        */
+       u_short d_sparespertrack;       /* # of spare sectors per track */
+       u_short d_sparespercyl;         /* # of spare sectors per cylinder */
+       /*
+        * Alternate cylinders include maintenance, replacement,
+        * configuration description areas, etc.
+        */
+       u_long  d_acylinders;           /* # of alt. cylinders per unit */
+
+                       /* hardware characteristics: */
+       /*
+        * d_interleave, d_trackskew and d_cylskew describe perturbations
+        * in the media format used to compensate for a slow controller.
+        * Interleave is physical sector interleave, set up by the formatter
+        * or controller when formatting.  When interleaving is in use,
+        * logically adjacent sectors are not physically contiguous,
+        * but instead are separated by some number of sectors.
+        * It is specified as the ratio of physical sectors traversed
+        * per logical sector.  Thus an interleave of 1:1 implies contiguous
+        * layout, while 2:1 implies that logical sector 0 is separated
+        * by one sector from logical sector 1.
+        * d_trackskew is the offset of sector 0 on track N
+        * relative to sector 0 on track N-1 on the same cylinder.
+        * Finally, d_cylskew is the offset of sector 0 on cylinder N
+        * relative to sector 0 on cylinder N-1.
+        */
+       u_short d_rpm;                  /* rotational speed */
+       u_short d_interleave;           /* hardware sector interleave */
+       u_short d_trackskew;            /* sector 0 skew, per track */
+       u_short d_cylskew;              /* sector 0 skew, per cylinder */
+       u_long  d_headswitch;           /* head switch time, usec */
+       u_long  d_trkseek;              /* track-to-track seek, usec */
+       u_long  d_flags;                /* generic flags */
+#define NDDATA 5
+       u_long  d_drivedata[NDDATA];    /* drive-type specific information */
+#define NSPARE 5
+       u_long  d_spare[NSPARE];        /* reserved for future use */
+       u_long  d_magic2;               /* the magic number (again) */
+       u_short d_checksum;             /* xor of data incl. partitions */
+                       /* filesystem and partition information: */
+       u_short d_npartitions;          /* number of partitions in following */
+       u_long  d_bbsize;               /* size of boot area at sn0, bytes */
+       u_long  d_sbsize;               /* max size of fs superblock, bytes */
+       struct bsd_partition {          /* the partition table */
+               u_long  p_size;         /* number of sectors in partition */
+               u_long  p_offset;       /* starting sector */
+               u_long  p_fsize;        /* filesystem basic fragment size */
+               u_char  p_fstype;       /* filesystem type, see below */
+               u_char  p_frag;         /* filesystem fragments per block */
+               u_short p_cpg;          /* filesystem cylinders per group */
+       } d_partitions[BSD_MAXPARTITIONS]; /* actually may be more */
+};
+
+/* d_type values: */
+#define        BSD_DTYPE_SMD           1               /* SMD, XSMD; VAX hp/up */
+#define        BSD_DTYPE_MSCP          2               /* MSCP */
+#define        BSD_DTYPE_DEC           3               /* other DEC (rk, rl) */
+#define        BSD_DTYPE_SCSI          4               /* SCSI */
+#define        BSD_DTYPE_ESDI          5               /* ESDI interface */
+#define        BSD_DTYPE_ST506         6               /* ST506 etc. */
+#define        BSD_DTYPE_HPIB          7               /* CS/80 on HP-IB */
+#define BSD_DTYPE_HPFL         8               /* HP Fiber-link */
+#define        BSD_DTYPE_FLOPPY        10              /* floppy */
+
+/* d_subtype values: */
+#define BSD_DSTYPE_INDOSPART   0x8             /* is inside dos partition */
+#define BSD_DSTYPE_DOSPART(s)  ((s) & 3)       /* dos partition number */
+#define BSD_DSTYPE_GEOMETRY    0x10            /* drive params in label */
+
+#ifdef DKTYPENAMES
+static char *bsd_dktypenames[] = {
+       "unknown",
+       "SMD",
+       "MSCP",
+       "old DEC",
+       "SCSI",
+       "ESDI",
+       "ST506",
+       "HP-IB",
+       "HP-FL",
+       "type 9",
+       "floppy",
+       0
+};
+#define BSD_DKMAXTYPES (sizeof(bsd_dktypenames) / sizeof(bsd_dktypenames[0]) - 1)
+#endif
+
+/*
+ * Filesystem type and version.
+ * Used to interpret other filesystem-specific
+ * per-partition information.
+ */
+#define        BSD_FS_UNUSED   0               /* unused */
+#define        BSD_FS_SWAP     1               /* swap */
+#define        BSD_FS_V6       2               /* Sixth Edition */
+#define        BSD_FS_V7       3               /* Seventh Edition */
+#define        BSD_FS_SYSV     4               /* System V */
+#define        BSD_FS_V71K     5               /* V7 with 1K blocks (4.1, 2.9) */
+#define        BSD_FS_V8       6               /* Eighth Edition, 4K blocks */
+#define        BSD_FS_BSDFFS   7               /* 4.2BSD fast file system */
+#define        BSD_FS_MSDOS    8               /* MS-DOS file system */
+#define        BSD_FS_BSDLFS   9               /* 4.4BSD log-structured file system */
+#define        BSD_FS_OTHER    10              /* in use, but unknown/unsupported */
+#define        BSD_FS_HPFS     11              /* OS/2 high-performance file system */
+#define        BSD_FS_ISO9660  12              /* ISO-9660 filesystem (cdrom) */
+#define BSD_FS_ISOFS   BSD_FS_ISO9660
+#define        BSD_FS_BOOT     13              /* partition contains bootstrap */
+#define BSD_FS_ADOS    14              /* AmigaDOS fast file system */
+#define BSD_FS_HFS     15              /* Macintosh HFS */
+
+#ifdef DKTYPENAMES
+static struct systypes bsd_fstypes[] = {
+        {BSD_FS_UNUSED, "unused"},
+       {BSD_FS_SWAP,   "swap"},
+       {BSD_FS_V6,     "Version 6"},
+       {BSD_FS_V7,     "Version 7"},
+       {BSD_FS_SYSV,   "System V"},
+       {BSD_FS_V71K,   "4.1BSD"},
+       {BSD_FS_V8,     "Eighth Edition"},
+       {BSD_FS_BSDFFS, "4.2BSD"},
+       {BSD_FS_MSDOS,  "MS-DOS"},
+       {BSD_FS_BSDLFS, "4.4LFS"},
+       {BSD_FS_OTHER,  "unknown"},
+       {BSD_FS_HPFS,   "HPFS"},
+       {BSD_FS_ISO9660,"ISO-9660"},
+       {BSD_FS_BOOT,   "boot"},
+       {BSD_FS_ADOS,   "ADOS"},
+       {BSD_FS_HFS,    "HFS"}
+};
+
+#define BSD_FSMAXTYPES (sizeof(bsd_fstypes) / sizeof(struct systypes))
+#endif
+
+/*
+ * flags shared by various drives:
+ */
+#define        BSD_D_REMOVABLE 0x01            /* removable media */
+#define        BSD_D_ECC       0x02            /* supports ECC */
+#define        BSD_D_BADSECT   0x04            /* supports bad sector forw. */
+#define        BSD_D_RAMDISK   0x08            /* disk emulator */
+#define        BSD_D_CHAIN     0x10            /* can do back-back transfers */
+#define        BSD_D_DOSPART   0x20            /* within MSDOS partition */
diff --git a/io.c b/io.c
new file mode 100644 (file)
index 0000000..0c99d94
--- /dev/null
+++ b/io.c
@@ -0,0 +1,529 @@
+//
+// io.c - simple io and input parsing routines
+//
+// Written by Eryk Vershen (eryk@apple.com)
+//
+
+/*
+ * Copyright 1996,1997 by Apple Computer, Inc.
+ *              All Rights Reserved 
+ *  
+ * Permission to use, copy, modify, and distribute this software and 
+ * its documentation for any purpose and without fee is hereby granted, 
+ * provided that the above copyright notice appears in all copies and 
+ * that both the copyright notice and this permission notice appear in 
+ * supporting documentation. 
+ *  
+ * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE 
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
+ * FOR A PARTICULAR PURPOSE. 
+ *  
+ * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR 
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, 
+ * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION 
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 
+ */
+
+#include <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);
+    }
+}
diff --git a/io.h b/io.h
new file mode 100644 (file)
index 0000000..9561b34
--- /dev/null
+++ b/io.h
@@ -0,0 +1,67 @@
+//
+// io.h - simple io and input parsing routines
+//
+// Written by Eryk Vershen (eryk@apple.com)
+//
+
+/*
+ * Copyright 1996,1997 by Apple Computer, Inc.
+ *              All Rights Reserved 
+ *  
+ * Permission to use, copy, modify, and distribute this software and 
+ * its documentation for any purpose and without fee is hereby granted, 
+ * provided that the above copyright notice appears in all copies and 
+ * that both the copyright notice and this permission notice appear in 
+ * supporting documentation. 
+ *  
+ * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE 
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
+ * FOR A PARTICULAR PURPOSE. 
+ *  
+ * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR 
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, 
+ * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION 
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 
+ */
+
+
+//
+// Defines
+//
+#define        PBLOCK_SIZE     512
+
+
+//
+// Types
+//
+
+
+//
+// Global Constants
+//
+extern const long kDefault;
+
+
+//
+// Global Variables
+//
+
+
+//
+// Forward declarations
+//
+void bad_input(char *fmt, ...);
+int close_device(int fildes);
+void flush_to_newline(int keep_newline);
+int get_command(char *prompt, int promptBeforeGet, int *command);
+long get_multiplier(long divisor);
+int get_number_argument(char *prompt, long *number, long default_value);
+int get_okay(char *prompt, int default_value);
+int get_string_argument(char *prompt, char **string, int reprompt);
+int getch();
+int number_of_digits(unsigned long value);
+int open_device(const char *path, int oflag);
+int read_block(int fd, unsigned long num, char *buf, int quiet);
+void ungetch(int c);
+int write_block(int fd, unsigned long num, char *buf);
diff --git a/list.src b/list.src
new file mode 100644 (file)
index 0000000..63288c5
--- /dev/null
+++ b/list.src
@@ -0,0 +1,34 @@
+pdisk/DoReadWrite.c
+pdisk/DoSCSICommandWithSense.c
+pdisk/DoTestUnitReady.c
+pdisk/HISTORY
+pdisk/MacSCSICommand.h
+pdisk/README
+pdisk/SCSIStuff.h
+pdisk/SCSI_misc.c
+pdisk/bitfield.c
+pdisk/bitfield.h
+pdisk/convert.c
+pdisk/convert.h
+pdisk/dpme.h
+pdisk/dump.c
+pdisk/dump.h
+pdisk/errors.c
+pdisk/errors.h
+pdisk/io.c
+pdisk/io.h
+pdisk/list.src
+pdisk/makefile
+pdisk/partition_map.c
+pdisk/partition_map.h
+pdisk/pdisk.8
+pdisk/pdisk.c
+pdisk/pdisk.h
+pdisk/pdisk.r
+pdisk/version.h
+pdisk/pdisk.mac.bin
+
+pdisk/fdisk.c
+pdisk/fdisk.h
+pdisk/fdisklabel.c
+pdisk/fdisklabel.h
diff --git a/partition_map.c b/partition_map.c
new file mode 100644 (file)
index 0000000..113f66b
--- /dev/null
@@ -0,0 +1,1061 @@
+//
+// partition_map.c - partition map routines
+//
+// Written by Eryk Vershen (eryk@apple.com)
+//
+
+/*
+ * Copyright 1996,1997 by Apple Computer, Inc.
+ *              All Rights Reserved 
+ *  
+ * Permission to use, copy, modify, and distribute this software and 
+ * its documentation for any purpose and without fee is hereby granted, 
+ * provided that the above copyright notice appears in all copies and 
+ * that both the copyright notice and this permission notice appear in 
+ * supporting documentation. 
+ *  
+ * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE 
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
+ * FOR A PARTICULAR PURPOSE. 
+ *  
+ * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR 
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, 
+ * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION 
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 
+ */
+
+#include <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);
+}
diff --git a/partition_map.h b/partition_map.h
new file mode 100644 (file)
index 0000000..90f2210
--- /dev/null
@@ -0,0 +1,92 @@
+//
+// partition_map.h - partition map routines
+//
+// Written by Eryk Vershen (eryk@apple.com)
+//
+
+/*
+ * Copyright 1996 by Apple Computer, Inc.
+ *              All Rights Reserved 
+ *  
+ * Permission to use, copy, modify, and distribute this software and 
+ * its documentation for any purpose and without fee is hereby granted, 
+ * provided that the above copyright notice appears in all copies and 
+ * that both the copyright notice and this permission notice appear in 
+ * supporting documentation. 
+ *  
+ * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE 
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
+ * FOR A PARTICULAR PURPOSE. 
+ *  
+ * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR 
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, 
+ * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION 
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 
+ */
+
+#include "dpme.h"
+
+
+//
+// Defines
+//
+
+
+//
+// Types
+//
+struct partition_map_header {
+    int fd;
+    char *name;
+    struct partition_map * disk_order;
+    struct partition_map * base_order;
+    Block0 *misc;
+    int writeable;
+    int changed;
+    int regular_file;
+    int blocks_in_map;
+    int maximum_in_map;
+    unsigned long media_size;
+};
+typedef struct partition_map_header partition_map_header;
+
+struct partition_map {
+    struct partition_map * next_on_disk;
+    struct partition_map * prev_on_disk;
+    struct partition_map * next_by_base;
+    struct partition_map * prev_by_base;
+    long disk_address;
+    struct partition_map_header * the_map;
+    DPME *data;
+};
+typedef struct partition_map partition_map;
+
+
+//
+// Global Constants
+//
+extern const char * kFreeType;
+extern const char * kMapType;
+extern const char * kUnixType;
+
+extern const char * kFreeName;
+
+
+//
+// Global Variables
+//
+
+
+//
+// Forward declarations
+//
+int add_partition_to_map(const char *name, const char *dptype, u32 base, u32 length, partition_map_header *map);
+void close_partition_map(partition_map_header *map);
+void delete_partition_from_map(partition_map *entry);
+partition_map* find_entry_by_disk_address(long index, partition_map_header *map);
+partition_map_header* init_partition_map(char *name, partition_map_header* oldmap);
+void move_entry_in_map(long old_index, long index, partition_map_header *map);
+partition_map_header* open_partition_map(char *name, int *valid_file);
+void resize_map(long new_size, partition_map_header *map);
+void write_partition_map(partition_map_header *map);
diff --git a/pdisk.8 b/pdisk.8
new file mode 100644 (file)
index 0000000..01eaa81
--- /dev/null
+++ b/pdisk.8
@@ -0,0 +1,182 @@
+.TH PDISK 8 "20 December 1996" "MkLinux DR2" "Linux Programmer's Manual"
+.SH NAME
+pdisk \- Apple partition table editor for Linux
+.SH SYNOPSIS
+.B pdisk
+.B "[\-h|\--help] [\-v|\--version] [\-l|\--list [name ...]]"
+.br
+.B pdisk
+.B "[\-r|\--readonly]"
+device ...
+.SH DESCRIPTION
+.B pdisk
+is a menu driven program which partitions disks using the standard Apple
+disk partitioning scheme described in "Inside Macintosh: Devices".
+It does not support the intel/dos partitioning scheme supported by 
+.BR fdisk .
+The
+.I device
+is usually one of the following:
+
+.nf
+.RS
+/dev/sda
+/dev/sdb
+/dev/sdc
+/dev/sdd
+/dev/sde
+/dev/sdf
+/dev/sdg
+/dev/hda
+/dev/hdb
+
+.RE
+.fi
+MkLinux interprets device names differently than standard Linux.
+In MkLinux /dev/sda is the device at SCSI id 0, /dev/sdb is the device at SCSI
+id 1, and so on.
+In standard Linux /dev/sda is the first hard disk on the SCSI bus (i.e. the
+one with the lowest id), /dev/sdb is the second hard disk, and so on.
+The
+.I partition
+is a
+.I device
+name followed by a partition number.
+The partition number is the index (starting from one) of the partition
+map entry in the partition map.
+For example,
+.B /dev/sda2
+is the partition described by the second entry in the partiton map on /dev/sda.
+
+.SH OPTIONS
+.TP
+.B \-v | \--version
+Prints version number of the
+.B pdisk
+program.
+.TP
+.B \-h | \--help
+Prints a rather lame set of help messages for the
+.B pdisk
+program.
+.TP
+.B \-l | \--list
+If no
+.IR name s
+are present then lists the partition tables for
+.BR /dev/sda ,
+.BR /dev/sdb ,
+.BR /dev/sdc ,
+.BR /dev/sdd ,
+.BR /dev/sde ,
+.BR /dev/sdf ,
+and
+.BR /dev/sdg .
+Otherwise, lists the partition tables for the specified
+.IR name s.
+.TP
+.B \-r | \--readonly
+Prevents
+.B pdisk
+from writing to the device.
+.SH "Editing Partition Tables"
+An argument which is simply the name of a
+.I device
+indicates that
+.B pdisk
+should edit the partition table of that device.
+
+The current top level editing commands are:
+
+.nf
+.RS
+h    command help
+p    print the partition table
+P    (print ordered by base address)
+i    initialize partition map
+s    change size of partition map
+c    create new partition
+C    (create with type also specified)
+d    delete a partition
+r    reorder partition entry in map
+w    write the partition table
+q    quit without saving changes
+
+.RE
+.fi
+Commands which take arguments prompt for each argument in turn.
+You can also type any number of the arguments separated by spaces
+and those prompts will be skipped.
+The only exception to typeahead are the confirmation prompts on the
+.B i
+and
+.B w
+commands.
+The idea being that if we expect you to confirm the decision we
+shouldn't undermine that by allowing you to be precipitate about it.
+
+Partitions are always specified by their number,
+which the index of the partition entry in the partition map.
+Most of the commands will change the index numbers of all partitions
+after the affected partition.
+You are advised to print the table as frequently as necessary.
+
+Creating more than fifteen partitions is not advised.
+There is currently a bug in the some (all?) of the kernels which causes
+access to the whole disk fail if more than fifteen partitions are in the map.
+
+The
+.B c
+(create new partition) command is the only one with complicated arguments.
+The first argument is the base address (in blocks) of the partition.
+Besides a raw number, you can also specify a partition number followed
+by the letter 'p' to indicate that the first block of the new partition should
+be the same as the first block of that existing free  space partition.
+The second argument is the length of the partition in blocks.
+This can be a raw number or can be a partition number followed by the
+letter 'p' to use the size of that partition or can be a number followed
+by 'k', 'm', or 'g' to indicate the size in kilobytes, megabytes, or gigabytes
+respectively.
+(These are powers of 1024, of course, not powers of 1000.)
+The last argument is the name of the partition.
+This can be a single word without quotes, or a string surrounded by
+single or double quotes.
+
+The
+.B C
+command is identical to the
+.B c
+command, with the addition of a partition type argument after the
+other arguments.
+
+The
+.B r
+(reorder) command allows the index number of partitions to be changed.
+The index numbers are constrained to be a contiguous sequence.
+
+The
+.B i
+(initalize) command prompts for the size of the device.
+This was done to get around a bug in the kernel where it reports the wrong
+size for the device.
+
+The
+.B w
+(write) command does write the partition map out,
+but there is currently a bug in the interaction between MkLinux and Mach
+which causes the partition map not to be reinterpreted.
+In order to use the new partition map you must reboot.
+
+.SH BUGS
+Some people believe there should really be just one disk partitioning utility.
+.br
+.B pdisk
+should be able to create HFS partitions that work.
+.br
+Even more help should be available during user input.
+.SH "SEE ALSO"
+.BR fdisk (8), 
+.BR mkswap (8),
+.BR mkfs (8)
+.SH AUTHOR
+Eryk Vershen (eryk@apple.com)
diff --git a/pdisk.c b/pdisk.c
new file mode 100644 (file)
index 0000000..52f98c7
--- /dev/null
+++ b/pdisk.c
@@ -0,0 +1,711 @@
+//
+// pdisk - an editor for Apple format partition tables
+//
+// Written by Eryk Vershen (eryk@apple.com)
+//
+// Still under development (as of 20 Dec 1996)
+//
+
+/*
+ * Copyright 1996,1997 by Apple Computer, Inc.
+ *              All Rights Reserved 
+ *  
+ * Permission to use, copy, modify, and distribute this software and 
+ * its documentation for any purpose and without fee is hereby granted, 
+ * provided that the above copyright notice appears in all copies and 
+ * that both the copyright notice and this permission notice appear in 
+ * supporting documentation. 
+ *  
+ * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE 
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
+ * FOR A PARTICULAR PURPOSE. 
+ *  
+ * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR 
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, 
+ * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION 
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 
+ */
+
+#include <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");
+}
diff --git a/pdisk.h b/pdisk.h
new file mode 100644 (file)
index 0000000..b1f9e3b
--- /dev/null
+++ b/pdisk.h
@@ -0,0 +1,53 @@
+//
+// pdisk.h - general header for pdisk program
+//
+// Written by Eryk Vershen (eryk@apple.com)
+//
+
+/*
+ * Copyright 1996,1997 by Apple Computer, Inc.
+ *              All Rights Reserved 
+ *  
+ * Permission to use, copy, modify, and distribute this software and 
+ * its documentation for any purpose and without fee is hereby granted, 
+ * provided that the above copyright notice appears in all copies and 
+ * that both the copyright notice and this permission notice appear in 
+ * supporting documentation. 
+ *  
+ * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE 
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
+ * FOR A PARTICULAR PURPOSE. 
+ *  
+ * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR 
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, 
+ * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION 
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 
+ */
+
+
+//
+// Defines
+//
+
+
+//
+// Types
+//
+
+
+//
+// Global Constants
+//
+
+
+//
+// Global Variables
+//
+extern int rflag;
+extern int hflag;
+
+
+//
+// Forward declarations
+//
diff --git a/pdisk.r b/pdisk.r
new file mode 100644 (file)
index 0000000..1e42dbb
--- /dev/null
+++ b/pdisk.r
@@ -0,0 +1,234 @@
+/*
+ * pdisk.r
+ */
+
+/*
+ * Copyright 1997 by Apple Computer, Inc.
+ *              All Rights Reserved 
+ *  
+ * Permission to use, copy, modify, and distribute this software and 
+ * its documentation for any purpose and without fee is hereby granted, 
+ * provided that the above copyright notice appears in all copies and 
+ * that both the copyright notice and this permission notice appear in 
+ * supporting documentation. 
+ *  
+ * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE 
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
+ * FOR A PARTICULAR PURPOSE. 
+ *  
+ * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR 
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, 
+ * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION 
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 
+ */
+
+#ifndef SystemSevenOrLater
+#define SystemSevenOrLater     1
+#endif
+#include "Types.r"
+#include "SysTypes.r"
+#include "version.h"
+
+
+resource 'vers' (1) {
+    kVersionMajor,
+    kVersionMinor*0x10 + kVersionBugFix,
+    kVersionStage,
+    kVersionDelta,
+    verUS,
+    VERSION,
+    $$format(
+       "%s (%02d%02d%02d)\n"
+       "© 1992-%4d Apple Computer Inc. All Rights Reserved",
+       VERSION, $$year % 100, $$month, $$day,
+       $$year
+    ),
+};
+
+
+type 'PDSK' as 'STR ';
+resource 'PDSK' (0, "Owner Resource", purgeable) {
+    $$format(
+       "pdisk\n© 1992-%4d Apple Computer Inc. All Rights Reserved.",
+       $$year
+    )
+};
+
+resource 'BNDL' (128) {
+    'PDSK',
+    0,
+    {
+       'FREF', { 0, 128 },
+       'ICN#', { 0, 128 }
+    }
+};
+
+resource 'FREF' (128) {
+    'APPL',
+    0,
+    ""
+};
+resource 'icl8' (128) {
+    $"FFFF FFFF FFFF FFFF FFFF FFFF 0000 0000"
+    $"0000 FFFF FFFF FFFF 0000 0000 0000 0000"
+    $"FF2B 2B2B 2B2B 2B2B 2B2B 2BFF 0000 0000"
+    $"00FF 0808 0808 0808 FF00 0000 0000 0000"
+    $"FF2B 2B2B 2B2B 2B2B 2B2B FF00 0000 0000"
+    $"FF08 0808 0808 0808 08FF 0000 0000 0000"
+    $"FFFC FCFC FCFC FCFC FCFC FF00 0000 00FF"
+    $"0808 FFFF 0808 0808 0808 FF00 0000 0000"
+    $"FF00 0000 0000 0000 0000 FF00 0000 00FF"
+    $"FFFF 0000 FF08 0808 0808 08FF 0000 0000"
+    $"FF2B 2B2B 2B2B 2B2B 2B2B FF00 FFFF FF08"
+    $"08FF FFFF FFFF FFFF FF08 0808 FFFF FFFF"
+    $"FF2B 2B2B 2B2B 2B2B 2B2B FF00 0000 FF08"
+    $"0808 FFFF 0808 0808 0808 0808 08FF FFFF"
+    $"FFFF FFFF FFFF FFFF FFFF FF00 0000 00FF"
+    $"0808 0808 0808 0808 0808 0808 08FF FFFF"
+    $"00FF F7FC F7FC F7FC F7FF 0000 0000 0000"
+    $"FF08 0808 0808 0808 0808 0808 08FF FFFF"
+    $"00FF FFFF FBFB FBFF FFFF 0000 0000 0000"
+    $"00FF FF08 0808 0808 0808 0808 08FF FFFF"
+    $"0000 0000 FFFF FF00 0000 0000 0000 0000"
+    $"0000 00FF FFFF FFFF FFFF FF08 08FF FFFF"
+    $"0000 0000 0000 0000 0000 0000 0000 0000"
+    $"0000 0000 0000 0000 0000 00FF FFFF FFFF"
+    $"0000 0000 0000 0000 0000 0000 0000 0000"
+    $"0000 0000 0000 0000 0000 0000 00FF FFFF"
+    $"0000 0000 0000 0000 FFFF FFFF FFFF FFFF"
+    $"FFFF FFFF FFFF FF00 0000 0000 0000 0000"
+    $"0000 0000 0000 0000 FF2B 2B2B 2B2B 2B2B"
+    $"2B2B 2B2B 2B2B FF00 0000 0000 0000 0000"
+    $"0000 0000 0000 00FF 2B2B 2B2B 2B2B 2B2B"
+    $"2B2B 2B2B 2B2B FF00 0000 0000 0000 0000"
+    $"0000 0000 0000 00FF FCFC FCFC FCFC FCFC"
+    $"FCFC FCFC FCFC FF00 0000 0000 0000 0000"
+    $"0000 0000 0000 00FF 0000 0000 0000 0000"
+    $"0000 0000 0000 FF00 0000 0000 0000 0000"
+    $"0000 0000 0000 00FF 2B2B 2B2B 2B2B 2B2B"
+    $"2B2B 2B2B 2BFF 0000 0000 0000 0000 0000"
+    $"0000 0000 0000 00FF 2B2B 2B2B 2B2B 2B2B"
+    $"2B2B 2B2B FF00 0000 0000 0000 0000 0000"
+    $"0000 0000 0000 00FF FFFF FFFF FFFF FFFF"
+    $"FFFF FFFF FF00 0000 0000 0000 0000 0000"
+    $"0000 0000 0000 FFFC F7FC F7FC F7FC F7FC"
+    $"F7FC F7FC FF00 00FF FFFF FFFF FFFF FFFF"
+    $"0000 0000 0000 FFFF FFFF FFFF FFFF FFFF"
+    $"FFFF FFFF FF00 00FF 2B2B 2B2B 2B2B 2BFF"
+    $"0000 0000 0000 0000 0000 0000 0000 0000"
+    $"0000 0000 0000 00FF 2B2B 2B2B 2B2B 2BFF"
+    $"0000 0000 0000 0000 0000 0000 0000 0000"
+    $"0000 0000 0000 00FF FCFC E3E3 E3FC FCFF"
+    $"0000 0000 0000 0000 0000 0000 0000 0000"
+    $"0000 0000 0000 00FF 0000 0000 0000 00FF"
+    $"0000 0000 0000 0000 0000 0000 0000 0000"
+    $"0000 0000 0000 FF2B 2B2B 2B2B 2B2B 2BFF"
+    $"0000 0000 0000 0000 0000 0000 0000 0000"
+    $"0000 0000 00FF 2B2B 2B2B 2B2B 2B2B 2BFF"
+    $"0000 0000 0000 0000 0000 0000 0000 0000"
+    $"0000 0000 00FF FFFF FFFF FFFF FFFF FFFF"
+    $"0000 0000 0000 0000 0000 0000 0000 0000"
+    $"0000 0000 00FF F7FC F7FC F7FC F7FC FF00"
+    $"0000 0000 0000 0000 0000 0000 0000 0000"
+    $"0000 0000 00FF FFFF FFFB FBFB FFFF FF00"
+    $"0000 0000 0000 0000 0000 0000 0000 0000"
+    $"0000 0000 0000 0000 00FF FFFF"
+};
+
+resource 'icl4' (128) {
+    $"FFFF FFFF FFFF 0000 00FF FFFF 0000 0000"
+    $"FCCC CCCC CCCF 0000 0F02 0202 F000 0000"
+    $"FCCC CCCC CCF0 0000 F020 2020 2F00 0000"
+    $"FEEE EEEE EEF0 000F 02FF 0202 02F0 0000"
+    $"F000 0000 00F0 000F FF00 F020 202F 0000"
+    $"FCCC CCCC CCF0 FFF2 0FFF FFFF F202 FFFF"
+    $"FCCC CCCC CCF0 00F0 20FF 2020 2020 2FFF"
+    $"FFFF FFFF FFF0 000F 0202 0202 0202 0FFF"
+    $"0FCE CECE CF00 0000 F020 2020 2020 2FFF"
+    $"0FFF EEEF FF00 0000 0FF2 0202 0202 0FFF"
+    $"0000 FFF0 0000 0000 000F FFFF FFF0 2FFF"
+    $"0000 0000 0000 0000 0000 0000 000F FFFF"
+    $"0000 0000 0000 0000 0000 0000 0000 0FFF"
+    $"0000 0000 FFFF FFFF FFFF FFF0 0000 0000"
+    $"0000 0000 FCCC CCCC CCCC CCF0 0000 0000"
+    $"0000 000F CCCC CCCC CCCC CCF0 0000 0000"
+    $"0000 000F EEEE EEEE EEEE EEF0 0000 0000"
+    $"0000 000F 0000 0000 0000 00F0 0000 0000"
+    $"0000 000F CCCC CCCC CCCC CF00 0000 0000"
+    $"0000 000F CCCC CCCC CCCC F000 0000 0000"
+    $"0000 000F FFFF FFFF FFFF F000 0000 0000"
+    $"0000 00FE CECE CECE CECE F00F FFFF FFFF"
+    $"0000 00FF FFFF FFFF FFFF F00F CCCC CCCF"
+    $"0000 0000 0000 0000 0000 000F CCCC CCCF"
+    $"0000 0000 0000 0000 0000 000F EE88 8EEF"
+    $"0000 0000 0000 0000 0000 000F 0000 000F"
+    $"0000 0000 0000 0000 0000 00FC CCCC CCCF"
+    $"0000 0000 0000 0000 0000 0FCC CCCC CCCF"
+    $"0000 0000 0000 0000 0000 0FFF FFFF FFFF"
+    $"0000 0000 0000 0000 0000 0FCE CECE CEF0"
+    $"0000 0000 0000 0000 0000 0FFF FEEE FFF0"
+    $"0000 0000 0000 0000 0000 0000 0FFF"
+};
+
+resource 'ICN#' (128) {
+    {
+/* 1 */ $"FFF0 3F00 8010 4080 8020 8040 FFE1 3020"
+       $"8021 C810 802E 7F8F 8022 3007 FFE1 0007"
+       $"5540 8007 7FC0 6007 0E00 1FE7 0000 001F"
+       $"0000 0007 00FF FE00 0080 0200 0100 0200"
+       $"01FF FE00 0100 0200 0100 0400 0100 0800"
+       $"01FF F800 0355 59FF 03FF F901 0000 0101"
+       $"0000 01FF 0000 0101 0000 0201 0000 0401"
+       $"0000 07FF 0000 0556 0000 07FE 0000 0070",
+
+/* 2 */ $"FFF0 3F00 FFF0 7F80 FFE0 FFC0 FFE1 FFE0"
+       $"FFE1 FFF0 FFEF FFFF FFE3 FFFF FFE1 FFFF"
+       $"7FC0 FFFF 7FC0 7FFF 0E00 1FFF 0000 001F"
+       $"0000 0007 00FF FE00 00FF FE00 01FF FE00"
+       $"01FF FE00 01FF FE00 01FF FC00 01FF F800"
+       $"01FF F800 03FF F9FF 03FF F9FF 0000 01FF"
+       $"0000 01FF 0000 01FF 0000 03FF 0000 07FF"
+       $"0000 07FF 0000 07FE 0000 07FE 0000 0070"
+    }
+};
+
+resource 'ics#' (128) {
+    {
+/* 1 */ $"FC30 8448 B4A7 8B7B 7083 007F 0003 1FF0"
+       $"1010 1010 2020 3FDF 0011 0011 0021 003E",
+/* 2 */ $"FC30 FC78 FCFF FBFF 70FF 007F 0003 1FF0"
+       $"1FF0 1FF0 3FE0 3FDF 001F 001F 003F 003E"
+    }
+};
+
+resource 'ics4' (128) {
+    $"FFFF FF00 00FF 0000 FCCC CF00 0F02 F000"
+    $"FC38 CF00 F0F0 2FFF FDDD F0FF 2FFF F2FF"
+    $"0FFF 0000 F020 20FF 0000 0000 0FFF FFFF"
+    $"0000 0000 0000 00FF 000F FFFF FFFF 0000"
+    $"000F CCCC CCCF 0000 000F CCCC CCCF 0000"
+    $"00FD DDDD DDF0 0000 00FF FFFF FF0F FFFF"
+    $"0000 0000 000F CCCF 0000 0000 000F CCCF"
+    $"0000 0000 00FD DDDF 0000 0000 00FF FFF0"
+};
+
+resource 'ics8' (128) {
+    $"FFFF FFFF FFFF 0000 0000 FFFF 0000 0000"
+    $"FF2B 2B2B 2BFF 0000 00FF 0808 FF00 0000"
+    $"FF2B D8E3 2BFF 0000 FF08 FF08 08FF FFFF"
+    $"FFF9 F9F9 FF00 FFFF 08FF FFFF FF08 FFFF"
+    $"00FF FFFF 0000 0000 FF08 0808 0808 FFFF"
+    $"0000 0000 0000 0000 00FF FFFF FFFF FFFF"
+    $"0000 0000 0000 0000 0000 0000 0000 FFFF"
+    $"0000 00FF FFFF FFFF FFFF FFFF 0000 0000"
+    $"0000 00FF 2B2B 2B2B 2B2B 2BFF 0000 0000"
+    $"0000 00FF 2B2B 2B2B 2B2B 2BFF 0000 0000"
+    $"0000 FFF9 F9F9 F9F9 F9F9 FF00 0000 0000"
+    $"0000 FFFF FFFF FFFF FFFF 00FF FFFF FFFF"
+    $"0000 0000 0000 0000 0000 00FF 2B2B 2BFF"
+    $"0000 0000 0000 0000 0000 00FF 2B2B 2BFF"
+    $"0000 0000 0000 0000 0000 FFF9 F9F9 F9FF"
+    $"0000 0000 0000 0000 0000 FFFF FFFF FF"
+};
+
diff --git a/version.h b/version.h
new file mode 100644 (file)
index 0000000..c461831
--- /dev/null
+++ b/version.h
@@ -0,0 +1,78 @@
+/*
+ * version.h - version number for pdisk program
+ *
+ * Written by Eryk Vershen (eryk@apple.com)
+ */
+
+/*
+ * Copyright 1997 by Apple Computer, Inc.
+ *              All Rights Reserved 
+ *  
+ * Permission to use, copy, modify, and distribute this software and 
+ * its documentation for any purpose and without fee is hereby granted, 
+ * provided that the above copyright notice appears in all copies and 
+ * that both the copyright notice and this permission notice appear in 
+ * supporting documentation. 
+ *  
+ * APPLE COMPUTER DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE 
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 
+ * FOR A PARTICULAR PURPOSE. 
+ *  
+ * IN NO EVENT SHALL APPLE COMPUTER BE LIABLE FOR ANY SPECIAL, INDIRECT, OR 
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN ACTION OF CONTRACT, 
+ * NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION 
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 
+ */
+
+
+/*
+ * Defines
+ */
+/*
+ *     TO ADJUST THE VERSION - change the following six macros.
+ *
+ * A version is of the form:   N.M{.X}{yZ}
+ * 
+ *     N is two digits indicating the major version
+ *     M is a single digit indicating relative revision
+ *     X is a single digit indicating a bug fix revision
+ *     y is a character from the set [dab] indicating stage (dev,alpha,beta)
+ *     Z is two digits indicating the delta within the stage
+ *
+ * Note that within the 'vers' resource all these fields end up
+ * comprising a four byte unsigned integer with the property that any later
+ * version will be be represented by a larger number.
+ */
+
+#define        VERSION "0.4a2"
+#define RELEASE_DATE "15 January 1997"
+
+#define        kVersionMajor   0x00            /* ie. N has two BCD digits */
+#define        kVersionMinor   0x4             /* ie. M has a single BCD digit */
+#define kVersionBugFix 0x0             /* ie. X has a single BCD digit */
+#define        kVersionStage   alpha           /* ie. y is one of the set - */
+                                       /*    {development,alpha,beta,final}
+                                        * also, release is a synonym for final
+                                        */
+#define        kVersionDelta   0x02            /* ie. Z has two BCD digits */
+
+
+/*
+ * Types
+ */
+
+
+/*
+ * Global Constants
+ */
+
+
+/*
+ * Global Variables
+ */
+
+
+/*
+ * Forward declarations
+ */