1 /* $NetBSD: fdisk.c,v 1.13 1997/06/24 06:38:50 perry Exp $ */ 2 3 /* 4 * Mach Operating System 5 * Copyright (c) 1992 Carnegie Mellon University 6 * All Rights Reserved. 7 * 8 * Permission to use, copy, modify and distribute this software and its 9 * documentation is hereby granted, provided that both the copyright 10 * notice and this permission notice appear in all copies of the 11 * software, derivative works or modified versions, and any portions 12 * thereof, and that both notices appear in supporting documentation. 13 * 14 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 15 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 16 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 17 * 18 * Carnegie Mellon requests users of this software to return to 19 * 20 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 21 * School of Computer Science 22 * Carnegie Mellon University 23 * Pittsburgh PA 15213-3890 24 * 25 * any improvements or extensions that they make and grant Carnegie Mellon 26 * the rights to redistribute these changes. 27 */ 28 29 #ifndef lint 30 static char rcsid[] = "$NetBSD: fdisk.c,v 1.13 1997/06/24 06:38:50 perry Exp $"; 31 #endif /* not lint */ 32 33 #include <sys/types.h> 34 #include <sys/disklabel.h> 35 #include <sys/ioctl.h> 36 #include <sys/stat.h> 37 38 #include <ctype.h> 39 #include <err.h> 40 #include <fcntl.h> 41 #include <stdio.h> 42 #include <stdlib.h> 43 #include <string.h> 44 #include <unistd.h> 45 46 #define LBUF 100 47 static char lbuf[LBUF]; 48 49 /* 50 * 14-Dec-89 Robert Baron (rvb) at Carnegie-Mellon University 51 * Copyright (c) 1989 Robert. V. Baron 52 * Created. 53 */ 54 55 char *disk = "/dev/rwd0d"; 56 57 struct disklabel disklabel; /* disk parameters */ 58 59 int cylinders, sectors, heads, cylindersectors, disksectors; 60 61 struct mboot { 62 unsigned char padding[2]; /* force the longs to be long alligned */ 63 unsigned char bootinst[DOSPARTOFF]; 64 struct dos_partition parts[4]; 65 unsigned short int signature; 66 }; 67 struct mboot mboot; 68 69 #define ACTIVE 0x80 70 #define BOOT_MAGIC 0xAA55 71 72 int dos_cylinders; 73 int dos_heads; 74 int dos_sectors; 75 int dos_cylindersectors; 76 77 #define DOSSECT(s,c) (((s) & 0x3f) | (((c) >> 2) & 0xc0)) 78 #define DOSCYL(c) ((c) & 0xff) 79 int partition = -1; 80 81 int a_flag; /* set active partition */ 82 int i_flag; /* replace partition data */ 83 int u_flag; /* update partition data */ 84 85 unsigned char bootcode[] = { 86 0x33, 0xc0, 0xfa, 0x8e, 0xd0, 0xbc, 0x00, 0x7c, 0x8e, 0xc0, 0x8e, 0xd8, 0xfb, 0x8b, 0xf4, 0xbf, 87 0x00, 0x06, 0xb9, 0x00, 0x02, 0xfc, 0xf3, 0xa4, 0xea, 0x1d, 0x06, 0x00, 0x00, 0xb0, 0x04, 0xbe, 88 0xbe, 0x07, 0x80, 0x3c, 0x80, 0x74, 0x0c, 0x83, 0xc6, 0x10, 0xfe, 0xc8, 0x75, 0xf4, 0xbe, 0xbd, 89 0x06, 0xeb, 0x43, 0x8b, 0xfe, 0x8b, 0x14, 0x8b, 0x4c, 0x02, 0x83, 0xc6, 0x10, 0xfe, 0xc8, 0x74, 90 0x0a, 0x80, 0x3c, 0x80, 0x75, 0xf4, 0xbe, 0xbd, 0x06, 0xeb, 0x2b, 0xbd, 0x05, 0x00, 0xbb, 0x00, 91 0x7c, 0xb8, 0x01, 0x02, 0xcd, 0x13, 0x73, 0x0c, 0x33, 0xc0, 0xcd, 0x13, 0x4d, 0x75, 0xef, 0xbe, 92 0x9e, 0x06, 0xeb, 0x12, 0x81, 0x3e, 0xfe, 0x7d, 0x55, 0xaa, 0x75, 0x07, 0x8b, 0xf7, 0xea, 0x00, 93 0x7c, 0x00, 0x00, 0xbe, 0x85, 0x06, 0x2e, 0xac, 0x0a, 0xc0, 0x74, 0x06, 0xb4, 0x0e, 0xcd, 0x10, 94 0xeb, 0xf4, 0xfb, 0xeb, 0xfe, 95 'M', 'i', 's', 's', 'i', 'n', 'g', ' ', 96 'o', 'p', 'e', 'r', 'a', 't', 'i', 'n', 'g', ' ', 's', 'y', 's', 't', 'e', 'm', 0, 97 'E', 'r', 'r', 'o', 'r', ' ', 'l', 'o', 'a', 'd', 'i', 'n', 'g', ' ', 98 'o', 'p', 'e', 'r', 'a', 't', 'i', 'n', 'g', ' ', 's', 'y', 's', 't', 'e', 'm', 0, 99 'I', 'n', 'v', 'a', 'l', 'i', 'd', ' ', 100 'p', 'a', 'r', 't', 'i', 't', 'i', 'o', 'n', ' ', 't', 'a', 'b', 'l', 'e', 0, 101 'A', 'u', 't', 'h', 'o', 'r', ' ', '-', ' ', 102 'S', 'i', 'e', 'g', 'm', 'a', 'r', ' ', 'S', 'c', 'h', 'm', 'i', 'd', 't', 0,0,0, 103 104 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 105 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 106 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 107 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 108 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 109 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 110 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 111 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 112 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 113 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 114 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 115 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 116 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 117 }; 118 119 struct part_type { 120 int type; 121 char *name; 122 } part_types[] = { 123 {0x00, "unused"}, 124 {0x01, "Primary DOS with 12 bit FAT"}, 125 {0x02, "XENIX / filesystem"}, 126 {0x03, "XENIX /usr filesystem"}, 127 {0x04, "Primary DOS with 16 bit FAT <32M"}, 128 {0x05, "Extended DOS"}, 129 {0x06, "Primary 'big' DOS, 16-bit FAT (> 32MB)"}, 130 {0x07, "OS/2 HPFS or NTFS or QNX2 or Advanced UNIX"}, 131 {0x08, "AIX filesystem"}, 132 {0x09, "AIX boot partition or Coherent"}, 133 {0x0A, "OS/2 Boot Manager or Coherent swap or OPUS"}, 134 {0x0E, "DOS (16-bit FAT), CHS-mapped"}, 135 {0x0F, "Ext. partition, CHS-mapped"}, 136 {0x10, "OPUS"}, 137 {0x11, "OS/2 BM: hidden DOS 12-bit FAT"}, 138 {0x12, "Compaq diagnostics"}, 139 {0x14, "OS/2 BM: hidden DOS 16-bit FAT <32M"}, 140 {0x16, "OS/2 BM: hidden DOS 16-bit FAT >=32M"}, 141 {0x17, "OS/2 BM: hidden IFS"}, 142 {0x18, "AST Windows swapfile"}, 143 {0x24, "NEC DOS"}, 144 {0x3C, "PartitionMagic recovery"}, 145 {0x40, "VENIX 286"}, 146 {0x41, "Linux/MINIX (sharing disk with DRDOS)"}, 147 {0x42, "SFS or Linux swap (sharing disk with DRDOS)"}, 148 {0x43, "Linux native (sharing disk with DRDOS)"}, 149 {0x50, "DM (disk manager)"}, 150 {0x51, "DM6 Aux1 (or Novell)"}, 151 {0x52, "CP/M or Microport SysV/AT"}, 152 {0x53, "DM6 Aux3"}, 153 {0x54, "DM6"}, 154 {0x55, "EZ-Drive (disk manager)"}, 155 {0x56, "Golden Bow (disk manager)"}, 156 {0x5C, "Priam Edisk (disk manager)"}, 157 {0x61, "SpeedStor"}, 158 {0x63, "GNU HURD or Mach or Sys V/386 (such as ISC UNIX)"}, 159 {0x64, "Novell Netware 2.xx"}, 160 {0x65, "Novell Netware 3.xx"}, 161 {0x70, "DiskSecure Multi-Boot"}, 162 {0x75, "PC/IX"}, 163 {0x77, "QNX4.x"}, 164 {0x78, "QNX4.x 2nd part"}, 165 {0x79, "QNX4.x 3rd part"}, 166 {0x80, "MINIX until 1.4a"}, 167 {0x81, "MINIX since 1.4b, early Linux, Mitac dmgr"}, 168 {0x82, "Linux swap"}, 169 {0x83, "Linux native"}, 170 {0x84, "OS/2 hidden C: drive"}, 171 {0x85, "Linux extended"}, 172 {0x86, "NTFS volume set??"}, 173 {0x87, "NTFS volume set??"}, 174 {0x93, "Amoeba filesystem"}, 175 {0x94, "Amoeba bad block table"}, 176 {0xA0, "IBM Thinkpad hibernation"}, 177 {0xA5, "NetBSD or FreeBSD or 386BSD"}, 178 {0xA6, "OpenBSD"}, 179 {0xA7, "NeXTSTEP 486"}, 180 {0xB7, "BSDI BSD/386 filesystem"}, 181 {0xB8, "BSDI BSD/386 swap"}, 182 {0xC1, "DRDOS/sec (FAT-12)"}, 183 {0xC4, "DRDOS/sec (FAT-16, < 32M)"}, 184 {0xC6, "DRDOS/sec (FAT-16, >= 32M)"}, 185 {0xC7, "Syrinx"}, 186 {0xDB, "CP/M or Concurrent CP/M or Concurrent DOS or CTOS"}, 187 {0xE1, "DOS access or SpeedStor 12-bit FAT extended partition"}, 188 {0xE3, "DOS R/O or SpeedStor"}, 189 {0xE4, "SpeedStor 16-bit FAT extended partition < 1024 cyl."}, 190 {0xF1, "SpeedStor"}, 191 {0xF2, "DOS 3.3+ Secondary"}, 192 {0xF4, "SpeedStor large partition"}, 193 {0xFE, "SpeedStor >1024 cyl. or LANstep"}, 194 {0xFF, "Xenix Bad Block Table"}, 195 }; 196 197 void usage __P((void)); 198 void print_s0 __P((int)); 199 void print_part __P((int)); 200 void init_sector0 __P((int)); 201 void intuit_translated_geometry __P((void)); 202 int try_heads __P((quad_t, quad_t, quad_t, quad_t, quad_t, quad_t, quad_t, 203 quad_t)); 204 int try_sectors __P((quad_t, quad_t, quad_t, quad_t, quad_t)); 205 void change_part __P((int)); 206 void print_params __P((void)); 207 void change_active __P((int)); 208 void get_params_to_use __P((void)); 209 void dos __P((int, unsigned char *, unsigned char *, unsigned char *)); 210 int open_disk __P((int)); 211 int read_disk __P((int, void *)); 212 int write_disk __P((int, void *)); 213 int get_params __P((void)); 214 int read_s0 __P((void)); 215 int write_s0 __P((void)); 216 int yesno __P((char *)); 217 void decimal __P((char *, int *)); 218 int type_match __P((const void *, const void *)); 219 char *get_type __P((int)); 220 221 int 222 main(argc, argv) 223 int argc; 224 char *argv[]; 225 { 226 int ch; 227 int part; 228 229 a_flag = i_flag = u_flag = 0; 230 while ((ch = getopt(argc, argv, "0123aiu")) != -1) 231 switch (ch) { 232 case '0': 233 partition = 0; 234 break; 235 case '1': 236 partition = 1; 237 break; 238 case '2': 239 partition = 2; 240 break; 241 case '3': 242 partition = 3; 243 break; 244 case 'a': 245 a_flag = 1; 246 break; 247 case 'i': 248 i_flag = 1; 249 case 'u': 250 u_flag = 1; 251 break; 252 default: 253 usage(); 254 } 255 argc -= optind; 256 argv += optind; 257 258 if (argc > 0) 259 disk = argv[0]; 260 261 if (open_disk(a_flag || i_flag || u_flag) < 0) 262 exit(1); 263 264 if (read_s0()) 265 init_sector0(1); 266 267 intuit_translated_geometry(); 268 269 printf("******* Working on device %s *******\n", disk); 270 if (u_flag) 271 get_params_to_use(); 272 else 273 print_params(); 274 275 printf("Warning: BIOS sector numbering starts with sector 1\n"); 276 printf("Information from DOS bootblock is:\n"); 277 if (partition == -1) { 278 for (part = 0; part < NDOSPART; part++) 279 change_part(part); 280 } else 281 change_part(partition); 282 283 if (u_flag || a_flag) 284 change_active(partition); 285 286 if (u_flag || a_flag) { 287 printf("\nWe haven't changed the partition table yet. "); 288 printf("This is your last chance.\n"); 289 print_s0(-1); 290 if (yesno("Should we write new partition table?")) 291 write_s0(); 292 } 293 294 exit(0); 295 } 296 297 void 298 usage() 299 { 300 301 (void)fprintf(stderr, "usage: fdisk [-aiu] [-0|-1|-2|-3] [device]\n"); 302 exit(1); 303 } 304 305 void 306 print_s0(which) 307 int which; 308 { 309 int part; 310 311 print_params(); 312 printf("Information from DOS bootblock is:\n"); 313 if (which == -1) { 314 for (part = 0; part < NDOSPART; part++) 315 printf("%d: ", part), print_part(part); 316 } else 317 print_part(which); 318 } 319 320 static struct dos_partition mtpart = { 0 }; 321 322 static inline unsigned short 323 getshort(p) 324 void *p; 325 { 326 unsigned char *cp = p; 327 328 return cp[0] | (cp[1] << 8); 329 } 330 331 static inline void 332 putshort(p, l) 333 void *p; 334 unsigned short l; 335 { 336 unsigned char *cp = p; 337 338 *cp++ = l; 339 *cp++ = l >> 8; 340 } 341 342 static inline unsigned long 343 getlong(p) 344 void *p; 345 { 346 unsigned char *cp = p; 347 348 return cp[0] | (cp[1] << 8) | (cp[2] << 16) | (cp[3] << 24); 349 } 350 351 static inline void 352 putlong(p, l) 353 void *p; 354 unsigned long l; 355 { 356 unsigned char *cp = p; 357 358 *cp++ = l; 359 *cp++ = l >> 8; 360 *cp++ = l >> 16; 361 *cp++ = l >> 24; 362 } 363 364 void 365 print_part(part) 366 int part; 367 { 368 struct dos_partition *partp; 369 370 partp = &mboot.parts[part]; 371 if (!memcmp(partp, &mtpart, sizeof(struct dos_partition))) { 372 printf("<UNUSED>\n"); 373 return; 374 } 375 printf("sysid %d (%s)\n", partp->dp_typ, get_type(partp->dp_typ)); 376 printf(" start %d, size %d (%d MB), flag %x\n", 377 getlong(&partp->dp_start), getlong(&partp->dp_size), 378 getlong(&partp->dp_size) * 512 / (1024 * 1024), partp->dp_flag); 379 printf("\tbeg: cylinder %4d, head %3d, sector %2d\n", 380 DPCYL(partp->dp_scyl, partp->dp_ssect), 381 partp->dp_shd, DPSECT(partp->dp_ssect)); 382 printf("\tend: cylinder %4d, head %3d, sector %2d\n", 383 DPCYL(partp->dp_ecyl, partp->dp_esect), 384 partp->dp_ehd, DPSECT(partp->dp_esect)); 385 } 386 387 void 388 init_sector0(start) 389 int start; 390 { 391 struct dos_partition *partp; 392 393 memcpy(mboot.bootinst, bootcode, sizeof(bootcode)); 394 putshort(&mboot.signature, BOOT_MAGIC); 395 396 partp = &mboot.parts[3]; 397 partp->dp_typ = DOSPTYP_386BSD; 398 partp->dp_flag = ACTIVE; 399 putlong(&partp->dp_start, start); 400 putlong(&partp->dp_size, disksectors - start); 401 402 dos(getlong(&partp->dp_start), 403 &partp->dp_scyl, &partp->dp_shd, &partp->dp_ssect); 404 dos(getlong(&partp->dp_start) + getlong(&partp->dp_size) - 1, 405 &partp->dp_ecyl, &partp->dp_ehd, &partp->dp_esect); 406 } 407 408 /* Prerequisite: the disklabel parameters and master boot record must 409 * have been read (i.e. dos_* and mboot are meaningful). 410 * Specification: modifies dos_cylinders, dos_heads, dos_sectors, and 411 * dos_cylindersectors to be consistent with what the 412 * partition table is using, if we can find a geometry 413 * which is consistent with all partition table entries. 414 * We may get the number of cylinders slightly wrong (in 415 * the conservative direction). The idea is to be able 416 * to create a NetBSD partition on a disk we don't know 417 * the translated geometry of. 418 * This whole routine should be replaced with a kernel interface to get 419 * the BIOS geometry (which in turn requires modifications to the i386 420 * boot loader to pass in the BIOS geometry for each disk). */ 421 void 422 intuit_translated_geometry() 423 { 424 int cylinders = -1, heads = -1, sectors = -1, i, j; 425 int c1, h1, s1, c2, h2, s2; 426 long a1, a2; 427 quad_t num, denom; 428 429 /* Try to deduce the number of heads from two different mappings. */ 430 for (i = 0; i < NDOSPART * 2; i++) { 431 if (get_mapping(i, &c1, &h1, &s1, &a1) < 0) 432 continue; 433 for (j = 0; j < 8; j++) { 434 if (get_mapping(j, &c2, &h2, &s2, &a2) < 0) 435 continue; 436 num = (quad_t)h1*(a2-s2) - h2*(a1-s1); 437 denom = (quad_t)c2*(a1-s1) - c1*(a2-s2); 438 if (denom != 0 && num % denom == 0) { 439 heads = num / denom; 440 break; 441 } 442 } 443 if (heads != -1) 444 break; 445 } 446 447 if (heads == -1) 448 return; 449 450 /* Now figure out the number of sectors from a single mapping. */ 451 for (i = 0; i < NDOSPART * 2; i++) { 452 if (get_mapping(i, &c1, &h1, &s1, &a1) < 0) 453 continue; 454 num = a1 - s1; 455 denom = c1 * heads + h1; 456 if (denom != 0 && num % denom == 0) { 457 sectors = num / denom; 458 break; 459 } 460 } 461 462 if (sectors == -1) 463 return; 464 465 /* Estimate the number of cylinders. */ 466 cylinders = dos_cylinders * dos_cylindersectors / heads / sectors; 467 468 /* Now verify consistency with each of the partition table entries. 469 * Be willing to shove cylinders up a little bit to make things work, 470 * but translation mismatches are fatal. */ 471 for (i = 0; i < NDOSPART * 2; i++) { 472 if (get_mapping(i, &c1, &h1, &s1, &a1) < 0) 473 continue; 474 if (sectors * (c1 * heads + h1) + s1 != a1) 475 return; 476 if (c1 >= cylinders) 477 cylinders = c1 + 1; 478 } 479 480 /* Everything checks out. Reset the geometry to use for further 481 * calculations. */ 482 dos_cylinders = cylinders; 483 dos_heads = heads; 484 dos_sectors = sectors; 485 dos_cylindersectors = heads * sectors; 486 } 487 488 /* For the purposes of intuit_translated_geometry(), treat the partition 489 * table as a list of eight mapping between (cylinder, head, sector) 490 * triplets and absolute sectors. Get the relevant geometry triplet and 491 * absolute sectors for a given entry, or return -1 if it isn't present. 492 * Note: for simplicity, the returned sector is 0-based. */ 493 int 494 get_mapping(i, cylinder, head, sector, absolute) 495 int i, *cylinder, *head, *sector; 496 long *absolute; 497 { 498 struct dos_partition *part = &mboot.parts[i / 2]; 499 500 if (part->dp_typ == 0) 501 return -1; 502 if (i % 2 == 0) { 503 *cylinder = DPCYL(part->dp_scyl, part->dp_ssect); 504 *head = part->dp_shd; 505 *sector = DPSECT(part->dp_ssect) - 1; 506 *absolute = getlong(&part->dp_start); 507 } else { 508 *cylinder = DPCYL(part->dp_ecyl, part->dp_esect); 509 *head = part->dp_ehd; 510 *sector = DPSECT(part->dp_esect) - 1; 511 *absolute = getlong(&part->dp_start) 512 + getlong(&part->dp_size) - 1; 513 } 514 return 0; 515 } 516 517 void 518 change_part(part) 519 int part; 520 { 521 struct dos_partition *partp; 522 523 partp = &mboot.parts[part]; 524 525 printf("The data for partition %d is:\n", part); 526 print_part(part); 527 528 if (!u_flag || !yesno("Do you want to change it?")) 529 return; 530 531 if (i_flag) { 532 memset(partp, 0, sizeof(*partp)); 533 if (part == 3) { 534 init_sector0(1); 535 printf("\nThe static data for the DOS partition 3 has been reinitialized to:\n"); 536 print_part(part); 537 } 538 } 539 540 do { 541 { 542 int sysid, start, size; 543 544 sysid = partp->dp_typ, 545 start = getlong(&partp->dp_start), 546 size = getlong(&partp->dp_size); 547 decimal("sysid", &sysid); 548 decimal("start", &start); 549 decimal("size", &size); 550 partp->dp_typ = sysid; 551 putlong(&partp->dp_start, start); 552 putlong(&partp->dp_size, size); 553 } 554 555 if (yesno("Explicitly specify beg/end address?")) { 556 int tsector, tcylinder, thead; 557 558 tcylinder = DPCYL(partp->dp_scyl, partp->dp_ssect); 559 thead = partp->dp_shd; 560 tsector = DPSECT(partp->dp_ssect); 561 decimal("beginning cylinder", &tcylinder); 562 decimal("beginning head", &thead); 563 decimal("beginning sector", &tsector); 564 partp->dp_scyl = DOSCYL(tcylinder); 565 partp->dp_shd = thead; 566 partp->dp_ssect = DOSSECT(tsector, tcylinder); 567 568 tcylinder = DPCYL(partp->dp_ecyl, partp->dp_esect); 569 thead = partp->dp_ehd; 570 tsector = DPSECT(partp->dp_esect); 571 decimal("ending cylinder", &tcylinder); 572 decimal("ending head", &thead); 573 decimal("ending sector", &tsector); 574 partp->dp_ecyl = DOSCYL(tcylinder); 575 partp->dp_ehd = thead; 576 partp->dp_esect = DOSSECT(tsector, tcylinder); 577 } else { 578 dos(getlong(&partp->dp_start), 579 &partp->dp_scyl, &partp->dp_shd, &partp->dp_ssect); 580 dos(getlong(&partp->dp_start) 581 + getlong(&partp->dp_size) - 1, 582 &partp->dp_ecyl, &partp->dp_ehd, &partp->dp_esect); 583 } 584 585 print_part(part); 586 } while (!yesno("Is this entry okay?")); 587 } 588 589 void 590 print_params() 591 { 592 593 printf("parameters extracted from in-core disklabel are:\n"); 594 printf("cylinders=%d heads=%d sectors/track=%d (%d sectors/cylinder)\n\n", 595 cylinders, heads, sectors, cylindersectors); 596 if (dos_sectors > 63 || dos_cylinders > 1023 || dos_heads > 255) 597 printf("Figures below won't work with BIOS for partitions not in cylinder 1\n"); 598 printf("parameters to be used for BIOS calculations are:\n"); 599 printf("cylinders=%d heads=%d sectors/track=%d (%d sectors/cylinder)\n\n", 600 dos_cylinders, dos_heads, dos_sectors, dos_cylindersectors); 601 } 602 603 void 604 change_active(which) 605 int which; 606 { 607 struct dos_partition *partp; 608 int part; 609 int active = 3; 610 611 partp = &mboot.parts[0]; 612 613 if (a_flag && which != -1) 614 active = which; 615 else { 616 for (part = 0; part < NDOSPART; part++) 617 if (partp[part].dp_flag & ACTIVE) 618 active = part; 619 } 620 if (yesno("Do you want to change the active partition?")) { 621 do { 622 decimal("active partition", &active); 623 } while (!yesno("Are you happy with this choice?")); 624 } 625 for (part = 0; part < NDOSPART; part++) 626 partp[part].dp_flag &= ~ACTIVE; 627 partp[active].dp_flag |= ACTIVE; 628 } 629 630 void 631 get_params_to_use() 632 { 633 634 print_params(); 635 if (yesno("Do you want to change our idea of what BIOS thinks?")) { 636 do { 637 decimal("BIOS's idea of #cylinders", &dos_cylinders); 638 decimal("BIOS's idea of #heads", &dos_heads); 639 decimal("BIOS's idea of #sectors", &dos_sectors); 640 dos_cylindersectors = dos_heads * dos_sectors; 641 print_params(); 642 } while (!yesno("Are you happy with this choice?")); 643 } 644 } 645 646 /***********************************************\ 647 * Change real numbers into strange dos numbers * 648 \***********************************************/ 649 void 650 dos(sector, cylinderp, headp, sectorp) 651 int sector; 652 unsigned char *cylinderp, *headp, *sectorp; 653 { 654 int cylinder, head; 655 656 cylinder = sector / dos_cylindersectors; 657 sector -= cylinder * dos_cylindersectors; 658 659 head = sector / dos_sectors; 660 sector -= head * dos_sectors; 661 662 *cylinderp = DOSCYL(cylinder); 663 *headp = head; 664 *sectorp = DOSSECT(sector + 1, cylinder); 665 } 666 667 int fd; 668 669 int 670 open_disk(u_flag) 671 int u_flag; 672 { 673 struct stat st; 674 675 if ((fd = open(disk, u_flag ? O_RDWR : O_RDONLY)) == -1) { 676 warn("%s", disk); 677 return (-1); 678 } 679 if (fstat(fd, &st) == -1) { 680 close(fd); 681 warn("%s", disk); 682 return (-1); 683 } 684 if (!S_ISCHR(st.st_mode) && !S_ISREG(st.st_mode)) { 685 close(fd); 686 warnx("%s is not a character device or regular file", disk); 687 return (-1); 688 } 689 if (get_params() == -1) { 690 close(fd); 691 return (-1); 692 } 693 return (0); 694 } 695 696 int 697 read_disk(sector, buf) 698 int sector; 699 void *buf; 700 { 701 702 if (lseek(fd, (off_t)(sector * 512), 0) == -1) 703 return (-1); 704 return (read(fd, buf, 512)); 705 } 706 707 int 708 write_disk(sector, buf) 709 int sector; 710 void *buf; 711 { 712 713 if (lseek(fd, (off_t)(sector * 512), 0) == -1) 714 return (-1); 715 return (write(fd, buf, 512)); 716 } 717 718 int 719 get_params() 720 { 721 722 if (ioctl(fd, DIOCGDINFO, &disklabel) == -1) { 723 warn("DIOCGDINFO"); 724 return (-1); 725 } 726 727 dos_cylinders = cylinders = disklabel.d_ncylinders; 728 dos_heads = heads = disklabel.d_ntracks; 729 dos_sectors = sectors = disklabel.d_nsectors; 730 dos_cylindersectors = cylindersectors = heads * sectors; 731 disksectors = cylinders * heads * sectors; 732 733 return (0); 734 } 735 736 int 737 read_s0() 738 { 739 740 if (read_disk(0, mboot.bootinst) == -1) { 741 warn("can't read fdisk partition table"); 742 return (-1); 743 } 744 if (getshort(&mboot.signature) != BOOT_MAGIC) { 745 warnx("invalid fdisk partition table found"); 746 /* So should we initialize things? */ 747 return (-1); 748 } 749 return (0); 750 } 751 752 int 753 write_s0() 754 { 755 int flag; 756 757 /* 758 * write enable label sector before write (if necessary), 759 * disable after writing. 760 * needed if the disklabel protected area also protects 761 * sector 0. (e.g. empty disk) 762 */ 763 flag = 1; 764 if (ioctl(fd, DIOCWLABEL, &flag) < 0) 765 warn("DIOCWLABEL"); 766 if (write_disk(0, mboot.bootinst) == -1) { 767 warn("can't write fdisk partition table"); 768 return -1; 769 } 770 flag = 0; 771 if (ioctl(fd, DIOCWLABEL, &flag) < 0) 772 warn("DIOCWLABEL"); 773 } 774 775 int 776 yesno(str) 777 char *str; 778 { 779 int ch, first; 780 781 printf("%s [n] ", str); 782 783 first = ch = getchar(); 784 while (ch != '\n' && ch != EOF) 785 ch = getchar(); 786 return (first == 'y' || first == 'Y'); 787 } 788 789 void 790 decimal(str, num) 791 char *str; 792 int *num; 793 { 794 int acc = 0; 795 char *cp; 796 797 for (;; printf("%s is not a valid decimal number.\n", lbuf)) { 798 printf("Supply a decimal value for \"%s\" [%d] ", str, *num); 799 800 fgets(lbuf, LBUF, stdin); 801 lbuf[strlen(lbuf)-1] = '\0'; 802 cp = lbuf; 803 804 cp += strspn(cp, " \t"); 805 if (*cp == '\0') 806 return; 807 808 if (!isdigit(*cp)) 809 continue; 810 acc = strtol(lbuf, &cp, 10); 811 812 cp += strspn(cp, " \t"); 813 if (*cp != '\0') 814 continue; 815 816 *num = acc; 817 return; 818 } 819 820 } 821 822 int 823 type_match(key, item) 824 const void *key, *item; 825 { 826 const int *typep = key; 827 const struct part_type *ptr = item; 828 829 if (*typep < ptr->type) 830 return (-1); 831 if (*typep > ptr->type) 832 return (1); 833 return (0); 834 } 835 836 char * 837 get_type(type) 838 int type; 839 { 840 struct part_type *ptr; 841 842 ptr = bsearch(&type, part_types, 843 sizeof(part_types) / sizeof(struct part_type), 844 sizeof(struct part_type), type_match); 845 if (ptr == 0) 846 return ("unknown"); 847 else 848 return (ptr->name); 849 } 850