fdisk.c revision 1.22 1 /* $NetBSD: fdisk.c,v 1.22 1997/12/22 01:54:07 enami 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.22 1997/12/22 01:54:07 enami 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 printf ("DOS partition table initialized.\n");
518 }
519
520 /* Prerequisite: the disklabel parameters and master boot record must
521 * have been read (i.e. dos_* and mboot are meaningful).
522 * Specification: modifies dos_cylinders, dos_heads, dos_sectors, and
523 * dos_cylindersectors to be consistent with what the
524 * partition table is using, if we can find a geometry
525 * which is consistent with all partition table entries.
526 * We may get the number of cylinders slightly wrong (in
527 * the conservative direction). The idea is to be able
528 * to create a NetBSD partition on a disk we don't know
529 * the translated geometry of.
530 * This whole routine should be replaced with a kernel interface to get
531 * the BIOS geometry (which in turn requires modifications to the i386
532 * boot loader to pass in the BIOS geometry for each disk). */
533 void
534 intuit_translated_geometry()
535 {
536
537 int cylinders = -1, heads = -1, sectors = -1, i, j;
538 int c1, h1, s1, c2, h2, s2;
539 long a1, a2;
540 quad_t num, denom;
541
542 /* Try to deduce the number of heads from two different mappings. */
543 for (i = 0; i < NDOSPART * 2; i++) {
544 if (get_mapping(i, &c1, &h1, &s1, &a1) < 0)
545 continue;
546 for (j = 0; j < 8; j++) {
547 if (get_mapping(j, &c2, &h2, &s2, &a2) < 0)
548 continue;
549 num = (quad_t)h1*(a2-s2) - (quad_t)h2*(a1-s1);
550 denom = (quad_t)c2*(a1-s1) - (quad_t)c1*(a2-s2);
551 if (denom != 0 && num % denom == 0) {
552 heads = num / denom;
553 break;
554 }
555 }
556 if (heads != -1)
557 break;
558 }
559
560 if (heads == -1)
561 return;
562
563 /* Now figure out the number of sectors from a single mapping. */
564 for (i = 0; i < NDOSPART * 2; i++) {
565 if (get_mapping(i, &c1, &h1, &s1, &a1) < 0)
566 continue;
567 num = a1 - s1;
568 denom = c1 * heads + h1;
569 if (denom != 0 && num % denom == 0) {
570 sectors = num / denom;
571 break;
572 }
573 }
574
575 if (sectors == -1)
576 return;
577
578 /* Estimate the number of cylinders. */
579 cylinders = dos_cylinders * dos_cylindersectors / heads / sectors;
580
581 /* Now verify consistency with each of the partition table entries.
582 * Be willing to shove cylinders up a little bit to make things work,
583 * but translation mismatches are fatal. */
584 for (i = 0; i < NDOSPART * 2; i++) {
585 if (get_mapping(i, &c1, &h1, &s1, &a1) < 0)
586 continue;
587 if (sectors * (c1 * heads + h1) + s1 != a1)
588 return;
589 if (c1 >= cylinders)
590 cylinders = c1 + 1;
591 }
592
593 /* Everything checks out. Reset the geometry to use for further
594 * calculations. */
595 dos_cylinders = cylinders;
596 dos_heads = heads;
597 dos_sectors = sectors;
598 dos_cylindersectors = heads * sectors;
599 }
600
601 /* For the purposes of intuit_translated_geometry(), treat the partition
602 * table as a list of eight mapping between (cylinder, head, sector)
603 * triplets and absolute sectors. Get the relevant geometry triplet and
604 * absolute sectors for a given entry, or return -1 if it isn't present.
605 * Note: for simplicity, the returned sector is 0-based. */
606 int
607 get_mapping(i, cylinder, head, sector, absolute)
608 int i, *cylinder, *head, *sector;
609 long *absolute;
610 {
611 struct dos_partition *part = &mboot.parts[i / 2];
612
613 if (part->dp_typ == 0)
614 return -1;
615 if (i % 2 == 0) {
616 *cylinder = DPCYL(part->dp_scyl, part->dp_ssect);
617 *head = part->dp_shd;
618 *sector = DPSECT(part->dp_ssect) - 1;
619 *absolute = getlong(&part->dp_start);
620 } else {
621 *cylinder = DPCYL(part->dp_ecyl, part->dp_esect);
622 *head = part->dp_ehd;
623 *sector = DPSECT(part->dp_esect) - 1;
624 *absolute = getlong(&part->dp_start)
625 + getlong(&part->dp_size) - 1;
626 }
627 return 0;
628 }
629
630 void
631 change_part(part, csysid, cstart, csize)
632 int part, csysid, cstart, csize;
633 {
634 struct dos_partition *partp;
635
636 partp = &mboot.parts[part];
637
638 if (s_flag) {
639 partp->dp_typ = csysid;
640 putlong(&partp->dp_start, cstart);
641 putlong(&partp->dp_size, csize);
642 dos(getlong(&partp->dp_start),
643 &partp->dp_scyl, &partp->dp_shd, &partp->dp_ssect);
644 dos(getlong(&partp->dp_start)
645 + getlong(&partp->dp_size) - 1,
646 &partp->dp_ecyl, &partp->dp_ehd, &partp->dp_esect);
647 if (f_flag)
648 return;
649 }
650
651 printf("The data for partition %d is:\n", part);
652 print_part(part);
653 if (!u_flag || !yesno("Do you want to change it?"))
654 return;
655
656 do {
657 {
658 int sysid, start, size;
659
660 sysid = partp->dp_typ,
661 start = getlong(&partp->dp_start),
662 size = getlong(&partp->dp_size);
663 decimal("sysid", &sysid);
664 decimal("start", &start);
665 decimal("size", &size);
666 partp->dp_typ = sysid;
667 putlong(&partp->dp_start, start);
668 putlong(&partp->dp_size, size);
669 }
670
671 if (yesno("Explicitly specify beg/end address?")) {
672 int tsector, tcylinder, thead;
673
674 tcylinder = DPCYL(partp->dp_scyl, partp->dp_ssect);
675 thead = partp->dp_shd;
676 tsector = DPSECT(partp->dp_ssect);
677 decimal("beginning cylinder", &tcylinder);
678 decimal("beginning head", &thead);
679 decimal("beginning sector", &tsector);
680 partp->dp_scyl = DOSCYL(tcylinder);
681 partp->dp_shd = thead;
682 partp->dp_ssect = DOSSECT(tsector, tcylinder);
683
684 tcylinder = DPCYL(partp->dp_ecyl, partp->dp_esect);
685 thead = partp->dp_ehd;
686 tsector = DPSECT(partp->dp_esect);
687 decimal("ending cylinder", &tcylinder);
688 decimal("ending head", &thead);
689 decimal("ending sector", &tsector);
690 partp->dp_ecyl = DOSCYL(tcylinder);
691 partp->dp_ehd = thead;
692 partp->dp_esect = DOSSECT(tsector, tcylinder);
693 } else {
694 dos(getlong(&partp->dp_start),
695 &partp->dp_scyl, &partp->dp_shd, &partp->dp_ssect);
696 dos(getlong(&partp->dp_start)
697 + getlong(&partp->dp_size) - 1,
698 &partp->dp_ecyl, &partp->dp_ehd, &partp->dp_esect);
699 }
700
701 print_part(part);
702 } while (!yesno("Is this entry okay?"));
703 }
704
705 void
706 print_params()
707 {
708
709 if (sh_flag) {
710 printf ("DLCYL=%d\nDLHEAD=%d\nDLSEC=%d\n",
711 cylinders, heads, sectors);
712 printf ("BCYL=%d\nBHEAD=%d\nBSEC=%d\n",
713 dos_cylinders, dos_heads, dos_sectors);
714 return;
715 }
716
717 /* Not sh_flag */
718 printf("parameters extracted from in-core disklabel are:\n");
719 printf("cylinders=%d heads=%d sectors/track=%d (%d sectors/cylinder)\n\n",
720 cylinders, heads, sectors, cylindersectors);
721 if (dos_sectors > 63 || dos_cylinders > 1023 || dos_heads > 255)
722 printf("Figures below won't work with BIOS for partitions not in cylinder 1\n");
723 printf("parameters to be used for BIOS calculations are:\n");
724 printf("cylinders=%d heads=%d sectors/track=%d (%d sectors/cylinder)\n\n",
725 dos_cylinders, dos_heads, dos_sectors, dos_cylindersectors);
726 }
727
728 void
729 change_active(which)
730 int which;
731 {
732 struct dos_partition *partp;
733 int part;
734 int active = 4;
735
736 partp = &mboot.parts[0];
737
738 if (a_flag && which != -1)
739 active = which;
740 else {
741 for (part = 0; part < NDOSPART; part++)
742 if (partp[part].dp_flag & ACTIVE)
743 active = part;
744 }
745 if (!f_flag) {
746 if (yesno("Do you want to change the active partition?")) {
747 printf ("Choosing 4 will make no partition active.\n");
748 do {
749 decimal("active partition", &active);
750 } while (!yesno("Are you happy with this choice?"));
751 } else
752 return;
753 } else
754 if (active != 4)
755 printf ("Making partition %d active.\n", active);
756
757 for (part = 0; part < NDOSPART; part++)
758 partp[part].dp_flag &= ~ACTIVE;
759 if (active < 4)
760 partp[active].dp_flag |= ACTIVE;
761 }
762
763 void
764 get_params_to_use()
765 {
766 if (b_flag) {
767 dos_cylinders = b_cyl;
768 dos_heads = b_head;
769 dos_sectors = b_sec;
770 dos_cylindersectors = dos_heads * dos_sectors;
771 return;
772 }
773
774 print_params();
775 if (yesno("Do you want to change our idea of what BIOS thinks?")) {
776 do {
777 decimal("BIOS's idea of #cylinders", &dos_cylinders);
778 decimal("BIOS's idea of #heads", &dos_heads);
779 decimal("BIOS's idea of #sectors", &dos_sectors);
780 dos_cylindersectors = dos_heads * dos_sectors;
781 print_params();
782 } while (!yesno("Are you happy with this choice?"));
783 }
784 }
785
786 /***********************************************\
787 * Change real numbers into strange dos numbers *
788 \***********************************************/
789 void
790 dos(sector, cylinderp, headp, sectorp)
791 int sector;
792 unsigned char *cylinderp, *headp, *sectorp;
793 {
794 int cylinder, head;
795
796 cylinder = sector / dos_cylindersectors;
797 sector -= cylinder * dos_cylindersectors;
798
799 head = sector / dos_sectors;
800 sector -= head * dos_sectors;
801
802 *cylinderp = DOSCYL(cylinder);
803 *headp = head;
804 *sectorp = DOSSECT(sector + 1, cylinder);
805 }
806
807 int fd;
808
809 int
810 open_disk(u_flag)
811 int u_flag;
812 {
813 static char namebuf[MAXPATHLEN + 1];
814 struct stat st;
815
816 fd = opendisk(disk, u_flag ? O_RDWR : O_RDONLY, namebuf,
817 sizeof(namebuf), 0);
818 if (fd < 0) {
819 warn("%s", namebuf);
820 return (-1);
821 }
822 disk = namebuf;
823 if (fstat(fd, &st) == -1) {
824 close(fd);
825 warn("%s", disk);
826 return (-1);
827 }
828 if (!S_ISCHR(st.st_mode) && !S_ISREG(st.st_mode)) {
829 close(fd);
830 warnx("%s is not a character device or regular file", disk);
831 return (-1);
832 }
833 if (get_params() == -1) {
834 close(fd);
835 return (-1);
836 }
837 return (0);
838 }
839
840 int
841 read_disk(sector, buf)
842 int sector;
843 void *buf;
844 {
845
846 if (lseek(fd, (off_t)(sector * 512), 0) == -1)
847 return (-1);
848 return (read(fd, buf, 512));
849 }
850
851 int
852 write_disk(sector, buf)
853 int sector;
854 void *buf;
855 {
856
857 if (lseek(fd, (off_t)(sector * 512), 0) == -1)
858 return (-1);
859 return (write(fd, buf, 512));
860 }
861
862 int
863 get_params()
864 {
865
866 if (ioctl(fd, DIOCGDINFO, &disklabel) == -1) {
867 warn("DIOCGDINFO");
868 return (-1);
869 }
870
871 dos_cylinders = cylinders = disklabel.d_ncylinders;
872 dos_heads = heads = disklabel.d_ntracks;
873 dos_sectors = sectors = disklabel.d_nsectors;
874 dos_cylindersectors = cylindersectors = heads * sectors;
875 disksectors = cylinders * heads * sectors;
876
877 return (0);
878 }
879
880 int
881 read_s0()
882 {
883
884 if (read_disk(0, mboot.bootinst) == -1) {
885 warn("can't read fdisk partition table");
886 return (-1);
887 }
888 if (getshort(&mboot.signature) != BOOT_MAGIC) {
889 warnx("invalid fdisk partition table found");
890 /* So should we initialize things? */
891 return (-1);
892 }
893 return (0);
894 }
895
896 int
897 write_s0()
898 {
899 int flag;
900
901 /*
902 * write enable label sector before write (if necessary),
903 * disable after writing.
904 * needed if the disklabel protected area also protects
905 * sector 0. (e.g. empty disk)
906 */
907 flag = 1;
908 if (ioctl(fd, DIOCWLABEL, &flag) < 0)
909 warn("DIOCWLABEL");
910 if (write_disk(0, mboot.bootinst) == -1) {
911 warn("can't write fdisk partition table");
912 return -1;
913 }
914 flag = 0;
915 if (ioctl(fd, DIOCWLABEL, &flag) < 0)
916 warn("DIOCWLABEL");
917 return 0;
918 }
919
920 int
921 yesno(str)
922 char *str;
923 {
924 int ch, first;
925
926 printf("%s [n] ", str);
927
928 first = ch = getchar();
929 while (ch != '\n' && ch != EOF)
930 ch = getchar();
931 return (first == 'y' || first == 'Y');
932 }
933
934 void
935 decimal(str, num)
936 char *str;
937 int *num;
938 {
939 int acc = 0;
940 char *cp;
941
942 for (;; printf("%s is not a valid decimal number.\n", lbuf)) {
943 printf("Supply a decimal value for \"%s\" [%d] ", str, *num);
944
945 fgets(lbuf, LBUF, stdin);
946 lbuf[strlen(lbuf)-1] = '\0';
947 cp = lbuf;
948
949 cp += strspn(cp, " \t");
950 if (*cp == '\0')
951 return;
952
953 if (!isdigit(*cp))
954 continue;
955 acc = strtol(lbuf, &cp, 10);
956
957 cp += strspn(cp, " \t");
958 if (*cp != '\0')
959 continue;
960
961 *num = acc;
962 return;
963 }
964
965 }
966
967 int
968 type_match(key, item)
969 const void *key, *item;
970 {
971 const int *typep = key;
972 const struct part_type *ptr = item;
973
974 if (*typep < ptr->type)
975 return (-1);
976 if (*typep > ptr->type)
977 return (1);
978 return (0);
979 }
980
981 char *
982 get_type(type)
983 int type;
984 {
985 struct part_type *ptr;
986
987 ptr = bsearch(&type, part_types,
988 sizeof(part_types) / sizeof(struct part_type),
989 sizeof(struct part_type), type_match);
990 if (ptr == 0)
991 return ("unknown");
992 return (ptr->name);
993 }
994