fdisk.c revision 1.29 1 /* $NetBSD: fdisk.c,v 1.29 1998/10/02 17:23:22 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.29 1998/10/02 17:23:22 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 if (csysid == 0 && cstart == 0 && csize == 0)
671 memset(partp, 0, sizeof *partp);
672 else {
673 partp->dp_typ = csysid;
674 #if 0
675 checkcyl(cstart / dos_cylindersectors);
676 #endif
677 putlong(&partp->dp_start, cstart);
678 putlong(&partp->dp_size, csize);
679 dos(getlong(&partp->dp_start),
680 &partp->dp_scyl, &partp->dp_shd, &partp->dp_ssect);
681 dos(getlong(&partp->dp_start)
682 + getlong(&partp->dp_size) - 1,
683 &partp->dp_ecyl, &partp->dp_ehd, &partp->dp_esect);
684 }
685 if (f_flag)
686 return;
687 }
688
689 printf("The data for partition %d is:\n", part);
690 print_part(part);
691 if (!u_flag || !yesno("Do you want to change it?"))
692 return;
693
694 do {
695 {
696 int sysid, start, size;
697
698 sysid = partp->dp_typ,
699 start = getlong(&partp->dp_start),
700 size = getlong(&partp->dp_size);
701 decimal("sysid", &sysid);
702 decimal("start", &start);
703 decimal("size", &size);
704 partp->dp_typ = sysid;
705 putlong(&partp->dp_start, start);
706 putlong(&partp->dp_size, size);
707 }
708
709 if (yesno("Explicitly specify beg/end address?")) {
710 int tsector, tcylinder, thead;
711
712 tcylinder = DPCYL(partp->dp_scyl, partp->dp_ssect);
713 thead = partp->dp_shd;
714 tsector = DPSECT(partp->dp_ssect);
715 decimal("beginning cylinder", &tcylinder);
716 #if 0
717 checkcyl(tcylinder);
718 #endif
719 decimal("beginning head", &thead);
720 decimal("beginning sector", &tsector);
721 partp->dp_scyl = DOSCYL(tcylinder);
722 partp->dp_shd = thead;
723 partp->dp_ssect = DOSSECT(tsector, tcylinder);
724
725 tcylinder = DPCYL(partp->dp_ecyl, partp->dp_esect);
726 thead = partp->dp_ehd;
727 tsector = DPSECT(partp->dp_esect);
728 decimal("ending cylinder", &tcylinder);
729 decimal("ending head", &thead);
730 decimal("ending sector", &tsector);
731 partp->dp_ecyl = DOSCYL(tcylinder);
732 partp->dp_ehd = thead;
733 partp->dp_esect = DOSSECT(tsector, tcylinder);
734 } else {
735
736 if (partp->dp_typ == 0
737 && getlong(&partp->dp_start) == 0
738 && getlong(&partp->dp_size) == 0)
739 memset(partp, 0, sizeof *partp);
740 else {
741 #if 0
742 checkcyl(getlong(&partp->dp_start)
743 / dos_cylindersectors);
744 #endif
745 dos(getlong(&partp->dp_start), &partp->dp_scyl,
746 &partp->dp_shd, &partp->dp_ssect);
747 dos(getlong(&partp->dp_start)
748 + getlong(&partp->dp_size) - 1,
749 &partp->dp_ecyl, &partp->dp_ehd,
750 &partp->dp_esect);
751 }
752 }
753
754 print_part(part);
755 } while (!yesno("Is this entry okay?"));
756 }
757
758 void
759 print_params()
760 {
761
762 if (sh_flag) {
763 printf ("DLCYL=%d\nDLHEAD=%d\nDLSEC=%d\n",
764 cylinders, heads, sectors);
765 printf ("BCYL=%d\nBHEAD=%d\nBSEC=%d\n",
766 dos_cylinders, dos_heads, dos_sectors);
767 return;
768 }
769
770 /* Not sh_flag */
771 printf("parameters extracted from in-core disklabel are:\n");
772 printf("cylinders=%d heads=%d sectors/track=%d (%d sectors/cylinder)\n\n",
773 cylinders, heads, sectors, cylindersectors);
774 if (dos_sectors > 63 || dos_heads > 255)
775 printf("Figures below won't work with BIOS for partitions not in cylinder 1\n");
776 printf("parameters to be used for BIOS calculations are:\n");
777 printf("cylinders=%d heads=%d sectors/track=%d (%d sectors/cylinder)\n\n",
778 dos_cylinders, dos_heads, dos_sectors, dos_cylindersectors);
779 }
780
781 void
782 change_active(which)
783 int which;
784 {
785 struct dos_partition *partp;
786 int part;
787 int active = 4;
788
789 partp = &mboot.parts[0];
790
791 if (a_flag && which != -1)
792 active = which;
793 else {
794 for (part = 0; part < NDOSPART; part++)
795 if (partp[part].dp_flag & ACTIVE)
796 active = part;
797 }
798 if (!f_flag) {
799 if (yesno("Do you want to change the active partition?")) {
800 printf ("Choosing 4 will make no partition active.\n");
801 do {
802 decimal("active partition", &active);
803 } while (!yesno("Are you happy with this choice?"));
804 } else
805 return;
806 } else
807 if (active != 4)
808 printf ("Making partition %d active.\n", active);
809
810 for (part = 0; part < NDOSPART; part++)
811 partp[part].dp_flag &= ~ACTIVE;
812 if (active < 4)
813 partp[active].dp_flag |= ACTIVE;
814 }
815
816 void
817 get_params_to_use()
818 {
819 if (b_flag) {
820 dos_cylinders = b_cyl;
821 dos_heads = b_head;
822 dos_sectors = b_sec;
823 dos_cylindersectors = dos_heads * dos_sectors;
824 return;
825 }
826
827 print_params();
828 if (yesno("Do you want to change our idea of what BIOS thinks?")) {
829 do {
830 decimal("BIOS's idea of #cylinders", &dos_cylinders);
831 decimal("BIOS's idea of #heads", &dos_heads);
832 decimal("BIOS's idea of #sectors", &dos_sectors);
833 dos_cylindersectors = dos_heads * dos_sectors;
834 print_params();
835 } while (!yesno("Are you happy with this choice?"));
836 }
837 }
838
839 /***********************************************\
840 * Change real numbers into strange dos numbers *
841 \***********************************************/
842 void
843 dos(sector, cylinderp, headp, sectorp)
844 int sector;
845 unsigned char *cylinderp, *headp, *sectorp;
846 {
847 int cylinder, head;
848
849 cylinder = sector / dos_cylindersectors;
850
851 sector -= cylinder * dos_cylindersectors;
852
853 head = sector / dos_sectors;
854 sector -= head * dos_sectors;
855
856 if (cylinder >= MAXCYL)
857 cylinder = MAXCYL - 1;
858 *cylinderp = DOSCYL(cylinder);
859 *headp = head;
860 *sectorp = DOSSECT(sector + 1, cylinder);
861 }
862
863 #if 0
864 void
865 checkcyl(cyl)
866 int cyl;
867 {
868 if (cyl >= MAXCYL)
869 warnx("partition start beyond BIOS limit");
870 }
871 #endif
872
873 int fd;
874
875 int
876 open_disk(u_flag)
877 int u_flag;
878 {
879 static char namebuf[MAXPATHLEN + 1];
880 struct stat st;
881
882 fd = opendisk(disk, u_flag ? O_RDWR : O_RDONLY, namebuf,
883 sizeof(namebuf), 0);
884 if (fd < 0) {
885 warn("%s", namebuf);
886 return (-1);
887 }
888 disk = namebuf;
889 if (fstat(fd, &st) == -1) {
890 close(fd);
891 warn("%s", disk);
892 return (-1);
893 }
894 if (!S_ISCHR(st.st_mode) && !S_ISREG(st.st_mode)) {
895 close(fd);
896 warnx("%s is not a character device or regular file", disk);
897 return (-1);
898 }
899 if (get_params() == -1) {
900 close(fd);
901 return (-1);
902 }
903 return (0);
904 }
905
906 int
907 read_disk(sector, buf)
908 int sector;
909 void *buf;
910 {
911
912 if (lseek(fd, (off_t)(sector * 512), 0) == -1)
913 return (-1);
914 return (read(fd, buf, 512));
915 }
916
917 int
918 write_disk(sector, buf)
919 int sector;
920 void *buf;
921 {
922
923 if (lseek(fd, (off_t)(sector * 512), 0) == -1)
924 return (-1);
925 return (write(fd, buf, 512));
926 }
927
928 int
929 get_params()
930 {
931
932 if (ioctl(fd, DIOCGDINFO, &disklabel) == -1) {
933 warn("DIOCGDINFO");
934 return (-1);
935 }
936
937 dos_cylinders = cylinders = disklabel.d_ncylinders;
938 dos_heads = heads = disklabel.d_ntracks;
939 dos_sectors = sectors = disklabel.d_nsectors;
940 dos_cylindersectors = cylindersectors = heads * sectors;
941 disksectors = cylinders * heads * sectors;
942
943 return (0);
944 }
945
946 int
947 read_s0()
948 {
949
950 if (read_disk(0, mboot.bootinst) == -1) {
951 warn("can't read fdisk partition table");
952 return (-1);
953 }
954 if (getshort(&mboot.signature) != BOOT_MAGIC) {
955 warnx("invalid fdisk partition table found");
956 return (-1);
957 }
958 return (0);
959 }
960
961 int
962 write_s0()
963 {
964 int flag;
965
966 /*
967 * write enable label sector before write (if necessary),
968 * disable after writing.
969 * needed if the disklabel protected area also protects
970 * sector 0. (e.g. empty disk)
971 */
972 flag = 1;
973 if (ioctl(fd, DIOCWLABEL, &flag) < 0)
974 warn("DIOCWLABEL");
975 if (write_disk(0, mboot.bootinst) == -1) {
976 warn("can't write fdisk partition table");
977 return -1;
978 }
979 flag = 0;
980 if (ioctl(fd, DIOCWLABEL, &flag) < 0)
981 warn("DIOCWLABEL");
982 return 0;
983 }
984
985 int
986 yesno(str)
987 char *str;
988 {
989 int ch, first;
990
991 printf("%s [n] ", str);
992
993 first = ch = getchar();
994 while (ch != '\n' && ch != EOF)
995 ch = getchar();
996 return (first == 'y' || first == 'Y');
997 }
998
999 void
1000 decimal(str, num)
1001 char *str;
1002 int *num;
1003 {
1004 int acc = 0;
1005 char *cp;
1006
1007 for (;; printf("%s is not a valid decimal number.\n", lbuf)) {
1008 printf("Supply a decimal value for \"%s\" [%d] ", str, *num);
1009
1010 fgets(lbuf, LBUF, stdin);
1011 lbuf[strlen(lbuf)-1] = '\0';
1012 cp = lbuf;
1013
1014 cp += strspn(cp, " \t");
1015 if (*cp == '\0')
1016 return;
1017
1018 if (!isdigit(*cp))
1019 continue;
1020 acc = strtol(lbuf, &cp, 10);
1021
1022 cp += strspn(cp, " \t");
1023 if (*cp != '\0')
1024 continue;
1025
1026 *num = acc;
1027 return;
1028 }
1029
1030 }
1031
1032 int
1033 type_match(key, item)
1034 const void *key, *item;
1035 {
1036 const int *typep = key;
1037 const struct part_type *ptr = item;
1038
1039 if (*typep < ptr->type)
1040 return (-1);
1041 if (*typep > ptr->type)
1042 return (1);
1043 return (0);
1044 }
1045
1046 char *
1047 get_type(type)
1048 int type;
1049 {
1050 struct part_type *ptr;
1051
1052 ptr = bsearch(&type, part_types,
1053 sizeof(part_types) / sizeof(struct part_type),
1054 sizeof(struct part_type), type_match);
1055 if (ptr == 0)
1056 return ("unknown");
1057 return (ptr->name);
1058 }
1059