|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1983 Regents of the University of California. ! 3: * All rights reserved. The Berkeley software License Agreement ! 4: * specifies the terms and conditions for redistribution. ! 5: */ ! 6: ! 7: #ifndef lint ! 8: char copyright[] = ! 9: "@(#) Copyright (c) 1983 Regents of the University of California.\n\ ! 10: All rights reserved.\n"; ! 11: #endif not lint ! 12: ! 13: #ifndef lint ! 14: static char sccsid[] = "@(#)newfs.c 6.16 (Berkeley) 5/1/88"; ! 15: #endif not lint ! 16: ! 17: /* ! 18: * newfs: friendly front end to mkfs ! 19: */ ! 20: #include <sys/param.h> ! 21: #include <sys/stat.h> ! 22: #include <sys/fs.h> ! 23: #include <sys/dir.h> ! 24: #include <sys/ioctl.h> ! 25: #include <sys/disklabel.h> ! 26: #include <sys/file.h> ! 27: ! 28: #include <stdio.h> ! 29: #include <ctype.h> ! 30: ! 31: #define COMPAT /* allow non-labeled disks */ ! 32: ! 33: /* ! 34: * The following two constants set the default block and fragment sizes. ! 35: * Both constants must be a power of 2 and meet the following constraints: ! 36: * MINBSIZE <= DESBLKSIZE <= MAXBSIZE ! 37: * sectorsize <= DESFRAGSIZE <= DESBLKSIZE ! 38: * DESBLKSIZE / DESFRAGSIZE <= 8 ! 39: */ ! 40: #define DFL_FRAGSIZE 1024 ! 41: #define DFL_BLKSIZE 8192 ! 42: ! 43: /* ! 44: * Cylinder groups may have up to many cylinders. The actual ! 45: * number used depends upon how much information can be stored ! 46: * on a single cylinder. The default is to use 16 cylinders ! 47: * per group. ! 48: */ ! 49: #define DESCPG 16 /* desired fs_cpg */ ! 50: ! 51: /* ! 52: * MINFREE gives the minimum acceptable percentage of file system ! 53: * blocks which may be free. If the freelist drops below this level ! 54: * only the superuser may continue to allocate blocks. This may ! 55: * be set to 0 if no reserve of free blocks is deemed necessary, ! 56: * however throughput drops by fifty percent if the file system ! 57: * is run at between 90% and 100% full; thus the default value of ! 58: * fs_minfree is 10%. With 10% free space, fragmentation is not a ! 59: * problem, so we choose to optimize for time. ! 60: */ ! 61: #define MINFREE 10 ! 62: #define DEFAULTOPT FS_OPTTIME ! 63: ! 64: /* ! 65: * ROTDELAY gives the minimum number of milliseconds to initiate ! 66: * another disk transfer on the same cylinder. It is used in ! 67: * determining the rotationally optimal layout for disk blocks ! 68: * within a file; the default of fs_rotdelay is 4ms. ! 69: */ ! 70: #define ROTDELAY 4 ! 71: ! 72: /* ! 73: * MAXCONTIG sets the default for the maximum number of blocks ! 74: * that may be allocated sequentially. Since UNIX drivers are ! 75: * not capable of scheduling multi-block transfers, this defaults ! 76: * to 1 (ie no contiguous blocks are allocated). ! 77: */ ! 78: #define MAXCONTIG 1 ! 79: ! 80: /* ! 81: * MAXBLKPG determines the maximum number of data blocks which are ! 82: * placed in a single cylinder group. The default is one indirect ! 83: * block worth of data blocks. ! 84: */ ! 85: #define MAXBLKPG(bsize) ((bsize) / sizeof(daddr_t)) ! 86: ! 87: /* ! 88: * Each file system has a number of inodes statically allocated. ! 89: * We allocate one inode slot per NBPI bytes, expecting this ! 90: * to be far more than we will ever need. ! 91: */ ! 92: #define NBPI 2048 ! 93: ! 94: /* ! 95: * For each cylinder we keep track of the availability of blocks at different ! 96: * rotational positions, so that we can lay out the data to be picked ! 97: * up with minimum rotational latency. NRPOS is the default number of ! 98: * rotational positions that we distinguish. With NRPOS of 8 the resolution ! 99: * of our summary information is 2ms for a typical 3600 rpm drive. ! 100: */ ! 101: #define NRPOS 8 /* number distinct rotational positions */ ! 102: ! 103: ! 104: int Nflag; /* run without writing file system */ ! 105: int fssize; /* file system size */ ! 106: int ntracks; /* # tracks/cylinder */ ! 107: int nsectors; /* # sectors/track */ ! 108: int nphyssectors; /* # sectors/track including spares */ ! 109: int secpercyl; /* sectors per cylinder */ ! 110: int trackspares = -1; /* spare sectors per track */ ! 111: int cylspares = -1; /* spare sectors per cylinder */ ! 112: int sectorsize; /* bytes/sector */ ! 113: #ifdef tahoe ! 114: int realsectorsize; /* bytes/sector in hardware */ ! 115: #endif ! 116: int rpm; /* revolutions/minute of drive */ ! 117: int interleave; /* hardware sector interleave */ ! 118: int trackskew = -1; /* sector 0 skew, per track */ ! 119: int headswitch; /* head switch time, usec */ ! 120: int trackseek; /* track-to-track seek, usec */ ! 121: int fsize = 0; /* fragment size */ ! 122: int bsize = 0; /* block size */ ! 123: int cpg = DESCPG; /* cylinders/cylinder group */ ! 124: int cpgflg; /* cylinders/cylinder group flag was given */ ! 125: int minfree = MINFREE; /* free space threshold */ ! 126: int opt = DEFAULTOPT; /* optimization preference (space or time) */ ! 127: int density = NBPI; /* number of bytes per inode */ ! 128: int maxcontig = MAXCONTIG; /* max contiguous blocks to allocate */ ! 129: int rotdelay = ROTDELAY; /* rotational delay between blocks */ ! 130: int maxbpg; /* maximum blocks per file in a cyl group */ ! 131: int nrpos = NRPOS; /* # of distinguished rotational positions */ ! 132: int bbsize = BBSIZE; /* boot block size */ ! 133: int sbsize = SBSIZE; /* superblock size */ ! 134: #ifdef COMPAT ! 135: int unlabelled; ! 136: #endif ! 137: ! 138: char device[MAXPATHLEN]; ! 139: ! 140: extern int errno; ! 141: char *index(); ! 142: char *rindex(); ! 143: ! 144: main(argc, argv) ! 145: int argc; ! 146: char *argv[]; ! 147: { ! 148: char *cp, *special; ! 149: register struct partition *pp; ! 150: register struct disklabel *lp; ! 151: struct disklabel *getdisklabel(); ! 152: struct partition oldpartition; ! 153: struct stat st; ! 154: int fsi, fso; ! 155: register int i; ! 156: int status; ! 157: ! 158: argc--, argv++; ! 159: while (argc > 0 && argv[0][0] == '-') { ! 160: for (cp = &argv[0][1]; *cp; cp++) ! 161: switch (*cp) { ! 162: ! 163: case 'N': ! 164: Nflag++; ! 165: break; ! 166: ! 167: case 'S': ! 168: if (argc < 1) ! 169: fatal("-S: missing sector size"); ! 170: argc--, argv++; ! 171: sectorsize = atoi(*argv); ! 172: if (sectorsize <= 0) ! 173: fatal("%s: bad sector size", *argv); ! 174: goto next; ! 175: ! 176: case 'a': ! 177: if (argc < 1) ! 178: fatal("-a: missing max contiguous blocks\n"); ! 179: argc--, argv++; ! 180: maxcontig = atoi(*argv); ! 181: if (maxcontig <= 0) ! 182: fatal("%s: bad max contiguous blocks\n", ! 183: *argv); ! 184: goto next; ! 185: ! 186: case 'b': ! 187: if (argc < 1) ! 188: fatal("-b: missing block size"); ! 189: argc--, argv++; ! 190: bsize = atoi(*argv); ! 191: if (bsize < MINBSIZE) ! 192: fatal("%s: bad block size", *argv); ! 193: goto next; ! 194: ! 195: case 'c': ! 196: if (argc < 1) ! 197: fatal("-c: missing cylinders/group"); ! 198: argc--, argv++; ! 199: cpg = atoi(*argv); ! 200: if (cpg <= 0) ! 201: fatal("%s: bad cylinders/group", *argv); ! 202: cpgflg++; ! 203: goto next; ! 204: ! 205: case 'd': ! 206: if (argc < 1) ! 207: fatal("-d: missing rotational delay\n"); ! 208: argc--, argv++; ! 209: rotdelay = atoi(*argv); ! 210: if (rotdelay < 0) ! 211: fatal("%s: bad rotational delay\n", ! 212: *argv); ! 213: goto next; ! 214: ! 215: case 'e': ! 216: if (argc < 1) ! 217: fatal("-e: missing blocks pre file in a cyl group\n"); ! 218: argc--, argv++; ! 219: maxbpg = atoi(*argv); ! 220: if (maxbpg <= 0) ! 221: fatal("%s: bad blocks per file in a cyl group\n", ! 222: *argv); ! 223: goto next; ! 224: ! 225: case 'f': ! 226: if (argc < 1) ! 227: fatal("-f: missing frag size"); ! 228: argc--, argv++; ! 229: fsize = atoi(*argv); ! 230: if (fsize <= 0) ! 231: fatal("%s: bad frag size", *argv); ! 232: goto next; ! 233: ! 234: case 'i': ! 235: if (argc < 1) ! 236: fatal("-i: missing bytes per inode\n"); ! 237: argc--, argv++; ! 238: density = atoi(*argv); ! 239: if (density <= 0) ! 240: fatal("%s: bad bytes per inode\n", ! 241: *argv); ! 242: goto next; ! 243: ! 244: case 'k': ! 245: if (argc < 1) ! 246: fatal("-k: track skew"); ! 247: argc--, argv++; ! 248: trackskew = atoi(*argv); ! 249: if (trackskew < 0) ! 250: fatal("%s: bad track skew", *argv); ! 251: goto next; ! 252: ! 253: case 'l': ! 254: if (argc < 1) ! 255: fatal("-l: interleave"); ! 256: argc--, argv++; ! 257: interleave = atoi(*argv); ! 258: if (interleave <= 0) ! 259: fatal("%s: bad interleave", *argv); ! 260: goto next; ! 261: ! 262: case 'm': ! 263: if (argc < 1) ! 264: fatal("-m: missing free space %%\n"); ! 265: argc--, argv++; ! 266: minfree = atoi(*argv); ! 267: if (minfree < 0 || minfree > 99) ! 268: fatal("%s: bad free space %%\n", ! 269: *argv); ! 270: goto next; ! 271: ! 272: case 'n': ! 273: if (argc < 1) ! 274: fatal("-n: missing rotational layout count\n"); ! 275: argc--, argv++; ! 276: nrpos = atoi(*argv); ! 277: if (nrpos <= 0) ! 278: fatal("%s: bad rotational layout count\n", ! 279: *argv); ! 280: goto next; ! 281: ! 282: case 'o': ! 283: if (argc < 1) ! 284: fatal("-o: missing optimization preference"); ! 285: argc--, argv++; ! 286: if (strcmp(*argv, "space") == 0) ! 287: opt = FS_OPTSPACE; ! 288: else if (strcmp(*argv, "time") == 0) ! 289: opt = FS_OPTTIME; ! 290: else ! 291: fatal("%s: bad optimization preference %s", ! 292: *argv, ! 293: "(options are `space' or `time')"); ! 294: goto next; ! 295: ! 296: case 'p': ! 297: if (argc < 1) ! 298: fatal("-p: spare sectors per track"); ! 299: argc--, argv++; ! 300: trackspares = atoi(*argv); ! 301: if (trackspares < 0) ! 302: fatal("%s: bad spare sectors per track", *argv); ! 303: goto next; ! 304: ! 305: case 'r': ! 306: if (argc < 1) ! 307: fatal("-r: missing revs/minute\n"); ! 308: argc--, argv++; ! 309: rpm = atoi(*argv); ! 310: if (rpm <= 0) ! 311: fatal("%s: bad revs/minute\n", *argv); ! 312: goto next; ! 313: ! 314: case 's': ! 315: if (argc < 1) ! 316: fatal("-s: missing file system size"); ! 317: argc--, argv++; ! 318: fssize = atoi(*argv); ! 319: if (fssize <= 0) ! 320: fatal("%s: bad file system size", ! 321: *argv); ! 322: goto next; ! 323: ! 324: case 't': ! 325: if (argc < 1) ! 326: fatal("-t: missing track total"); ! 327: argc--, argv++; ! 328: ntracks = atoi(*argv); ! 329: if (ntracks <= 0) ! 330: fatal("%s: bad total tracks", *argv); ! 331: goto next; ! 332: ! 333: case 'u': ! 334: if (argc < 1) ! 335: fatal("-u: missing sectors/track"); ! 336: argc--, argv++; ! 337: nsectors = atoi(*argv); ! 338: if (nsectors <= 0) ! 339: fatal("%s: bad sectors/track", *argv); ! 340: goto next; ! 341: ! 342: case 'x': ! 343: if (argc < 1) ! 344: fatal("-x: spare sectors per cylinder"); ! 345: argc--, argv++; ! 346: cylspares = atoi(*argv); ! 347: if (cylspares < 0) ! 348: fatal("%s: bad spare sectors per cylinder", *argv); ! 349: goto next; ! 350: ! 351: default: ! 352: fatal("-%c: unknown flag", *cp); ! 353: } ! 354: next: ! 355: argc--, argv++; ! 356: } ! 357: if (argc < 1) { ! 358: #ifdef COMPAT ! 359: fprintf(stderr, ! 360: "usage: newfs [ fsoptions ] special-device [device-type]\n"); ! 361: #else ! 362: fprintf(stderr, "usage: newfs [ fsoptions ] special-device\n"); ! 363: #endif ! 364: fprintf(stderr, "where fsoptions are:\n"); ! 365: fprintf(stderr, "\t-N do not create file system, %s\n", ! 366: "just print out parameters"); ! 367: fprintf(stderr, "\t-b block size\n"); ! 368: fprintf(stderr, "\t-f frag size\n"); ! 369: fprintf(stderr, "\t-m minimum free space %%\n"); ! 370: fprintf(stderr, "\t-o optimization preference %s\n", ! 371: "(`space' or `time')"); ! 372: fprintf(stderr, "\t-a maximum contiguous blocks\n"); ! 373: fprintf(stderr, "\t-d rotational delay between %s\n", ! 374: "contiguous blocks"); ! 375: fprintf(stderr, "\t-e maximum blocks per file in a %s\n", ! 376: "cylinder group"); ! 377: fprintf(stderr, "\t-i number of bytes per inode\n"); ! 378: fprintf(stderr, "\t-c cylinders/group\n"); ! 379: fprintf(stderr, "\t-n number of distinguished %s\n", ! 380: "rotational positions"); ! 381: fprintf(stderr, "\t-s file system size (sectors)\n"); ! 382: fprintf(stderr, "\t-r revolutions/minute\n"); ! 383: fprintf(stderr, "\t-S sector size\n"); ! 384: fprintf(stderr, "\t-u sectors/track\n"); ! 385: fprintf(stderr, "\t-t tracks/cylinder\n"); ! 386: fprintf(stderr, "\t-p spare sectors per track\n"); ! 387: fprintf(stderr, "\t-x spare sectors per cylinder\n"); ! 388: fprintf(stderr, "\t-l hardware sector interleave\n"); ! 389: fprintf(stderr, "\t-k sector 0 skew, per track\n"); ! 390: exit(1); ! 391: } ! 392: special = argv[0]; ! 393: cp = rindex(special, '/'); ! 394: if (cp != 0) ! 395: special = cp + 1; ! 396: if (*special == 'r' && special[1] != 'a' && special[1] != 'b') ! 397: special++; ! 398: (void)sprintf(device, "/dev/r%s", special); ! 399: special = device; ! 400: if (!Nflag) { ! 401: fso = open(special, O_WRONLY); ! 402: if (fso < 0) { ! 403: perror(special); ! 404: exit(1); ! 405: } ! 406: } else ! 407: fso = -1; ! 408: fsi = open(special, O_RDONLY); ! 409: if (fsi < 0) { ! 410: perror(special); ! 411: exit(1); ! 412: } ! 413: if (fstat(fsi, &st) < 0) { ! 414: fprintf(stderr, "newfs: "); perror(special); ! 415: exit(2); ! 416: } ! 417: if ((st.st_mode & S_IFMT) != S_IFCHR) ! 418: fatal("%s: not a character device", special); ! 419: cp = index(argv[0], '\0') - 1; ! 420: if (cp == 0 || (*cp < 'a' || *cp > 'h') && !isdigit(*cp)) ! 421: fatal("%s: can't figure out file system partition", argv[0]); ! 422: #ifdef COMPAT ! 423: lp = getdisklabel(special, fsi, argv[1]); ! 424: #else ! 425: lp = getdisklabel(special, fsi); ! 426: #endif ! 427: if (isdigit(*cp)) ! 428: pp = &lp->d_partitions[0]; ! 429: else ! 430: pp = &lp->d_partitions[*cp - 'a']; ! 431: if (pp->p_size == 0) ! 432: fatal("%s: `%c' partition is unavailable", argv[0], *cp); ! 433: if (fssize == 0) ! 434: fssize = pp->p_size; ! 435: if (fssize > pp->p_size) ! 436: fatal("%s: maximum file system size on the `%c' partition is %d", ! 437: argv[0], *cp, pp->p_size); ! 438: if (rpm == 0) { ! 439: rpm = lp->d_rpm; ! 440: if (rpm <= 0) ! 441: rpm = 3600; ! 442: } ! 443: if (ntracks == 0) { ! 444: ntracks = lp->d_ntracks; ! 445: if (ntracks <= 0) ! 446: fatal("%s: no default #tracks", argv[0]); ! 447: } ! 448: if (nsectors == 0) { ! 449: nsectors = lp->d_nsectors; ! 450: if (nsectors <= 0) ! 451: fatal("%s: no default #sectors/track", argv[0]); ! 452: } ! 453: if (sectorsize == 0) { ! 454: sectorsize = lp->d_secsize; ! 455: if (sectorsize <= 0) ! 456: fatal("%s: no default sector size", argv[0]); ! 457: } ! 458: if (trackskew == -1) { ! 459: trackskew = lp->d_trackskew; ! 460: if (trackskew < 0) ! 461: trackskew = 0; ! 462: } ! 463: if (interleave == 0) { ! 464: interleave = lp->d_interleave; ! 465: if (interleave <= 0) ! 466: interleave = 1; ! 467: } ! 468: if (fsize == 0) { ! 469: fsize = pp->p_fsize; ! 470: if (fsize <= 0) ! 471: fsize = MAX(DFL_FRAGSIZE, lp->d_secsize); ! 472: } ! 473: if (bsize == 0) { ! 474: bsize = pp->p_frag * pp->p_fsize; ! 475: if (bsize <= 0) ! 476: bsize = MIN(DFL_BLKSIZE, 8 * fsize); ! 477: } ! 478: if (minfree < 10 && opt != FS_OPTSPACE) { ! 479: fprintf(stderr, "Warning: changing optimization to space "); ! 480: fprintf(stderr, "because minfree is less than 10%%\n"); ! 481: opt = FS_OPTSPACE; ! 482: } ! 483: if (trackspares == -1) { ! 484: trackspares = lp->d_sparespertrack; ! 485: if (trackspares < 0) ! 486: trackspares = 0; ! 487: } ! 488: nphyssectors = nsectors + trackspares; ! 489: if (cylspares == -1) { ! 490: cylspares = lp->d_sparespercyl; ! 491: if (cylspares < 0) ! 492: cylspares = 0; ! 493: } ! 494: secpercyl = nsectors * ntracks - cylspares; ! 495: if (secpercyl != lp->d_secpercyl) ! 496: fprintf(stderr, "%s (%d) %s (%d)\n", ! 497: "Warning: calculated sectors per cylinder", secpercyl, ! 498: "disagrees with disk label", lp->d_secpercyl); ! 499: if (maxbpg == 0) ! 500: maxbpg = MAXBLKPG(bsize); ! 501: headswitch = lp->d_headswitch; ! 502: trackseek = lp->d_trkseek; ! 503: bbsize = lp->d_bbsize; ! 504: sbsize = lp->d_sbsize; ! 505: oldpartition = *pp; ! 506: #ifdef tahoe ! 507: realsectorsize = sectorsize; ! 508: if (sectorsize != DEV_BSIZE) { /* XXX */ ! 509: int secperblk = DEV_BSIZE / sectorsize; ! 510: ! 511: sectorsize = DEV_BSIZE; ! 512: nsectors /= secperblk; ! 513: nphyssectors /= secperblk; ! 514: secpercyl /= secperblk; ! 515: fssize /= secperblk; ! 516: pp->p_size /= secperblk; ! 517: } ! 518: #endif ! 519: mkfs(pp, special, fsi, fso); ! 520: #ifdef tahoe ! 521: if (realsectorsize != DEV_BSIZE) ! 522: pp->p_size *= DEV_BSIZE / realsectorsize; ! 523: #endif ! 524: if (!Nflag && bcmp(pp, &oldpartition, sizeof(oldpartition))) ! 525: rewritelabel(special, fso, lp); ! 526: exit(0); ! 527: } ! 528: ! 529: #ifdef COMPAT ! 530: struct disklabel * ! 531: getdisklabel(s, fd, type) ! 532: char *s, *type; ! 533: int fd; ! 534: { ! 535: static struct disklabel lab; ! 536: struct disklabel *getdiskbyname(); ! 537: ! 538: if (ioctl(fd, DIOCGDINFO, (char *)&lab) < 0) { ! 539: if (type == NULL) { ! 540: perror("ioctl (GDINFO)"); ! 541: fatal( ! 542: "%s: can't read disk label; disk type must be specified", s); ! 543: } ! 544: unlabelled++; ! 545: return (getdiskbyname(type)); ! 546: } ! 547: return (&lab); ! 548: } ! 549: #else ! 550: struct disklabel * ! 551: getdisklabel(s, fd) ! 552: char *s; ! 553: int fd; ! 554: { ! 555: static struct disklabel lab; ! 556: ! 557: if (ioctl(fd, DIOCGDINFO, (char *)&lab) < 0) { ! 558: perror("ioctl (GDINFO)"); ! 559: fatal("%s: can't read disk label", s); ! 560: } ! 561: return (&lab); ! 562: } ! 563: #endif ! 564: ! 565: rewritelabel(s, fd, lp) ! 566: char *s; ! 567: int fd; ! 568: register struct disklabel *lp; ! 569: { ! 570: ! 571: #ifdef COMPAT ! 572: if (unlabelled) ! 573: return; ! 574: #endif ! 575: lp->d_checksum = 0; ! 576: lp->d_checksum = dkcksum(lp); ! 577: if (ioctl(fd, DIOCWDINFO, (char *)lp) < 0) { ! 578: perror("ioctl (WDINFO)"); ! 579: fatal("%s: can't rewrite disk label", s); ! 580: } ! 581: #if vax ! 582: if (lp->d_type == DTYPE_SMD && lp->d_flags & D_BADSECT) { ! 583: register i; ! 584: int cfd; ! 585: daddr_t alt; ! 586: char specname[64]; ! 587: char blk[1024]; ! 588: char *cp; ! 589: ! 590: /* ! 591: * Make name for 'c' partition. ! 592: */ ! 593: strcpy(specname, s); ! 594: cp = specname + strlen(specname) - 1; ! 595: if (!isdigit(*cp)) ! 596: *cp = 'c'; ! 597: cfd = open(specname, O_WRONLY); ! 598: if (cfd < 0) { ! 599: perror(specname); ! 600: exit(2); ! 601: } ! 602: bzero(blk, sizeof(blk)); ! 603: *(struct disklabel *)(blk + LABELOFFSET) = *lp; ! 604: alt = lp->d_ncylinders * lp->d_secpercyl - lp->d_nsectors; ! 605: for (i = 1; i < 11 && i < lp->d_nsectors; i += 2) { ! 606: if (lseek(cfd, (off_t)(alt + i) * lp->d_secsize, L_SET) == -1) { ! 607: perror("lseek to badsector area"); ! 608: exit(30); ! 609: } ! 610: if (write(cfd, blk, lp->d_secsize) < lp->d_secsize) { ! 611: int oerrno = errno; ! 612: fprintf(stderr, "alternate label %d ", i/2); ! 613: errno = oerrno; ! 614: perror("write"); ! 615: } ! 616: } ! 617: } ! 618: #endif ! 619: } ! 620: ! 621: /*VARARGS*/ ! 622: fatal(fmt, arg1, arg2) ! 623: char *fmt; ! 624: { ! 625: ! 626: fprintf(stderr, "newfs: "); ! 627: fprintf(stderr, fmt, arg1, arg2); ! 628: putc('\n', stderr); ! 629: exit(10); ! 630: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.