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