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