130715Sbostic /* 230715Sbostic * Copyright (c) 1987 Regents of the University of California. 330715Sbostic * All rights reserved. The Berkeley software License Agreement 430715Sbostic * specifies the terms and conditions for redistribution. 530715Sbostic */ 630715Sbostic 730418Skarels #ifndef lint 8*34032Skarels static char sccsid[] = "@(#)disklabel.c 5.12 (Berkeley) 04/20/88"; 930418Skarels /* from static char sccsid[] = "@(#)disklabel.c 1.2 (Symmetric) 11/28/85"; */ 1030418Skarels #endif 1130418Skarels 1230418Skarels #include <stdio.h> 1330418Skarels #include <ctype.h> 1430418Skarels #include <sys/param.h> 1530715Sbostic #include <sys/signal.h> 1630418Skarels #include <sys/errno.h> 1730418Skarels #include <sys/file.h> 1830715Sbostic #include <sys/ioctl.h> 1930677Skarels #include <sys/fs.h> 2030715Sbostic #include <strings.h> 2130418Skarels #define DKTYPENAMES 2230418Skarels #include <sys/disklabel.h> 2330418Skarels 2430418Skarels /* 2530418Skarels * Disklabel: read and write disklabels. 2630418Skarels * The label is usually placed on one of the first sectors of the disk. 2730418Skarels * Many machines (VAX 11/750) also place a bootstrap in the same area, 2830418Skarels * in which case the label is embedded in the bootstrap. 2930418Skarels * The bootstrap source must leave space at the proper offset 3030418Skarels * for the label on such machines. 3130418Skarels */ 3230418Skarels 3330677Skarels #ifdef vax 3430677Skarels #define RAWPARTITION 'c' 3530677Skarels #else 3630677Skarels #define RAWPARTITION 'a' 3730677Skarels #endif 3830677Skarels 3930677Skarels #ifndef BBSIZE 4030418Skarels #define BBSIZE 8192 /* size of boot area, with label */ 4130677Skarels #endif 4230418Skarels 4330418Skarels #ifdef vax 4430418Skarels #define BOOT /* also have bootstrap in "boot area" */ 4530418Skarels #define BOOTDIR "/usr/mdec" /* source of boot binaries */ 4630677Skarels #else 4730677Skarels #ifdef lint 4830677Skarels #define BOOT 4930418Skarels #endif 5030677Skarels #endif 5130418Skarels 5230715Sbostic #define DEFEDITOR "/usr/ucb/vi" 5330715Sbostic #define streq(a,b) (strcmp(a,b) == 0) 5430715Sbostic 5530715Sbostic #ifdef BOOT 5630418Skarels char *xxboot; 5730418Skarels char *bootxx; 5830715Sbostic #endif 5931617Skarels 6031617Skarels char *dkname; 6130418Skarels char *specname; 6230715Sbostic char tmpfil[] = "/tmp/EdDk.aXXXXXX"; 6330418Skarels 6430418Skarels extern int errno; 6530418Skarels char namebuf[BBSIZE], *np = namebuf; 6631617Skarels struct disklabel lab; 6731617Skarels struct disklabel *readlabel(), *makebootarea(); 6830418Skarels char bootarea[BBSIZE]; 69*34032Skarels char boot0[MAXPATHLEN]; 70*34032Skarels char boot1[MAXPATHLEN]; 7130418Skarels 72*34032Skarels enum { UNSPEC, EDIT, NOWRITE, READ, RESTORE, WRITE, WRITEABLE } op = UNSPEC; 7330418Skarels 7430677Skarels int rflag; 7530677Skarels 76*34032Skarels #ifdef DEBUG 77*34032Skarels int debug; 78*34032Skarels #endif 79*34032Skarels 8030418Skarels main(argc, argv) 8130418Skarels int argc; 8230418Skarels char *argv[]; 8330418Skarels { 84*34032Skarels extern int optind; 8530418Skarels register struct disklabel *lp; 86*34032Skarels FILE *t; 87*34032Skarels int ch, f; 8830715Sbostic char *name = 0, *type; 8930418Skarels 90*34032Skarels while ((ch = getopt(argc, argv, "NRWerw")) != EOF) 91*34032Skarels switch (ch) { 92*34032Skarels case 'N': 93*34032Skarels if (op != UNSPEC) 94*34032Skarels usage(); 95*34032Skarels op = NOWRITE; 96*34032Skarels break; 9730715Sbostic case 'R': 98*34032Skarels if (op != UNSPEC) 99*34032Skarels usage(); 10030715Sbostic op = RESTORE; 10130715Sbostic break; 102*34032Skarels case 'W': 103*34032Skarels if (op != UNSPEC) 104*34032Skarels usage(); 105*34032Skarels op = WRITEABLE; 106*34032Skarels break; 10730715Sbostic case 'e': 108*34032Skarels if (op != UNSPEC) 109*34032Skarels usage(); 11030715Sbostic op = EDIT; 11130715Sbostic break; 11230715Sbostic case 'r': 11330715Sbostic ++rflag; 11430715Sbostic break; 11530715Sbostic case 'w': 116*34032Skarels if (op != UNSPEC) 117*34032Skarels usage(); 11830715Sbostic op = WRITE; 11930715Sbostic break; 120*34032Skarels #ifdef DEBUG 121*34032Skarels case 'd': 122*34032Skarels debug++; 123*34032Skarels break; 124*34032Skarels #endif 12530715Sbostic case '?': 12630715Sbostic default: 12730715Sbostic usage(); 12830715Sbostic } 12930715Sbostic argc -= optind; 13030715Sbostic argv += optind; 131*34032Skarels if (op == UNSPEC) 132*34032Skarels op = READ; 13330715Sbostic if (argc < 1) 13430715Sbostic usage(); 13530715Sbostic 13630715Sbostic dkname = argv[0]; 13730418Skarels if (dkname[0] != '/') { 13832439Sbostic (void)sprintf(np, "/dev/r%s%c", dkname, RAWPARTITION); 13930418Skarels specname = np; 14030418Skarels np += strlen(specname) + 1; 14130418Skarels } else 14230418Skarels specname = dkname; 14330418Skarels f = open(specname, op == READ ? O_RDONLY : O_RDWR); 14430418Skarels if (f < 0 && errno == ENOENT && dkname[0] != '/') { 14532439Sbostic (void)sprintf(specname, "/dev/r%s", dkname); 14630418Skarels np = namebuf + strlen(specname) + 1; 14730418Skarels f = open(specname, op == READ ? O_RDONLY : O_RDWR); 14830418Skarels } 14930418Skarels if (f < 0) 15030418Skarels Perror(specname); 15130418Skarels 15230715Sbostic switch(op) { 15330715Sbostic case EDIT: 15430715Sbostic if (argc != 1) 15530715Sbostic usage(); 156*34032Skarels lp = readlabel(f); 15730715Sbostic if (edit(lp)) 15830715Sbostic writelabel(f, bootarea, lp); 15930715Sbostic break; 160*34032Skarels case NOWRITE: { 161*34032Skarels int flag = 0; 162*34032Skarels if (ioctl(f, DIOCWLABEL, (char *)&flag) < 0) 163*34032Skarels Perror("ioctl DIOCWLABEL"); 164*34032Skarels break; 165*34032Skarels } 16630418Skarels case READ: 16730715Sbostic if (argc != 1) 16830715Sbostic usage(); 169*34032Skarels lp = readlabel(f); 17030418Skarels display(stdout, lp); 17130715Sbostic (void) checklabel(lp); 17230418Skarels break; 17330715Sbostic case RESTORE: 17430715Sbostic #ifdef BOOT 175*34032Skarels if (rflag) { 176*34032Skarels if (argc == 4) { /* [ priboot secboot ] */ 177*34032Skarels xxboot = argv[2]; 178*34032Skarels bootxx = argv[3]; 179*34032Skarels lab.d_secsize = DEV_BSIZE; /* XXX */ 180*34032Skarels lab.d_bbsize = BBSIZE; /* XXX */ 181*34032Skarels } 182*34032Skarels else if (argc == 3) /* [ disktype ] */ 183*34032Skarels makelabel(argv[2], (char *)NULL, &lab); 184*34032Skarels else { 185*34032Skarels fprintf(stderr, 186*34032Skarels "Must specify either disktype or bootfiles with -r flag of RESTORE option\n"); 187*34032Skarels exit(1); 188*34032Skarels } 189*34032Skarels } 190*34032Skarels else 19131617Skarels #endif 19230715Sbostic if (argc != 2) 19330715Sbostic usage(); 19431617Skarels lp = makebootarea(bootarea, &lab); 19530715Sbostic if (!(t = fopen(argv[1],"r"))) 19630715Sbostic Perror(argv[1]); 19730715Sbostic if (getasciilabel(t, lp)) 19830715Sbostic writelabel(f, bootarea, lp); 19930418Skarels break; 20030418Skarels case WRITE: 20130715Sbostic type = argv[1]; 20230715Sbostic #ifdef BOOT 20330715Sbostic if (argc > 5 || argc < 2) 20430715Sbostic usage(); 20530715Sbostic if (argc > 3) { 20630715Sbostic bootxx = argv[--argc]; 20730715Sbostic xxboot = argv[--argc]; 20830715Sbostic } 20930715Sbostic #else 21030715Sbostic if (argc > 3 || argc < 2) 21130715Sbostic usage(); 21230715Sbostic #endif 21330715Sbostic if (argc > 2) 21430715Sbostic name = argv[--argc]; 21530418Skarels makelabel(type, name, &lab); 21631617Skarels lp = makebootarea(bootarea, &lab); 21730418Skarels *lp = lab; 21830715Sbostic if (checklabel(lp) == 0) 21930715Sbostic writelabel(f, bootarea, lp); 22030418Skarels break; 221*34032Skarels case WRITEABLE: { 222*34032Skarels int flag = 1; 223*34032Skarels if (ioctl(f, DIOCWLABEL, (char *)&flag) < 0) 224*34032Skarels Perror("ioctl DIOCWLABEL"); 225*34032Skarels break; 22630418Skarels } 227*34032Skarels } 22830418Skarels exit(0); 22930418Skarels } 23030418Skarels 231*34032Skarels /* 232*34032Skarels * Construct a prototype disklabel from /etc/disktab. As a side 233*34032Skarels * effect, set the names of the primary and secondary boot files 234*34032Skarels * if specified. 235*34032Skarels */ 23630418Skarels makelabel(type, name, lp) 23730418Skarels char *type, *name; 23830418Skarels register struct disklabel *lp; 23930418Skarels { 24030418Skarels register struct disklabel *dp; 241*34032Skarels char *strcpy(); 24230418Skarels 24330418Skarels dp = getdiskbyname(type); 24430418Skarels if (dp == NULL) { 24530418Skarels fprintf(stderr, "%s: unknown disk type\n", type); 24630418Skarels exit(1); 24730418Skarels } 24830418Skarels *lp = *dp; 249*34032Skarels #ifdef BOOT 250*34032Skarels /* 251*34032Skarels * Check if disktab specifies the bootstraps (b0 or b1). 252*34032Skarels */ 253*34032Skarels if (!xxboot && lp->d_boot0) { 254*34032Skarels if (*lp->d_boot0 != '/') 255*34032Skarels (void)sprintf(boot0, "%s/%s", BOOTDIR, lp->d_boot0); 256*34032Skarels else 257*34032Skarels (void)strcpy(boot0, lp->d_boot0); 258*34032Skarels xxboot = boot0; 259*34032Skarels } 260*34032Skarels if (!bootxx && lp->d_boot1) { 261*34032Skarels if (*lp->d_boot1 != '/') 262*34032Skarels (void)sprintf(boot1, "%s/%s", BOOTDIR, lp->d_boot1); 263*34032Skarels else 264*34032Skarels (void)strcpy(boot1, lp->d_boot1); 265*34032Skarels bootxx = boot1; 266*34032Skarels } 267*34032Skarels /* 268*34032Skarels * If bootstraps not specified anywhere, makebootarea() 269*34032Skarels * will choose ones based on the name of the disk special 270*34032Skarels * file. E.g. /dev/ra0 -> raboot, bootra 271*34032Skarels */ 272*34032Skarels #endif /*BOOT*/ 273*34032Skarels /* d_packname is union d_boot[01], so zero */ 274*34032Skarels bzero(lp->d_packname, sizeof(lp->d_packname)); 27530418Skarels if (name) 276*34032Skarels (void)strncpy(lp->d_packname, name, sizeof(lp->d_packname)); 27730418Skarels } 27830418Skarels 27930418Skarels writelabel(f, boot, lp) 28030418Skarels int f; 28130418Skarels char *boot; 28230418Skarels register struct disklabel *lp; 28330418Skarels { 28430715Sbostic register int i; 285*34032Skarels int flag; 286*34032Skarels off_t lseek(); 28730418Skarels 28830418Skarels lp->d_magic = DISKMAGIC; 28930418Skarels lp->d_magic2 = DISKMAGIC; 29030418Skarels lp->d_checksum = 0; 29130418Skarels lp->d_checksum = dkcksum(lp); 29230677Skarels if (rflag) { 293*34032Skarels /* 294*34032Skarels * First set the kernel disk label, 295*34032Skarels * then write a label to the raw disk. 296*34032Skarels * If the SDINFO ioctl fails because it is unimplemented, 297*34032Skarels * keep going; otherwise, the kernel consistency checks 298*34032Skarels * may prevent us from changing the current (in-core) 299*34032Skarels * label. 300*34032Skarels */ 301*34032Skarels if (ioctl(f, DIOCSDINFO, lp) < 0 && 302*34032Skarels errno != ENODEV && errno != ENOTTY) 303*34032Skarels Perror("ioctl DIOCSDINFO"); 30431617Skarels (void)lseek(f, (off_t)0, L_SET); 305*34032Skarels /* 306*34032Skarels * write enable label sector before write (if necessary), 307*34032Skarels * disable after writing. 308*34032Skarels */ 309*34032Skarels flag = 1; 310*34032Skarels if (ioctl(f, DIOCWLABEL, &flag) < 0) 311*34032Skarels perror("ioctl DIOCWLABEL"); 312*34032Skarels if (write(f, boot, lp->d_bbsize) != lp->d_bbsize) 31330677Skarels Perror("write"); 314*34032Skarels flag = 0; 315*34032Skarels (void) ioctl(f, DIOCWLABEL, &flag); 31630677Skarels } else if (ioctl(f, DIOCWDINFO, lp) < 0) 31730677Skarels Perror("ioctl DIOCWDINFO"); 318*34032Skarels #ifdef vax 31930677Skarels if (lp->d_type == DTYPE_SMD && lp->d_flags & D_BADSECT) { 32030677Skarels daddr_t alt; 32130677Skarels 32230677Skarels alt = lp->d_ncylinders * lp->d_secpercyl - lp->d_nsectors; 32330677Skarels for (i = 1; i < 11 && i < lp->d_nsectors; i += 2) { 32430715Sbostic (void)lseek(f, (off_t)((alt + i) * lp->d_secsize), L_SET); 32530677Skarels if (write(f, boot, lp->d_secsize) < lp->d_secsize) { 32630677Skarels int oerrno = errno; 32730677Skarels fprintf(stderr, "alternate label %d ", i/2); 32830677Skarels errno = oerrno; 32930677Skarels perror("write"); 33030677Skarels } 33130418Skarels } 33230418Skarels } 33330419Skarels #endif 33430418Skarels } 33530418Skarels 33630418Skarels /* 33731617Skarels * Fetch disklabel for disk. 33831617Skarels * Use ioctl to get label unless -r flag is given. 33930418Skarels */ 34030418Skarels struct disklabel * 341*34032Skarels readlabel(f) 342*34032Skarels int f; 34330418Skarels { 34430418Skarels register struct disklabel *lp; 34530418Skarels 346*34032Skarels if (rflag) { 34731617Skarels if (read(f, bootarea, BBSIZE) < BBSIZE) 34831401Skarels Perror(specname); 34931617Skarels for (lp = (struct disklabel *)bootarea; 35031617Skarels lp <= (struct disklabel *)(bootarea + BBSIZE - sizeof(*lp)); 35130677Skarels lp = (struct disklabel *)((char *)lp + 16)) 35230677Skarels if (lp->d_magic == DISKMAGIC && 35330677Skarels lp->d_magic2 == DISKMAGIC) 35430677Skarels break; 35531617Skarels if (lp > (struct disklabel *)(bootarea+BBSIZE-sizeof(*lp)) || 35630677Skarels lp->d_magic != DISKMAGIC || lp->d_magic2 != DISKMAGIC || 35730677Skarels dkcksum(lp) != 0) { 35830677Skarels fprintf(stderr, 35930418Skarels "Bad pack magic number (label is damaged, or pack is unlabeled)\n"); 360*34032Skarels /* lp = (struct disklabel *)(bootarea + LABELOFFSET); */ 361*34032Skarels exit (1); 36230677Skarels } 363*34032Skarels } else { 364*34032Skarels lp = &lab; 365*34032Skarels if (ioctl(f, DIOCGDINFO, lp) < 0) 366*34032Skarels Perror("ioctl DIOCGDINFO"); 36730418Skarels } 36830418Skarels return (lp); 36930418Skarels } 37030418Skarels 37130418Skarels struct disklabel * 37231617Skarels makebootarea(boot, dp) 37330418Skarels char *boot; 37430418Skarels register struct disklabel *dp; 37530418Skarels { 37630418Skarels struct disklabel *lp; 37730418Skarels register char *p; 37830418Skarels int b; 37930418Skarels #ifdef BOOT 38030715Sbostic char *dkbasename; 381*34032Skarels #endif /*BOOT*/ 38230715Sbostic 383*34032Skarels lp = (struct disklabel *)(boot + (LABELSECTOR * dp->d_secsize) + 384*34032Skarels LABELOFFSET); 385*34032Skarels #ifdef BOOT 386*34032Skarels if (!rflag) 387*34032Skarels return (lp); 388*34032Skarels 389*34032Skarels if (xxboot == NULL || bootxx == NULL) { 39030418Skarels dkbasename = np; 39130418Skarels if ((p = rindex(dkname, '/')) == NULL) 39230418Skarels p = dkname; 39330418Skarels else 39430418Skarels p++; 39530418Skarels while (*p && !isdigit(*p)) 39630418Skarels *np++ = *p++; 39730418Skarels *np++ = '\0'; 39830418Skarels 399*34032Skarels if (xxboot == NULL) { 400*34032Skarels (void)sprintf(np, "%s/%sboot", BOOTDIR, dkbasename); 401*34032Skarels if (access(np, F_OK) < 0 && dkbasename[0] == 'r') 402*34032Skarels dkbasename++; 403*34032Skarels xxboot = np; 404*34032Skarels (void)sprintf(xxboot, "%s/%sboot", BOOTDIR, dkbasename); 405*34032Skarels np += strlen(xxboot) + 1; 406*34032Skarels } 407*34032Skarels if (bootxx == NULL) { 408*34032Skarels (void)sprintf(np, "%s/boot%s", BOOTDIR, dkbasename); 409*34032Skarels if (access(np, F_OK) < 0 && dkbasename[0] == 'r') 410*34032Skarels dkbasename++; 411*34032Skarels bootxx = np; 412*34032Skarels (void)sprintf(bootxx, "%s/boot%s", BOOTDIR, dkbasename); 413*34032Skarels np += strlen(bootxx) + 1; 414*34032Skarels } 41530418Skarels } 416*34032Skarels #ifdef DEBUG 417*34032Skarels if (debug) 418*34032Skarels fprintf(stderr, "bootstraps: xxboot = %s, bootxx = %s\n", 419*34032Skarels xxboot, bootxx); 420*34032Skarels #endif 42130418Skarels 42230418Skarels b = open(xxboot, O_RDONLY); 42330418Skarels if (b < 0) 42430418Skarels Perror(xxboot); 42530715Sbostic if (read(b, boot, (int)dp->d_secsize) < 0) 42630418Skarels Perror(xxboot); 42730418Skarels close(b); 42830418Skarels b = open(bootxx, O_RDONLY); 42930418Skarels if (b < 0) 43030418Skarels Perror(bootxx); 43130715Sbostic if (read(b, &boot[dp->d_secsize], (int)(dp->d_bbsize-dp->d_secsize)) < 0) 43230418Skarels Perror(bootxx); 43330715Sbostic (void)close(b); 434*34032Skarels #endif /*BOOT*/ 43530418Skarels 43630418Skarels for (p = (char *)lp; p < (char *)lp + sizeof(struct disklabel); p++) 43730418Skarels if (*p) { 43830418Skarels fprintf(stderr, 43930418Skarels "Bootstrap doesn't leave room for disk label\n"); 44030418Skarels exit(2); 44130418Skarels } 44230418Skarels return (lp); 44330418Skarels } 44430418Skarels 44530418Skarels display(f, lp) 44630418Skarels FILE *f; 44730418Skarels register struct disklabel *lp; 44830418Skarels { 44930715Sbostic register int i, j; 45030418Skarels register struct partition *pp; 45130418Skarels 45230418Skarels fprintf(f, "# %s:\n", specname); 45330418Skarels if ((unsigned) lp->d_type < DKMAXTYPES) 45430418Skarels fprintf(f, "type: %s\n", dktypenames[lp->d_type]); 45530418Skarels else 45630418Skarels fprintf(f, "type: %d\n", lp->d_type); 45730418Skarels fprintf(f, "disk: %.*s\n", sizeof(lp->d_typename), lp->d_typename); 458*34032Skarels fprintf(f, "label: %.*s\n", sizeof(lp->d_packname), lp->d_packname); 45931401Skarels fprintf(f, "flags:"); 46030418Skarels if (lp->d_flags & D_REMOVABLE) 46131401Skarels fprintf(f, " removeable"); 46230418Skarels if (lp->d_flags & D_ECC) 46331401Skarels fprintf(f, " ecc"); 46430418Skarels if (lp->d_flags & D_BADSECT) 46531401Skarels fprintf(f, " badsect"); 46630418Skarels fprintf(f, "\n"); 46730418Skarels fprintf(f, "bytes/sector: %d\n", lp->d_secsize); 46830418Skarels fprintf(f, "sectors/track: %d\n", lp->d_nsectors); 46930418Skarels fprintf(f, "tracks/cylinder: %d\n", lp->d_ntracks); 47031386Skarels fprintf(f, "sectors/cylinder: %d\n", lp->d_secpercyl); 47130418Skarels fprintf(f, "cylinders: %d\n", lp->d_ncylinders); 47230715Sbostic fprintf(f, "rpm: %d\n", lp->d_rpm); 47330418Skarels fprintf(f, "interleave: %d\n", lp->d_interleave); 47430418Skarels fprintf(f, "trackskew: %d\n", lp->d_trackskew); 47530418Skarels fprintf(f, "cylinderskew: %d\n", lp->d_cylskew); 47630418Skarels fprintf(f, "headswitch: %d\t\t# milliseconds\n", lp->d_headswitch); 47730418Skarels fprintf(f, "track-to-track seek: %d\t# milliseconds\n", lp->d_trkseek); 47830418Skarels fprintf(f, "drivedata: "); 47930418Skarels for (i = NDDATA - 1; i >= 0; i--) 48030418Skarels if (lp->d_drivedata[i]) 48130418Skarels break; 48230418Skarels if (i < 0) 48330418Skarels i = 0; 48430418Skarels for (j = 0; j <= i; j++) 48530418Skarels fprintf(f, "%d ", lp->d_drivedata[j]); 48630418Skarels fprintf(f, "\n\n%d partitions:\n", lp->d_npartitions); 48730863Skarels fprintf(f, 48830863Skarels "# size offset fstype [fsize bsize cpg]\n"); 48930418Skarels pp = lp->d_partitions; 49030418Skarels for (i = 0; i < lp->d_npartitions; i++, pp++) { 49130418Skarels if (pp->p_size) { 49230863Skarels fprintf(f, " %c: %8d %8d ", 'a' + i, 49330863Skarels pp->p_size, pp->p_offset); 49430418Skarels if ((unsigned) pp->p_fstype < FSMAXTYPES) 49530418Skarels fprintf(f, "%8.8s", fstypenames[pp->p_fstype]); 49630418Skarels else 49730418Skarels fprintf(f, "%8d", pp->p_fstype); 49830863Skarels switch (pp->p_fstype) { 49930863Skarels 50030863Skarels case FS_UNUSED: /* XXX */ 50130863Skarels fprintf(f, " %5d %5d %5.5s ", 50230863Skarels pp->p_fsize, pp->p_fsize * pp->p_frag, ""); 50330863Skarels break; 50430863Skarels 50530863Skarels case FS_BSDFFS: 50630863Skarels fprintf(f, " %5d %5d %5d ", 50730863Skarels pp->p_fsize, pp->p_fsize * pp->p_frag, 50830863Skarels pp->p_cpg); 50930863Skarels break; 51030863Skarels 51130863Skarels default: 51230863Skarels fprintf(f, "%20.20s", ""); 51330863Skarels break; 51430863Skarels } 51530418Skarels fprintf(f, "\t# (Cyl. %4d", 51630418Skarels pp->p_offset / lp->d_secpercyl); 51730418Skarels if (pp->p_offset % lp->d_secpercyl) 51830418Skarels putc('*', f); 51930418Skarels else 52030418Skarels putc(' ', f); 52130418Skarels fprintf(f, "- %d", 52230418Skarels (pp->p_offset + 52330418Skarels pp->p_size + lp->d_secpercyl - 1) / 52430418Skarels lp->d_secpercyl - 1); 52530418Skarels if (pp->p_size % lp->d_secpercyl) 52630418Skarels putc('*', f); 52730863Skarels fprintf(f, ")\n"); 52830418Skarels } 52930418Skarels } 53032121Stef fflush(f); 53130418Skarels } 53230418Skarels 53330715Sbostic edit(lp) 53430715Sbostic struct disklabel *lp; 53530418Skarels { 53630715Sbostic register int c; 53730715Sbostic struct disklabel label; 53830715Sbostic FILE *fd; 53930715Sbostic char *mktemp(); 54030715Sbostic 54130715Sbostic (void) mktemp(tmpfil); 54230715Sbostic fd = fopen(tmpfil, "w"); 54330715Sbostic if (fd == NULL) { 54430715Sbostic fprintf(stderr, "%s: Can't create\n", tmpfil); 54530715Sbostic return (0); 54630715Sbostic } 54730715Sbostic (void)fchmod(fd, 0600); 54830715Sbostic display(fd, lp); 54930715Sbostic fclose(fd); 55030715Sbostic for (;;) { 55130715Sbostic if (!editit()) 55230715Sbostic break; 55330715Sbostic fd = fopen(tmpfil, "r"); 55430715Sbostic if (fd == NULL) { 555*34032Skarels fprintf(stderr, "%s: Can't reopen for reading\n", 556*34032Skarels tmpfil); 55730715Sbostic break; 55830715Sbostic } 55930863Skarels bzero((char *)&label, sizeof(label)); 56030715Sbostic if (getasciilabel(fd, &label)) { 56130715Sbostic *lp = label; 56230715Sbostic (void) unlink(tmpfil); 56330715Sbostic return (1); 56430715Sbostic } 56530715Sbostic printf("re-edit the label? [y]: "); fflush(stdout); 56630715Sbostic c = getchar(); 56730715Sbostic if (c != EOF && c != (int)'\n') 56830715Sbostic while (getchar() != (int)'\n') 56930715Sbostic ; 57030715Sbostic if (c == (int)'n') 57130715Sbostic break; 57230715Sbostic } 57330715Sbostic (void) unlink(tmpfil); 57430715Sbostic return (0); 57530418Skarels } 57630418Skarels 57730715Sbostic editit() 57830715Sbostic { 57930715Sbostic register int pid, xpid; 58030715Sbostic int stat, omask; 58130715Sbostic extern char *getenv(); 58230418Skarels 58330715Sbostic omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGHUP)); 58430715Sbostic while ((pid = fork()) < 0) { 58530715Sbostic extern int errno; 58630715Sbostic 58730715Sbostic if (errno == EPROCLIM) { 58830715Sbostic fprintf(stderr, "You have too many processes\n"); 58930715Sbostic return(0); 59030715Sbostic } 59130715Sbostic if (errno != EAGAIN) { 59230715Sbostic perror("fork"); 59330715Sbostic return(0); 59430715Sbostic } 59530715Sbostic sleep(1); 59630715Sbostic } 59730715Sbostic if (pid == 0) { 59830715Sbostic register char *ed; 59930715Sbostic 60030715Sbostic sigsetmask(omask); 60130715Sbostic setgid(getgid()); 60230715Sbostic setuid(getuid()); 60330715Sbostic if ((ed = getenv("EDITOR")) == (char *)0) 60430715Sbostic ed = DEFEDITOR; 60530715Sbostic execlp(ed, ed, tmpfil, 0); 60630715Sbostic perror(ed); 60730715Sbostic exit(1); 60830715Sbostic } 60930715Sbostic while ((xpid = wait(&stat)) >= 0) 61030715Sbostic if (xpid == pid) 61130715Sbostic break; 61230715Sbostic sigsetmask(omask); 61330715Sbostic return(!stat); 61430715Sbostic } 61530715Sbostic 61630715Sbostic char * 61730715Sbostic skip(cp) 61830715Sbostic register char *cp; 61930715Sbostic { 62030715Sbostic 62130715Sbostic while (*cp != '\0' && isspace(*cp)) 62230715Sbostic cp++; 62330715Sbostic if (*cp == '\0' || *cp == '#') 62430715Sbostic return ((char *)NULL); 62530715Sbostic return (cp); 62630715Sbostic } 62730715Sbostic 62830715Sbostic char * 62930715Sbostic word(cp) 63030715Sbostic register char *cp; 63130715Sbostic { 63230715Sbostic register char c; 63330715Sbostic 63431401Skarels while (*cp != '\0' && !isspace(*cp) && *cp != '#') 63531401Skarels cp++; 63630715Sbostic if ((c = *cp) != '\0') { 63730715Sbostic *cp++ = '\0'; 63830715Sbostic if (c != '#') 63930715Sbostic return (skip(cp)); 64030715Sbostic } 64130715Sbostic return ((char *)NULL); 64230715Sbostic } 64330715Sbostic 64430418Skarels /* 64530418Skarels * Read an ascii label in from fd f, 64630418Skarels * in the same format as that put out by display(), 64730418Skarels * and fill in lp. 64830418Skarels */ 64930418Skarels getasciilabel(f, lp) 65030715Sbostic FILE *f; 65130418Skarels register struct disklabel *lp; 65230418Skarels { 65330715Sbostic register char **cpp, *cp; 65430863Skarels register struct partition *pp; 65530715Sbostic char *tp, *s, line[BUFSIZ]; 65630715Sbostic int v, lineno = 0, errors = 0; 65730715Sbostic 65830715Sbostic lp->d_bbsize = BBSIZE; /* XXX */ 65930715Sbostic lp->d_sbsize = SBSIZE; /* XXX */ 66030715Sbostic while (fgets(line, sizeof(line) - 1, f)) { 66130715Sbostic lineno++; 66230715Sbostic if (cp = index(line,'\n')) 66330715Sbostic *cp = '\0'; 66430715Sbostic cp = skip(line); 66530715Sbostic if (cp == NULL) 66630715Sbostic continue; 66730715Sbostic tp = index(cp, ':'); 66830715Sbostic if (tp == NULL) { 66930715Sbostic fprintf(stderr, "line %d: syntax error\n", lineno); 67030715Sbostic errors++; 67130715Sbostic continue; 67230715Sbostic } 67330715Sbostic *tp++ = '\0', tp = skip(tp); 67430715Sbostic if (streq(cp, "type")) { 67530715Sbostic if (tp == NULL) 67630715Sbostic tp = "unknown"; 67730715Sbostic cpp = dktypenames; 67830715Sbostic for (; cpp < &dktypenames[DKMAXTYPES]; cpp++) 67930715Sbostic if ((s = *cpp) && streq(s, tp)) { 68030715Sbostic lp->d_type = cpp - dktypenames; 68130715Sbostic goto next; 68230715Sbostic } 68330715Sbostic v = atoi(tp); 68430715Sbostic if ((unsigned)v >= DKMAXTYPES) 68530715Sbostic fprintf(stderr, "line %d:%s %d\n", lineno, 68630715Sbostic "Warning, unknown disk type", v); 68730715Sbostic lp->d_type = v; 68830715Sbostic continue; 68930715Sbostic } 69030715Sbostic if (streq(cp, "flags")) { 691*34032Skarels for (v = 0; (cp = tp) && *cp != '\0';) { 692*34032Skarels tp = word(cp); 69330715Sbostic if (streq(cp, "removeable")) 69430715Sbostic v |= D_REMOVABLE; 69530715Sbostic else if (streq(cp, "ecc")) 69630715Sbostic v |= D_ECC; 69730715Sbostic else if (streq(cp, "badsect")) 69830715Sbostic v |= D_BADSECT; 69930715Sbostic else { 70030715Sbostic fprintf(stderr, 70130715Sbostic "line %d: %s: bad flag\n", 70230715Sbostic lineno, cp); 70330715Sbostic errors++; 70430715Sbostic } 70530715Sbostic } 70630715Sbostic lp->d_flags = v; 70730715Sbostic continue; 70830715Sbostic } 70930715Sbostic if (streq(cp, "drivedata")) { 71030715Sbostic register int i; 71130715Sbostic 71231386Skarels for (i = 0; (cp = tp) && *cp != '\0' && i < NDDATA;) { 71330715Sbostic lp->d_drivedata[i++] = atoi(cp); 71431386Skarels tp = word(cp); 71530715Sbostic } 71630715Sbostic continue; 71730715Sbostic } 71830715Sbostic if (sscanf(cp, "%d partitions", &v) == 1) { 71930863Skarels if (v == 0 || (unsigned)v > MAXPARTITIONS) { 72030715Sbostic fprintf(stderr, 72130715Sbostic "line %d: bad # of partitions\n", lineno); 72230863Skarels lp->d_npartitions = MAXPARTITIONS; 72330863Skarels errors++; 72430863Skarels } else 72530715Sbostic lp->d_npartitions = v; 72630715Sbostic continue; 72730715Sbostic } 72830715Sbostic if (tp == NULL) 72930715Sbostic tp = ""; 73030715Sbostic if (streq(cp, "disk")) { 73130715Sbostic strncpy(lp->d_typename, tp, sizeof (lp->d_typename)); 73230715Sbostic continue; 73330715Sbostic } 73430715Sbostic if (streq(cp, "label")) { 735*34032Skarels strncpy(lp->d_packname, tp, sizeof (lp->d_packname)); 73630715Sbostic continue; 73730715Sbostic } 73830715Sbostic if (streq(cp, "bytes/sector")) { 73930715Sbostic v = atoi(tp); 74030715Sbostic if (v <= 0 || (v % 512) != 0) { 74130715Sbostic fprintf(stderr, 74230715Sbostic "line %d: %s: bad sector size\n", 74330715Sbostic lineno, tp); 74430715Sbostic errors++; 74530715Sbostic } else 74630715Sbostic lp->d_secsize = v; 74730715Sbostic continue; 74830715Sbostic } 74930715Sbostic if (streq(cp, "sectors/track")) { 75030715Sbostic v = atoi(tp); 75130715Sbostic if (v <= 0) { 75230715Sbostic fprintf(stderr, "line %d: %s: bad %s\n", 75330715Sbostic lineno, tp, cp); 75430715Sbostic errors++; 75530715Sbostic } else 75630715Sbostic lp->d_nsectors = v; 75730715Sbostic continue; 75830715Sbostic } 75931386Skarels if (streq(cp, "sectors/cylinder")) { 76031386Skarels v = atoi(tp); 76131386Skarels if (v <= 0) { 76231386Skarels fprintf(stderr, "line %d: %s: bad %s\n", 76331386Skarels lineno, tp, cp); 76431386Skarels errors++; 76531386Skarels } else 76631386Skarels lp->d_secpercyl = v; 76731386Skarels continue; 76831386Skarels } 76930715Sbostic if (streq(cp, "tracks/cylinder")) { 77030715Sbostic v = atoi(tp); 77130715Sbostic if (v <= 0) { 77230715Sbostic fprintf(stderr, "line %d: %s: bad %s\n", 77330715Sbostic lineno, tp, cp); 77430715Sbostic errors++; 77530715Sbostic } else 77630715Sbostic lp->d_ntracks = v; 77730715Sbostic continue; 77830715Sbostic } 77930715Sbostic if (streq(cp, "cylinders")) { 78030715Sbostic v = atoi(tp); 78130715Sbostic if (v <= 0) { 78230715Sbostic fprintf(stderr, "line %d: %s: bad %s\n", 78330715Sbostic lineno, tp, cp); 78430715Sbostic errors++; 78530715Sbostic } else 78630715Sbostic lp->d_ncylinders = v; 78730715Sbostic continue; 78830715Sbostic } 78930715Sbostic if (streq(cp, "rpm")) { 79030715Sbostic v = atoi(tp); 79130715Sbostic if (v <= 0) { 79230715Sbostic fprintf(stderr, "line %d: %s: bad %s\n", 79330715Sbostic lineno, tp, cp); 79430715Sbostic errors++; 79530715Sbostic } else 79630715Sbostic lp->d_rpm = v; 79730715Sbostic continue; 79830715Sbostic } 79930715Sbostic if (streq(cp, "interleave")) { 80030715Sbostic v = atoi(tp); 80130715Sbostic if (v <= 0) { 80230715Sbostic fprintf(stderr, "line %d: %s: bad %s\n", 80330715Sbostic lineno, tp, cp); 80430715Sbostic errors++; 80530715Sbostic } else 80630715Sbostic lp->d_interleave = v; 80730715Sbostic continue; 80830715Sbostic } 80930715Sbostic if (streq(cp, "trackskew")) { 81030715Sbostic v = atoi(tp); 81130715Sbostic if (v < 0) { 81230715Sbostic fprintf(stderr, "line %d: %s: bad %s\n", 81330715Sbostic lineno, tp, cp); 81430715Sbostic errors++; 81530715Sbostic } else 81630715Sbostic lp->d_trackskew = v; 81730715Sbostic continue; 81830715Sbostic } 81930715Sbostic if (streq(cp, "cylinderskew")) { 82030715Sbostic v = atoi(tp); 82130715Sbostic if (v < 0) { 82230715Sbostic fprintf(stderr, "line %d: %s: bad %s\n", 82330715Sbostic lineno, tp, cp); 82430715Sbostic errors++; 82530715Sbostic } else 82630715Sbostic lp->d_cylskew = v; 82730715Sbostic continue; 82830715Sbostic } 82930715Sbostic if (streq(cp, "headswitch")) { 83030715Sbostic v = atoi(tp); 83130715Sbostic if (v < 0) { 83230715Sbostic fprintf(stderr, "line %d: %s: bad %s\n", 83330715Sbostic lineno, tp, cp); 83430715Sbostic errors++; 83530715Sbostic } else 83630715Sbostic lp->d_headswitch = v; 83730715Sbostic continue; 83830715Sbostic } 83930715Sbostic if (streq(cp, "track-to-track seek")) { 84030715Sbostic v = atoi(tp); 84130715Sbostic if (v < 0) { 84230715Sbostic fprintf(stderr, "line %d: %s: bad %s\n", 84330715Sbostic lineno, tp, cp); 84430715Sbostic errors++; 84530715Sbostic } else 84630715Sbostic lp->d_trkseek = v; 84730715Sbostic continue; 84830715Sbostic } 84930715Sbostic if ('a' <= *cp && *cp <= 'z' && cp[1] == '\0') { 85030863Skarels unsigned part = *cp - 'a'; 85130715Sbostic 85230863Skarels if (part > lp->d_npartitions) { 85330715Sbostic fprintf(stderr, 85430715Sbostic "line %d: bad partition name\n", lineno); 85530715Sbostic errors++; 85630715Sbostic continue; 85730715Sbostic } 85830863Skarels pp = &lp->d_partitions[part]; 85930863Skarels #define NXTNUM(n) { \ 86030863Skarels cp = tp, tp = word(cp); \ 86130863Skarels if (tp == NULL) \ 86230863Skarels tp = cp; \ 86330863Skarels (n) = atoi(cp); \ 86430863Skarels } 86530863Skarels 86630863Skarels NXTNUM(v); 86730715Sbostic if (v < 0) { 86830715Sbostic fprintf(stderr, 86930715Sbostic "line %d: %s: bad partition size\n", 87030715Sbostic lineno, cp); 87130715Sbostic errors++; 87230715Sbostic } else 87330863Skarels pp->p_size = v; 87430863Skarels NXTNUM(v); 87530715Sbostic if (v < 0) { 87630715Sbostic fprintf(stderr, 87730715Sbostic "line %d: %s: bad partition offset\n", 87830715Sbostic lineno, cp); 87930715Sbostic errors++; 88030715Sbostic } else 88130863Skarels pp->p_offset = v; 88230715Sbostic cp = tp, tp = word(cp); 88330715Sbostic cpp = fstypenames; 88430715Sbostic for (; cpp < &fstypenames[FSMAXTYPES]; cpp++) 88530715Sbostic if ((s = *cpp) && streq(s, cp)) { 88630863Skarels pp->p_fstype = cpp - fstypenames; 88730863Skarels goto gottype; 88830715Sbostic } 889*34032Skarels if (isdigit(*cp)) 890*34032Skarels v = atoi(cp); 891*34032Skarels else 892*34032Skarels v = FSMAXTYPES; 893*34032Skarels if ((unsigned)v >= FSMAXTYPES) { 89430715Sbostic fprintf(stderr, "line %d: %s %s\n", lineno, 89530715Sbostic "Warning, unknown filesystem type", cp); 896*34032Skarels v = FS_UNUSED; 897*34032Skarels } 89830863Skarels pp->p_fstype = v; 89930863Skarels gottype: 90030863Skarels 90130863Skarels switch (pp->p_fstype) { 90230863Skarels 90330863Skarels case FS_UNUSED: /* XXX */ 90430863Skarels NXTNUM(pp->p_fsize); 90530863Skarels if (pp->p_fsize == 0) 90630863Skarels break; 90730863Skarels NXTNUM(v); 90830863Skarels pp->p_frag = v / pp->p_fsize; 90930863Skarels break; 91030863Skarels 91130863Skarels case FS_BSDFFS: 91230863Skarels NXTNUM(pp->p_fsize); 91330863Skarels if (pp->p_fsize == 0) 91430863Skarels break; 91530863Skarels NXTNUM(v); 91630863Skarels pp->p_frag = v / pp->p_fsize; 91730863Skarels NXTNUM(pp->p_cpg); 91830863Skarels break; 91930863Skarels 92030863Skarels default: 92130863Skarels break; 92230863Skarels } 92330715Sbostic continue; 92430715Sbostic } 92530715Sbostic fprintf(stderr, "line %d: %s: Unknown disklabel field\n", 92630715Sbostic lineno, cp); 92730715Sbostic errors++; 92830715Sbostic next: 92930715Sbostic ; 93030715Sbostic } 93130715Sbostic errors += checklabel(lp); 93230715Sbostic return (errors == 0); 93330418Skarels } 93430418Skarels 93530715Sbostic /* 93630715Sbostic * Check disklabel for errors and fill in 93730715Sbostic * derived fields according to supplied values. 93830715Sbostic */ 93930715Sbostic checklabel(lp) 94030715Sbostic register struct disklabel *lp; 94130418Skarels { 94230715Sbostic register struct partition *pp; 94330715Sbostic int i, errors = 0; 94430715Sbostic char part; 94530418Skarels 94630715Sbostic if (lp->d_secsize == 0) { 94730715Sbostic fprintf(stderr, "sector size %d\n", lp->d_secsize); 94830715Sbostic return (1); 94930715Sbostic } 95030715Sbostic if (lp->d_nsectors == 0) { 95130715Sbostic fprintf(stderr, "sectors/track %d\n", lp->d_nsectors); 95230715Sbostic return (1); 95330715Sbostic } 95430715Sbostic if (lp->d_ntracks == 0) { 95530715Sbostic fprintf(stderr, "tracks/cylinder %d\n", lp->d_ntracks); 95630715Sbostic return (1); 95730715Sbostic } 95830715Sbostic if (lp->d_ncylinders == 0) { 95930715Sbostic fprintf(stderr, "cylinders/unit %d\n", lp->d_ncylinders); 96030715Sbostic errors++; 96130715Sbostic } 96230715Sbostic if (lp->d_rpm == 0) 96330715Sbostic Warning("revolutions/minute %d\n", lp->d_rpm); 96430715Sbostic if (lp->d_secpercyl == 0) 96530715Sbostic lp->d_secpercyl = lp->d_nsectors * lp->d_ntracks; 96630715Sbostic if (lp->d_secperunit == 0) 96730715Sbostic lp->d_secperunit = lp->d_secpercyl * lp->d_ncylinders; 96830715Sbostic if (lp->d_bbsize == 0) { 96930715Sbostic fprintf(stderr, "boot block size %d\n", lp->d_bbsize); 97030715Sbostic errors++; 97130715Sbostic } else if (lp->d_bbsize % lp->d_secsize) 97230715Sbostic Warning("boot block size %% sector-size != 0\n"); 97330715Sbostic if (lp->d_sbsize == 0) { 97430715Sbostic fprintf(stderr, "super block size %d\n", lp->d_sbsize); 97530715Sbostic errors++; 97630715Sbostic } else if (lp->d_sbsize % lp->d_secsize) 97730715Sbostic Warning("super block size %% sector-size != 0\n"); 97830715Sbostic if (lp->d_npartitions > MAXPARTITIONS) 97930715Sbostic Warning("number of partitions (%d) > MAXPARTITIONS (%d)\n", 98030715Sbostic lp->d_npartitions, MAXPARTITIONS); 98130715Sbostic for (i = 0; i < lp->d_npartitions; i++) { 98230715Sbostic part = 'a' + i; 98330715Sbostic pp = &lp->d_partitions[i]; 98430715Sbostic if (pp->p_size == 0 && pp->p_offset != 0) 98530715Sbostic Warning("partition %c: size 0, but offset %d\n", 98630715Sbostic part, pp->p_offset); 98730715Sbostic #ifdef notdef 98830715Sbostic if (pp->p_size % lp->d_secpercyl) 98930715Sbostic Warning("partition %c: size %% cylinder-size != 0\n", 99030715Sbostic part); 99130715Sbostic if (pp->p_offset % lp->d_secpercyl) 99230715Sbostic Warning("partition %c: offset %% cylinder-size != 0\n", 99330715Sbostic part); 99430715Sbostic #endif 99530715Sbostic if (pp->p_offset > lp->d_secperunit) { 99630715Sbostic fprintf(stderr, 99730715Sbostic "partition %c: offset past end of unit\n", part); 99830715Sbostic errors++; 99930715Sbostic } 100030715Sbostic if (pp->p_offset + pp->p_size > lp->d_secperunit) { 100130715Sbostic fprintf(stderr, 100230715Sbostic "partition %c: partition extends past end of unit\n", 100330715Sbostic part); 100430715Sbostic errors++; 100530715Sbostic } 100630715Sbostic } 100730715Sbostic for (; i < MAXPARTITIONS; i++) { 100830715Sbostic part = 'a' + i; 100930715Sbostic pp = &lp->d_partitions[i]; 101030715Sbostic if (pp->p_size || pp->p_offset) 101130715Sbostic Warning("unused partition %c: size %d offset %d\n", 1012*34032Skarels 'a' + i, pp->p_size, pp->p_offset); 101330715Sbostic } 101430715Sbostic return (errors); 101530715Sbostic } 101630715Sbostic 101730715Sbostic /*VARARGS1*/ 101830715Sbostic Warning(fmt, a1, a2, a3, a4, a5) 101930715Sbostic char *fmt; 102030715Sbostic { 102130715Sbostic 102230715Sbostic fprintf(stderr, "Warning, "); 102330715Sbostic fprintf(stderr, fmt, a1, a2, a3, a4, a5); 102430715Sbostic fprintf(stderr, "\n"); 102530715Sbostic } 102630715Sbostic 102730715Sbostic Perror(str) 102830715Sbostic char *str; 102930715Sbostic { 103030715Sbostic fputs("disklabel: ", stderr); perror(str); 103130418Skarels exit(4); 103230418Skarels } 103330715Sbostic 103430715Sbostic usage() 103530715Sbostic { 103630715Sbostic #ifdef BOOT 1037*34032Skarels fprintf(stderr, "%-62s%s\n%-62s%s\n%-62s%s\n%-62s%s\n%-62s%s\n", 103830715Sbostic "usage: disklabel [-r] disk", "(to read label)", 103930715Sbostic "or disklabel -w [-r] disk type [ packid ] [ xxboot bootxx ]", "(to write label)", 104030715Sbostic "or disklabel -e [-r] disk", "(to edit label)", 1041*34032Skarels "or disklabel -R [-r] disk protofile [ type | xxboot bootxx ]", "(to restore label)", 1042*34032Skarels "or disklabel [-NW] disk", "(to write disable/enable label)"); 104330715Sbostic #else 1044*34032Skarels fprintf(stderr, "%-43s%s\n%-43s%s\n%-43s%s\n%-43s%s\n%-43s%s\n", 104530715Sbostic "usage: disklabel [-r] disk", "(to read label)", 104630715Sbostic "or disklabel -w [-r] disk type [ packid ]", "(to write label)", 104730715Sbostic "or disklabel -e [-r] disk", "(to edit label)", 1048*34032Skarels "or disklabel -R [-r] disk protofile", "(to restore label)", 1049*34032Skarels "or disklabel [-NW] disk", "(to write disable/enable label)"); 105030715Sbostic #endif 105130715Sbostic exit(1); 105230715Sbostic } 1053