|
|
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.