Alistair Delva | beaee83 | 2021-02-24 11:27:23 -0800 | [diff] [blame] | 1 | /* Copyright 1997-2003,2005-2007,2009 Alain Knaff. |
| 2 | * This file is part of mtools. |
| 3 | * |
| 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. |
| 8 | * |
| 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. |
| 13 | * |
| 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/>. |
| 16 | * |
| 17 | * mformat.c |
| 18 | */ |
| 19 | #define DONT_NEED_WAIT |
| 20 | |
| 21 | #include "sysincludes.h" |
| 22 | #include "msdos.h" |
| 23 | #include "mtools.h" |
| 24 | #include "mainloop.h" |
| 25 | #include "fsP.h" |
| 26 | #include "file.h" |
| 27 | #include "plain_io.h" |
| 28 | #include "nameclash.h" |
| 29 | #include "buffer.h" |
Alistair Delva | beaee83 | 2021-02-24 11:27:23 -0800 | [diff] [blame] | 30 | #include "partition.h" |
Yi Kong | 39bbd96 | 2022-01-09 19:41:38 +0800 | [diff] [blame] | 31 | #include "open_image.h" |
| 32 | #include "lba.h" |
Alistair Delva | beaee83 | 2021-02-24 11:27:23 -0800 | [diff] [blame] | 33 | |
| 34 | #ifdef OS_linux |
| 35 | #include "linux/hdreg.h" |
Alistair Delva | beaee83 | 2021-02-24 11:27:23 -0800 | [diff] [blame] | 36 | #include "linux/fs.h" |
Alistair Delva | beaee83 | 2021-02-24 11:27:23 -0800 | [diff] [blame] | 37 | #endif |
| 38 | |
Yi Kong | 39bbd96 | 2022-01-09 19:41:38 +0800 | [diff] [blame] | 39 | static void set_offset(hsc *h, unsigned long offset, |
| 40 | uint16_t heads, uint16_t sectors) |
Alistair Delva | beaee83 | 2021-02-24 11:27:23 -0800 | [diff] [blame] | 41 | { |
Yi Kong | 39bbd96 | 2022-01-09 19:41:38 +0800 | [diff] [blame] | 42 | uint16_t head, sector; |
| 43 | unsigned int cyl; |
Alistair Delva | beaee83 | 2021-02-24 11:27:23 -0800 | [diff] [blame] | 44 | |
| 45 | if(! heads || !sectors) |
| 46 | head = sector = cyl = 0; /* linear mode */ |
| 47 | else { |
| 48 | sector = offset % sectors; |
| 49 | offset = offset / sectors; |
| 50 | |
| 51 | head = offset % heads; |
Yi Kong | 39bbd96 | 2022-01-09 19:41:38 +0800 | [diff] [blame] | 52 | offset = offset / heads; |
| 53 | if(offset > 1023) |
| 54 | cyl = 1023; |
| 55 | else |
| 56 | cyl = (uint16_t) offset; |
Alistair Delva | beaee83 | 2021-02-24 11:27:23 -0800 | [diff] [blame] | 57 | } |
Yi Kong | 39bbd96 | 2022-01-09 19:41:38 +0800 | [diff] [blame] | 58 | if(head > UINT8_MAX) { |
| 59 | /* sector or head out of range => linear mode */ |
| 60 | head = sector = cyl = 0; |
| 61 | } |
| 62 | h->head = (uint8_t) head; |
Alistair Delva | beaee83 | 2021-02-24 11:27:23 -0800 | [diff] [blame] | 63 | h->sector = ((sector+1) & 0x3f) | ((cyl & 0x300)>>2); |
| 64 | h->cyl = cyl & 0xff; |
| 65 | } |
| 66 | |
| 67 | void setBeginEnd(struct partition *partTable, |
Yi Kong | 39bbd96 | 2022-01-09 19:41:38 +0800 | [diff] [blame] | 68 | uint32_t begin, uint32_t end, |
| 69 | uint16_t iheads, uint16_t isectors, |
| 70 | int activate, uint8_t type, unsigned int fat_bits) |
Alistair Delva | beaee83 | 2021-02-24 11:27:23 -0800 | [diff] [blame] | 71 | { |
Yi Kong | 39bbd96 | 2022-01-09 19:41:38 +0800 | [diff] [blame] | 72 | uint8_t heads, sectors; |
| 73 | |
| 74 | if(iheads > UINT8_MAX) { |
| 75 | fprintf(stderr, |
| 76 | "Too many heads for partition: %d\n", |
| 77 | iheads); |
| 78 | exit(1); |
| 79 | } |
| 80 | heads=(uint8_t) iheads; |
| 81 | if(isectors > UINT8_MAX) { |
| 82 | fprintf(stderr, |
| 83 | "Too many sectors for partition: %d\n", |
| 84 | isectors); |
| 85 | exit(1); |
| 86 | } |
| 87 | sectors=(uint8_t) isectors; |
| 88 | |
Alistair Delva | beaee83 | 2021-02-24 11:27:23 -0800 | [diff] [blame] | 89 | set_offset(&partTable->start, begin, heads, sectors); |
| 90 | set_offset(&partTable->end, end-1, heads, sectors); |
| 91 | set_dword(partTable->start_sect, begin); |
| 92 | set_dword(partTable->nr_sects, end-begin); |
| 93 | if(activate) |
| 94 | partTable->boot_ind = 0x80; |
| 95 | else |
| 96 | partTable->boot_ind = 0; |
| 97 | if(!type) { |
| 98 | if (fat_bits == 0) { |
| 99 | /** |
| 100 | * Fat bits unknown / not specified. We look |
| 101 | * at size to get a rough estimate what FAT |
| 102 | * bits are used. Note: this is only an |
| 103 | * estimate, the precise calculation would |
| 104 | * involve the number of clusters, which is |
| 105 | * not necessarily known here. |
| 106 | */ |
| 107 | /* cc977219 would have a cutoff number of 32680, |
| 108 | * corresponding to a FAT12 partition with 4K |
| 109 | * clusters, however other information hints that |
| 110 | * only partitions with less than 4096 sectors are |
| 111 | * considered */ |
| 112 | if(end-begin < 4096) |
| 113 | fat_bits = 12; |
| 114 | else |
| 115 | fat_bits = 16; |
| 116 | } |
| 117 | |
| 118 | /* Description of various partition types in |
| 119 | * https://en.wikipedia.org/wiki/Partition_type#List_of_partition_IDs |
| 120 | * and |
| 121 | * https://docs.microsoft.com/en-us/previous-versions/windows/it-pro/windows-2000-server/cc977219(v=technet.10) |
| 122 | */ |
| 123 | if (fat_bits == 32) |
| 124 | /* FAT 32 partition. For now, we disregard the |
| 125 | * possibility of FAT 32 CHS partitions */ |
| 126 | type = 0x0C; /* Win95 FAT32, LBA */ |
| 127 | else if (end < 65536) { |
| 128 | /* FAT 12 or FAT 16 partitions which fit entirely below |
| 129 | the 32M mark */ |
| 130 | /* The 32M restriction doesn't apply to logical |
| 131 | partitions within an extended partition, but for the |
| 132 | moment mpartition only makes primary partitions */ |
| 133 | if(fat_bits == 12) |
| 134 | /* FAT 12 partition */ |
| 135 | type = 0x01; /* DOS FAT12, CHS */ |
| 136 | else if (fat_bits == 16) |
| 137 | /* FAT 16 partition */ |
| 138 | type = 0x04; /* DOS FAT16, CHS */ |
Yi Kong | 39bbd96 | 2022-01-09 19:41:38 +0800 | [diff] [blame] | 139 | } else if (end < sectors * heads * 1024u) |
Alistair Delva | beaee83 | 2021-02-24 11:27:23 -0800 | [diff] [blame] | 140 | /* FAT 12 or FAT16 partition above the 32M |
| 141 | * mark but below the 1024 cylinder mark. |
| 142 | * Indeed, there can be no CHS partition |
| 143 | * beyond 1024 cylinders */ |
| 144 | type = 0x06; /* DOS BIG FAT16 or FAT12, CHS */ |
| 145 | else |
| 146 | type = 0x0E; /* Win95 BIG FAT16, LBA */ |
| 147 | } |
| 148 | partTable->sys_ind = type; |
| 149 | } |
| 150 | |
Alistair Delva | beaee83 | 2021-02-24 11:27:23 -0800 | [diff] [blame] | 151 | |
| 152 | /* setsize function. Determines scsicam mapping if this cannot be inferred from |
| 153 | * any existing partitions. Shamelessly snarfed from the Linux kernel ;-) */ |
| 154 | |
| 155 | /* |
| 156 | * Function : static int setsize(unsigned long capacity,unsigned int *cyls, |
| 157 | * unsigned int *hds, unsigned int *secs); |
| 158 | * |
| 159 | * Purpose : to determine a near-optimal int 0x13 mapping for a |
| 160 | * SCSI disk in terms of lost space of size capacity, storing |
| 161 | * the results in *cyls, *hds, and *secs. |
| 162 | * |
| 163 | * Returns : -1 on failure, 0 on success. |
| 164 | * |
| 165 | * Extracted from |
| 166 | * |
| 167 | * WORKING X3T9.2 |
| 168 | * DRAFT 792D |
| 169 | * |
| 170 | * |
| 171 | * Revision 6 |
| 172 | * 10-MAR-94 |
| 173 | * Information technology - |
| 174 | * SCSI-2 Common access method |
| 175 | * transport and SCSI interface module |
| 176 | * |
| 177 | * ANNEX A : |
| 178 | * |
| 179 | * setsize() converts a read capacity value to int 13h |
| 180 | * head-cylinder-sector requirements. It minimizes the value for |
| 181 | * number of heads and maximizes the number of cylinders. This |
| 182 | * will support rather large disks before the number of heads |
| 183 | * will not fit in 4 bits (or 6 bits). This algorithm also |
| 184 | * minimizes the number of sectors that will be unused at the end |
| 185 | * of the disk while allowing for very large disks to be |
| 186 | * accommodated. This algorithm does not use physical geometry. |
| 187 | */ |
| 188 | |
| 189 | static int setsize(unsigned long capacity,unsigned int *cyls, |
| 190 | uint16_t *hds, uint16_t *secs) { |
Yi Kong | 39bbd96 | 2022-01-09 19:41:38 +0800 | [diff] [blame] | 191 | int rv = 0; |
Alistair Delva | beaee83 | 2021-02-24 11:27:23 -0800 | [diff] [blame] | 192 | unsigned long heads, sectors, cylinders, temp; |
| 193 | |
| 194 | cylinders = 1024L; /* Set number of cylinders to max */ |
| 195 | sectors = 62L; /* Maximize sectors per track */ |
| 196 | |
| 197 | temp = cylinders * sectors; /* Compute divisor for heads */ |
| 198 | heads = capacity / temp; /* Compute value for number of heads */ |
| 199 | if (capacity % temp) { /* If no remainder, done! */ |
| 200 | heads++; /* Else, increment number of heads */ |
| 201 | temp = cylinders * heads; /* Compute divisor for sectors */ |
| 202 | sectors = capacity / temp; /* Compute value for sectors per |
| 203 | track */ |
| 204 | if (capacity % temp) { /* If no remainder, done! */ |
| 205 | sectors++; /* Else, increment number of sectors */ |
| 206 | temp = heads * sectors; /* Compute divisor for cylinders */ |
| 207 | cylinders = capacity / temp;/* Compute number of cylinders */ |
| 208 | } |
| 209 | } |
Yi Kong | 39bbd96 | 2022-01-09 19:41:38 +0800 | [diff] [blame] | 210 | if (cylinders == 0) rv=-1;/* Give error if 0 cylinders */ |
Alistair Delva | beaee83 | 2021-02-24 11:27:23 -0800 | [diff] [blame] | 211 | |
| 212 | *cyls = (unsigned int) cylinders; /* Stuff return values */ |
Yi Kong | 39bbd96 | 2022-01-09 19:41:38 +0800 | [diff] [blame] | 213 | *secs = (uint16_t) sectors; |
| 214 | *hds = (uint16_t) heads; |
Alistair Delva | beaee83 | 2021-02-24 11:27:23 -0800 | [diff] [blame] | 215 | return(rv); |
| 216 | } |
| 217 | |
Yi Kong | 39bbd96 | 2022-01-09 19:41:38 +0800 | [diff] [blame] | 218 | static void setsize0(uint32_t capacity,unsigned int *cyls, |
Alistair Delva | beaee83 | 2021-02-24 11:27:23 -0800 | [diff] [blame] | 219 | uint16_t *hds, uint16_t *secs) |
| 220 | { |
| 221 | int r; |
| 222 | |
| 223 | /* 1. First try "Megabyte" sizes */ |
| 224 | if(capacity < 1024 * 2048 && !(capacity % 1024)) { |
| 225 | *cyls = capacity >> 11; |
| 226 | *hds = 64; |
| 227 | *secs = 32; |
| 228 | return; |
| 229 | } |
| 230 | |
| 231 | /* then try scsicam's size */ |
| 232 | r = setsize(capacity,cyls,hds,secs); |
| 233 | if(r || *hds > 255 || *secs > 63) { |
| 234 | /* scsicam failed. Do megabytes anyways */ |
| 235 | *cyls = capacity >> 11; |
| 236 | *hds = 64; |
| 237 | *secs = 32; |
| 238 | return; |
| 239 | } |
| 240 | } |
| 241 | |
| 242 | |
| 243 | static void usage(int ret) NORETURN; |
| 244 | static void usage(int ret) |
| 245 | { |
| 246 | fprintf(stderr, |
| 247 | "Mtools version %s, dated %s\n", mversion, mdate); |
| 248 | fprintf(stderr, |
| 249 | "Usage: %s [-pradcv] [-I] [-B bootsect-template] [-s sectors] " |
| 250 | "[-t cylinders] " |
| 251 | "[-h heads] [-T type] [-b begin] [-l length] " |
| 252 | "drive\n", progname); |
| 253 | exit(ret); |
| 254 | } |
| 255 | |
| 256 | void mpartition(int argc, char **argv, int dummy UNUSEDP) NORETURN; |
| 257 | void mpartition(int argc, char **argv, int dummy UNUSEDP) |
| 258 | { |
| 259 | Stream_t *Stream; |
| 260 | unsigned int dummy2; |
| 261 | |
Yi Kong | 39bbd96 | 2022-01-09 19:41:38 +0800 | [diff] [blame] | 262 | unsigned int i; |
Alistair Delva | beaee83 | 2021-02-24 11:27:23 -0800 | [diff] [blame] | 263 | |
Yi Kong | 39bbd96 | 2022-01-09 19:41:38 +0800 | [diff] [blame] | 264 | uint16_t sec_per_cyl; |
Alistair Delva | beaee83 | 2021-02-24 11:27:23 -0800 | [diff] [blame] | 265 | int doprint = 0; |
| 266 | int verbose = 0; |
| 267 | int create = 0; |
| 268 | int force = 0; |
| 269 | unsigned int length = 0; |
| 270 | int do_remove = 0; |
| 271 | int initialize = 0; |
Yi Kong | 39bbd96 | 2022-01-09 19:41:38 +0800 | [diff] [blame] | 272 | |
| 273 | uint32_t tot_sectors=0; |
| 274 | /* Needs to be long due to BLKGETSIZE ioctl */ |
| 275 | |
| 276 | uint8_t type = 0; |
Alistair Delva | beaee83 | 2021-02-24 11:27:23 -0800 | [diff] [blame] | 277 | int begin_set = 0; |
| 278 | int size_set = 0; |
| 279 | int end_set = 0; |
Alistair Delva | beaee83 | 2021-02-24 11:27:23 -0800 | [diff] [blame] | 280 | int activate = 0; |
| 281 | int has_activated = 0; |
| 282 | int inconsistency=0; |
| 283 | unsigned int begin=0; |
| 284 | unsigned int end=0; |
Alistair Delva | beaee83 | 2021-02-24 11:27:23 -0800 | [diff] [blame] | 285 | int dirty = 0; |
Yi Kong | 39bbd96 | 2022-01-09 19:41:38 +0800 | [diff] [blame] | 286 | int open2flags = 0; |
Alistair Delva | beaee83 | 2021-02-24 11:27:23 -0800 | [diff] [blame] | 287 | |
| 288 | int c; |
| 289 | struct device used_dev; |
Yi Kong | 39bbd96 | 2022-01-09 19:41:38 +0800 | [diff] [blame] | 290 | unsigned int argtracks; |
| 291 | uint16_t argheads, argsectors; |
Alistair Delva | beaee83 | 2021-02-24 11:27:23 -0800 | [diff] [blame] | 292 | |
| 293 | char drive, name[EXPAND_BUF]; |
| 294 | unsigned char buf[512]; |
| 295 | struct partition *partTable=(struct partition *)(buf+ 0x1ae); |
| 296 | struct device *dev; |
| 297 | char errmsg[2100]; |
| 298 | char *bootSector=0; |
Yi Kong | 39bbd96 | 2022-01-09 19:41:38 +0800 | [diff] [blame] | 299 | struct partition *tpartition; |
Alistair Delva | beaee83 | 2021-02-24 11:27:23 -0800 | [diff] [blame] | 300 | |
| 301 | argtracks = 0; |
| 302 | argheads = 0; |
| 303 | argsectors = 0; |
| 304 | |
| 305 | /* get command line options */ |
| 306 | if(helpFlag(argc, argv)) |
| 307 | usage(0); |
| 308 | while ((c = getopt(argc, argv, "i:adprcIT:t:h:s:fvpb:l:S:B:")) != EOF) { |
| 309 | char *endptr=NULL; |
| 310 | errno=0; |
| 311 | switch (c) { |
| 312 | case 'i': |
| 313 | set_cmd_line_image(optarg); |
| 314 | break; |
| 315 | case 'B': |
| 316 | bootSector = optarg; |
| 317 | break; |
| 318 | case 'a': |
| 319 | /* no privs, as it could be abused to |
| 320 | * make other partitions unbootable, or |
| 321 | * to boot a rogue kernel from this one */ |
| 322 | open2flags |= NO_PRIV; |
| 323 | activate = 1; |
| 324 | dirty = 1; |
| 325 | break; |
| 326 | case 'd': |
| 327 | activate = -1; |
| 328 | dirty = 1; |
| 329 | break; |
| 330 | case 'p': |
| 331 | doprint = 1; |
| 332 | break; |
| 333 | case 'r': |
| 334 | do_remove = 1; |
| 335 | dirty = 1; |
| 336 | break; |
| 337 | case 'I': |
| 338 | /* could be abused to nuke all other |
| 339 | * partitions */ |
| 340 | open2flags |= NO_PRIV; |
| 341 | initialize = 1; |
| 342 | dirty = 1; |
| 343 | break; |
| 344 | case 'c': |
| 345 | create = 1; |
| 346 | dirty = 1; |
| 347 | break; |
| 348 | |
| 349 | case 'T': |
| 350 | /* could be abused to "manually" create |
| 351 | * extended partitions */ |
| 352 | open2flags |= NO_PRIV; |
Yi Kong | 39bbd96 | 2022-01-09 19:41:38 +0800 | [diff] [blame] | 353 | type = strtou8(optarg, &endptr, 0); |
Alistair Delva | beaee83 | 2021-02-24 11:27:23 -0800 | [diff] [blame] | 354 | break; |
| 355 | |
| 356 | case 't': |
Yi Kong | 39bbd96 | 2022-01-09 19:41:38 +0800 | [diff] [blame] | 357 | argtracks = atoui(optarg); |
Alistair Delva | beaee83 | 2021-02-24 11:27:23 -0800 | [diff] [blame] | 358 | break; |
| 359 | case 'h': |
Yi Kong | 39bbd96 | 2022-01-09 19:41:38 +0800 | [diff] [blame] | 360 | argheads = atou16(optarg); |
Alistair Delva | beaee83 | 2021-02-24 11:27:23 -0800 | [diff] [blame] | 361 | break; |
| 362 | case 's': |
Yi Kong | 39bbd96 | 2022-01-09 19:41:38 +0800 | [diff] [blame] | 363 | argsectors = atou16(optarg); |
Alistair Delva | beaee83 | 2021-02-24 11:27:23 -0800 | [diff] [blame] | 364 | break; |
| 365 | |
| 366 | case 'f': |
| 367 | /* could be abused by creating overlapping |
| 368 | * partitions and other such Snafu */ |
| 369 | open2flags |= NO_PRIV; |
| 370 | force = 1; |
| 371 | break; |
| 372 | |
| 373 | case 'v': |
| 374 | verbose++; |
| 375 | break; |
Alistair Delva | beaee83 | 2021-02-24 11:27:23 -0800 | [diff] [blame] | 376 | case 'b': |
| 377 | begin_set = 1; |
| 378 | begin = strtoui(optarg, &endptr, 0); |
| 379 | break; |
| 380 | case 'l': |
| 381 | size_set = 1; |
Yi Kong | 39bbd96 | 2022-01-09 19:41:38 +0800 | [diff] [blame] | 382 | length = parseSize(optarg); |
Alistair Delva | beaee83 | 2021-02-24 11:27:23 -0800 | [diff] [blame] | 383 | break; |
| 384 | |
| 385 | default: |
| 386 | usage(1); |
| 387 | } |
Yi Kong | 39bbd96 | 2022-01-09 19:41:38 +0800 | [diff] [blame] | 388 | check_number_parse_errno((char)c, optarg, endptr); |
Alistair Delva | beaee83 | 2021-02-24 11:27:23 -0800 | [diff] [blame] | 389 | } |
| 390 | |
| 391 | if (argc - optind != 1 || |
| 392 | !argv[optind][0] || argv[optind][1] != ':') |
| 393 | usage(1); |
| 394 | |
| 395 | drive = ch_toupper(argv[optind][0]); |
| 396 | |
| 397 | /* check out a drive whose letter and parameters match */ |
| 398 | sprintf(errmsg, "Drive '%c:' not supported", drive); |
| 399 | Stream = 0; |
| 400 | for(dev=devices;dev->drive;dev++) { |
| 401 | int mode ; |
| 402 | |
| 403 | FREE(&(Stream)); |
| 404 | /* drive letter */ |
| 405 | if (dev->drive != drive) |
| 406 | continue; |
| 407 | if (dev->partition < 1 || dev->partition > 4) { |
| 408 | sprintf(errmsg, |
| 409 | "Drive '%c:' is not a partition", |
| 410 | drive); |
| 411 | continue; |
| 412 | } |
| 413 | used_dev = *dev; |
| 414 | |
| 415 | SET_INT(used_dev.tracks, argtracks); |
| 416 | SET_INT(used_dev.heads, argheads); |
| 417 | SET_INT(used_dev.sectors, argsectors); |
| 418 | |
| 419 | expand(dev->name, name); |
| 420 | |
| 421 | mode = dirty ? O_RDWR : O_RDONLY; |
| 422 | if(initialize) |
| 423 | mode |= O_CREAT; |
| 424 | |
| 425 | #ifdef USING_NEW_VOLD |
| 426 | strcpy(name, getVoldName(dev, name)); |
| 427 | #endif |
Yi Kong | 39bbd96 | 2022-01-09 19:41:38 +0800 | [diff] [blame] | 428 | Stream = OpenImage(&used_dev, dev, name, mode, errmsg, |
| 429 | open2flags | SKIP_PARTITION | ALWAYS_GET_GEOMETRY, |
| 430 | mode, NULL, NULL, NULL); |
Alistair Delva | beaee83 | 2021-02-24 11:27:23 -0800 | [diff] [blame] | 431 | |
| 432 | if (!Stream) { |
| 433 | #ifdef HAVE_SNPRINTF |
| 434 | snprintf(errmsg,sizeof(errmsg)-1, |
| 435 | "init: open: %s", strerror(errno)); |
| 436 | #else |
| 437 | sprintf(errmsg,"init: open: %s", strerror(errno)); |
| 438 | #endif |
| 439 | continue; |
| 440 | } |
| 441 | |
Yi Kong | 39bbd96 | 2022-01-09 19:41:38 +0800 | [diff] [blame] | 442 | tot_sectors = used_dev.tot_sectors; |
Alistair Delva | beaee83 | 2021-02-24 11:27:23 -0800 | [diff] [blame] | 443 | |
| 444 | /* read the partition table */ |
Yi Kong | 39bbd96 | 2022-01-09 19:41:38 +0800 | [diff] [blame] | 445 | if (PREADS(Stream, (char *) buf, 0, 512) != 512 && !initialize){ |
Alistair Delva | beaee83 | 2021-02-24 11:27:23 -0800 | [diff] [blame] | 446 | #ifdef HAVE_SNPRINTF |
| 447 | snprintf(errmsg, sizeof(errmsg)-1, |
| 448 | "Error reading from '%s', wrong parameters?", |
| 449 | name); |
| 450 | #else |
| 451 | sprintf(errmsg, |
| 452 | "Error reading from '%s', wrong parameters?", |
| 453 | name); |
| 454 | #endif |
| 455 | continue; |
| 456 | } |
| 457 | if(verbose>=2) |
| 458 | print_sector("Read sector", buf, 512); |
| 459 | break; |
| 460 | } |
| 461 | |
| 462 | /* print error msg if needed */ |
| 463 | if ( dev->drive == 0 ){ |
| 464 | FREE(&Stream); |
| 465 | fprintf(stderr,"%s: %s\n", argv[0],errmsg); |
| 466 | exit(1); |
| 467 | } |
| 468 | |
| 469 | if((used_dev.sectors || used_dev.heads) && |
| 470 | (!used_dev.sectors || !used_dev.heads)) { |
| 471 | fprintf(stderr,"You should either indicate both the number of sectors and the number of heads,\n"); |
| 472 | fprintf(stderr," or none of them\n"); |
| 473 | exit(1); |
| 474 | } |
| 475 | |
| 476 | if(initialize) { |
| 477 | if (bootSector) { |
| 478 | int fd; |
| 479 | fd = open(bootSector, O_RDONLY | O_BINARY | O_LARGEFILE); |
| 480 | if (fd < 0) { |
| 481 | perror("open MBR"); |
| 482 | exit(1); |
| 483 | } |
| 484 | if(read(fd, (char *) buf, 512) < 512) { |
| 485 | perror("read MBR"); |
| 486 | exit(1); |
| 487 | } |
| 488 | } |
| 489 | memset((char *)(partTable+1), 0, 4*sizeof(*partTable)); |
| 490 | set_word(((unsigned char*)buf)+510, 0xaa55); |
| 491 | } |
| 492 | |
| 493 | /* check for boot signature, and place it if needed */ |
| 494 | if((buf[510] != 0x55) || (buf[511] != 0xaa)) { |
| 495 | fprintf(stderr,"Boot signature not set\n"); |
| 496 | fprintf(stderr, |
| 497 | "Use the -I flag to initialize the partition table, and set the boot signature\n"); |
| 498 | inconsistency = 1; |
| 499 | } |
| 500 | |
Yi Kong | 39bbd96 | 2022-01-09 19:41:38 +0800 | [diff] [blame] | 501 | tpartition=&partTable[dev->partition]; |
Alistair Delva | beaee83 | 2021-02-24 11:27:23 -0800 | [diff] [blame] | 502 | if(do_remove){ |
Yi Kong | 39bbd96 | 2022-01-09 19:41:38 +0800 | [diff] [blame] | 503 | if(!tpartition->sys_ind) |
Alistair Delva | beaee83 | 2021-02-24 11:27:23 -0800 | [diff] [blame] | 504 | fprintf(stderr, |
| 505 | "Partition for drive %c: does not exist\n", |
| 506 | drive); |
Yi Kong | 39bbd96 | 2022-01-09 19:41:38 +0800 | [diff] [blame] | 507 | if((tpartition->sys_ind & 0x3f) == 5) { |
Alistair Delva | beaee83 | 2021-02-24 11:27:23 -0800 | [diff] [blame] | 508 | fprintf(stderr, |
| 509 | "Partition for drive %c: may be an extended partition\n", |
| 510 | drive); |
| 511 | fprintf(stderr, |
| 512 | "Use the -f flag to remove it anyways\n"); |
| 513 | inconsistency = 1; |
| 514 | } |
Yi Kong | 39bbd96 | 2022-01-09 19:41:38 +0800 | [diff] [blame] | 515 | memset(tpartition, 0, sizeof(*tpartition)); |
Alistair Delva | beaee83 | 2021-02-24 11:27:23 -0800 | [diff] [blame] | 516 | } |
| 517 | |
Yi Kong | 39bbd96 | 2022-01-09 19:41:38 +0800 | [diff] [blame] | 518 | if(create && tpartition->sys_ind) { |
Alistair Delva | beaee83 | 2021-02-24 11:27:23 -0800 | [diff] [blame] | 519 | fprintf(stderr, |
| 520 | "Partition for drive %c: already exists\n", drive); |
| 521 | fprintf(stderr, |
| 522 | "Use the -r flag to remove it before attempting to recreate it\n"); |
| 523 | } |
| 524 | |
Yi Kong | 39bbd96 | 2022-01-09 19:41:38 +0800 | [diff] [blame] | 525 | /* if number of heads and sectors not known yet, set "reasonable" |
| 526 | * defaults */ |
| 527 | compute_lba_geom_from_tot_sectors(&used_dev); |
Alistair Delva | beaee83 | 2021-02-24 11:27:23 -0800 | [diff] [blame] | 528 | |
Yi Kong | 39bbd96 | 2022-01-09 19:41:38 +0800 | [diff] [blame] | 529 | /* find out whether there is any activated partition. Moreover |
| 530 | * if no offset of a partition to be created have been |
| 531 | * specificed, find out whether it may be placed between the |
| 532 | * preceding and following partition already existing */ |
Alistair Delva | beaee83 | 2021-02-24 11:27:23 -0800 | [diff] [blame] | 533 | has_activated = 0; |
| 534 | for(i=1; i<5; i++){ |
Yi Kong | 39bbd96 | 2022-01-09 19:41:38 +0800 | [diff] [blame] | 535 | struct partition *partition=&partTable[i]; |
| 536 | if(!partition->sys_ind) |
Alistair Delva | beaee83 | 2021-02-24 11:27:23 -0800 | [diff] [blame] | 537 | continue; |
| 538 | |
Yi Kong | 39bbd96 | 2022-01-09 19:41:38 +0800 | [diff] [blame] | 539 | if(partition->boot_ind) |
Alistair Delva | beaee83 | 2021-02-24 11:27:23 -0800 | [diff] [blame] | 540 | has_activated++; |
| 541 | |
Alistair Delva | beaee83 | 2021-02-24 11:27:23 -0800 | [diff] [blame] | 542 | if(i<dev->partition && !begin_set) |
Yi Kong | 39bbd96 | 2022-01-09 19:41:38 +0800 | [diff] [blame] | 543 | begin = END(partition); |
Alistair Delva | beaee83 | 2021-02-24 11:27:23 -0800 | [diff] [blame] | 544 | if(i>dev->partition && !end_set && !size_set) { |
Yi Kong | 39bbd96 | 2022-01-09 19:41:38 +0800 | [diff] [blame] | 545 | end = BEGIN(partition); |
Alistair Delva | beaee83 | 2021-02-24 11:27:23 -0800 | [diff] [blame] | 546 | end_set = 1; |
| 547 | } |
| 548 | } |
| 549 | |
Alistair Delva | beaee83 | 2021-02-24 11:27:23 -0800 | [diff] [blame] | 550 | if(!used_dev.sectors && !used_dev.heads) { |
Yi Kong | 39bbd96 | 2022-01-09 19:41:38 +0800 | [diff] [blame] | 551 | if(tot_sectors) { |
| 552 | setsize0((uint32_t)tot_sectors,&dummy2,&used_dev.heads, |
Alistair Delva | beaee83 | 2021-02-24 11:27:23 -0800 | [diff] [blame] | 553 | &used_dev.sectors); |
Yi Kong | 39bbd96 | 2022-01-09 19:41:38 +0800 | [diff] [blame] | 554 | } else { |
Alistair Delva | beaee83 | 2021-02-24 11:27:23 -0800 | [diff] [blame] | 555 | used_dev.heads = 64; |
| 556 | used_dev.sectors = 32; |
| 557 | } |
| 558 | } |
| 559 | |
| 560 | if(verbose) |
Yi Kong | 39bbd96 | 2022-01-09 19:41:38 +0800 | [diff] [blame] | 561 | fprintf(stderr,"sectors: %d heads: %d %u\n", |
Alistair Delva | beaee83 | 2021-02-24 11:27:23 -0800 | [diff] [blame] | 562 | used_dev.sectors, used_dev.heads, tot_sectors); |
| 563 | |
| 564 | sec_per_cyl = used_dev.sectors * used_dev.heads; |
| 565 | if(create) { |
Yi Kong | 39bbd96 | 2022-01-09 19:41:38 +0800 | [diff] [blame] | 566 | unsigned int overlap; |
| 567 | if(!end_set && !size_set && tot_sectors) { |
Alistair Delva | beaee83 | 2021-02-24 11:27:23 -0800 | [diff] [blame] | 568 | end = tot_sectors - tot_sectors % sec_per_cyl; |
| 569 | end_set = 1; |
| 570 | } |
| 571 | |
| 572 | /* if the partition starts right at the beginning of |
| 573 | * the disk, keep one track unused to allow place for |
| 574 | * the master boot record */ |
| 575 | if(!begin && !begin_set) |
Yi Kong | 39bbd96 | 2022-01-09 19:41:38 +0800 | [diff] [blame] | 576 | begin = used_dev.sectors ? used_dev.sectors : 2048; |
Alistair Delva | beaee83 | 2021-02-24 11:27:23 -0800 | [diff] [blame] | 577 | |
Yi Kong | 39bbd96 | 2022-01-09 19:41:38 +0800 | [diff] [blame] | 578 | /* Do not try to align partitions (other than first) on track |
| 579 | * boundaries here: apparently this was a thing of the past */ |
Alistair Delva | beaee83 | 2021-02-24 11:27:23 -0800 | [diff] [blame] | 580 | |
Alistair Delva | beaee83 | 2021-02-24 11:27:23 -0800 | [diff] [blame] | 581 | if(size_set) { |
Yi Kong | 39bbd96 | 2022-01-09 19:41:38 +0800 | [diff] [blame] | 582 | end = begin + length; |
Alistair Delva | beaee83 | 2021-02-24 11:27:23 -0800 | [diff] [blame] | 583 | } else if(!end_set) { |
| 584 | fprintf(stderr,"Unknown size\n"); |
| 585 | exit(1); |
| 586 | } |
| 587 | |
Yi Kong | 39bbd96 | 2022-01-09 19:41:38 +0800 | [diff] [blame] | 588 | /* Make sure partition boundaries are correctly ordered |
| 589 | * (end > begin) */ |
| 590 | if(begin >= end) { |
| 591 | fprintf(stderr, "Begin larger than end\n"); |
| 592 | exit(1); |
| 593 | } |
| 594 | |
| 595 | /* Check whether new partition doesn't overlap with |
| 596 | * any of those already in place */ |
| 597 | if((overlap=findOverlap(partTable, 4, begin, end))) { |
| 598 | fprintf(stderr, |
| 599 | "Partition would overlap with partition %d\n", |
| 600 | overlap); |
| 601 | exit(1); |
| 602 | } |
| 603 | |
| 604 | setBeginEnd(tpartition, begin, end, |
Alistair Delva | beaee83 | 2021-02-24 11:27:23 -0800 | [diff] [blame] | 605 | used_dev.heads, used_dev.sectors, |
| 606 | !has_activated, type, |
Yi Kong | 39bbd96 | 2022-01-09 19:41:38 +0800 | [diff] [blame] | 607 | abs(dev->fat_bits)); |
Alistair Delva | beaee83 | 2021-02-24 11:27:23 -0800 | [diff] [blame] | 608 | } |
| 609 | |
| 610 | if(activate) { |
Yi Kong | 39bbd96 | 2022-01-09 19:41:38 +0800 | [diff] [blame] | 611 | if(!tpartition->sys_ind) { |
Alistair Delva | beaee83 | 2021-02-24 11:27:23 -0800 | [diff] [blame] | 612 | fprintf(stderr, |
| 613 | "Partition for drive %c: does not exist\n", |
| 614 | drive); |
| 615 | } else { |
| 616 | switch(activate) { |
| 617 | case 1: |
Yi Kong | 39bbd96 | 2022-01-09 19:41:38 +0800 | [diff] [blame] | 618 | tpartition->boot_ind=0x80; |
Alistair Delva | beaee83 | 2021-02-24 11:27:23 -0800 | [diff] [blame] | 619 | break; |
| 620 | case -1: |
Yi Kong | 39bbd96 | 2022-01-09 19:41:38 +0800 | [diff] [blame] | 621 | tpartition->boot_ind=0x00; |
Alistair Delva | beaee83 | 2021-02-24 11:27:23 -0800 | [diff] [blame] | 622 | break; |
| 623 | } |
| 624 | } |
| 625 | } |
| 626 | |
Alistair Delva | beaee83 | 2021-02-24 11:27:23 -0800 | [diff] [blame] | 627 | inconsistency |= consistencyCheck(partTable, doprint, verbose, |
Yi Kong | 39bbd96 | 2022-01-09 19:41:38 +0800 | [diff] [blame] | 628 | &has_activated, tot_sectors, |
Alistair Delva | beaee83 | 2021-02-24 11:27:23 -0800 | [diff] [blame] | 629 | &used_dev, dev->partition); |
| 630 | |
Alistair Delva | beaee83 | 2021-02-24 11:27:23 -0800 | [diff] [blame] | 631 | switch(has_activated) { |
| 632 | case 0: |
| 633 | fprintf(stderr, |
| 634 | "Warning: no active (bootable) partition present\n"); |
| 635 | break; |
| 636 | case 1: |
| 637 | break; |
| 638 | default: |
| 639 | fprintf(stderr, |
| 640 | "Warning: %d active (bootable) partitions present\n", |
| 641 | has_activated); |
| 642 | fprintf(stderr, |
| 643 | "Usually, a disk should have exactly one active partition\n"); |
| 644 | break; |
| 645 | } |
| 646 | |
| 647 | if(inconsistency && !force) { |
| 648 | fprintf(stderr, |
| 649 | "inconsistency detected!\n" ); |
Yi Kong | 39bbd96 | 2022-01-09 19:41:38 +0800 | [diff] [blame] | 650 | if(dirty) { |
Alistair Delva | beaee83 | 2021-02-24 11:27:23 -0800 | [diff] [blame] | 651 | fprintf(stderr, |
| 652 | "Retry with the -f switch to go ahead anyways\n"); |
Yi Kong | 39bbd96 | 2022-01-09 19:41:38 +0800 | [diff] [blame] | 653 | exit(1); |
| 654 | } |
| 655 | } |
| 656 | |
| 657 | if(doprint && tpartition->sys_ind) { |
| 658 | printf("The following command will recreate the partition for drive %c:\n", |
| 659 | drive); |
| 660 | used_dev.tracks = |
| 661 | (_DWORD(tpartition->nr_sects) + |
| 662 | (BEGIN(tpartition) % sec_per_cyl)) / |
| 663 | sec_per_cyl; |
| 664 | printf("mpartition -c -b %d -l %d -t %d -h %d -s %d -b %u %c:\n", |
| 665 | BEGIN(tpartition), PART_SIZE(tpartition), |
| 666 | used_dev.tracks, used_dev.heads, used_dev.sectors, |
| 667 | BEGIN(tpartition), drive); |
Alistair Delva | beaee83 | 2021-02-24 11:27:23 -0800 | [diff] [blame] | 668 | } |
| 669 | |
| 670 | if(dirty) { |
| 671 | /* write data back to the disk */ |
| 672 | if(verbose>=2) |
| 673 | print_sector("Writing sector", buf, 512); |
Yi Kong | 39bbd96 | 2022-01-09 19:41:38 +0800 | [diff] [blame] | 674 | if (PWRITES(Stream, (char *) buf, 0, 512) != 512) { |
Alistair Delva | beaee83 | 2021-02-24 11:27:23 -0800 | [diff] [blame] | 675 | fprintf(stderr,"Error writing partition table"); |
| 676 | exit(1); |
| 677 | } |
| 678 | if(verbose>=3) |
| 679 | print_sector("Sector written", buf, 512); |
| 680 | } |
| 681 | FREE(&Stream); |
| 682 | exit(0); |
| 683 | } |