fdisk.c revision 1.10 1 /* $NetBSD: fdisk.c,v 1.10 1995/03/18 14:55:36 cgd 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.10 1995/03/18 14:55:36 cgd 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
85 unsigned char bootcode[] = {
86 0x33, 0xc0, 0xfa, 0x8e, 0xd0, 0xbc, 0x00, 0x7c, 0x8e, 0xc0, 0x8e, 0xd8, 0xfb, 0x8b, 0xf4, 0xbf,
87 0x00, 0x06, 0xb9, 0x00, 0x02, 0xfc, 0xf3, 0xa4, 0xea, 0x1d, 0x06, 0x00, 0x00, 0xb0, 0x04, 0xbe,
88 0xbe, 0x07, 0x80, 0x3c, 0x80, 0x74, 0x0c, 0x83, 0xc6, 0x10, 0xfe, 0xc8, 0x75, 0xf4, 0xbe, 0xbd,
89 0x06, 0xeb, 0x43, 0x8b, 0xfe, 0x8b, 0x14, 0x8b, 0x4c, 0x02, 0x83, 0xc6, 0x10, 0xfe, 0xc8, 0x74,
90 0x0a, 0x80, 0x3c, 0x80, 0x75, 0xf4, 0xbe, 0xbd, 0x06, 0xeb, 0x2b, 0xbd, 0x05, 0x00, 0xbb, 0x00,
91 0x7c, 0xb8, 0x01, 0x02, 0xcd, 0x13, 0x73, 0x0c, 0x33, 0xc0, 0xcd, 0x13, 0x4d, 0x75, 0xef, 0xbe,
92 0x9e, 0x06, 0xeb, 0x12, 0x81, 0x3e, 0xfe, 0x7d, 0x55, 0xaa, 0x75, 0x07, 0x8b, 0xf7, 0xea, 0x00,
93 0x7c, 0x00, 0x00, 0xbe, 0x85, 0x06, 0x2e, 0xac, 0x0a, 0xc0, 0x74, 0x06, 0xb4, 0x0e, 0xcd, 0x10,
94 0xeb, 0xf4, 0xfb, 0xeb, 0xfe,
95 'M', 'i', 's', 's', 'i', 'n', 'g', ' ',
96 'o', 'p', 'e', 'r', 'a', 't', 'i', 'n', 'g', ' ', 's', 'y', 's', 't', 'e', 'm', 0,
97 'E', 'r', 'r', 'o', 'r', ' ', 'l', 'o', 'a', 'd', 'i', 'n', 'g', ' ',
98 'o', 'p', 'e', 'r', 'a', 't', 'i', 'n', 'g', ' ', 's', 'y', 's', 't', 'e', 'm', 0,
99 'I', 'n', 'v', 'a', 'l', 'i', 'd', ' ',
100 'p', 'a', 'r', 't', 'i', 't', 'i', 'o', 'n', ' ', 't', 'a', 'b', 'l', 'e', 0,
101 'A', 'u', 't', 'h', 'o', 'r', ' ', '-', ' ',
102 'S', 'i', 'e', 'g', 'm', 'a', 'r', ' ', 'S', 'c', 'h', 'm', 'i', 'd', 't', 0,0,0,
103
104 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
105 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
106 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
107 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
108 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
109 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
110 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
111 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
112 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
113 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
114 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
115 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
116 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
117 };
118
119 struct part_type {
121 int type;
122 char *name;
123 } part_types[] = {
124 {0x00, "unused"},
125 {0x01, "Primary DOS with 12 bit FAT"},
126 {0x02, "XENIX / filesystem"},
127 {0x03, "XENIX /usr filesystem"},
128 {0x04, "Primary DOS with 16 bit FAT"},
129 {0x05, "Extended DOS"},
130 {0x06, "Primary 'big' DOS (> 32MB)"},
131 {0x07, "OS/2 HPFS, QNX or Advanced UNIX"},
132 {0x08, "AIX filesystem"},
133 {0x09, "AIX boot partition or Coherent"},
134 {0x0A, "OS/2 Boot Manager or OPUS"},
135 {0x10, "OPUS"},
136 {0x40, "VENIX 286"},
137 {0x50, "DM"},
138 {0x51, "DM"},
139 {0x52, "CP/M or Microport SysV/AT"},
140 {0x56, "GB"},
141 {0x61, "Speed"},
142 {0x63, "ISC UNIX, other System V/386, GNU HURD or Mach"},
143 {0x64, "Novell Netware 2.xx"},
144 {0x65, "Novell Netware 3.xx"},
145 {0x75, "PCIX"},
146 {0x80, "Minix 1.1 ... 1.4a"},
147 {0x81, "Minix 1.4b ... 1.5.10"},
148 {0x82, "Linux swap"},
149 {0x83, "Linux filesystem"},
150 {0x93, "Amoeba filesystem"},
151 {0x94, "Amoeba bad block table"},
152 {0xA5, "NetBSD or 386BSD"},
153 {0xB7, "BSDI BSD/386 filesystem"},
154 {0xB8, "BSDI BSD/386 swap"},
155 {0xDB, "Concurrent CPM or C.DOS or CTOS"},
156 {0xE1, "Speed"},
157 {0xE3, "Speed"},
158 {0xE4, "Speed"},
159 {0xF1, "Speed"},
160 {0xF2, "DOS 3.3+ Secondary"},
161 {0xF4, "Speed"},
162 {0xFF, "BBT (Bad Blocks Table)"},
163 };
164
165 void usage __P((void));
166 void print_s0 __P((int));
167 void print_part __P((int));
168 void init_sector0 __P((int));
169 void change_part __P((int));
170 void print_params __P((void));
171 void change_active __P((int));
172 void get_params_to_use __P((void));
173 void dos __P((int, unsigned char *, unsigned char *, unsigned char *));
174 int open_disk __P((int));
175 int read_disk __P((int, void *));
176 int write_disk __P((int, void *));
177 int get_params __P((void));
178 int read_s0 __P((void));
179 int write_s0 __P((void));
180 int yesno __P((char *));
181 void decimal __P((char *, int *));
182 int type_match __P((const void *, const void *));
183 char *get_type __P((int));
184
185 int
186 main(argc, argv)
187 int argc;
188 char *argv[];
189 {
190 int ch;
191 int part;
192
193 a_flag = i_flag = u_flag = 0;
194 while ((ch = getopt(argc, argv, "0123aiu")) != -1)
195 switch (ch) {
196 case '0':
197 partition = 0;
198 break;
199 case '1':
200 partition = 1;
201 break;
202 case '2':
203 partition = 2;
204 break;
205 case '3':
206 partition = 3;
207 break;
208 case 'a':
209 a_flag = 1;
210 break;
211 case 'i':
212 i_flag = 1;
213 case 'u':
214 u_flag = 1;
215 break;
216 default:
217 usage();
218 }
219 argc -= optind;
220 argv += optind;
221
222 if (argc > 0)
223 disk = argv[0];
224
225 if (open_disk(a_flag || i_flag || u_flag) < 0)
226 exit(1);
227
228 printf("******* Working on device %s *******\n", disk);
229 if (u_flag)
230 get_params_to_use();
231 else
232 print_params();
233
234 if (read_s0())
235 init_sector0(1);
236
237 printf("Warning: BIOS sector numbering starts with sector 1\n");
238 printf("Information from DOS bootblock is:\n");
239 if (partition == -1) {
240 for (part = 0; part < NDOSPART; part++)
241 change_part(part);
242 } else
243 change_part(partition);
244
245 if (u_flag || a_flag)
246 change_active(partition);
247
248 if (u_flag || a_flag) {
249 printf("\nWe haven't changed the partition table yet. ");
250 printf("This is your last chance.\n");
251 print_s0(-1);
252 if (yesno("Should we write new partition table?"))
253 write_s0();
254 }
255
256 exit(0);
257 }
258
259 void
260 usage()
261 {
262
263 (void)fprintf(stderr, "usage: fdisk [-aiu] [-0|-1|-2|-3] [device]\n");
264 exit(1);
265 }
266
267 void
268 print_s0(which)
269 int which;
270 {
271 int part;
272
273 print_params();
274 printf("Information from DOS bootblock is:\n");
275 if (which == -1) {
276 for (part = 0; part < NDOSPART; part++)
277 printf("%d: ", part), print_part(part);
278 } else
279 print_part(which);
280 }
281
282 static struct dos_partition mtpart = { 0 };
283
284 void
285 print_part(part)
286 int part;
287 {
288 struct dos_partition *partp;
289
290 partp = &mboot.parts[part];
291 if (!memcmp(partp, &mtpart, sizeof(struct dos_partition))) {
292 printf("<UNUSED>\n");
293 return;
294 }
295 printf("sysid %d (%s)\n", partp->dp_typ, get_type(partp->dp_typ));
296 printf(" start %d, size %d (%d MB), flag %x\n",
297 partp->dp_start, partp->dp_size,
298 partp->dp_size * 512 / (1024 * 1024), partp->dp_flag);
299 printf("\tbeg: cylinder %4d, head %3d, sector %2d\n",
300 DPCYL(partp->dp_scyl, partp->dp_ssect),
301 partp->dp_shd, DPSECT(partp->dp_ssect));
302 printf("\tend: cylinder %4d, head %3d, sector %2d\n",
303 DPCYL(partp->dp_ecyl, partp->dp_esect),
304 partp->dp_ehd, DPSECT(partp->dp_esect));
305 }
306
307 void
308 init_sector0(start)
309 int start;
310 {
311 struct dos_partition *partp;
312
313 memcpy(mboot.bootinst, bootcode, sizeof(bootcode));
314 mboot.signature = BOOT_MAGIC;
315
316 partp = &mboot.parts[3];
317 partp->dp_typ = DOSPTYP_386BSD;
318 partp->dp_flag = ACTIVE;
319 partp->dp_start = start;
320 partp->dp_size = disksectors - start;
321
322 dos(partp->dp_start,
323 &partp->dp_scyl, &partp->dp_shd, &partp->dp_ssect);
324 dos(partp->dp_start + partp->dp_size - 1,
325 &partp->dp_ecyl, &partp->dp_ehd, &partp->dp_esect);
326 }
327
328 void
329 change_part(part)
330 int part;
331 {
332 struct dos_partition *partp;
333
334 partp = &mboot.parts[part];
335
336 printf("The data for partition %d is:\n", part);
337 print_part(part);
338
339 if (!u_flag || !yesno("Do you want to change it?"))
340 return;
341
342 if (i_flag) {
343 memset(partp, 0, sizeof(*partp));
344 if (part == 3) {
345 init_sector0(1);
346 printf("\nThe static data for the DOS partition 3 has been reinitialized to:\n");
347 print_part(part);
348 }
349 }
350
351 do {
352 {
353 int sysid, start, size;
354
355 sysid = partp->dp_typ,
356 start = partp->dp_start,
357 size = partp->dp_size;
358 decimal("sysid", &sysid);
359 decimal("start", &start);
360 decimal("size", &size);
361 partp->dp_typ = sysid;
362 partp->dp_start = start;
363 partp->dp_size = size;
364 }
365
366 if (yesno("Explicitly specify beg/end address?")) {
367 int tsector, tcylinder, thead;
368
369 tcylinder = DPCYL(partp->dp_scyl, partp->dp_ssect);
370 thead = partp->dp_shd;
371 tsector = DPSECT(partp->dp_ssect);
372 decimal("beginning cylinder", &tcylinder);
373 decimal("beginning head", &thead);
374 decimal("beginning sector", &tsector);
375 partp->dp_scyl = DOSCYL(tcylinder);
376 partp->dp_shd = thead;
377 partp->dp_ssect = DOSSECT(tsector, tcylinder);
378
379 tcylinder = DPCYL(partp->dp_ecyl, partp->dp_esect);
380 thead = partp->dp_ehd;
381 tsector = DPSECT(partp->dp_esect);
382 decimal("ending cylinder", &tcylinder);
383 decimal("ending head", &thead);
384 decimal("ending sector", &tsector);
385 partp->dp_ecyl = DOSCYL(tcylinder);
386 partp->dp_ehd = thead;
387 partp->dp_esect = DOSSECT(tsector, tcylinder);
388 } else {
389 dos(partp->dp_start,
390 &partp->dp_scyl, &partp->dp_shd, &partp->dp_ssect);
391 dos(partp->dp_start + partp->dp_size - 1,
392 &partp->dp_ecyl, &partp->dp_ehd, &partp->dp_esect);
393 }
394
395 print_part(part);
396 } while (!yesno("Is this entry okay?"));
397 }
398
399 void
400 print_params()
401 {
402
403 printf("parameters extracted from in-core disklabel are:\n");
404 printf("cylinders=%d heads=%d sectors/track=%d (%d sectors/cylinder)\n\n",
405 cylinders, heads, sectors, cylindersectors);
406 if (dos_sectors > 63 || dos_cylinders > 1023 || dos_heads > 255)
407 printf("Figures below won't work with BIOS for partitions not in cylinder 1\n");
408 printf("parameters to be used for BIOS calculations are:\n");
409 printf("cylinders=%d heads=%d sectors/track=%d (%d sectors/cylinder)\n\n",
410 dos_cylinders, dos_heads, dos_sectors, dos_cylindersectors);
411 }
412
413 void
414 change_active(which)
415 int which;
416 {
417 struct dos_partition *partp;
418 int part;
419 int active = 3;
420
421 partp = &mboot.parts[0];
422
423 if (a_flag && which != -1)
424 active = which;
425 else {
426 for (part = 0; part < NDOSPART; part++)
427 if (partp[part].dp_flag & ACTIVE)
428 active = part;
429 }
430 if (yesno("Do you want to change the active partition?")) {
431 do {
432 decimal("active partition", &active);
433 } while (!yesno("Are you happy with this choice?"));
434 }
435 for (part = 0; part < NDOSPART; part++)
436 partp[part].dp_flag &= ~ACTIVE;
437 partp[active].dp_flag |= ACTIVE;
438 }
439
440 void
441 get_params_to_use()
442 {
443
444 print_params();
445 if (yesno("Do you want to change our idea of what BIOS thinks?")) {
446 do {
447 decimal("BIOS's idea of #cylinders", &dos_cylinders);
448 decimal("BIOS's idea of #heads", &dos_heads);
449 decimal("BIOS's idea of #sectors", &dos_sectors);
450 dos_cylindersectors = dos_heads * dos_sectors;
451 print_params();
452 } while (!yesno("Are you happy with this choice?"));
453 }
454 }
455
456 /***********************************************\
457 * Change real numbers into strange dos numbers *
458 \***********************************************/
459 void
460 dos(sector, cylinderp, headp, sectorp)
461 int sector;
462 unsigned char *cylinderp, *headp, *sectorp;
463 {
464 int cylinder, head;
465
466 cylinder = sector / dos_cylindersectors;
467 sector -= cylinder * dos_cylindersectors;
468
469 head = sector / dos_sectors;
470 sector -= head * dos_sectors;
471
472 *cylinderp = DOSCYL(cylinder);
473 *headp = head;
474 *sectorp = DOSSECT(sector + 1, cylinder);
475 }
476
477 int fd;
478
479 int
480 open_disk(u_flag)
481 int u_flag;
482 {
483 struct stat st;
484
485 if ((fd = open(disk, u_flag ? O_RDWR : O_RDONLY)) == -1) {
486 warn("%s", disk);
487 return (-1);
488 }
489 if (fstat(fd, &st) == -1) {
490 close(fd);
491 warn("%s", disk);
492 return (-1);
493 }
494 if (!S_ISCHR(st.st_mode) && !S_ISREG(st.st_mode)) {
495 close(fd);
496 warnx("%s is not a character device or regular file", disk);
497 return (-1);
498 }
499 if (get_params() == -1) {
500 close(fd);
501 return (-1);
502 }
503 return (0);
504 }
505
506 int
507 read_disk(sector, buf)
508 int sector;
509 void *buf;
510 {
511
512 if (lseek(fd, (off_t)(sector * 512), 0) == -1)
513 return (-1);
514 return (read(fd, buf, 512));
515 }
516
517 int
518 write_disk(sector, buf)
519 int sector;
520 void *buf;
521 {
522
523 if (lseek(fd, (off_t)(sector * 512), 0) == -1)
524 return (-1);
525 return (write(fd, buf, 512));
526 }
527
528 int
529 get_params()
530 {
531
532 if (ioctl(fd, DIOCGDINFO, &disklabel) == -1) {
533 warn("DIOCGDINFO");
534 return (-1);
535 }
536
537 dos_cylinders = cylinders = disklabel.d_ncylinders;
538 dos_heads = heads = disklabel.d_ntracks;
539 dos_sectors = sectors = disklabel.d_nsectors;
540 dos_cylindersectors = cylindersectors = heads * sectors;
541 disksectors = cylinders * heads * sectors;
542
543 return (0);
544 }
545
546 int
547 read_s0()
548 {
549
550 if (read_disk(0, mboot.bootinst) == -1) {
551 warn("can't read fdisk partition table");
552 return (-1);
553 }
554 if (mboot.signature != BOOT_MAGIC) {
555 warn("invalid fdisk partition table found");
556 /* So should we initialize things? */
557 return (-1);
558 }
559 return (0);
560 }
561
562 int
563 write_s0()
564 {
565 int flag;
566
567 /*
568 * write enable label sector before write (if necessary),
569 * disable after writing.
570 * needed if the disklabel protected area also protects
571 * sector 0. (e.g. empty disk)
572 */
573 flag = 1;
574 if (ioctl(fd, DIOCWLABEL, &flag) < 0)
575 warn("DIOCWLABEL");
576 if (write_disk(0, mboot.bootinst) == -1) {
577 warn("can't write fdisk partition table");
578 return -1;
579 }
580 flag = 0;
581 if (ioctl(fd, DIOCWLABEL, &flag) < 0)
582 warn("DIOCWLABEL");
583 }
584
585 int
586 yesno(str)
587 char *str;
588 {
589 int ch, first;
590
591 printf("%s [n] ", str);
592
593 first = ch = getchar();
594 while (ch != '\n' && ch != EOF)
595 ch = getchar();
596 return (first == 'y' || first == 'Y');
597 }
598
599 void
600 decimal(str, num)
601 char *str;
602 int *num;
603 {
604 int acc = 0;
605 char *cp;
606
607 for (;; printf("%s is not a valid decimal number.\n", lbuf)) {
608 printf("Supply a decimal value for \"%s\" [%d] ", str, *num);
609
610 fgets(lbuf, LBUF, stdin);
611 lbuf[strlen(lbuf)-1] = '\0';
612 cp = lbuf;
613
614 cp += strspn(cp, " \t");
615 if (*cp == '\0')
616 return;
617
618 if (!isdigit(*cp))
619 continue;
620 acc = strtol(lbuf, &cp, 10);
621
622 cp += strspn(cp, " \t");
623 if (*cp != '\0')
624 continue;
625
626 *num = acc;
627 return;
628 }
629
630 }
631
632 int
633 type_match(key, item)
634 const void *key, *item;
635 {
636 const int *typep = key;
637 const struct part_type *ptr = item;
638
639 if (*typep < ptr->type)
640 return (-1);
641 if (*typep > ptr->type)
642 return (1);
643 return (0);
644 }
645
646 char *
647 get_type(type)
648 int type;
649 {
650 struct part_type *ptr;
651
652 ptr = bsearch(&type, part_types,
653 sizeof(part_types) / sizeof(struct part_type),
654 sizeof(struct part_type), type_match);
655 if (ptr == 0)
656 return ("unknown");
657 else
658 return (ptr->name);
659 }
660