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