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