1: /* 2: * Public domain, June 1995 3: * 4: * @(#)disklabel.c 1.4 (2.11BSD GTE) 1996/5/2 5: */ 6: 7: #define DKTYPENAMES 8: #include "../h/param.h" 9: #include "saio.h" 10: 11: int Nolabelerr = 1; /* Inhibit spurious label error msgs */ 12: char module[] = "disklabel"; /* This program's name */ 13: char line[80], device[80]; 14: 15: extern long atol(); 16: extern struct iob iob[]; 17: extern struct devsw devsw[]; 18: 19: main() 20: { 21: register int f; 22: register struct disklabel *lp; 23: struct iob *io; 24: 25: printf("%s\n", module); 26: 27: while (1) 28: { 29: printf("Disk? "); 30: gets(line); 31: if (!line[0]) 32: continue; 33: strcpy(device, line); 34: f = open(device, F_WRITE); 35: if (f < 0) 36: { 37: printf("Error opening '%s' for writing\n", device); 38: continue; 39: } 40: io = &iob[f - 3]; 41: if (io->i_flgs & F_TAPE) 42: { 43: printf("Can not label tapes.\n"); 44: continue; 45: } 46: break; 47: } 48: /* 49: * The open() will have retrieved the label sector. This explicit read 50: * is for debugging and testing because the driver's open routine may be 51: * under development and the automatic retrieval of the label is commented 52: * out. 53: */ 54: if (devlabel(io, READLABEL) < 0) 55: { 56: printf("Can not read label sector from '%s'\n", device); 57: return; /* back to Boot */ 58: } 59: lp = &io->i_label; 60: if (lp->d_magic != DISKMAGIC || lp->d_magic2 != DISKMAGIC || 61: dkcksum(lp)) 62: { 63: printf("'%s' is unlabeled or the label is corrupt.\n", device); 64: printf("Proceed? [y/n] "); 65: if (gyon() == 'n') 66: return; /* back to Boot */ 67: /* 68: * We next call the driver's entry which attempts to identify the drive 69: * and set up a default (1 partition) label with the best guess as to 70: * geometry, etc. If this call fails then the driver does not support 71: * labels ('nullsys' is being used in the device table). 72: */ 73: if (devlabel(io, DEFAULTLABEL) < 0) 74: { 75: printf("The '%s' driver does not support labels.\n", 76: devsw[io->i_ino.i_dev].dv_name); 77: return; /* back to Boot */ 78: } 79: } 80: doit(io); 81: return; 82: } 83: 84: doit(io) 85: register struct iob *io; 86: { 87: int c, dirty = 0; 88: struct disklabel *lp = &io->i_label; 89: 90: while (1) 91: { 92: printf("d(isplay) D(efault) m(odify) w(rite) q(uit)? "); 93: c = egetchar("dDmwq"); 94: switch (c) 95: { 96: case 'm': 97: modifylabel(lp); 98: overlapchk(lp); 99: (void)checklabel(lp); 100: /* 101: * We make the assumption that the label was modified - the dirty 102: * flag is set so we can ask if the changes should be discarded on a 'q'. 103: */ 104: dirty = 1; 105: break; 106: case 'w': 107: overlapchk(lp); 108: (void)checklabel(lp); 109: devlabel(io, WRITELABEL); 110: /* 111: * Changed label was committed to disk so we can clear the dirty flag now 112: * and not ask the user if the changes should be kept when a 'q'uit is done. 113: */ 114: dirty = 0; 115: break; 116: case 'd': 117: displaylabel(lp); 118: break; 119: case 'D': 120: devlabel(io, DEFAULTLABEL); 121: dirty = 1; 122: break; 123: case 'q': 124: if (!dirty) 125: return; 126: printf("Label changed. Discard changes [y/n]? "); 127: if (gyon() == 'n') 128: break; 129: return; 130: default: 131: break; 132: } 133: } 134: /* NOTREACHED */ 135: } 136: 137: modifylabel(lp) 138: register struct disklabel *lp; 139: { 140: register int c; 141: 142: while (1) 143: { 144: printf("modify\n"); 145: printf("d(isplay) g(eometry) m(isc) p(artitions) q(uit)? "); 146: c = egetchar("dgmpq"); 147: switch (c) 148: { 149: case 'd': 150: displaylabel(lp); 151: break; 152: case 'g': 153: dogeometry(lp); 154: break; 155: case 'm': 156: domisc(lp); 157: break; 158: case 'p': 159: dopartitions(lp); 160: break; 161: case 'q': 162: return; 163: default: 164: break; 165: } 166: } 167: /* NOTREACHED */ 168: } 169: 170: dogeometry(lp) 171: struct disklabel *lp; 172: { 173: register int c; 174: 175: while (1) 176: { 177: printf("modify geometry\n"); 178: printf("d(isplay) s(ector/trk) t(rk/cyl) c(yl) S(ector/cyl) q(uit)? "); 179: c = egetchar("dstcSq"); 180: switch (c) 181: { 182: case 'd': 183: displaylabel(lp); 184: break; 185: case 's': 186: fillin_int(&lp->d_nsectors, 187: "sectors/track [%d]: ", 512); 188: break; 189: case 't': 190: fillin_int(&lp->d_ntracks, 191: "tracks/cylinder [%d]: ", 127); 192: break; 193: case 'c': 194: fillin_int(&lp->d_ncylinders, 195: "cylinders [%d]: ", 4096); 196: break; 197: case 'S': 198: lp->d_secpercyl= lp->d_nsectors * lp->d_ntracks; 199: fillin_int(&lp->d_secpercyl, 200: "sectors/cylinder [%d]: ", 65535); 201: break; 202: case 'q': 203: if (lp->d_secpercyl == 0) 204: lp->d_secpercyl = lp->d_nsectors * 205: lp->d_ntracks; 206: lp->d_secperunit = (long)lp->d_ncylinders * 207: lp->d_secpercyl; 208: return; 209: default: 210: break; 211: } 212: } 213: /* NOTREACHED */ 214: } 215: 216: domisc(lp) 217: register struct disklabel *lp; 218: { 219: register int c; 220: char junk[32]; 221: 222: while (1) 223: { 224: printf("modify misc\n"); 225: printf("d(isplay) t(ype) n(ame) l(abel) f(lags) r(pm) D(rivedata) q(uit)? "); 226: c = egetchar("dtnlfrDq"); 227: switch (c) 228: { 229: case 'd': 230: displaylabel(lp); 231: break; 232: case 't': 233: if (lp->d_type >= DKMAXTYPES) 234: lp->d_type = 0; 235: printf("type [%s]: ", dktypenames[lp->d_type]); 236: gets(line); 237: if (line[0]) 238: lp->d_type = findtype(dktypenames, 239: line, 240: lp->d_type); 241: break; 242: case 'n': 243: strncpy(junk, lp->d_typename, 244: sizeof (lp->d_typename)); 245: junk[sizeof (lp->d_typename)] = '\0'; 246: printf("disk [%s]: ", junk); 247: gets(line); 248: if (line[0]) 249: strncpy(lp->d_typename, line, 250: sizeof (lp->d_typename)); 251: break; 252: case 'l': 253: strncpy(junk, lp->d_packname, 254: sizeof (lp->d_packname)); 255: junk[sizeof (lp->d_packname)] = '\0'; 256: printf("label [%s]: ", junk); 257: gets(line); 258: if (line[0]) 259: strncpy(lp->d_packname, line, 260: sizeof (lp->d_packname)); 261: break; 262: case 'f': 263: doflags(lp); 264: break; 265: case 'r': 266: fillin_int(&lp->d_rpm, "rpm [%d]: ", 32767); 267: break; 268: case 'D': 269: dodrivedata(lp); 270: break; 271: case 'q': 272: return; 273: default: 274: break; 275: } 276: } 277: /* NOTREACHED */ 278: } 279: 280: dodrivedata(lp) 281: struct disklabel *lp; 282: { 283: register u_long *ulp; 284: register int i; 285: 286: for (i = 0, ulp = lp->d_drivedata; i < NDDATA; i++, ulp++) 287: { 288: printf("modify misc drivedata\n"); 289: printf("drivedata #%d [%D]: ", i, *ulp); 290: gets(line); 291: if (line[0]) 292: *ulp = atol(line); 293: } 294: return; 295: } 296: 297: doflags(lp) 298: register struct disklabel *lp; 299: { 300: register int c; 301: 302: while (1) 303: { 304: printf("modify misc flags\n"); 305: printf("d(isplay) c(lear) e(cc) b(adsect) r(emovable) q(uit)? "); 306: c = egetchar("dcerbq"); 307: switch (c) 308: { 309: case 'c': 310: lp->d_flags = 0; 311: break; 312: case 'd': 313: displaylabel(lp); 314: break; 315: case 'r': 316: lp->d_flags |= D_REMOVABLE; 317: break; 318: case 'e': 319: lp->d_flags |= D_ECC; 320: break; 321: case 'b': 322: lp->d_flags |= D_BADSECT; 323: break; 324: case 'q': 325: return; 326: default: 327: break; 328: } 329: } 330: /* NOTREACHED */ 331: } 332: 333: dopartitions(lp) 334: struct disklabel *lp; 335: { 336: register int c; 337: int i; 338: 339: while (1) 340: { 341: printf("modify partitions\n"); 342: printf("d(isplay) n(umber) s(elect) q(uit)? "); 343: c = egetchar("dsnq"); 344: switch (c) 345: { 346: case 'd': 347: displaylabel(lp); 348: break; 349: case 'n': 350: printf("Number of partitions (%d max) [%d]? ", 351: MAXPARTITIONS, lp->d_npartitions); 352: gets(line); 353: if (line[0] == '\0') 354: i = lp->d_npartitions; 355: else 356: i = atoi(line); 357: if (i > 0 && i <= MAXPARTITIONS) 358: lp->d_npartitions = i; 359: break; 360: case 's': 361: printf("a b c d e f g h q(uit)? "); 362: i = getpartnum(); 363: if (i < 0) 364: break; 365: if (i >= lp->d_npartitions) 366: lp->d_npartitions = i + 1; 367: dopartmods(lp, i); 368: break; 369: case 'q': 370: return; 371: default: 372: break; 373: } 374: } 375: /* NOTREACHED */ 376: } 377: 378: dopartmods(lp, part) 379: struct disklabel *lp; 380: int part; 381: { 382: char pname = 'a' + part; 383: int i, c; 384: register struct partition *pp = &lp->d_partitions[part]; 385: u_int cyl; 386: daddr_t off, sec, size; 387: 388: printf("sizes and offsets may be given as sectors, cylinders\n"); 389: printf("or cylinders plus sectors: 6200, 32c, 19c10s respectively\n"); 390: 391: while (1) 392: { 393: printf("modify partition '%c'\n", pname); 394: printf("d(isplay) z(ero) t(ype) o(ffset) s(ize) f(rag) F(size) q(uit)? "); 395: c = egetchar("dztosfFq"); 396: switch (c) 397: { 398: case 'z': 399: pp->p_size = 0; 400: pp->p_offset = 0; 401: pp->p_fstype = FS_UNUSED; 402: break; 403: case 'd': 404: displaylabel(lp); 405: break; 406: case 't': 407: if (pp->p_fstype >= FSMAXTYPES) 408: pp->p_fstype = FS_UNUSED; 409: printf("'%c' fstype [%s]: ", pname, 410: fstypenames[pp->p_fstype]); 411: gets(line); 412: if (line[0]) 413: pp->p_fstype = findtype(fstypenames, 414: line, 415: pp->p_fstype); 416: break; 417: case 'o': 418: printf("'%c' offset [%D]: ",pname,pp->p_offset); 419: gets(line); 420: if (line[0] == '\0') 421: break; 422: i = parse_sec_cyl(lp, line, &sec, &cyl); 423: if (i < 0) 424: break; 425: if (cyl) 426: off = (long)lp->d_secpercyl * cyl; 427: else 428: off = 0; 429: off += sec; 430: pp->p_offset = off; 431: break; 432: case 's': 433: printf("'%c' size [%D]: ", pname, pp->p_size); 434: gets(line); 435: if (line[0] == '\0') 436: break; 437: i = parse_sec_cyl(lp, line, &sec, &cyl); 438: if (i < 0) 439: break; 440: if (cyl) 441: size = (long)lp->d_secpercyl * cyl; 442: else 443: size = 0; 444: size += sec; 445: pp->p_size = size; 446: break; 447: case 'f': 448: printf("'%c' frags/fs-block [1]: ", pname); 449: gets(line); 450: if (line[0] == '\0') 451: break; 452: i = atoi(line); 453: if (i <= 0 || i > 255) 454: { 455: printf("frags/block <= 0 || > 255\n"); 456: pp->p_frag = 1; 457: } 458: else 459: pp->p_frag = i; 460: break; 461: case 'F': /* Not really used at the present */ 462: printf("'%c' frag size [1024]: ", pname); 463: gets(line); 464: if (line[0] == '\0') 465: break; 466: i = atoi(line); 467: if (i <= 0 || (i % NBPG)) 468: { 469: printf("fragsize <= 0 || ! % NBPG\n"); 470: pp->p_fsize = 0; 471: } 472: else 473: pp->p_fsize = i; 474: break; 475: case 'q': 476: if (pp->p_fsize == 0) 477: pp->p_fsize = 1024; 478: if (pp->p_frag == 0) 479: pp->p_frag = 1; 480: return; 481: default: 482: break; 483: } 484: } 485: /* NOTREACHED */ 486: } 487: 488: getpartnum() 489: { 490: register int c; 491: 492: c = egetchar("abcdefghq"); 493: if (c == 'q') 494: return(-1); 495: return(c - 'a'); 496: } 497: 498: findtype(list, name, deflt) 499: char **list; 500: char *name; 501: int deflt; 502: { 503: register char **cpp; 504: int i; 505: 506: for (i = 0, cpp = list; *cpp; cpp++, i++) 507: { 508: if (strcmp(*cpp, name) == 0) 509: return(i); 510: } 511: printf("%s not found in list. The possible choices are:\n\n", name); 512: for (cpp = list; *cpp; cpp++) 513: printf(" %s\n", *cpp); 514: putchar('\n'); 515: return(deflt); 516: } 517: 518: /* 519: * Sizes and offsets can be specified in four ways: 520: * 521: * Number of sectors: 32678 522: * Number of cylinders: 110c 523: * Number of cylinders and sectors: 29c14s 524: * Number of sectors and cylinders: 22s134c 525: * 526: * The trailing 's' or 'c' can be left off in the last two cases. 527: * 528: * The geometry section of the label must have been filled in previously. 529: * A warning is issued if the cylinder or cylinder+sector forms are used 530: * and the necessary geometry information is not present. 531: */ 532: 533: parse_sec_cyl(lp, line, sec, cyl) 534: struct disklabel *lp; 535: char line[]; 536: daddr_t *sec; 537: u_int *cyl; 538: { 539: register char *cp; 540: int error = 0; 541: long tmp, tmpcyl = 0, tmpsec = 0; 542: 543: for (tmp = 0, cp = line; *cp; cp++) 544: { 545: if (*cp >= '0' && *cp <= '9') 546: { 547: tmp *= 10; 548: tmp += (*cp - '0'); 549: } 550: else if (*cp == 'c') 551: { 552: if (tmpcyl) 553: { 554: printf("duplicate 'c'ylinder specified\n"); 555: error = 1; 556: break; 557: } 558: tmpcyl = tmp; 559: tmp = 0; 560: } 561: else if (*cp == 's') 562: { 563: if (tmpsec) 564: { 565: printf("duplicate 's'ector specified\n"); 566: error = 1; 567: break; 568: } 569: tmpsec = tmp; 570: tmp = 0; 571: } 572: else 573: { 574: printf("illegal character '%c'\n", *cp); 575: error = 1; 576: break; 577: } 578: } 579: if (error) 580: return(-1); 581: 582: /* 583: * At this point if either a 's' or 'c' was encountered in the string then 584: * one or both of 'tmpsec' and 'tmpcyl' will be non-zero. If the trailing 585: * character was omitted we need to figure out which variable gets the 586: * contents left in 'tmp' when the terminating null character was seen. This 587: * is because "15c8" and "18s3" are both valid and indicate "15 cylinders + 588: * 8 sectors" and "18 sectors + 3 cylinders" respectively. 589: * 590: * If neither 'tmpsec' or 'tmpcyl' are nonzero then we have a simple sector 591: * number in 'tmp'. 592: */ 593: if (tmpsec || tmpcyl) 594: { 595: if (tmpsec) 596: tmpcyl = tmp; 597: else 598: tmpsec = tmp; 599: } 600: else 601: { 602: tmpsec = tmp; 603: tmpcyl = 0; 604: } 605: /* 606: * It is an error condition to specify a number of cylinders and not 607: * have previously defined the geometry - it is impossible to calculate 608: * the number of sectors in the partition without geometry. 609: */ 610: if (tmpcyl && lp->d_secpercyl == 0) 611: { 612: printf("# cylinders specified but no geometry info present!\n"); 613: return(-1); 614: } 615: 616: /* 617: * Sanity check to make sure erroneous number of cylinders is not believed 618: * due to truncation (number of cylinders is really a 'u_int') 619: */ 620: 621: if (tmpcyl > 65535L) 622: { 623: printf("Number of cylinders specified (%D) is ridiculous!\n", 624: tmpcyl); 625: return(-1); 626: } 627: *cyl = (u_int)tmpcyl; 628: *sec = tmpsec; 629: return(0); 630: } 631: 632: fillin_int(where, fmt, limit) 633: u_int *where; 634: char *fmt; 635: u_int limit; 636: { 637: u_int i; 638: 639: printf(fmt, *where); 640: gets(line); 641: if (line[0]) 642: { 643: i = (u_int)atoi(line); 644: if (i > limit) 645: { 646: printf("%d is out of bounds (> %d)\n", i, limit); 647: return; 648: } 649: *where = i; 650: } 651: } 652: 653: fillin_long(where, fmt, limit) 654: u_long *where; 655: char *fmt; 656: u_long limit; 657: { 658: u_long l; 659: 660: printf(fmt, *where); 661: gets(line); 662: if (line[0]) 663: { 664: l = (u_int)atol(line); 665: if (l > limit) 666: { 667: printf("%D is out of bounds (> %D)\n", l, limit); 668: return; 669: } 670: *where = l; 671: } 672: } 673: 674: gyon() 675: { 676: register int c; 677: 678: c = egetchar("yYnN"); 679: if (c >= 'A' && c <= 'Z') 680: c += ('a' - 'A'); 681: return(c); 682: } 683: 684: egetchar(str) 685: char *str; 686: { 687: register int c; 688: 689: while (1) 690: { 691: c = getchar(); 692: if (index(str, c)) 693: break; 694: putchar('\007'); 695: } 696: putchar(c); 697: putchar('\n'); 698: return(c); 699: } 700: 701: /* 702: * Check disklabel for errors and fill in 703: * derived fields according to supplied values. 704: * 705: * Adapted from the disklabel utility. 706: */ 707: checklabel(lp) 708: register struct disklabel *lp; 709: { 710: register struct partition *pp; 711: int i, errors = 0; 712: char part; 713: 714: if (lp->d_nsectors == 0) 715: { 716: printf("sectors/track %d\n", lp->d_nsectors); 717: return(1); 718: } 719: if (lp->d_ntracks == 0) 720: { 721: printf("tracks/cylinder %d\n", lp->d_ntracks); 722: return(1); 723: } 724: if (lp->d_ncylinders == 0) 725: { 726: printf("cylinders/unit %d\n", lp->d_ncylinders); 727: errors++; 728: } 729: if (lp->d_rpm == 0) 730: Warning("revolutions/minute %d", lp->d_rpm); 731: if (lp->d_secpercyl == 0) 732: lp->d_secpercyl = lp->d_nsectors * lp->d_ntracks; 733: if (lp->d_secperunit == 0) 734: lp->d_secperunit = (long) lp->d_secpercyl * lp->d_ncylinders; 735: 736: for (i = 0; i < lp->d_npartitions; i++) 737: { 738: part = 'a' + i; 739: pp = &lp->d_partitions[i]; 740: if (pp->p_size == 0 && pp->p_offset != 0) 741: Warning("partition %c: size 0, but offset %d", 742: part, pp->p_offset); 743: #ifdef notdef 744: if (pp->p_size % lp->d_secpercyl) 745: Warning("partition %c: size %% cylinder-size != 0", 746: part); 747: if (pp->p_offset % lp->d_secpercyl) 748: Warning("partition %c: offset %% cylinder-size != 0", 749: part); 750: #endif 751: if (pp->p_offset > lp->d_secperunit) 752: { 753: printf("partition %c: offset past end of unit %D %D\n", 754: part, pp->p_offset, lp->d_secperunit); 755: errors++; 756: } 757: if (pp->p_offset + pp->p_size > lp->d_secperunit) 758: { 759: printf("partition %c: extends past end of unit %D %D %D\n", 760: part, pp->p_offset, pp->p_size, lp->d_secperunit); 761: errors++; 762: } 763: } 764: for (; i < MAXPARTITIONS; i++) 765: { 766: part = 'a' + i; 767: pp = &lp->d_partitions[i]; 768: if (pp->p_size || pp->p_offset) 769: Warning("unused partition %c: size %D offset %D", 770: 'a' + i, pp->p_size, pp->p_offset); 771: } 772: return(errors); 773: } 774: 775: /*VARARGS1*/ 776: Warning(fmt, a1, a2, a3, a4, a5) 777: char *fmt; 778: { 779: 780: printf("Warning, "); 781: printf(fmt, a1, a2, a3, a4, a5); 782: printf("\n"); 783: }