1 /* $NetBSD: fdisk.c,v 1.12 1997/03/29 20:46:17 thorpej 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.12 1997/03/29 20:46:17 thorpej 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"}, 128 {0x05, "Extended DOS"}, 129 {0x06, "Primary 'big' DOS (> 32MB)"}, 130 {0x07, "OS/2 HPFS, QNX or Advanced UNIX"}, 131 {0x08, "AIX filesystem"}, 132 {0x09, "AIX boot partition or Coherent"}, 133 {0x0A, "OS/2 Boot Manager or OPUS"}, 134 {0x10, "OPUS"}, 135 {0x40, "VENIX 286"}, 136 {0x50, "DM"}, 137 {0x51, "DM"}, 138 {0x52, "CP/M or Microport SysV/AT"}, 139 {0x56, "GB"}, 140 {0x61, "Speed"}, 141 {0x63, "ISC UNIX, other System V/386, GNU HURD or Mach"}, 142 {0x64, "Novell Netware 2.xx"}, 143 {0x65, "Novell Netware 3.xx"}, 144 {0x75, "PCIX"}, 145 {0x80, "Minix 1.1 ... 1.4a"}, 146 {0x81, "Minix 1.4b ... 1.5.10"}, 147 {0x82, "Linux swap"}, 148 {0x83, "Linux filesystem"}, 149 {0x93, "Amoeba filesystem"}, 150 {0x94, "Amoeba bad block table"}, 151 {0xA5, "NetBSD or 386BSD"}, 152 {0xB7, "BSDI BSD/386 filesystem"}, 153 {0xB8, "BSDI BSD/386 swap"}, 154 {0xDB, "Concurrent CPM or C.DOS or CTOS"}, 155 {0xE1, "Speed"}, 156 {0xE3, "Speed"}, 157 {0xE4, "Speed"}, 158 {0xF1, "Speed"}, 159 {0xF2, "DOS 3.3+ Secondary"}, 160 {0xF4, "Speed"}, 161 {0xFF, "BBT (Bad Blocks Table)"}, 162 }; 163 164 void usage __P((void)); 165 void print_s0 __P((int)); 166 void print_part __P((int)); 167 void init_sector0 __P((int)); 168 void intuit_translated_geometry __P((void)); 169 int try_heads __P((quad_t, quad_t, quad_t, quad_t, quad_t, quad_t, quad_t, 170 quad_t)); 171 int try_sectors __P((quad_t, quad_t, quad_t, quad_t, quad_t)); 172 void change_part __P((int)); 173 void print_params __P((void)); 174 void change_active __P((int)); 175 void get_params_to_use __P((void)); 176 void dos __P((int, unsigned char *, unsigned char *, unsigned char *)); 177 int open_disk __P((int)); 178 int read_disk __P((int, void *)); 179 int write_disk __P((int, void *)); 180 int get_params __P((void)); 181 int read_s0 __P((void)); 182 int write_s0 __P((void)); 183 int yesno __P((char *)); 184 void decimal __P((char *, int *)); 185 int type_match __P((const void *, const void *)); 186 char *get_type __P((int)); 187 188 int 189 main(argc, argv) 190 int argc; 191 char *argv[]; 192 { 193 int ch; 194 int part; 195 196 a_flag = i_flag = u_flag = 0; 197 while ((ch = getopt(argc, argv, "0123aiu")) != -1) 198 switch (ch) { 199 case '0': 200 partition = 0; 201 break; 202 case '1': 203 partition = 1; 204 break; 205 case '2': 206 partition = 2; 207 break; 208 case '3': 209 partition = 3; 210 break; 211 case 'a': 212 a_flag = 1; 213 break; 214 case 'i': 215 i_flag = 1; 216 case 'u': 217 u_flag = 1; 218 break; 219 default: 220 usage(); 221 } 222 argc -= optind; 223 argv += optind; 224 225 if (argc > 0) 226 disk = argv[0]; 227 228 if (open_disk(a_flag || i_flag || u_flag) < 0) 229 exit(1); 230 231 if (read_s0()) 232 init_sector0(1); 233 234 intuit_translated_geometry(); 235 236 printf("******* Working on device %s *******\n", disk); 237 if (u_flag) 238 get_params_to_use(); 239 else 240 print_params(); 241 242 printf("Warning: BIOS sector numbering starts with sector 1\n"); 243 printf("Information from DOS bootblock is:\n"); 244 if (partition == -1) { 245 for (part = 0; part < NDOSPART; part++) 246 change_part(part); 247 } else 248 change_part(partition); 249 250 if (u_flag || a_flag) 251 change_active(partition); 252 253 if (u_flag || a_flag) { 254 printf("\nWe haven't changed the partition table yet. "); 255 printf("This is your last chance.\n"); 256 print_s0(-1); 257 if (yesno("Should we write new partition table?")) 258 write_s0(); 259 } 260 261 exit(0); 262 } 263 264 void 265 usage() 266 { 267 268 (void)fprintf(stderr, "usage: fdisk [-aiu] [-0|-1|-2|-3] [device]\n"); 269 exit(1); 270 } 271 272 void 273 print_s0(which) 274 int which; 275 { 276 int part; 277 278 print_params(); 279 printf("Information from DOS bootblock is:\n"); 280 if (which == -1) { 281 for (part = 0; part < NDOSPART; part++) 282 printf("%d: ", part), print_part(part); 283 } else 284 print_part(which); 285 } 286 287 static struct dos_partition mtpart = { 0 }; 288 289 static inline unsigned short 290 getshort(p) 291 void *p; 292 { 293 unsigned char *cp = p; 294 295 return cp[0] | (cp[1] << 8); 296 } 297 298 static inline void 299 putshort(p, l) 300 void *p; 301 unsigned short l; 302 { 303 unsigned char *cp = p; 304 305 *cp++ = l; 306 *cp++ = l >> 8; 307 } 308 309 static inline unsigned long 310 getlong(p) 311 void *p; 312 { 313 unsigned char *cp = p; 314 315 return cp[0] | (cp[1] << 8) | (cp[2] << 16) | (cp[3] << 24); 316 } 317 318 static inline void 319 putlong(p, l) 320 void *p; 321 unsigned long l; 322 { 323 unsigned char *cp = p; 324 325 *cp++ = l; 326 *cp++ = l >> 8; 327 *cp++ = l >> 16; 328 *cp++ = l >> 24; 329 } 330 331 void 332 print_part(part) 333 int part; 334 { 335 struct dos_partition *partp; 336 337 partp = &mboot.parts[part]; 338 if (!memcmp(partp, &mtpart, sizeof(struct dos_partition))) { 339 printf("<UNUSED>\n"); 340 return; 341 } 342 printf("sysid %d (%s)\n", partp->dp_typ, get_type(partp->dp_typ)); 343 printf(" start %d, size %d (%d MB), flag %x\n", 344 getlong(&partp->dp_start), getlong(&partp->dp_size), 345 getlong(&partp->dp_size) * 512 / (1024 * 1024), partp->dp_flag); 346 printf("\tbeg: cylinder %4d, head %3d, sector %2d\n", 347 DPCYL(partp->dp_scyl, partp->dp_ssect), 348 partp->dp_shd, DPSECT(partp->dp_ssect)); 349 printf("\tend: cylinder %4d, head %3d, sector %2d\n", 350 DPCYL(partp->dp_ecyl, partp->dp_esect), 351 partp->dp_ehd, DPSECT(partp->dp_esect)); 352 } 353 354 void 355 init_sector0(start) 356 int start; 357 { 358 struct dos_partition *partp; 359 360 memcpy(mboot.bootinst, bootcode, sizeof(bootcode)); 361 putshort(&mboot.signature, BOOT_MAGIC); 362 363 partp = &mboot.parts[3]; 364 partp->dp_typ = DOSPTYP_386BSD; 365 partp->dp_flag = ACTIVE; 366 putlong(&partp->dp_start, start); 367 putlong(&partp->dp_size, disksectors - start); 368 369 dos(getlong(&partp->dp_start), 370 &partp->dp_scyl, &partp->dp_shd, &partp->dp_ssect); 371 dos(getlong(&partp->dp_start) + getlong(&partp->dp_size) - 1, 372 &partp->dp_ecyl, &partp->dp_ehd, &partp->dp_esect); 373 } 374 375 /* Prerequisite: the disklabel parameters and master boot record must 376 * have been read (i.e. dos_* and mboot are meaningful). 377 * Specification: modifies dos_cylinders, dos_heads, dos_sectors, and 378 * dos_cylindersectors to be consistent with what the 379 * partition table is using, if we can find a geometry 380 * which is consistent with all partition table entries. 381 * We may get the number of cylinders slightly wrong (in 382 * the conservative direction). The idea is to be able 383 * to create a NetBSD partition on a disk we don't know 384 * the translated geometry of. 385 * This whole routine should be replaced with a kernel interface to get 386 * the BIOS geometry (which in turn requires modifications to the i386 387 * boot loader to pass in the BIOS geometry for each disk). */ 388 void 389 intuit_translated_geometry() 390 { 391 int cylinders = -1, heads = -1, sectors = -1, i, j; 392 int c1, h1, s1, c2, h2, s2; 393 long a1, a2; 394 quad_t num, denom; 395 396 /* Try to deduce the number of heads from two different mappings. */ 397 for (i = 0; i < NDOSPART * 2; i++) { 398 if (get_mapping(i, &c1, &h1, &s1, &a1) < 0) 399 continue; 400 for (j = 0; j < 8; j++) { 401 if (get_mapping(j, &c2, &h2, &s2, &a2) < 0) 402 continue; 403 num = (quad_t)h1*(a2-s2) - h2*(a1-s1); 404 denom = (quad_t)c2*(a1-s1) - c1*(a2-s2); 405 if (denom != 0 && num % denom == 0) { 406 heads = num / denom; 407 break; 408 } 409 } 410 if (heads != -1) 411 break; 412 } 413 414 if (heads == -1) 415 return; 416 417 /* Now figure out the number of sectors from a single mapping. */ 418 for (i = 0; i < NDOSPART * 2; i++) { 419 if (get_mapping(i, &c1, &h1, &s1, &a1) < 0) 420 continue; 421 num = a1 - s1; 422 denom = c1 * heads + h1; 423 if (denom != 0 && num % denom == 0) { 424 sectors = num / denom; 425 break; 426 } 427 } 428 429 if (sectors == -1) 430 return; 431 432 /* Estimate the number of cylinders. */ 433 cylinders = dos_cylinders * dos_cylindersectors / heads / sectors; 434 435 /* Now verify consistency with each of the partition table entries. 436 * Be willing to shove cylinders up a little bit to make things work, 437 * but translation mismatches are fatal. */ 438 for (i = 0; i < NDOSPART * 2; i++) { 439 if (get_mapping(i, &c1, &h1, &s1, &a1) < 0) 440 continue; 441 if (sectors * (c1 * heads + h1) + s1 != a1) 442 return; 443 if (c1 >= cylinders) 444 cylinders = c1 + 1; 445 } 446 447 /* Everything checks out. Reset the geometry to use for further 448 * calculations. */ 449 dos_cylinders = cylinders; 450 dos_heads = heads; 451 dos_sectors = sectors; 452 dos_cylindersectors = heads * sectors; 453 } 454 455 /* For the purposes of intuit_translated_geometry(), treat the partition 456 * table as a list of eight mapping between (cylinder, head, sector) 457 * triplets and absolute sectors. Get the relevant geometry triplet and 458 * absolute sectors for a given entry, or return -1 if it isn't present. 459 * Note: for simplicity, the returned sector is 0-based. */ 460 int 461 get_mapping(i, cylinder, head, sector, absolute) 462 int i, *cylinder, *head, *sector; 463 long *absolute; 464 { 465 struct dos_partition *part = &mboot.parts[i / 2]; 466 467 if (part->dp_typ == 0) 468 return -1; 469 if (i % 2 == 0) { 470 *cylinder = DPCYL(part->dp_scyl, part->dp_ssect); 471 *head = part->dp_shd; 472 *sector = DPSECT(part->dp_ssect) - 1; 473 *absolute = getlong(&part->dp_start); 474 } else { 475 *cylinder = DPCYL(part->dp_ecyl, part->dp_esect); 476 *head = part->dp_ehd; 477 *sector = DPSECT(part->dp_esect) - 1; 478 *absolute = getlong(&part->dp_start) 479 + getlong(&part->dp_size) - 1; 480 } 481 return 0; 482 } 483 484 void 485 change_part(part) 486 int part; 487 { 488 struct dos_partition *partp; 489 490 partp = &mboot.parts[part]; 491 492 printf("The data for partition %d is:\n", part); 493 print_part(part); 494 495 if (!u_flag || !yesno("Do you want to change it?")) 496 return; 497 498 if (i_flag) { 499 memset(partp, 0, sizeof(*partp)); 500 if (part == 3) { 501 init_sector0(1); 502 printf("\nThe static data for the DOS partition 3 has been reinitialized to:\n"); 503 print_part(part); 504 } 505 } 506 507 do { 508 { 509 int sysid, start, size; 510 511 sysid = partp->dp_typ, 512 start = getlong(&partp->dp_start), 513 size = getlong(&partp->dp_size); 514 decimal("sysid", &sysid); 515 decimal("start", &start); 516 decimal("size", &size); 517 partp->dp_typ = sysid; 518 putlong(&partp->dp_start, start); 519 putlong(&partp->dp_size, size); 520 } 521 522 if (yesno("Explicitly specify beg/end address?")) { 523 int tsector, tcylinder, thead; 524 525 tcylinder = DPCYL(partp->dp_scyl, partp->dp_ssect); 526 thead = partp->dp_shd; 527 tsector = DPSECT(partp->dp_ssect); 528 decimal("beginning cylinder", &tcylinder); 529 decimal("beginning head", &thead); 530 decimal("beginning sector", &tsector); 531 partp->dp_scyl = DOSCYL(tcylinder); 532 partp->dp_shd = thead; 533 partp->dp_ssect = DOSSECT(tsector, tcylinder); 534 535 tcylinder = DPCYL(partp->dp_ecyl, partp->dp_esect); 536 thead = partp->dp_ehd; 537 tsector = DPSECT(partp->dp_esect); 538 decimal("ending cylinder", &tcylinder); 539 decimal("ending head", &thead); 540 decimal("ending sector", &tsector); 541 partp->dp_ecyl = DOSCYL(tcylinder); 542 partp->dp_ehd = thead; 543 partp->dp_esect = DOSSECT(tsector, tcylinder); 544 } else { 545 dos(getlong(&partp->dp_start), 546 &partp->dp_scyl, &partp->dp_shd, &partp->dp_ssect); 547 dos(getlong(&partp->dp_start) 548 + getlong(&partp->dp_size) - 1, 549 &partp->dp_ecyl, &partp->dp_ehd, &partp->dp_esect); 550 } 551 552 print_part(part); 553 } while (!yesno("Is this entry okay?")); 554 } 555 556 void 557 print_params() 558 { 559 560 printf("parameters extracted from in-core disklabel are:\n"); 561 printf("cylinders=%d heads=%d sectors/track=%d (%d sectors/cylinder)\n\n", 562 cylinders, heads, sectors, cylindersectors); 563 if (dos_sectors > 63 || dos_cylinders > 1023 || dos_heads > 255) 564 printf("Figures below won't work with BIOS for partitions not in cylinder 1\n"); 565 printf("parameters to be used for BIOS calculations are:\n"); 566 printf("cylinders=%d heads=%d sectors/track=%d (%d sectors/cylinder)\n\n", 567 dos_cylinders, dos_heads, dos_sectors, dos_cylindersectors); 568 } 569 570 void 571 change_active(which) 572 int which; 573 { 574 struct dos_partition *partp; 575 int part; 576 int active = 3; 577 578 partp = &mboot.parts[0]; 579 580 if (a_flag && which != -1) 581 active = which; 582 else { 583 for (part = 0; part < NDOSPART; part++) 584 if (partp[part].dp_flag & ACTIVE) 585 active = part; 586 } 587 if (yesno("Do you want to change the active partition?")) { 588 do { 589 decimal("active partition", &active); 590 } while (!yesno("Are you happy with this choice?")); 591 } 592 for (part = 0; part < NDOSPART; part++) 593 partp[part].dp_flag &= ~ACTIVE; 594 partp[active].dp_flag |= ACTIVE; 595 } 596 597 void 598 get_params_to_use() 599 { 600 601 print_params(); 602 if (yesno("Do you want to change our idea of what BIOS thinks?")) { 603 do { 604 decimal("BIOS's idea of #cylinders", &dos_cylinders); 605 decimal("BIOS's idea of #heads", &dos_heads); 606 decimal("BIOS's idea of #sectors", &dos_sectors); 607 dos_cylindersectors = dos_heads * dos_sectors; 608 print_params(); 609 } while (!yesno("Are you happy with this choice?")); 610 } 611 } 612 613 /***********************************************\ 614 * Change real numbers into strange dos numbers * 615 \***********************************************/ 616 void 617 dos(sector, cylinderp, headp, sectorp) 618 int sector; 619 unsigned char *cylinderp, *headp, *sectorp; 620 { 621 int cylinder, head; 622 623 cylinder = sector / dos_cylindersectors; 624 sector -= cylinder * dos_cylindersectors; 625 626 head = sector / dos_sectors; 627 sector -= head * dos_sectors; 628 629 *cylinderp = DOSCYL(cylinder); 630 *headp = head; 631 *sectorp = DOSSECT(sector + 1, cylinder); 632 } 633 634 int fd; 635 636 int 637 open_disk(u_flag) 638 int u_flag; 639 { 640 struct stat st; 641 642 if ((fd = open(disk, u_flag ? O_RDWR : O_RDONLY)) == -1) { 643 warn("%s", disk); 644 return (-1); 645 } 646 if (fstat(fd, &st) == -1) { 647 close(fd); 648 warn("%s", disk); 649 return (-1); 650 } 651 if (!S_ISCHR(st.st_mode) && !S_ISREG(st.st_mode)) { 652 close(fd); 653 warnx("%s is not a character device or regular file", disk); 654 return (-1); 655 } 656 if (get_params() == -1) { 657 close(fd); 658 return (-1); 659 } 660 return (0); 661 } 662 663 int 664 read_disk(sector, buf) 665 int sector; 666 void *buf; 667 { 668 669 if (lseek(fd, (off_t)(sector * 512), 0) == -1) 670 return (-1); 671 return (read(fd, buf, 512)); 672 } 673 674 int 675 write_disk(sector, buf) 676 int sector; 677 void *buf; 678 { 679 680 if (lseek(fd, (off_t)(sector * 512), 0) == -1) 681 return (-1); 682 return (write(fd, buf, 512)); 683 } 684 685 int 686 get_params() 687 { 688 689 if (ioctl(fd, DIOCGDINFO, &disklabel) == -1) { 690 warn("DIOCGDINFO"); 691 return (-1); 692 } 693 694 dos_cylinders = cylinders = disklabel.d_ncylinders; 695 dos_heads = heads = disklabel.d_ntracks; 696 dos_sectors = sectors = disklabel.d_nsectors; 697 dos_cylindersectors = cylindersectors = heads * sectors; 698 disksectors = cylinders * heads * sectors; 699 700 return (0); 701 } 702 703 int 704 read_s0() 705 { 706 707 if (read_disk(0, mboot.bootinst) == -1) { 708 warn("can't read fdisk partition table"); 709 return (-1); 710 } 711 if (getshort(&mboot.signature) != BOOT_MAGIC) { 712 warnx("invalid fdisk partition table found"); 713 /* So should we initialize things? */ 714 return (-1); 715 } 716 return (0); 717 } 718 719 int 720 write_s0() 721 { 722 int flag; 723 724 /* 725 * write enable label sector before write (if necessary), 726 * disable after writing. 727 * needed if the disklabel protected area also protects 728 * sector 0. (e.g. empty disk) 729 */ 730 flag = 1; 731 if (ioctl(fd, DIOCWLABEL, &flag) < 0) 732 warn("DIOCWLABEL"); 733 if (write_disk(0, mboot.bootinst) == -1) { 734 warn("can't write fdisk partition table"); 735 return -1; 736 } 737 flag = 0; 738 if (ioctl(fd, DIOCWLABEL, &flag) < 0) 739 warn("DIOCWLABEL"); 740 } 741 742 int 743 yesno(str) 744 char *str; 745 { 746 int ch, first; 747 748 printf("%s [n] ", str); 749 750 first = ch = getchar(); 751 while (ch != '\n' && ch != EOF) 752 ch = getchar(); 753 return (first == 'y' || first == 'Y'); 754 } 755 756 void 757 decimal(str, num) 758 char *str; 759 int *num; 760 { 761 int acc = 0; 762 char *cp; 763 764 for (;; printf("%s is not a valid decimal number.\n", lbuf)) { 765 printf("Supply a decimal value for \"%s\" [%d] ", str, *num); 766 767 fgets(lbuf, LBUF, stdin); 768 lbuf[strlen(lbuf)-1] = '\0'; 769 cp = lbuf; 770 771 cp += strspn(cp, " \t"); 772 if (*cp == '\0') 773 return; 774 775 if (!isdigit(*cp)) 776 continue; 777 acc = strtol(lbuf, &cp, 10); 778 779 cp += strspn(cp, " \t"); 780 if (*cp != '\0') 781 continue; 782 783 *num = acc; 784 return; 785 } 786 787 } 788 789 int 790 type_match(key, item) 791 const void *key, *item; 792 { 793 const int *typep = key; 794 const struct part_type *ptr = item; 795 796 if (*typep < ptr->type) 797 return (-1); 798 if (*typep > ptr->type) 799 return (1); 800 return (0); 801 } 802 803 char * 804 get_type(type) 805 int type; 806 { 807 struct part_type *ptr; 808 809 ptr = bsearch(&type, part_types, 810 sizeof(part_types) / sizeof(struct part_type), 811 sizeof(struct part_type), type_match); 812 if (ptr == 0) 813 return ("unknown"); 814 else 815 return (ptr->name); 816 } 817