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