/*- * Copyright (c) 2001, 2002 Mitsuru IWASAKI * All rights reserved. * * NOTE: This utility was created based on FreeBSD fdisk(8) and * lphdisk 0.4 (http://www.procyon.com/~pda/lphdisk/) for * experimental purpose. This software may be rewritten using * FreeBSD libdisk(3) from scratch in future. * * lphdisk is released under the Artistic License * http://www.perl.com/language/misc/Artistic.html * * $FreeBSD$ */ #include #include #include #include #include #include #include #include #include #include #include #include #define MBRSIGOFF 510 #define MAX_SEC_SIZE 2048 /* maximum section size that is supported */ #define MIN_SEC_SIZE 512 /* the sector size to start sensing at */ int secsize = 0; /* the sensed sector size */ const char *disk; const char *disks[] = { "/dev/ad0", "/dev/wd0", "/dev/da0", "/dev/od0", 0 }; struct disklabel disklabel; /* disk parameters */ static int cyls, sectors, heads, cylsecs, disksecs; struct mboot { unsigned char padding[2]; /* force the longs to be long aligned */ unsigned char *bootinst; /* boot code */ off_t bootinst_size; struct dos_partition parts[4]; }; struct mboot mboot = {{0}, NULL, 0}; #define BOOT_MAGIC 0xAA55 int dos_cyls; int dos_heads; int dos_sectors; int dos_cylsecs; int fd; /* * The header, with sector and checksum values set to 0 * __ __ __ __ __ __ * 54 69 6D 4F 00 00 00 00 00 00 00 00 02 00 00 00 00 00 00 00 * Checksum Size in Sectors - 2 */ unsigned char header[512] = { /* we start with an empty header */ 0x54, 0x69, 0x6D, 0x4F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; static int get_params(void) { int error; u_int u; off_t o; error = ioctl(fd, DIOCGFWSECTORS, &u); if (error == 0) sectors = dos_sectors = u; error = ioctl(fd, DIOCGFWHEADS, &u); if (error == 0) heads = dos_heads = u; dos_cylsecs = cylsecs = heads * sectors; disksecs = cyls * heads * sectors; error = ioctl(fd, DIOCGSECTORSIZE, &u); if (error != 0) u = 512; error = ioctl(fd, DIOCGMEDIASIZE, &o); if (error == 0) { disksecs = o / u; cyls = dos_cyls = o / (u * dos_heads * dos_sectors); } return (disksecs); } /* Getting device status */ static int open_disk(void) { struct stat st; if (stat(disk, &st) == -1) { warnx("can't get file status of %s", disk); return (-1); } if (!(st.st_mode & S_IFCHR)) warnx("device %s is not character special", disk); if ((fd = open(disk, O_RDONLY)) == -1) { if(errno == ENXIO) return (-2); warnx("can't open device %s", disk); return (-1); } if (get_params() == -1) { warnx("can't get disk parameters on %s", disk); return (-1); } return (fd); } static ssize_t read_disk(off_t sector, void *buf) { lseek(fd,(sector * 512), 0); if( secsize == 0 ) { for( secsize = MIN_SEC_SIZE; secsize <= MAX_SEC_SIZE; secsize *= 2 ) { /* try the read */ int size = read(fd, buf, secsize); if( size == secsize ) /* it worked so return */ return (secsize); } } else { return (read(fd, buf, secsize)); } /* we failed to read at any of the sizes */ return (-1); } static int read_s0() { mboot.bootinst_size = secsize; if (mboot.bootinst != NULL) free(mboot.bootinst); if ((mboot.bootinst = malloc(mboot.bootinst_size)) == NULL) { warnx("unable to allocate buffer to read fdisk " "partition table"); return (-1); } if (read_disk(0, mboot.bootinst) == -1) { warnx("can't read fdisk partition table"); return (-1); } if (*(uint16_t *)&mboot.bootinst[MBRSIGOFF] != BOOT_MAGIC) { warnx("invalid fdisk partition table found"); /* So should we initialize things */ return (-1); } memcpy(mboot.parts, &mboot.bootinst[DOSPARTOFF], sizeof(mboot.parts)); return (0); } /* * create header */ void create_header(u_int32_t partsize) { unsigned int lowbyte = 0; /* low byte of each byte pair */ unsigned int highbyte = 0; /* high byte of each byte pair */ unsigned int word = 0; /* byte pair for checksum addition */ unsigned int checksum = 0; /* running checksum total */ int i = 0; /* general counter variable */ header[19] = (partsize >> 24) & 0xff; /* first byte in sector size */ header[18] = (partsize >> 16) & 0xff; /* second byte in sector size */ header[17] = (partsize >> 8) & 0xff; /* third byte in sector size */ header[16] = partsize & 0xff; /* fourth (last) byte in sector size */ for (i = 20; i < 512; i++) { header[i] = 0xff; /* header filler with FFs */ } for (i = 511; i > 7; i = i - 2) { /* compute the checksum */ lowbyte = header[i-1]; /* read low byte */ highbyte = header[i]; /* read high byte */ word = lowbyte + (0x100 * highbyte); /* merge bytes into word */ checksum = checksum + word; /* add word to checksum */ } checksum = ~checksum; /* invert checksum */ header[6] = checksum & 0xff; /* significant high byte of checksum */ header[7] = (checksum >> 8) & 0xff; /* significant low byte of checksum */ #if 0 for (i = 0; i < 32; i++) { printf(" %02x", header[i]); } printf("\n"); #endif } /* * format the partition */ int do_format(u_int32_t partsize) { FILE *partfile; /* declare FILE structure */ int i = 0; /* generic counter variable */ unsigned char fresh_sector[512]; /* a PHDISK.EXE "formatted" sector */ if (!(partfile = fopen("phformat.dump", "w"))) { return(-1); } for (i = 0; i < 512; i++) { fresh_sector[i] = 0x50; } fwrite(header, 1, 512, partfile); /* write string of magic_header */ fwrite(header, 1, 512, partfile); /* write string of magic_header */ /* write partsize "blank" sectors */ for (i = 0; i < partsize; i++) { fwrite(fresh_sector, 1, 512, partfile); } fclose(partfile); /* close partition */ } int main(int argc, char *argv[]) { int i; int rv = 0; int phpart = -1; struct dos_partition *partp; u_int32_t phsize = 0; for (i = 0; disks[i]; i++) { disk = disks[i]; rv = open_disk(); if(rv != -2) break; } if (rv < 0) { err(1, "cannot open any disk"); } /* (abu)use mboot.bootinst to probe for the sector size */ if ((mboot.bootinst = malloc(MAX_SEC_SIZE)) == NULL) { err(1, "cannot allocate buffer to determine disk sector size"); } read_disk(0, mboot.bootinst); free(mboot.bootinst); mboot.bootinst = NULL; read_s0(); for (i = 0; i < NDOSPART; i++) { partp = ((struct dos_partition *) &mboot.parts) + i; if (partp->dp_start == 0 && partp->dp_size == 0) { continue; } /* Save to Disk partition? */ if (partp->dp_typ == 0xA0) { phpart = i; phsize = partp->dp_size - 2; break; } } if (phpart == -1) { warn("there is no Save to Disk partitions"); exit(1); } create_header(phsize); do_format(phsize); printf("The phformat.dump was created.\n"); printf("Run the following command as root if it seems to be OK.\n"); printf("# cp phformat.dump %ss%d\n", disk, phpart+1); exit(0); }