1 /* Copyright 1997-2003,2005-2007,2009 Alain Knaff.
2 * This file is part of mtools.
4 * Mtools is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
9 * Mtools is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with Mtools. If not, see <http://www.gnu.org/licenses/>.
19 #define DONT_NEED_WAIT
21 #include "sysincludes.h"
28 #include "nameclash.h"
31 #include "partition.h"
34 #include "linux/hdreg.h"
39 (sector(x)-1u+(head(x)+cyl(x)*used_dev->heads)*used_dev->sectors)
42 static __inline__ void print_hsc(hsc *h)
44 printf(" h=%d s=%d c=%d\n",
45 head(*h), sector(*h), cyl(*h));
48 static void set_offset(hsc *h, unsigned long offset,
49 uint16_t heads, uint16_t sectors)
51 uint16_t head, sector;
54 if(! heads || !sectors)
55 head = sector = cyl = 0; /* linear mode */
57 sector = offset % sectors;
58 offset = offset / sectors;
60 head = offset % heads;
61 offset = offset / heads;
65 cyl = (uint16_t) offset;
67 if(head > UINT8_MAX) {
68 /* sector or head out of range => linear mode */
69 head = sector = cyl = 0;
71 h->head = (uint8_t) head;
72 h->sector = ((sector+1) & 0x3f) | ((cyl & 0x300)>>2);
76 void setBeginEnd(struct partition *partTable,
77 uint32_t begin, uint32_t end,
78 uint16_t iheads, uint16_t isectors,
79 int activate, uint8_t type, int fat_bits)
81 uint8_t heads, sectors;
83 if(iheads > UINT8_MAX) {
85 "Too many heads for partition: %d\n",
89 heads=(uint8_t) iheads;
90 if(isectors > UINT8_MAX) {
92 "Too many sectors for partition: %d\n",
96 sectors=(uint8_t) isectors;
98 set_offset(&partTable->start, begin, heads, sectors);
99 set_offset(&partTable->end, end-1, heads, sectors);
100 set_dword(partTable->start_sect, begin);
101 set_dword(partTable->nr_sects, end-begin);
103 partTable->boot_ind = 0x80;
105 partTable->boot_ind = 0;
109 * Fat bits unknown / not specified. We look
110 * at size to get a rough estimate what FAT
111 * bits are used. Note: this is only an
112 * estimate, the precise calculation would
113 * involve the number of clusters, which is
114 * not necessarily known here.
116 /* cc977219 would have a cutoff number of 32680,
117 * corresponding to a FAT12 partition with 4K
118 * clusters, however other information hints that
119 * only partitions with less than 4096 sectors are
127 /* Description of various partition types in
128 * https://en.wikipedia.org/wiki/Partition_type#List_of_partition_IDs
130 * https://docs.microsoft.com/en-us/previous-versions/windows/it-pro/windows-2000-server/cc977219(v=technet.10)
133 /* FAT 32 partition. For now, we disregard the
134 * possibility of FAT 32 CHS partitions */
135 type = 0x0C; /* Win95 FAT32, LBA */
136 else if (end < 65536) {
137 /* FAT 12 or FAT 16 partitions which fit entirely below
139 /* The 32M restriction doesn't apply to logical
140 partitions within an extended partition, but for the
141 moment mpartition only makes primary partitions */
143 /* FAT 12 partition */
144 type = 0x01; /* DOS FAT12, CHS */
145 else if (fat_bits == 16)
146 /* FAT 16 partition */
147 type = 0x04; /* DOS FAT16, CHS */
148 } else if (end < sectors * heads * 1024u)
149 /* FAT 12 or FAT16 partition above the 32M
150 * mark but below the 1024 cylinder mark.
151 * Indeed, there can be no CHS partition
152 * beyond 1024 cylinders */
153 type = 0x06; /* DOS BIG FAT16 or FAT12, CHS */
155 type = 0x0E; /* Win95 BIG FAT16, LBA */
157 partTable->sys_ind = type;
160 int consistencyCheck(struct partition *partTable, int doprint,
162 int *has_activated, unsigned int *last_end,
164 struct device *used_dev, unsigned int target_partition)
172 /* quick consistency check */
176 if(!partTable[i].sys_ind)
178 if(partTable[i].boot_ind)
182 *last_end > BEGIN(partTable[i])) {
184 "Partitions %d and %d badly ordered or overlapping\n",
189 *last_end = END(partTable[i]);
192 if(doprint && verbose) {
193 if(i==target_partition)
197 printf("Partition %d\n",i);
199 printf(" active=%x\n", partTable[i].boot_ind);
201 print_hsc(&partTable[i].start);
202 printf(" type=0x%x\n", partTable[i].sys_ind);
204 print_hsc(&partTable[i].end);
205 printf(" start=%d\n", BEGIN(partTable[i]));
206 printf(" nr=%d\n", _DWORD(partTable[i].nr_sects));
210 return inconsistency;
213 /* setsize function. Determines scsicam mapping if this cannot be inferred from
214 * any existing partitions. Shamelessly snarfed from the Linux kernel ;-) */
217 * Function : static int setsize(unsigned long capacity,unsigned int *cyls,
218 * unsigned int *hds, unsigned int *secs);
220 * Purpose : to determine a near-optimal int 0x13 mapping for a
221 * SCSI disk in terms of lost space of size capacity, storing
222 * the results in *cyls, *hds, and *secs.
224 * Returns : -1 on failure, 0 on success.
234 * Information technology -
235 * SCSI-2 Common access method
236 * transport and SCSI interface module
240 * setsize() converts a read capacity value to int 13h
241 * head-cylinder-sector requirements. It minimizes the value for
242 * number of heads and maximizes the number of cylinders. This
243 * will support rather large disks before the number of heads
244 * will not fit in 4 bits (or 6 bits). This algorithm also
245 * minimizes the number of sectors that will be unused at the end
246 * of the disk while allowing for very large disks to be
247 * accommodated. This algorithm does not use physical geometry.
250 static int setsize(unsigned long capacity,unsigned int *cyls,
251 uint16_t *hds, uint16_t *secs) {
253 unsigned long heads, sectors, cylinders, temp;
255 cylinders = 1024L; /* Set number of cylinders to max */
256 sectors = 62L; /* Maximize sectors per track */
258 temp = cylinders * sectors; /* Compute divisor for heads */
259 heads = capacity / temp; /* Compute value for number of heads */
260 if (capacity % temp) { /* If no remainder, done! */
261 heads++; /* Else, increment number of heads */
262 temp = cylinders * heads; /* Compute divisor for sectors */
263 sectors = capacity / temp; /* Compute value for sectors per
265 if (capacity % temp) { /* If no remainder, done! */
266 sectors++; /* Else, increment number of sectors */
267 temp = heads * sectors; /* Compute divisor for cylinders */
268 cylinders = capacity / temp;/* Compute number of cylinders */
271 if (cylinders == 0) rv=-1;/* Give error if 0 cylinders */
273 *cyls = (unsigned int) cylinders; /* Stuff return values */
274 *secs = (uint16_t) sectors;
275 *hds = (uint16_t) heads;
279 static void setsize0(uint32_t capacity,unsigned int *cyls,
280 uint16_t *hds, uint16_t *secs)
284 /* 1. First try "Megabyte" sizes */
285 if(capacity < 1024 * 2048 && !(capacity % 1024)) {
286 *cyls = capacity >> 11;
292 /* then try scsicam's size */
293 r = setsize(capacity,cyls,hds,secs);
294 if(r || *hds > 255 || *secs > 63) {
295 /* scsicam failed. Do megabytes anyways */
296 *cyls = capacity >> 11;
304 static void usage(int ret) NORETURN;
305 static void usage(int ret)
308 "Mtools version %s, dated %s\n", mversion, mdate);
310 "Usage: %s [-pradcv] [-I] [-B bootsect-template] [-s sectors] "
312 "[-h heads] [-T type] [-b begin] [-l length] "
313 "drive\n", progname);
317 static void checkTotalSectors(unsigned long tot_sectors) {
318 if(tot_sectors > UINT32_MAX) {
319 fprintf(stderr, "Too many total sectors %ld\n",
325 void mpartition(int argc, char **argv, int dummy UNUSEDP) NORETURN;
326 void mpartition(int argc, char **argv, int dummy UNUSEDP)
333 uint16_t sec_per_cyl;
338 unsigned int length = 0;
342 unsigned long tot_sectors=0;
343 /* Needs to be long due to BLKGETSIZE ioctl */
349 unsigned int last_end = 0;
351 int has_activated = 0;
353 unsigned int begin=0;
357 int open2flags = NO_OFFSET;
360 struct device used_dev;
361 unsigned int argtracks;
362 uint16_t argheads, argsectors;
364 char drive, name[EXPAND_BUF];
365 unsigned char buf[512];
366 struct partition *partTable=(struct partition *)(buf+ 0x1ae);
375 /* get command line options */
376 if(helpFlag(argc, argv))
378 while ((c = getopt(argc, argv, "i:adprcIT:t:h:s:fvpb:l:S:B:")) != EOF) {
383 set_cmd_line_image(optarg);
389 /* no privs, as it could be abused to
390 * make other partitions unbootable, or
391 * to boot a rogue kernel from this one */
392 open2flags |= NO_PRIV;
408 /* could be abused to nuke all other
410 open2flags |= NO_PRIV;
420 /* could be abused to "manually" create
421 * extended partitions */
422 open2flags |= NO_PRIV;
423 type = strtou8(optarg, &endptr, 0);
427 argtracks = atoui(optarg);
430 argheads = atou16(optarg);
433 argsectors = atou16(optarg);
437 /* could be abused by creating overlapping
438 * partitions and other such Snafu */
439 open2flags |= NO_PRIV;
448 /* could be abused to create partitions
449 * extending beyond the actual size of the
451 open2flags |= NO_PRIV;
452 tot_sectors = strtoui(optarg, &endptr, 0);
457 begin = strtoui(optarg, &endptr, 0);
461 length = strtoui(optarg, &endptr, 0);
467 check_number_parse_errno((char)c, optarg, endptr);
470 if (argc - optind != 1 ||
471 !argv[optind][0] || argv[optind][1] != ':')
474 drive = ch_toupper(argv[optind][0]);
476 /* check out a drive whose letter and parameters match */
477 sprintf(errmsg, "Drive '%c:' not supported", drive);
479 for(dev=devices;dev->drive;dev++) {
484 if (dev->drive != drive)
486 if (dev->partition < 1 || dev->partition > 4) {
488 "Drive '%c:' is not a partition",
494 SET_INT(used_dev.tracks, argtracks);
495 SET_INT(used_dev.heads, argheads);
496 SET_INT(used_dev.sectors, argsectors);
498 expand(dev->name, name);
500 mode = dirty ? O_RDWR : O_RDONLY;
504 #ifdef USING_NEW_VOLD
505 strcpy(name, getVoldName(dev, name));
507 Stream = SimpleFileOpen(&used_dev, dev, name, mode,
508 errmsg, open2flags, 1, 0);
512 snprintf(errmsg,sizeof(errmsg)-1,
513 "init: open: %s", strerror(errno));
515 sprintf(errmsg,"init: open: %s", strerror(errno));
521 /* try to find out the size */
525 unsigned char cmd[10];
526 unsigned char data[10];
527 cmd[0] = SCSI_READ_CAPACITY;
528 memset ((void *) &cmd[2], 0, 8);
529 memset ((void *) &data[0], 137, 10);
530 scsi_cmd(get_fd(Stream), cmd, 10, SCSI_IO_READ,
531 data, 10, get_extra_data(Stream));
534 ((uint32_t)data[0] << 24) +
535 ((uint32_t)data[1] << 16) +
536 ((uint32_t)data[2] << 8) +
537 ((uint32_t)data[3] );
539 printf("%lu sectors in total\n", tot_sectors);
543 if (tot_sectors == 0) {
544 ioctl(get_fd(Stream), BLKGETSIZE, &tot_sectors);
548 /* read the partition table */
549 if (READS(Stream, (char *) buf, 0, 512) != 512 && !initialize){
551 snprintf(errmsg, sizeof(errmsg)-1,
552 "Error reading from '%s', wrong parameters?",
556 "Error reading from '%s', wrong parameters?",
562 print_sector("Read sector", buf, 512);
566 /* print error msg if needed */
567 if ( dev->drive == 0 ){
569 fprintf(stderr,"%s: %s\n", argv[0],errmsg);
573 if((used_dev.sectors || used_dev.heads) &&
574 (!used_dev.sectors || !used_dev.heads)) {
575 fprintf(stderr,"You should either indicate both the number of sectors and the number of heads,\n");
576 fprintf(stderr," or none of them\n");
583 fd = open(bootSector, O_RDONLY | O_BINARY | O_LARGEFILE);
588 if(read(fd, (char *) buf, 512) < 512) {
593 memset((char *)(partTable+1), 0, 4*sizeof(*partTable));
594 set_word(((unsigned char*)buf)+510, 0xaa55);
597 /* check for boot signature, and place it if needed */
598 if((buf[510] != 0x55) || (buf[511] != 0xaa)) {
599 fprintf(stderr,"Boot signature not set\n");
601 "Use the -I flag to initialize the partition table, and set the boot signature\n");
606 if(!partTable[dev->partition].sys_ind)
608 "Partition for drive %c: does not exist\n",
610 if((partTable[dev->partition].sys_ind & 0x3f) == 5) {
612 "Partition for drive %c: may be an extended partition\n",
615 "Use the -f flag to remove it anyways\n");
618 memset(&partTable[dev->partition], 0, sizeof(*partTable));
621 if(create && partTable[dev->partition].sys_ind) {
623 "Partition for drive %c: already exists\n", drive);
625 "Use the -r flag to remove it before attempting to recreate it\n");
628 /* if number of heads and sectors not known yet, set "reasonable"
632 if(!used_dev.sectors)
633 used_dev.sectors = 63;
635 /* find out whether there is any activated partition */
638 if(!partTable[i].sys_ind)
641 if(partTable[i].boot_ind)
644 if(i<dev->partition && !begin_set)
645 begin = END(partTable[i]);
646 if(i>dev->partition && !end_set && !size_set) {
647 end = BEGIN(partTable[i]);
653 if(!used_dev.sectors && !used_dev.heads) {
655 struct hd_geometry geom;
656 if(ioctl(get_fd(Stream), HDIO_GETGEO, &geom) == 0) {
657 used_dev.heads = geom.heads;
658 used_dev.sectors = geom.sectors;
664 if(!used_dev.sectors && !used_dev.heads) {
666 checkTotalSectors(tot_sectors);
667 setsize0((uint32_t)tot_sectors,&dummy2,&used_dev.heads,
671 used_dev.sectors = 32;
676 fprintf(stderr,"sectors: %d heads: %d %lu\n",
677 used_dev.sectors, used_dev.heads, tot_sectors);
679 sec_per_cyl = used_dev.sectors * used_dev.heads;
681 if(!end_set && tot_sectors) {
682 checkTotalSectors(tot_sectors);
683 end = (uint32_t) tot_sectors -
684 (uint32_t) tot_sectors % sec_per_cyl;
688 /* if the partition starts right at the beginning of
689 * the disk, keep one track unused to allow place for
690 * the master boot record */
691 if(!begin && !begin_set)
692 begin = used_dev.sectors;
693 if(!size_set && used_dev.tracks) {
695 length = sec_per_cyl * used_dev.tracks;
697 /* round the size in order to take
698 * into account any "hidden" sectors */
700 /* do we anchor this at the beginning ?*/
701 if(begin_set || dev->partition <= 2 || !end_set)
702 length -= begin % sec_per_cyl;
703 else if(end - length < begin)
704 /* truncate any overlap */
705 length = end - begin;
708 if(!begin_set && dev->partition >2 && end_set)
709 begin = end - length;
711 end = begin + length;
712 } else if(!end_set) {
713 fprintf(stderr,"Unknown size\n");
717 setBeginEnd(&partTable[dev->partition], begin, end,
718 used_dev.heads, used_dev.sectors,
719 !has_activated, type,
724 if(!partTable[dev->partition].sys_ind) {
726 "Partition for drive %c: does not exist\n",
731 partTable[dev->partition].boot_ind=0x80;
734 partTable[dev->partition].boot_ind=0x00;
741 inconsistency |= consistencyCheck(partTable, doprint, verbose,
742 &has_activated, &last_end, &j,
743 &used_dev, dev->partition);
745 if(tot_sectors && last_end >tot_sectors) {
747 "Partition %d extends beyond end of disk\n",
753 switch(has_activated) {
756 "Warning: no active (bootable) partition present\n");
762 "Warning: %d active (bootable) partitions present\n",
765 "Usually, a disk should have exactly one active partition\n");
769 if(inconsistency && !force) {
771 "inconsistency detected!\n" );
774 "Retry with the -f switch to go ahead anyways\n");
779 if(doprint && partTable[dev->partition].sys_ind) {
780 printf("The following command will recreate the partition for drive %c:\n",
783 (_DWORD(partTable[dev->partition].nr_sects) +
784 (BEGIN(partTable[dev->partition]) % sec_per_cyl)) /
786 printf("mpartition -c -t %d -h %d -s %d -b %u %c:\n",
787 used_dev.tracks, used_dev.heads, used_dev.sectors,
788 BEGIN(partTable[dev->partition]), drive);
792 /* write data back to the disk */
794 print_sector("Writing sector", buf, 512);
795 if (WRITES(Stream, (char *) buf, 0, 512) != 512) {
796 fprintf(stderr,"Error writing partition table");
800 print_sector("Sector written", buf, 512);