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