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