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