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