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