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