|
|
1.1 root 1: /*
2: * fdisk.c
3: *
4: * Last hacked: 07/06/92, COHERENT 386
5: *
6: * cc -o fdisk fdisk.c -f
7: * Change partitioning IBM-AT (or other type) hard disk.
8: * Usage: /etc/fdisk [ -crvxB ] [ -b bootb ] [ device ... ]
9: * Options:
10: * -B Invoked during installation
11: * -b Add master boot block code from "bootb"
12: * -c Configure hard disk geometry
13: * -r Read only
14: * -v Print c:h:s start and end values
15: * -x Use devices /dev/xt[01]x instead of /dev/at[01]x
16: * If no device argument is given, fdisk supplies "/dev/[ax]t[01]x"
17: * as appropriate.
18: */
19:
20: #include <stdio.h>
21: #include <l.out.h>
22: #include <setjmp.h>
23: #include <sys/devices.h>
24: #include <sys/fdisk.h>
25: #include <sys/hdioctl.h>
26: #include <sys/stat.h>
27: #include "fdisk0.h"
28:
29: /* Globals. */
30: int Bflag; /* special patching during installation */
31: char *argv0; /* Command name, for error messages. */
32: int badflag; /* Partition table is bad. */
33: char buf[NBUF]; /* Input buffer. */
34: int cfd; /* Current file descriptor. */
35: int cflag; /* Configure disk geometry. */
36: int cylflag; /* Specify base and size in cylinders. */
37: unsigned int cylsize; /* Cylinder size in sectors. */
38: unsigned char *defargs[3] = { "/dev/at0x", "/dev/at1x", NULL };
39: unsigned char *device; /* Partition table device name. */
40: unsigned char *drivename; /* Disk drive name. */
41: unsigned char drive_x[] = "Drive x"; /* Needs to be written on */
42: int drivenum; /* Drive number. */
43: int freepart; /* Free partition. */
44: unsigned long freesize; /* Free size. */
45: unsigned long freestart; /* First free sector. */
46: HDISK_S hd; /* Structure to house boot block. */
47: hdparm_t hdparms; /* Hard disk parameter block. */
48: int isatflag; /* Device is an AT-type disk. */
49: jmp_buf loop; /* Interactive input loop entry point. */
50: char *mboot; /* Name of new master boot file. */
51: int megflag; /* Specify sizes in megabytes. */
52: unsigned int nspt; /* Number of sectors per track. */
53: unsigned int ncyls; /* Number of cylinders. */
54: HDISK_S newhd; /* Structure to house new boot block. */
55: unsigned int nheads; /* Number of heads per track. */
56: int nmods; /* Modifications to the table. */
57: unsigned long nsectors; /* Total sectors. */
58: int openmode = 2; /* Default open mode: read/write. */
59: int partbase; /* Partition number base (0 or 4). */
60: int qflag; /* Quit. */
61: int rflag; /* Readonly. */
62: int vflag; /* Print c:h:s start and end values. */
63:
64: main(argc, argv) int argc; char *argv[];
65: {
66: register char *s;
67: int fd0, fd1, i;
68: struct stat sb;
69:
70: /* Sanity check. */
71: argv0 = argv[0];
72: if (sizeof hd != SSIZE)
73: fatal("invalid HDISK_S size %u != %u", sizeof hd, SSIZE);
74: while (argc > 1 && **++argv == '-') {
75: --argc;
76: for (s = &argv[0][1]; *s; ++s) {
77: switch(*s) {
78: case 'B':
79: ++Bflag;
80: break;
81: case 'b':
82: if (argc-- < 2)
83: usage();
84: mboot = *++argv;
85: break;
86: case 'c':
87: ++cflag;
88: break;
89: case 'r':
90: ++rflag;
91: openmode = 0;
92: break;
93: case 'v':
94: ++vflag;
95: break;
96: case 'V':
97: fprintf(stderr, "%s: V%s\n", argv0, VERSION);
98: break;
99: case 'x':
100: defargs[0][5] = defargs[1][5] = 'x';
101: break;
102: default:
103: usage();
104: break;
105: }
106: }
107: }
108: if (openmode == 0 && mboot != NULL)
109: fatal("cannot specify both 'b' and 'r' options");
110: if (--argc == 0) {
111: /* No arguments specified, take defaults. */
112: argv = defargs;
113: fd0 = open(argv[0], 0);
114: fd1 = open(argv[1], 0);
115: if (fd1 >= 0) {
116: ++argc;
117: close(fd1);
118: } else
119: argv[1] = NULL;
120: if (fd0 >= 0) {
121: ++argc;
122: close(fd0);
123: } else
124: ++argv;
125: if (argc == 0)
126: fatal("cannot open default devices");
127: }
128: cls(0);
129: printf(
130: "This program will let you change partition information for each disk drive.\n"
131: "A disk drive can be divided into one to four logical partitions.\n"
132: "You can change the active partition (the partition which your\n"
133: "system boots by default) or change the layout of logical partitions.\n"
134: "Other programs which change hard disk partition information\n"
135: "may list logical partitions in a different order.\n"
136: "Hit <Esc><Enter> to return to the main menu at any time.\n"
137: );
138: get_line("Now hit <Enter>.");
139: for (i = 0; (device = *argv++) != NULL; ++i) {
140: /*
141: * Set the drive number, drive name, partition base.
142: * /etc/build calls /etc/fdisk with an ordered list of args
143: * which correspond to the drive number, so this usually works.
144: * But there is no obvious way to find the correct drive number
145: * when the user invokes /etc/fdisk directly; hence the
146: * kludge below for AT disks.
147: */
148: drivenum = i;
149: partbase = i * NPARTN;
150: drivename = drive_x;
151: drivename[6] = drivenum + '0';
152:
153: /*
154: * Check if device is an AT device.
155: * The fix_chs() kludge only works for AT-type disks.
156: */
157: if (stat(device, &sb) < 0)
158: fatal("cannot stat \"%s\"", device);
159: isatflag = (major(sb.st_rdev) == AT_MAJOR);
160: if (isatflag) {
161: /* Kludge, see comment above... */
162: if (minor(sb.st_rdev) == AT0X_MINOR) {
163: drivenum = partbase = 0;
164: drivename = "Drive 0";
165: } else if (minor(sb.st_rdev) == AT1X_MINOR) {
166: drivenum = 1;
167: partbase = 4;
168: drivename = "Drive 1";
169: } /* else huh? */
170: }
171:
172: /* Do it. */
173: fdisk(*argv == NULL);
174: if (qflag)
175: break;
176: }
177: exit(0);
178: }
179:
180: /*
181: * If 286, copy /coherent to /tmp/coherent and
182: * patch /tmp/coherent disk parameters "atparms" with hdparms.
183: * [Primary/secondary patch stuff disappears with COH 3.2.1.]
184: */
185: void
186: atpatch()
187: {
188: register int i;
189: int dbase;
190: unsigned char *hdp;
191: FILE *fp;
192:
193: if (!Bflag)
194: return;
195: if (drivenum == 0)
196: dbase = 0;
197: else if (drivenum == 1)
198: dbase = sizeof hdparms;
199: else
200: fatal("unrecognized drive number");
201:
202: /*
203: * Write commands to patchfile - they run after kernel is linked.
204: */
205: fp = fopen(PATCHFILE, "a");
206: #if !_I386
207: fprintf(fp, "/conf/patch /mnt/drv/at \\\n");
208: for (i = 0, hdp = (char *)&hdparms; i < sizeof hdparms; i++, hdp++) {
209: fprintf(fp, " atparm_+%d=%u:c \\\n", dbase + i, *hdp);
210: }
211: fprintf(fp, "\n");
212: #endif
213: fprintf(fp, "/conf/patch /mnt/coherent >/dev/null \\\n");
214: for (i = 0, hdp = (char *)&hdparms; i < sizeof hdparms; i++, hdp++) {
215: #if _I386
216: fprintf(fp, " atparm+%d=%u:c \\\n", dbase + i, *hdp);
217: #else
218: fprintf(fp, " atparm_+%d=%u:c \\\n", dbase + i, *hdp);
219: #endif
220: }
221: fprintf(fp, "\n");
222: fclose(fp);
223: }
224:
225: /*
226: * Change the active partition.
227: */
228: void
229: change_active()
230: {
231: int active, oactive, i;
232:
233: active = oactive = -1;
234: for (i=0; i < NPARTN; i++)
235: if (hd.hd_partn[i].p_boot == 0x80) {
236: hd.hd_partn[i].p_boot = 0; /* make inactive */
237: active = oactive = i; /* remember old */
238: }
239: if (!yes_no("Do you want to make a partition active")) {
240: active = -1;
241: if (active != oactive)
242: ++nmods;
243: return;
244: }
245: if (active == -1)
246: active = 0; /* default */
247: active = get_int("Active partition", active + partbase, partbase, partbase + NPARTN-1);
248: active -= partbase;
249: hd.hd_partn[active].p_boot = 0x80; /* make active */
250: if (active != oactive)
251: ++nmods;
252: }
253:
254: /*
255: * Interactively change the table entry for logical partition n.
256: * Grunge city.
257: */
258: void
259: change_part(n) int n;
260: {
261: register FDISK_S *p;
262: int sys, old;
263: unsigned int c, h, s;
264: unsigned long size, osize, base, obase, end;
265: static int optflag;
266:
267: /* Get options first time through. */
268: if (optflag == 0) {
269: cls(0);
270: printf(
271: "Existing data on a partition will be lost if you change the\n"
272: "base or the size of the partition. Be sure you have backed up\n"
273: "all data from any partition which you are going to change.\n"
274: "\n"
275: "You may specify partition bases in cylinders or in tracks.\n"
276: );
277: cylflag = yes_no("Do you want to specify bases in cylinders");
278: printf("You may specify partition sizes in %s or in megabytes.\n",
279: cylflag ? "cylinders" : "tracks");
280: megflag = !yes_no("Do you want to specify partition sizes in %s",
281: cylflag ? "cylinders" : "tracks");
282: ++optflag;
283: print_part(0);
284: }
285: p = &hd.hd_partn[n];
286: printf("\nPartition %d:\n", n + partbase);
287: size = p->p_size;
288:
289: /* Get new system type. */
290: old = p->p_sys;
291: again:
292: if (old != SYS_EMPTY)
293: printf("The current operating system type is %s.\n", sys_type(old));
294: if (yes_no("Do you want this to be a COHERENT partition"))
295: sys = SYS_COH;
296: #if 0
297: /* any partition they modify better be left as COH or empty! */
298: else if (old != SYS_COH && yes_no("Do you want the partition type left unchanged"))
299: sys = old;
300: else if (old != SYS_EMPTY && yes_no("Do you want the partition marked as unused"))
301: sys = SYS_EMPTY;
302: #endif
303: else if (yes_no("Do you want the partition marked as unused"))
304: sys = SYS_EMPTY;
305: else {
306: printf(
307: #if 0
308: "This program can mark a partition as a COHERENT partition,\n"
309: "leave its type unchanged, or mark it as unused. It cannot\n"
310: "initialize a partition for use by any other operating system;\n"
311: "to do so, you must mark it as unused now and subsequently use\n"
312: "the disk partitioning program provided by the other system\n"
313: "to initialize it correctly.\n"
314: #else
315: "\nThis program can mark a partition as a COHERENT partition\n"
316: "or mark it as unused. It CANNOT initialize a partition for\n"
317: "use by any other operating system. To do so, you must mark\n"
318: "it as unused now and subsequently use the disk partitioning\n"
319: "program provided by the other system to initialize it correctly.\n\n"
320: #endif
321: );
322: if (yes_no("Do you still want to modify this partition"))
323: goto again;
324: return;
325: }
326: if (sys != old) {
327: p->p_sys = sys;
328: ++nmods;
329: }
330: if (sys == SYS_EMPTY) {
331: printf(
332: "For you convenience in partitioning your hard disk, this program\n"
333: "lets you create unused partitions with nonzero base and size.\n"
334: "However, other disk partitioning software may not work correctly\n"
335: "unless unused partitions have base and size zero.\n"
336: );
337: if (yes_no("Do you want to zero the partition base and size")) {
338: memset(p, 0, sizeof(FDISK_S));
339: nmods++;
340: printf("\n");
341: return;
342: }
343: }
344: getbase:
345: /* Specify the base. */
346: /* Default: old or first free or track 1. */
347: obase = p->p_base;
348: base = (size != 0L) ? obase : (freesize != 0) ? freestart : nspt;
349: if (cylflag) { /* in cylinders */
350: base = sec_to_c(base);
351: base = get_long("Base cylinder", base, 0L, (long) ncyls - 1);
352: if (base == 0)
353: base = nspt; /* skip first track for cyl 0 */
354: else
355: base *= nspt * nheads; /* cylinders to sectors */
356: } else { /* in tracks */
357: base = sec_upto_t(base);
358: base = get_long("Base track", base, 1L, (long)ncyls * nheads - 1);
359: base *= nspt; /* tracks to sectors */
360: }
361:
362: /* Check that base falls at a track boundary. */
363: /* It might not if the disk was previously partitioned. */
364: c = sec_to_c(base);
365: h = sec_to_h(base);
366: s = sec_to_s(base);
367: if (s != 1) {
368: printf("Partitions should begin at a track boundary.\n");
369: printf("The partition does not begin at a track boundary with the selected base.\n");
370: printf("The next track boundary is at track %u\n", sec_upto_t(base));
371: if (yes_no("Do you want to change the partition base"))
372: goto getbase;
373: }
374:
375: /* Update the partition table base and start information. */
376: if (base != obase) {
377: ++nmods;
378: p->p_base = base;
379: p->p_bcyl = c & 0xFF;
380: p->p_bhd = h;
381: p->p_bsec = ((c >> 2) & CYLMASK ) | s;
382: }
383:
384: /* Specify the partition size. */
385: /* Default size: free block size, old size, largest possible. */
386: osize = size;
387: size = (base == freestart) ? freesize : (osize != 0L) ? osize : nsectors - base;
388: if (megflag) { /* in megabytes */
389: size = meg(size);
390: if ((long)meg(nsectors - base) == 0) {
391: printf("Less than a megabyte of space remains.\n");
392: size = nsectors - base;
393: } else {
394: size = get_long("Partition size in megabytes", size, 0L,
395: (long) meg(nsectors - base));
396: size *= 1000000L; /* megabytes to bytes */
397: size /= SSIZE; /* to sectors */
398: size = sec_upto_c(size); /* round up to cylinders */
399: size *= nspt * nheads; /* cylinders to sectors */
400: }
401: } else if (cylflag) { /* in cylinders */
402: /* Tricky stuff again. */
403: end = base + size - 1;
404: size = sec_to_c(end) - sec_to_c(base) + 1;
405: size = get_long("Partition size in cylinders", size, 0L,
406: (long) ncyls - sec_to_c(base));
407: size *= nspt * nheads; /* cylinders to sectors */
408: } else { /* in tracks */
409: size = sec_upto_t(size);
410: size = get_long("Partition size in tracks", size, 0L,
411: (long) sec_upto_t(nsectors - base));
412: size *= nspt; /* tracks to sectors */
413: }
414: /*
415: * Adjust size to end at cylinder boundary
416: * if it did not start at cylinder boundary.
417: */
418: if ((megflag || cylflag) && size != 0 && base % cylsize != 0 && size > base % cylsize)
419: size -= base % cylsize;
420:
421: /* Check the size. */
422: if (base + size > nsectors)
423: size = nsectors - base; /* roundup too big */
424: end = base + size - 1;
425: c = sec_to_c(end);
426: h = sec_to_h(end);
427: s = sec_to_s(end);
428: if (s != nspt) {
429: printf("Partitions should end at a track boundary.\n");
430: printf("A partition with %u more sectors would end at a track boundary.\n", nspt - s);
431: if (yes_no("Do you want to add %u sectors to the partition size",
432: nspt - s)) {
433: size += nspt - s;
434: s = nspt;
435: }
436: }
437:
438: /* Update the partition table size and end. */
439: if (base != obase || size != osize) {
440: ++nmods;
441: p->p_size = size;
442: p->p_ecyl = c & 0xFF;
443: p->p_ehd = h;
444: p->p_esec = ((c >> 2) & CYLMASK ) | s;
445: }
446: printf("\n");
447: }
448:
449: /*
450: * Check a c:h:s entry in the partition table for consistency.
451: * Try correcting any inconsistency found, with warning to the user.
452: * The flag is 1 for beginning, 0 for end.
453: */
454: void
455: check_chs(p, flag) FDISK_S *p; int flag;
456: {
457: unsigned int c, h, s, nc, nh, ns;
458: unsigned long n;
459:
460: again:
461: if (flag) {
462: c = bcyl(p);
463: h = bhd(p);
464: s = bsec(p);
465: n = p->p_base;
466: } else {
467: c = ecyl(p);
468: h = ehd(p);
469: s = esec(p);
470: n = p->p_base + p->p_size - 1;
471: }
472: if (c >= ncyls
473: || h >= nheads
474: || (s == 0 || s > nspt)
475: || n != chs_to_sec(c, h, s)) {
476: nc = sec_to_c(n);
477: nh = sec_to_h(n);
478: ns = sec_to_s(n);
479: cls(1);
480: printf("According to your computer system, the disk contains\n");
481: printf("%u cylinders (0 to %u), %u heads (0 to %u), and %u sectors\n",
482: ncyls, ncyls - 1, nheads, nheads -1, nspt);
483: printf("per track (1 to %u). According to the partition table, a partition\n",
484: nspt);
485: printf("%s at sector %lu, which corresponds to a c:h:s of %u:%u:%u.\n",
486: (flag) ? "begins" : "ends" , n, nc, nh, ns);
487: printf("But the partition table entry gives a c:h:s of %u:%u:%u.\n",
488: c, h, s);
489:
490: if (flag) {
491: printf(
492: "\n"
493: "An inconsistency in a partition table entry usually occurs because\n"
494: "the system CMOS RAM area specifies the hard disk geometry incorrectly;\n"
495: "that is, your disk does not contain %u cylinders, %u heads, and %u sectors.\n",
496: ncyls, nheads, nspt);
497: if (!cflag) {
498: printf(
499: "If you think the disk geometry values above are wrong, invoke this program\n"
500: "again using the \"-c\" option to correct them. Because changing these\n"
501: "values is dangerous and you have not specified the \"-c\" option, this\n"
502: "program will now terminate.\n"
503: );
504: exit(1);
505: }
506: if (isatflag) {
507: printf(
508: "This program lets you to resolve the inconsistency by specifying correct\n"
509: "values for the disk geometry (number of cylinders, heads and sectors) or by\n"
510: "making the partition table entry consistent with the given values.\n"
511: );
512: if (yes_no("Do you think the above disk geometry values are wrong")) {
513: fix_chs();
514: goto again;
515: }
516: }
517: }
518:
519: printf("This program will now change the c:h:s of the entry to %u:%u:%u\n",
520: nc, nh, ns);
521: printf(
522: "to resolve this inconsistency. Changing a partition table entry can\n"
523: "make data on existing filesystems inaccessible. If you feel this change is\n"
524: "incorrect, exit from this program now without updating the partition table.\n"
525: );
526: if (yes_no("Do you want to exit from this program"))
527: exit(1);
528: ++nmods;
529: if (flag) {
530: p->p_bcyl = nc & 0xFF;
531: p->p_bhd = nh;
532: p->p_bsec = ((nc >> 2) & CYLMASK ) | ns;
533: } else {
534: p->p_ecyl = nc & 0xFF;
535: p->p_ehd = nh;
536: p->p_esec = ((nc >> 2) & CYLMASK ) | ns;
537: }
538: }
539: }
540:
541: /*
542: * Clear the IBM-AT console screen.
543: * Prompt for <Enter> if the flag is true or if rflag.
544: */
545: void
546: cls(flag) register int flag;
547: {
548: if (flag || rflag) {
549: printf("\nHit <Enter> to continue...");
550: fflush(stdout);
551: fgets(buf, sizeof buf, stdin);
552: }
553: putchar(0x1B);
554: putchar('[');
555: putchar('2');
556: putchar('J');
557: fflush(stdout);
558: }
559:
560: #if DOSSHRINK
561: /*
562: * Shrink an MS-DOS partition.
563: * PFM.
564: */
565: void
566: dos_shrink(n) int n;
567: {
568: cls(0);
569: printf(
570: "You can sometimes shrink an existing MS-DOS partition to make room for\n"
571: "a COHERENT partition if your disk is entirely allocated to MS-DOS.\n"
572: "This program will attempt to shrink the MS-DOS partition without destroying\n"
573: "the data on it. However, you should BACK UP ALL DATA from the MS-DOS\n"
574: "partition to diskettes before you try to shrink it.\n"
575: );
576: if (freepart == -1) {
577: printf("%s", drivename);
578: printf(
579: " does not contain an unused partition. Shrinking an MS-DOS\n"
580: "partition will create additional free space on the disk, but there\n"
581: "is currently no partition table entry available for the freed space.\n"
582: );
583: if (!yes_no("Do you want to shrink the MS-DOS partition anyway"))
584: return;
585: }
586:
587: /* Go for smoke. */
588: sprintf(buf, "/etc/dosshrink %s %d %s\n", device, n, device);
589: buf[strlen(buf) - 2] = 'a' + n;
590: if (system(buf) != 0) {
591: printf("Shrinking of MS-DOS partition failed.\n");
592: return;
593: }
594:
595: /* Read the partition table again to get the changed entry. */
596: if (lseek(cfd, 0L, 0) != 0L)
597: fatal("%s: seek failed", device);
598: else if (read(cfd, &newhd, sizeof hd) != sizeof hd) {
599: close(cfd);
600: fatal("%s: read error", device);
601: } else
602: memcpy(&hd.hd_partn[n], &newhd.hd_partn[n], sizeof(FDISK_S));
603: }
604: #endif /* DOSSHRINK */
605:
606: /*
607: * Print drive information.
608: */
609: void
610: drive_info()
611: {
612: printf("%s has %u cylinders, %u heads, and %u sectors per track.\n",
613: drivename, ncyls, nheads, nspt);
614: printf("It contains:\n");
615: printf("\t%u cylinders of %lu bytes each,\n",
616: ncyls, (long)cylsize * SSIZE);
617: printf("\t%u tracks of %lu bytes each,\n",
618: ncyls * nheads, (long)nspt * SSIZE);
619: printf("\t%lu sectors of %d bytes each,\n",
620: nsectors, SSIZE);
621: printf("or a total of %ld bytes (%.2f megabytes).\n",
622: nsectors * SSIZE, meg(nsectors));
623: }
624:
625: /*
626: * Print a fatal error message and die.
627: */
628: void
629: fatal(args) char *args;
630: {
631: fprintf(stderr, "%s: %r\n", argv0, &args);
632: exit(1);
633: }
634:
635: /*
636: * Print/change configuration for given device.
637: * The 'lastflag' is true if the current device is the last one.
638: */
639: void
640: fdisk(lastflag) int lastflag;
641: {
642: int nfd, p, flag;
643: unsigned action;
644: static int firstflag = 1;
645:
646: nmods = 0;
647: if ((cfd = open(device, openmode)) < 0)
648: fatal("cannot open \"%s\"", device);
649:
650: /* Obtain drive characteristics. */
651: if (ioctl(cfd, HDGETA, (char *)&hdparms) == -1)
652: fatal("cannot get \"%s\" drive characteristics", device);
653: ncyls = (hdparms.ncyl[1] << 8) | hdparms.ncyl[0];
654: if (ncyls > 1024) {
655: printf(
656: "\n"
657: "The disk controller says your disk has %d cylinders.\n"
658: "COHERENT requires cylinder numbers in the range 0 to 1023.\n"
659: "Accordingly, this program will use 1024 as the effective\n"
660: "number of cylinders on your disk.\n"
661: , ncyls);
662: ncyls = 1024;
663: }
664: nheads = hdparms.nhead;
665: nspt = hdparms.nspt;
666: cylsize = nheads * nspt;
667: nsectors = (long)ncyls * cylsize;
668:
669: /* Print drive characteristics and allow user to patch. */
670: if (cflag && isatflag) {
671: cls(1);
672: printf("According to your computer system:\n");
673: drive_info();
674: if (!yes_no("Do you think the above values are correct"))
675: fix_chs();
676: }
677: close(cfd);
678:
679: /* Read the current boot block. */
680: cfd = get_boot(device, openmode, &hd); /* read boot */
681: if (cflag)
682: saveboot();
683:
684: /* Check for Ontrack Disk Manager. */
685: if (*(unsigned short *)(&hd.hd_boot[0xFC]) == HDSIG) {
686: printf(
687: "\n"
688: "Your hard disk appears to include Disk Manager software. Disk Manager can\n"
689: "partition your disk into more than four partitions, but COHERENT only\n"
690: "understands the first four partitions. If you have more than four\n"
691: "partitions on your disk, you will not see information about the additional\n"
692: "partitions, so proceed with extreme caution.\n"
693: "To install COHERENT while leaving Disk Manager intact, you must\n"
694: "remove all data from one of the first four disk partitions.\n"
695: );
696: if (firstflag && mboot != NULL)
697: printf(
698: "\n"
699: "If you use the COHERENT master bootstrap and you have more than four\n"
700: "Disk Manager partitions, ALL data in any Disk Manager partition\n"
701: "other than the first four partitions WILL BE LOST!\n"
702: );
703: if (!yes_no("Do you want to continue partitioning your disk"))
704: exit(1);
705: }
706:
707: /* Read master boot if desired. */
708: if (firstflag && mboot != NULL) {
709: nfd = get_boot(mboot, 0, &newhd); /* read new boot */
710: close(nfd);
711: if (newhd.hd_sig != HDSIG)
712: fatal("invalid signature in \"%s\"", mboot);
713: memcpy(hd.hd_boot, newhd.hd_boot, sizeof hd.hd_boot);
714: nmods++;
715: }
716: firstflag = 0; /* replace mboot only on first device */
717:
718: /* If no signature, zap the partition entries. */
719: if (hd.hd_sig != HDSIG) {
720: printf(
721: "The boot block on this disk drive does not contain a valid partition table.\n"
722: "This program will now create a valid partition table with zeroed entries.\n"
723: "Exit from this program immediately if you do not want to zero the entries.\n"
724: );
725: if (yes_no("Do you want to exit instead of zeroing the partition table"))
726: exit(1);
727: memset(hd.hd_partn, 0, NPARTN * sizeof(FDISK_S));
728: hd.hd_sig = HDSIG;
729: nmods++;
730: }
731:
732: /* If readonly, print information and return. */
733: if (openmode == 0) {
734: print_part(0);
735: close(cfd);
736: return;
737: }
738:
739: /* Interactive input loop. */
740: for (flag = 1; ; ) {
741: setjmp(loop);
742: print_part(flag);
743: flag = 0;
744: printf(
745: "Possible actions:\n"
746: "\t0 = Quit\n"
747: "\t1 = Change active partition (or make no partition active)\n"
748: "\t2 = Change one logical partition\n"
749: "\t3 = Change all logical partitions\n"
750: "\t4 = Delete one logical partition\n"
751: "\t5 = Change drive characteristics\n"
752: "\t6 = Display drive information\n"
753: );
754: if (lastflag)
755: action = get_int("Action", 0, 0, 6);
756: else {
757: printf("\t7 = Proceed with next drive\n");
758: action = get_int("Action", 7, 0, 7);
759: }
760:
761: switch(action) {
762: case 0:
763: if (quit(device, cfd) == 1) {
764: qflag = 1;
765: return;
766: }
767: continue;
768: case 1:
769: printf("Change active partition:\n");
770: change_active();
771: continue;
772: case 2:
773: p = (freepart != -1) ? freepart : 0;
774: p = get_int("Which partition", p + partbase, partbase, partbase + NPARTN - 1);
775: p -= partbase;
776: if (action == 2)
777: change_part(p);
778: continue;
779: case 3:
780: for (p=0; p < NPARTN; ) {
781: change_part(p++);
782: if (p < NPARTN)
783: print_part(0);
784: }
785: continue;
786: case 4:
787: p = get_int("Which partition", partbase, partbase, partbase + NPARTN - 1);
788: p -= partbase;
789: memset(&hd.hd_partn[p], 0, sizeof(FDISK_S));
790: nmods++;
791: continue;
792: case 5:
793: cls(0);
794: printf("According to your computer system:\n");
795: drive_info();
796: if (!yes_no("Do you think the above values are correct"))
797: fix_chs();
798: continue;
799: case 6:
800: cls(0);
801: drive_info();
802: flag = 1;
803: continue;
804: case 7:
805: if (quit(device, cfd) == 1)
806: return;
807: continue;
808: default:
809: continue;
810: }
811: }
812: }
813:
814: /*
815: * Interactively obtain new disk geometry values.
816: * Update running /coherent with correct values using HDSETA.
817: * Call atpatch to create patched /tmp/coherent and /tmp/boot.[01].
818: */
819: void
820: fix_chs()
821: {
822: register int i;
823:
824: printf(
825: "Warning: if you specify incorrect disk parameter values, data on\n"
826: "existing partitions may be lost or your disk may not operate correctly.\n"
827: "Consult your disk controller manual or call your disk vendor\n"
828: "if you do not know the correct values.\n"
829: );
830: if (!yes_no("Are you sure you want to change the disk parameter values"))
831: return;
832:
833: /*
834: * Modify current values before displaying them as defaults.
835: */
836: i = (hdparms.wpcc[1] << 8) | (hdparms.wpcc[0]);
837: if (i < -1 || i >= ncyls)
838: i = -1;
839: hdparms.ctrl &= 0x0f;
840:
841: ncyls = get_int("Number of cylinders", ncyls, 1, 1024);
842: nheads = get_int("Number of heads", nheads, 1, 255);
843: nspt = get_int("Number of sectors per track", nspt, 1, 255);
844: hdparms.ctrl = get_int("Control byte", hdparms.ctrl, 0, 255);
845: i = get_int("Write pre-compensation cylinder", i, -1, ncyls+1);
846: hdparms.wpcc[1] = i >> 8;
847: hdparms.wpcc[0] = i & 0xFF;
848: cylsize = nheads * nspt;
849: nsectors = (long)ncyls * cylsize;
850: hdparms.ncyl[1] = ncyls >> 8;
851: hdparms.ncyl[0] = ncyls & 0xFF;
852: hdparms.nhead = nheads;
853: hdparms.nspt = nspt;
854: if (ioctl(cfd, HDSETA, (char *)&hdparms) == -1)
855: fatal("cannot set \"%s\" drive characteristics", device);
856: if (isatflag)
857: atpatch();
858: }
859:
860: /*
861: * Read boot block from a file into the given structure.
862: * Return a file descriptor to the open file.
863: */
864: int
865: get_boot(name, mode, hdp) char *name; HDISK_S *hdp;
866: {
867: int fd;
868:
869: /* Open the file. */
870: if ((fd = open(name, mode)) < 0)
871: fatal("cannot open \"%s\"", name);
872: /* Read the current boot block into the hd structure. */
873: if (read(fd, hdp, sizeof hd) != sizeof hd) {
874: close(fd);
875: fatal("read error on \"%s\"", name);
876: }
877: return fd;
878: }
879:
880: /*
881: * Prompt for integer input from the user.
882: * Accept data in range min to max.
883: * Return a valid result.
884: */
885: int
886: get_int(prompt, defval, min, max) char *prompt; register int defval, min, max;
887: {
888: int val;
889: char *s;
890:
891: for (;;) {
892: s = get_line("%s [%u]?", prompt, defval);
893: if (*s == '\0')
894: return defval; /* take default */
895: val = atoi(s);
896: if (val >= min && val <= max)
897: return val;
898: printf("Please enter a value between %u and %u.\n", min, max);
899: }
900: }
901:
902: /*
903: * Print the args and get a line from the user to buf[].
904: * Strip the trailing newline and return a pointer to the first non-space.
905: */
906: char *
907: get_line(args) char *args;
908: {
909: register char *s;
910:
911: printf("%r ", &args);
912: fflush(stdout);
913: fgets(buf, sizeof buf, stdin);
914: buf[strlen(buf) - 1] = '\0';
915: for (s = buf; ; ++s) {
916: if (*s == 0x1B) /* <Esc> returns to loop */
917: longjmp(loop, 1);
918: else if (*s != ' ' && *s != '\t')
919: return s;
920: }
921: }
922:
923: /*
924: * Prompt for long input from the user.
925: * Accept data in range min to max.
926: * Return the result.
927: */
928: long
929: get_long(prompt, defval, min, max) char *prompt; register long defval, min, max;
930: {
931: long val;
932: char *s;
933:
934: for (;;) {
935: s = get_line("%s [%lu]?", prompt, defval);
936: if (*s == '\0')
937: return defval; /* take default */
938: val = atol(s);
939: if (val >= min && val <= max)
940: return val;
941: printf("Please enter a value between %lu and %lu.\n", min, max);
942: }
943: }
944:
945: /*
946: * Compare two partition table entries.
947: * Called by qsort.
948: * The result is sorted by base, with empty entries at the end.
949: */
950: int
951: pcompare(pp1, pp2) FDISK_S **pp1, **pp2;
952: {
953: register FDISK_S *p1, *p2;
954:
955: p1 = *pp1;
956: p2 = *pp2;
957: if (p1->p_size == 0)
958: return (p2->p_size == 0) ? 0 : 1;
959: else if (p2->p_size == 0)
960: return -1;
961: else if (p1->p_base < p2->p_base)
962: return -1;
963: else if (p1->p_base == p2->p_base)
964: return 0;
965: else
966: return 1;
967: }
968:
969: /*
970: * Output partition information.
971: */
972: void
973: print_part(flag) int flag;
974: {
975: register FDISK_S *p;
976: register char c, *s, *dname;
977: int i;
978: unsigned long end;
979:
980: cls(flag);
981: printf("%s currently has the following logical partitions:\n", drivename);
982: printf(
983: " [ In Cylinders ] [ In Tracks ]\n"
984: "Number Type Start End Size Start End Size Mbytes Blocks Name\n");
985: for (i = 0; i < NPARTN; ++i) {
986: p = &hd.hd_partn[i];
987: if (p->p_size == 0L)
988: end = p->p_base = 0L;
989: else
990: end = p->p_base + p->p_size - 1;
991: printf("%d", partbase + i);
992: printf("%s\t", (p->p_boot == 0x80) ? " Boot" : "");
993: printf("%8s ", sys_type(p->p_sys));
994: printf("%5u ", sec_to_c(p->p_base));
995: printf("%4u ", sec_to_c(end));
996: printf("%5u ", sec_upto_c(p->p_size));
997: printf("%6lu ", p->p_base / nspt);
998: printf("%6lu ", end / nspt);
999: printf("%6u ", sec_upto_t(p->p_size));
1000: printf("%6.2f ", meg(p->p_size));
1001: printf("%7lu ", p->p_size);
1002: if ((dname = malloc(strlen(device)+1)) == NULL)
1003: fatal("out of memory");
1004: strcpy(dname, device);
1005: if (strncmp(dname, "/tmp", 4) == 0)
1006: dname += 4;
1007: s = &dname[strlen(dname) - 1];
1008: c = *s;
1009: *s = 'a' + i;
1010: printf("%s", dname);
1011: *s = c;
1012: if (vflag) {
1013: printf("\n\t%3u:%u:%u ", bcyl(p), bhd(p), bsec(p));
1014: printf("%3u:%u:%u ", ecyl(p), ehd(p), esec(p));
1015: }
1016: printf("\n");
1017: }
1018: sanity();
1019: printf("\n");
1020: }
1021:
1022: /*
1023: * Done.
1024: * If changes, prompt for confirmation and save.
1025: * Return 1 to quit, 0 to not quit.
1026: */
1027: int
1028: quit(fname) char *fname;
1029: {
1030: if (badflag) {
1031: printf("Because the partition table defines overlapping disk\n");
1032: printf("partitions, it will not be saved to the disk if you quit.\n");
1033: if (!yes_no("Do you wish to quit without saving the changes"))
1034: return 0;
1035: } else if (nmods != 0) {
1036: if (yes_no("\nAre you sure you want to write the updated partition table")) {
1037: if (lseek(cfd, 0L, 0) != 0L)
1038: fatal("seek failed on \"%s\"", fname);
1039: else if (write(cfd, &hd, sizeof hd) != sizeof hd)
1040: fatal("write error on \"%s\"", fname);
1041: /*
1042: * This HDGETA is for the benefit of the SCSI driver,
1043: * which needs to reset the parameters if they changed.
1044: */
1045: if (ioctl(cfd, HDGETA, (char *)&hdparms) == -1)
1046: fprintf(stderr, "HDGETA failed on \"%s\"\n", fname);
1047: sync();
1048: } else if (!yes_no("Changes will not be saved. Quit anyway"))
1049: longjmp(loop, 2);
1050: else
1051: printf("Changes not saved.\n");
1052: } else
1053: printf("The partition table is unchanged.\n");
1054: close(cfd);
1055: return 1;
1056: }
1057:
1058: /*
1059: * Check a partition table for sanity.
1060: * Sort the partitions, look for gaps and overlaps.
1061: */
1062: void
1063: sanity()
1064: {
1065: register int i;
1066: FDISK_S *p[NPARTN];
1067: unsigned long base, next, size, safe;
1068:
1069: badflag = 0;
1070: freepart = -1;
1071: freesize = freestart = 0;
1072: for (i = 0; i < NPARTN; i++) {
1073: p[i] = &hd.hd_partn[i];
1074: if (p[i]->p_size != 0) {
1075: check_chs(p[i], 1); /* check start c:h:s */
1076: check_chs(p[i], 0); /* check end c:h:s */
1077: } else if (freepart == -1)
1078: freepart = i; /* first free partition */
1079: }
1080: qsort(p, NPARTN, sizeof(FDISK_S *), pcompare);
1081: next = 1; /* next block available after boot sector */
1082: for (i = 0; i < NPARTN; i++) {
1083: base = p[i]->p_base;
1084: size = p[i]->p_size;
1085: if (size == 0)
1086: break; /* done when empty reached */
1087: if (base < next) {
1088: if (next == 1)
1089: printf("Partition overlaps boot sector.\n");
1090: else if (cylflag)
1091: printf("Partitions overlap starting at cylinder %lu.\n", base / cylsize);
1092: else
1093: printf("Partitions overlap starting at track %lu.\n", base / nspt);
1094: ++badflag;
1095: } else if (base != next) {
1096: if (i == 0 && (base == nspt || base == cylsize))
1097: ; /* first partition at 0:1:1 or 1:0:1 */
1098: else
1099: unused(base, next);
1100: }
1101: if (base + size > next)
1102: next = base + size;
1103: }
1104: safe = nsectors - nspt * nheads; /* safely usable sectors */
1105: if (next < safe)
1106: unused(safe, next);
1107: else if (next > safe)
1108: printf(
1109: "\n"
1110: "Warning: the last cylinder of a hard disk is usually reserved for use by\n"
1111: "disk diagnostic programs. The current disk partitioning uses part of the\n"
1112: "the last cylinder in a disk partition. Mark Williams strongly recommends\n"
1113: "that you change the partitioning to avoid using the last cylinder.\n"
1114: );
1115: }
1116:
1117: struct nlist nl[2] = {
1118: #if _I386
1119: { "rootdev", 0, 0 },
1120: #else
1121: { "rootdev_", 0, 0 },
1122: #endif
1123: { "", 0, 0 }
1124: };
1125:
1126: /*
1127: * Save/restore a copy of boot block to/from floppy.
1128: * Some fuss required to find the name of the root device.
1129: */
1130: void
1131: saveboot()
1132: {
1133: register int fd;
1134: dev_t dev;
1135: char *floppy;
1136:
1137: /* Open kernel memory and read value of rootdev_. */
1138: if ((fd = open(KMEM, 0)) < 0)
1139: return;
1140: nlist(COH, nl);
1141: if (lseek(fd, (long)nl[0].n_value, 0) == -1L)
1142: return;
1143: if (read(fd, &dev, sizeof(dev_t)) != sizeof(dev_t))
1144: return;
1145: close(fd);
1146:
1147: /*
1148: * Bail out if not running floppy-based COHERENT
1149: * or if floppy open fails.
1150: */
1151: if (dev == makedev(FL_MAJOR, 14))
1152: floppy = "/dev/rfha0";
1153: else if (dev == makedev(FL_MAJOR, 15))
1154: floppy = "/dev/rfva0";
1155: else
1156: return; /* not running from floppy */
1157: if ((fd = open(floppy, 2)) == -1)
1158: return; /* open failed, bag out */
1159:
1160: cls(0);
1161: sync();
1162: printf(
1163: "If you are installing COHERENT on your hard disk for the first time and you\n"
1164: "want to use your drive with other operating systems, we recommend that you\n"
1165: "save a copy of the current boot block (which includes the partition table)\n"
1166: "to a diskette. You can restore the original boot block from the diskette\n"
1167: "if your COHERENT installation fails or if you are subsequently unable to run\n"
1168: "another operating system on the drive.\n"
1169: "\n"
1170: "You will be asked about saving and restoring the boot block once for each\n"
1171: "hard drive you are using. Use a separate diskette for each hard drive.\n"
1172: );
1173: if (yes_no("Do you want to save the original boot block")) {
1174: printf(
1175: "\n"
1176: "Remove the COHERENT boot diskette, insert a formatted blank diskette,\n"
1177: );
1178: get_line("then hit <Enter>.");
1179: if (write(fd, &hd, sizeof hd) != sizeof hd)
1180: fprintf(stderr, "fdisk: write error on \"%s\"\n", floppy);
1181: else
1182: printf(
1183: "\n"
1184: "Remove the diskette containing the original boot block.\n"
1185: "Label it and file it with your COHERENT installation disks.\n"
1186: );
1187: } else if (yes_no("Do you want to restore a previously saved boot block")) {
1188: printf(
1189: "\n"
1190: "WARNING: This step will overwrite your hard disk partition table\n"
1191: "with the previously saved copy from the diskette in drive A:.\n"
1192: "Type <Ctrl-C> if you do not want to overwrite the existing partition table.\n"
1193: "\n"
1194: "Remove the COHERENT boot diskette,\n"
1195: "insert the diskette containing the saved boot block,\n"
1196: );
1197: get_line("then hit <Enter>.");
1198: if (read(fd, &hd, sizeof hd) != sizeof hd)
1199: fprintf(stderr, "fdisk: read error on \"%s\"\n", floppy);
1200: else if (lseek(cfd, 0L, 0) != 0L)
1201: fatal("seek failed on \"%s\"", device);
1202: else if (write(cfd, &hd, sizeof hd) != sizeof hd)
1203: fatal("write error on \"%s\"", device);
1204: } else {
1205: close(fd);
1206: return;
1207: }
1208: close(fd);
1209: sync();
1210: get_line("\nReplace the COHERENT boot diskette, then hit <Enter>.");
1211: }
1212:
1213: /*
1214: * Execute a command.
1215: */
1216: void
1217: sys(cmd) char *cmd;
1218: {
1219: if (system(cmd) != 0)
1220: fatal("command \"%s\" failed", cmd);
1221: }
1222:
1223: /*
1224: * Convert system type code i to a string describing the system type.
1225: * Return a pointer to statically allocated buffer.
1226: */
1227: char *
1228: sys_type(i) register int i;
1229: {
1230: static char buf[8+1]; /* longest name is "COHERENT" or "<Unused>"XS */
1231: register char *s;
1232:
1233: switch (i) {
1234: case SYS_EMPTY: s = "<Unused>"; break;
1235: case SYS_DOS_12:
1236: case SYS_DOS_16:
1237: case SYS_DOS_LARGE:
1238: s = "MS-DOS"; break;
1239: case SYS_DOS_XP:
1240: s = "Ext.DOS"; break;
1241: case SYS_XENIX: s = "Xenix"; break;
1242: case SYS_COH: s = "Coherent"; break;
1243: case SYS_SWAP: s = "Swap"; break;
1244: default: s = NULL; break;
1245: }
1246:
1247: if (s == NULL)
1248: sprintf(buf, "%8u", i);
1249: else
1250: strcpy(buf, s);
1251: return buf;
1252: }
1253:
1254: /*
1255: * Report unused portion of disk.
1256: */
1257: void
1258: unused(base, next) unsigned long base, next;
1259: {
1260: register unsigned long n, x, y;
1261: register char *s;
1262:
1263: n = base - next;
1264: if (cylflag && n >= cylsize) {
1265: s = "cylinder";
1266: x = sec_to_c(n);
1267: y = sec_upto_c(next);
1268: } else if (n >= nspt) {
1269: s = "track";
1270: x = n / nspt;
1271: y = sec_upto_t(next);
1272: } else {
1273: s = "sector";
1274: x = n;
1275: y = next;
1276: }
1277: if (x == 1)
1278: printf("%lu %s (%.2f megabytes) is unused starting at %s %lu.\n",
1279: x, s, meg(n), s, y);
1280: else
1281: printf("%lu %ss (%.2f megabytes) are unused starting at %s %lu.\n",
1282: x, s, meg(n), s, y);
1283: if (freesize < n) {
1284: freesize = n;
1285: freestart = next;
1286: }
1287: }
1288:
1289: /*
1290: * Print a usage message and die.
1291: */
1292: void
1293: usage()
1294: {
1295: fprintf(stderr, USAGE);
1296: exit(1);
1297: }
1298:
1299: /*
1300: * Get the answer to a yes/no question.
1301: * Return 1 for yes, 0 for no.
1302: */
1303: int
1304: yes_no(args) char *args;
1305: {
1306: register char *s;
1307:
1308: for (;;) {
1309: printf("%r", &args);
1310: s = get_line(" [y or n]?");
1311: if (*s == 'y')
1312: return 1;
1313: else if (*s == 'n')
1314: return 0;
1315: }
1316: }
1317:
1318: /* end of fdisk.c */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.