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