/****************************************************************************** * This little utility, which I call ManyApplePartitions, creates an Apple * format partition table (rather than Microsoft/Intel format, as the Apple * one is easier to understand and doesn't have size limits), and sets up a * bunch of partitions on a disk device and formats them with BFS. Once that * is done, the partitions should reappear automatically when you reboot. * * Requested by Mark Hellegers, who wants a LOT of partitions for his own * nefarious purposes. Written mostly for the educational experience. * Watch out, you can easily corrupt the data on an existing disk drive * if you use this program with the wrong arguments! * * By Alexander G. M. Smith, April 2001. Released to the public domain. */ #include #include #include #include #include #include #include /* Apple partition structures. */ enum { /* signature values */ sbSIGWord = 0x4552, /* driver descriptor map signature */ pMapSIG = 0x504D /* partition map signature */ }; struct AppleBlock0Struct { unsigned short sbSig; /* device signature */ unsigned short sbBlkSize; /* block size of the device*/ unsigned long sbBlkCount; /* number of blocks on the device*/ unsigned short sbDevType; /* reserved */ unsigned short sbDevId; /* reserved */ unsigned long sbData; /* reserved */ unsigned short sbDrvrCount; /* number of driver descriptor entries */ unsigned long ddBlock; /* first driver's starting block */ unsigned short ddSize; /* driver's size, in 512-byte blocks */ unsigned short ddType; /* operating system type (MacOS = 1) */ unsigned short ddPad[243]; /* additional drivers, if any */ } AppleBlock0; struct ApplePartitionStruct { unsigned short pmSig; /* partition signature */ unsigned short pmSigPad; /* reserved */ unsigned long pmMapBlkCnt; /* number of blocks in partition map */ unsigned long pmPyPartStart; /* first physical block of partition */ unsigned long pmPartBlkCnt; /* number of blocks in partition */ unsigned char pmPartName[32];/* partition name */ unsigned char pmParType[32]; /* partition type */ unsigned long pmLgDataStart; /* first logical block of data area */ unsigned long pmDataCnt; /* number of blocks in data area */ unsigned long pmPartStatus; /* partition status information */ unsigned long pmLgBootStart; /* first logical block of boot code */ unsigned long pmBootSize; /* size of boot code, in bytes */ unsigned long pmBootAddr; /* boot code load address */ unsigned long pmBootAddr2; /* reserved */ unsigned long pmBootEntry; /* boot code entry point */ unsigned long pmBootEntry2; /* reserved */ unsigned long pmBootCksum; /* boot code checksum */ unsigned char pmProcessor[16]; /* processor type */ unsigned short pmPad[188]; /* reserved */ } ApplePartition; int main (int argc, char** argv) { char CommandString [PATH_MAX]; int DeviceFile = -1; device_geometry DeviceGeometry; char *DevicePath; off_t DeviceSize; off_t FreeSize; int NumPartitions; off_t OverheadSize; char PartitionDirectory [PATH_MAX]; int PartitionFile = -1; int PartitionIndex; partition_info PartitionInfo; char *PartitionNamePntr; off_t PartitionSize; int PreviousOverheadSize; int ReturnCode = -20; if (argc < 3) { printf ("\nUsage: %s DevicePath NumPartitions [PartitionSize]\n\n", argv[0]); printf ("This creates NumPartitions quantity of disk partitions\n"); printf ("each optionally of PartitionSize in bytes (if you don't\n"); printf ("specify the size it will use the whole disk size divided\n"); printf ("by the number of partitions). DevicePath is the path name\n"); printf ("of the raw device to use. It will also format the partitions\n"); printf ("with BFS, but not mount them (BeOS should auto-mount them\n"); printf ("when it reboots). The partition table is written in Apple\n"); printf ("Macintosh style, but without the boot driver code partition\n"); printf ("so real Macs may not like it, but then they can't understand\n"); printf ("BFS anyways. Any free space on the device is put into a final\n"); printf ("free space partition, which isn't formatted. Later you can\n"); printf ("use DriveSetup to break that free space into more partitions.\n"); printf ("\nMake sure you are using the right disk drive. This program\n"); printf ("will erase everything that's allready on the specified drive!\n"); printf ("\nExamples:\n"); printf ("\nManyApplePartitions /dev/disk/floppy/raw 1\n"); printf (" sets up 1 partition using the whole disk, BFS needs 900KB,\n"); printf (" so you can't get more than 1 partition on a regular floppy.\n"); printf ("\nManyApplePartitions " "/dev/disk/virtual/AGMSRAMDiskDevice/raw 30 2000000\n"); printf (" makes 30 partitions of size 2000000 bytes each, or fewer\n"); printf (" partitions if your RAM disk isn't big enough.\n"); printf ("\nBy Alexander G. M. Smith, April 10, 2001. " "Released to the public domain.\n"); goto ErrorExit; } /* Open the raw device using the user's path name, and find out its geometry, so that we can figure out the total size (and verify that the use did give us a real device). */ DevicePath = argv[1]; if (DevicePath[0] != '/' || strlen (DevicePath) >= sizeof (PartitionInfo.device)) { printf ("Your device path should start with a / (slash) and\n"); printf ("not be longer than %d characters. It's currently\n", (int) (sizeof (PartitionInfo.device) - 1)); printf ("specified as \"%s\".\n", DevicePath); goto ErrorExit; } DeviceFile = open (DevicePath, O_RDWR); if (DeviceFile < 0) { printf ("Unable to open the raw device file \"%s\".\n", DevicePath); goto ErrorExit; } if (ioctl (DeviceFile, B_GET_GEOMETRY, &DeviceGeometry, sizeof (DeviceGeometry)) < 0) { printf ("Unable to get geometry of the raw device file \"%s\",\n" "maybe it isn't a device?\n", DevicePath); goto ErrorExit; } DeviceSize = (off_t) DeviceGeometry.bytes_per_sector * (off_t) DeviceGeometry.sectors_per_track * (off_t) DeviceGeometry.head_count * (off_t) DeviceGeometry.cylinder_count; printf ("Total device size of %s is %qd bytes.\n", DevicePath, DeviceSize); if (DeviceSize == 0) { printf ("Zero bytes? That often means that a removeable disk\n" "isn't inserted. Please insert the disk and try again.\n"); goto ErrorExit; } if (DeviceGeometry.bytes_per_sector != 512) { printf ("Each disk block is %d bytes. This code and the Apple\n" "partition table use 512 bytes. It may still work, try commenting\n" "out this check and do some testing. Either it will work at\n" "slightly slower speed, or it won't properly write partial\n" "disk sectors.\n", (int) DeviceGeometry.bytes_per_sector); goto ErrorExit; } /* Get the user provided number of partitions. */ NumPartitions = atoi (argv[2]); if (NumPartitions < 1) NumPartitions = 1; /* Find the desired partition size, either specified by the user, or divide the device total size equally into partitions (minus a bit of overhead). */ if (argc >= 4) PartitionSize = atoll (argv[3]); /* A 64 bit number. */ else /* Have block0, partition entries of table, of free space == 3 used. */ { PartitionSize = (DeviceSize - 3 * 512 - NumPartitions * 512) / NumPartitions; PartitionSize = PartitionSize / 512 * 512; /* Round down so it fits. */ } /* Round up the desired partition size to a multiple of 512 bytes. */ PartitionSize = (PartitionSize + 512 - 1) / 512 * 512; if (PartitionSize < 512) PartitionSize = 512; /* Limit the number of partitions to the available space. Leave enough space at the start of the drive for the partition table, which uses 512 bytes per partition plus 512 bytes for the disk header, plus 512 bytes for the partition table's own partition plus 512 bytes for the free space partition (even if there isn't any free space). Since the number of partitions affects the table size, iterate until we compute the maximum number of usable partitions. */ OverheadSize = 0; PreviousOverheadSize = 1; while (OverheadSize != PreviousOverheadSize) { if (OverheadSize + NumPartitions * PartitionSize > DeviceSize) NumPartitions = (DeviceSize - OverheadSize) / PartitionSize; if (NumPartitions < 1) { printf ("No partitions to make, maybe your size is too big?\n"); goto ErrorExit; } PreviousOverheadSize = OverheadSize; OverheadSize = 3 * 512 + NumPartitions * 512; } FreeSize = DeviceSize - (NumPartitions * PartitionSize + OverheadSize); FreeSize = FreeSize / 512 * 512; /* Round down to multiples of 512. */ printf ("Making %d partitions of %qd bytes on device \"%s\",\n" "this will use up the first %qd bytes on the device (including a\n" "%qd byte partition table), leaving %qd bytes free.\n", NumPartitions, PartitionSize, DevicePath, NumPartitions * PartitionSize + OverheadSize, OverheadSize, FreeSize); /* Find the name of the directory to make the partitions in. Just take the device path name and cut off everything after the last / (slash) character. */ strcpy (PartitionDirectory, DevicePath); PartitionNamePntr = strrchr (PartitionDirectory, '/'); if (PartitionNamePntr == NULL || PartitionNamePntr == PartitionDirectory) { printf ("Can't find trailing / in the device path name \"%s\".\n", DevicePath); goto ErrorExit; } PartitionNamePntr++; /* Point just after the last / character. */ /* OK, now format the partitions. */ for (PartitionIndex = 0; PartitionIndex < NumPartitions; PartitionIndex++) { /* Create the partition dummy file, just temporarily, long enough to do the format, then we get rid of it. */ sprintf (PartitionNamePntr, "1_%d", PartitionIndex); printf ("\nCreating partition named \"%s\",\n", PartitionDirectory); PartitionFile = creat (PartitionDirectory, 0644 /* rwx permission flags, 0644 means owner R/W, others R. */); if (PartitionFile < 0) { printf ("Unable to create file \"%s\".\n", PartitionDirectory); goto ErrorExit; } /* Set up the partition info to make the file represent a portion of the raw device. */ memset (&PartitionInfo, 0, sizeof (&PartitionInfo)); PartitionInfo.logical_block_size = 512; /* Apple stuff uses 512. */ PartitionInfo.offset = OverheadSize + PartitionIndex * PartitionSize; PartitionInfo.size = PartitionSize; PartitionInfo.session = 1; /* We use session 1 to avoid standard #0. */ PartitionInfo.partition = PartitionIndex; strcpy (PartitionInfo.device, DevicePath); printf ("with starting offset %qd and size: %qd\n", PartitionInfo.offset, PartitionInfo.size); if (ioctl (PartitionFile, B_SET_PARTITION, &PartitionInfo, sizeof (PartitionInfo)) < 0) { printf ("B_SET_PARTITION failed to set the partition info!\n"); printf ("Perhaps you need to delete \"%s\" (and others) " "and try again?\n", PartitionDirectory); goto ErrorExit; } close (PartitionFile); PartitionFile = -1; /* Now try to format the new partition with the BFS file system. */ sprintf (CommandString, "mkbfs %s Disk%03d", PartitionDirectory, PartitionIndex); printf ("Executing command \"%s\".\n", CommandString); if (system (CommandString) < 0) { printf ("Failed to format the partition with command \"%s\".\n", CommandString); goto ErrorExit; } /* Add an entry to the end of the Apple style partition table. */ memset (&ApplePartition, 0, sizeof (ApplePartition)); ApplePartition.pmSig = B_HOST_TO_BENDIAN_INT16 (pMapSIG); ApplePartition.pmMapBlkCnt = B_HOST_TO_BENDIAN_INT32 (NumPartitions + 1 /* for partition table's partition */ + (FreeSize > 0) /* plus 1 for the free space partition, if any */); ApplePartition.pmPyPartStart = B_HOST_TO_BENDIAN_INT32 (PartitionInfo.offset / 512); ApplePartition.pmPartBlkCnt = B_HOST_TO_BENDIAN_INT32 (PartitionInfo.size / 512); sprintf (ApplePartition.pmPartName, "Partition %03d", PartitionIndex); strcpy (ApplePartition.pmParType, "Be_BFS"); ApplePartition.pmDataCnt = B_HOST_TO_BENDIAN_INT32 (PartitionInfo.size / 512); ApplePartition.pmPartStatus = B_HOST_TO_BENDIAN_INT32 ( 1 /* Valid */ | 2 /* Partition is allocated */ | 16 /* Allows reading */ | 32 /* Allows writing */); if (write_pos (DeviceFile, 1024 + PartitionIndex * 512 /* Position */, &ApplePartition, sizeof (ApplePartition)) != sizeof (ApplePartition)) { printf ("Error while writing block %d of the Apple partition table.\n", PartitionIndex + 2); goto ErrorExit; } /* Delete the dummy partition file. The MountVolume system will recreate it from the data in our permanent partition table if you try to mount that volume, so we don't need it. */ if (unlink (PartitionDirectory) < 0) { printf ("Unable to delete the temporary partition file \"%s\".\n", PartitionDirectory); goto ErrorExit; } } /* Write the first part of an Apple style partition table. First 512 byte block is the device header, which describes boot things, which we don't have. So all that's important is the signature and disk size. */ memset (&AppleBlock0, 0, sizeof (AppleBlock0)); AppleBlock0.sbSig = B_HOST_TO_BENDIAN_INT16 (sbSIGWord); AppleBlock0.sbBlkSize = B_HOST_TO_BENDIAN_INT16 (512); AppleBlock0.sbBlkCount = B_HOST_TO_BENDIAN_INT32 (DeviceSize / 512); if (write_pos (DeviceFile, 0 /* Position */, &AppleBlock0, sizeof (AppleBlock0)) != sizeof (AppleBlock0)) { printf ("Error while writing block 0 of the Apple partition table.\n"); goto ErrorExit; } /* Now write the partition table entry for the partition table itself. */ memset (&ApplePartition, 0, sizeof (ApplePartition)); ApplePartition.pmSig = B_HOST_TO_BENDIAN_INT16 (pMapSIG); ApplePartition.pmMapBlkCnt = B_HOST_TO_BENDIAN_INT32 (NumPartitions + 1 /* for partition table's partition */ + (FreeSize > 0) /* plus 1 for the free space partition, if any */); ApplePartition.pmPyPartStart = B_HOST_TO_BENDIAN_INT32 (1); ApplePartition.pmPartBlkCnt = B_HOST_TO_BENDIAN_INT32 ( NumPartitions + 1 + (FreeSize > 0)); strcpy (ApplePartition.pmPartName, "Apple"); strcpy (ApplePartition.pmParType, "Apple_partition_map"); ApplePartition.pmDataCnt = B_HOST_TO_BENDIAN_INT32 ( NumPartitions + 1 + (FreeSize > 0)); ApplePartition.pmPartStatus = B_HOST_TO_BENDIAN_INT32 ( 1 /* Valid */ | 2 /* Partition is allocated */ | 16 /* Allows reading */ | 32 /* Allows writing */); if (write_pos (DeviceFile, 512 /* Position */, &ApplePartition, sizeof (ApplePartition)) != sizeof (ApplePartition)) { printf ("Error while writing block 1 of the Apple partition table.\n"); goto ErrorExit; } /* Write the optional free space partition, if there is any free space. The 512 byte block is always in our partition table overhead, but if there is no free space, it sits there unused (don't want to clutter up the partition table with a zero free space partition). */ if (FreeSize > 0) { memset (&ApplePartition, 0, sizeof (ApplePartition)); ApplePartition.pmSig = B_HOST_TO_BENDIAN_INT16 (pMapSIG); ApplePartition.pmMapBlkCnt = B_HOST_TO_BENDIAN_INT32 (NumPartitions + 1 /* for partition table's partition */ + (FreeSize > 0) /* plus 1 for the free space partition, if any */); ApplePartition.pmPyPartStart = B_HOST_TO_BENDIAN_INT32 ( (OverheadSize + NumPartitions * PartitionSize) / 512); ApplePartition.pmPartBlkCnt = B_HOST_TO_BENDIAN_INT32 ( FreeSize / 512); strcpy (ApplePartition.pmPartName, "Free Space at End"); strcpy (ApplePartition.pmParType, "Apple_Free"); ApplePartition.pmDataCnt = B_HOST_TO_BENDIAN_INT32 (FreeSize / 512); ApplePartition.pmPartStatus = B_HOST_TO_BENDIAN_INT32 ( 1 /* Valid */ | 2 /* Partition is allocated */ | 16 /* Allows reading */ | 32 /* Allows writing */); if (write_pos (DeviceFile, (2 + NumPartitions) * 512 /* Position */, &ApplePartition, sizeof (ApplePartition)) != sizeof (ApplePartition)) { printf ("Error while writing free blocks entry in partition table.\n"); goto ErrorExit; } } printf ("\n%s has finished, seemingly successfully.\n", argv[0]); ReturnCode = 0; ErrorExit: if (PartitionFile >= 0) close (PartitionFile); if (DeviceFile >= 0) close (DeviceFile); return ReturnCode; }