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