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