warnx(msg);
warnx("%s", msg);
char	*word __P((char *));int	getasciilabel __P((FILE *, struct disklabel *));int	checklabel __P((struct disklabel *));int	cmplabel __P((struct disklabel *, struct disklabel *));void	setbootflag __P((struct disklabel *));void	usage __P((void));u_short	dkcksum __P((struct disklabel *));intmain(argc, argv)	int argc;	char *argv[];{	int ch, f, writeable, error = 0;	char *fstabfile = NULL;	struct disklabel *lp;	FILE *t;	while ((ch = getopt(argc, argv, "BEFf:NRWb:cdenrs:tvw")) != -1)		switch (ch) {#if NUMBOOT > 0		case 'B':			++installboot;			break;		case 'b':			xxboot = optarg;			break;#if NUMBOOT > 1		case 's':			bootxx = optarg;			break;#endif#endif		case 'N':			if (op != UNSPEC)				usage();			writeable = 0;			op = SETWRITEABLE;			break;		case 'R':			if (op != UNSPEC)				usage();			op = RESTORE;			break;		case 'W':			if (op != UNSPEC)				usage();			writeable = 1;			op = SETWRITEABLE;			break;		case 'c':			++cflag;			break;		case 'd':			++dflag;			break;		case 'e':			if (op != UNSPEC)				usage();			op = EDIT;			break;		case 'E':			if (op != UNSPEC)				usage();			op = EDITOR;			break;		case 'f':			fstabfile = optarg;			break;		case 'r':			++rflag;			break;		case 't':			++tflag;			break;		case 'w':			if (op != UNSPEC)				usage();			op = WRITE;			break;		case 'n':			donothing++;			break;		case 'v':			verbose++;			break;		case '?':		default:			usage();	}	argc -= optind;	argv += optind;#if NUMBOOT > 0	if (installboot) {		rflag++;		if (op == UNSPEC)			op = WRITEBOOT;	} else {		if (op == UNSPEC)			op = READ;	}#else	if (op == UNSPEC)		op = READ;#endif	if (argc < 1 || (rflag && cflag + dflag > 0) ||	    (fstabfile && op != EDITOR))		usage();	dkname = argv[0];	f = opendev(dkname, (op == READ ? O_RDONLY : O_RDWR), OPENDEV_PART,	    &specname);	if (f < 0)		err(4, "%s", specname);#ifdef DOSLABEL	/*	 * Check for presence of DOS partition table in	 * master boot record. Return pointer to OpenBSD	 * partition, if present. If no valid partition table,	 * return 0. If valid partition table present, but no	 * partition to use, return a pointer to a non-386bsd	 * partition.	 */	dosdp = readmbr(f);#endif	switch (op) {	case EDIT:		if (argc != 1)			usage();		if ((lp = readlabel(f)) == NULL)			exit(1);		error = edit(lp, f);		break;	case EDITOR:		if (argc != 1)			usage();		if ((lp = readlabel(f)) == NULL)			exit(1);		error = editor(lp, f, specname, fstabfile);		break;	case READ:		if (argc != 1)			usage();		if ((lp = readlabel(f)) == NULL)			exit(1);		if (tflag)			makedisktab(stdout, lp);		else			display(stdout, lp);		error = checklabel(lp);		break;	case RESTORE:		if (argc < 2 || argc > 3)			usage();#if NUMBOOT > 0		if (installboot && argc == 3)			makelabel(argv[2], NULL, &lab);#endif		lp = makebootarea(bootarea, &lab, f);		if (!(t = fopen(argv[1], "r")))			err(4, "%s", argv[1]);		if (getasciilabel(t, lp))			error = writelabel(f, bootarea, lp);		break;	case SETWRITEABLE:		if (!donothing) {			if (ioctl(f, DIOCWLABEL, (char *)&writeable) < 0)				err(4, "ioctl DIOCWLABEL");		}		break;	case WRITE:		if (argc < 2 || argc > 3)			usage();		makelabel(argv[1], argc == 3 ? argv[2] : NULL, &lab);		lp = makebootarea(bootarea, &lab, f);		*lp = lab;		if (checklabel(lp) == 0)			error = writelabel(f, bootarea, lp);		break;#if NUMBOOT > 0	case WRITEBOOT:	{		struct disklabel tlab;		if ((lp = readlabel(f)) == NULL)			exit(1);		tlab = *lp;		if (argc == 2)			makelabel(argv[1], NULL, &lab);		lp = makebootarea(bootarea, &lab, f);		*lp = tlab;		if (checklabel(lp) == 0)			error = writelabel(f, bootarea, lp);		break;	}#endif	}	exit(error);}/* * Construct a prototype disklabel from /etc/disktab.  As a side * effect, set the names of the primary and secondary boot files * if specified. */voidmakelabel(type, name, lp)	char *type, *name;	struct disklabel *lp;{	struct disklabel *dp;	dp = getdiskbyname(type);	if (dp == NULL)		errx(1, "unknown disk type: %s", type);	*lp = *dp;#if NUMBOOT > 0	/*	 * Set bootstrap name(s).	 * 1. If set from command line, use those,	 * 2. otherwise, check if disktab specifies them (b0 or b1),	 * 3. otherwise, makebootarea() will choose ones based on the name	 *    of the disk special file. E.g. /dev/ra0 -> raboot, bootra	 */	if (!xxboot && lp->d_boot0) {		if (*lp->d_boot0 != '/')			(void)sprintf(boot0, "%s%s",				      _PATH_BOOTDIR, lp->d_boot0);		else			(void)strcpy(boot0, lp->d_boot0);		xxboot = boot0;	}#if NUMBOOT > 1	if (!bootxx && lp->d_boot1) {		if (*lp->d_boot1 != '/')			(void)sprintf(boot1, "%s%s",				      _PATH_BOOTDIR, lp->d_boot1);		else			(void)strcpy(boot1, lp->d_boot1);		bootxx = boot1;	}#endif#endif	/* d_packname is union d_boot[01], so zero */	memset(lp->d_packname, 0, sizeof(lp->d_packname));	if (name)		(void)strncpy(lp->d_packname, name, sizeof(lp->d_packname));}intwritelabel(f, boot, lp)	int f;	char *boot;	struct disklabel *lp;{	int writeable;	off_t sectoffset = 0;	if (nwflag) {		warnx("DANGER! The disklabel was not found at the correct location!");		warnx("To repair this situation, use `disklabel %s > file' to",		    dkname);		warnx("save it, then use `disklabel -R %s file' to replace it.",		    dkname);		warnx("A new disklabel is not being installed now.");		return(0); /* Actually 1 but we want to exit */	}#if NUMBOOT > 0	setbootflag(lp);#endif	lp->d_magic = DISKMAGIC;	lp->d_magic2 = DISKMAGIC;	lp->d_checksum = 0;	lp->d_checksum = dkcksum(lp);	if (rflag) {#ifdef DOSLABEL		struct partition *pp = &lp->d_partitions[2];		/*		 * If OpenBSD DOS partition is missing, or if 		 * the label to be written is not within partition,		 * prompt first. Need to allow this in case operator		 * wants to convert the drive for dedicated use.		 * In this case, partition 'a' had better start at 0,		 * otherwise we reject the request as meaningless. -wfj		 */		if (dosdp && pp->p_size &&		    (dosdp->dp_typ == DOSPTYP_OPENBSD ||		    dosdp->dp_typ == DOSPTYP_FREEBSD ||		    dosdp->dp_typ == DOSPTYP_NETBSD)) {		        sectoffset = (off_t)get_le(&dosdp->dp_start) *			    lp->d_secsize;		} else {			if (dosdp) {				int first, ch;				printf("Erase the previous contents of the disk? [n]: ");				fflush(stdout);				first = ch = getchar();				while (ch != '\n' && ch != EOF)					ch = getchar();				if (first != 'y' && first != 'Y')					exit(0);			}			sectoffset = 0;		}#if NUMBOOT > 0		/*		 * If we are not installing a boot program		 * we must read the current bootarea so we don't		 * clobber the existing boot.		 */		if (!installboot) {			struct disklabel tlab;			if (lseek(f, sectoffset, SEEK_SET) < 0) {				perror("lseek");				return (1);			}			tlab = *lp;			if (read(f, boot, tlab.d_bbsize) != tlab.d_bbsize) {				perror("read");				return (1);			}			*lp =tlab;		}#endif#endif		/*		 * First set the kernel disk label,		 * then write a label to the raw disk.		 * If the SDINFO ioctl fails because it is unimplemented,		 * keep going; otherwise, the kernel consistency checks		 * may prevent us from changing the current (in-core)		 * label.		 */		if (!donothing) {			if (ioctl(f, DIOCSDINFO, lp) < 0 &&			    errno != ENODEV && errno != ENOTTY) {				l_perror("ioctl DIOCSDINFO");				return (1);			}		}		if (verbose)			printf("writing label to block %qd (0x%qx)\n",			    sectoffset/DEV_BSIZE,			    sectoffset/DEV_BSIZE);		if (!donothing) {			if (lseek(f, sectoffset, SEEK_SET) < 0) {				perror("lseek");				return (1);			}			/*			 * write enable label sector before write (if necessary),			 * disable after writing.			 */			writeable = 1;						if (ioctl(f, DIOCWLABEL, &writeable) < 0)				perror("ioctl DIOCWLABEL");#ifdef __alpha__			/*			 * The Alpha requires that the boot block be checksummed.			 * The first 63 8-byte quantites are summed into the 64th.			 */			{				int i;				u_int64_t *dp, sum;				dp = (u_int64_t *)boot;				sum = 0;				for (i = 0; i < 63; i++)					sum += dp[i];				dp[63] = sum;			}#endif			if (write(f, boot, lp->d_bbsize) != lp->d_bbsize) {				perror("write");				return (1);			}		}#if NUMBOOT > 0		/*		 * Output the remainder of the disklabel		 */		if (!donothing && bootbuf && write(f, bootbuf, bootsize) != bootsize) {			perror("write");			return(1);		}#endif		writeable = 0;		if (!donothing)			if (ioctl(f, DIOCWLABEL, &writeable) < 0)				perror("ioctl DIOCWLABEL");	} else {		if (!donothing) {			if (ioctl(f, DIOCWDINFO, lp) < 0) {				l_perror("ioctl DIOCWDINFO");				return (1);			}		}	}#ifdef __vax__	if (lp->d_type == DTYPE_SMD && lp->d_flags & D_BADSECT) {		daddr_t alt;		int i;		alt = lp->d_ncylinders * lp->d_secpercyl - lp->d_nsectors;		for (i = 1; i < 11 && i < lp->d_nsectors; i += 2) {			(void)lseek(f, (off_t)((alt + i) * lp->d_secsize),			    SEEK_SET);			if (!donothing)				if (write(f, boot, lp->d_secsize) < lp->d_secsize)					warn("alternate label %d write", i/2);		}	}#endif	return (0);}voidl_perror(s)	char *s;{	switch (errno) {	case ESRCH:		warnx("%s: No disk label on disk;\n"		    "use \"disklabel -r\" to install initial label", s);		break;	case EINVAL:		warnx("%s: Label magic number or checksum is wrong!\n"		    "(disklabel or kernel is out of date?)", s);		break;	case EBUSY:		warnx("%s: Open partition would move or shrink", s);		break;	case EXDEV:		warnx("%s: Labeled partition or 'a' partition must start "		    "at beginning of disk", s);		break;	default:		warn("%s", s);		break;	}}#ifdef DOSLABEL/* * Fetch DOS partition table from disk. */struct dos_partition *readmbr(f)	int f;{	static int mbr[DEV_BSIZE / sizeof(int)];	struct dos_partition *dp;	u_int16_t signature;	int part;	/*	 * This must be done this way due to alignment restrictions	 * in for example mips processors.         */	dp = (struct dos_partition *)mbr;	if (lseek(f, (off_t)DOSBBSECTOR * DEV_BSIZE, SEEK_SET) < 0 ||	    read(f, mbr, sizeof(mbr)) < sizeof(mbr))		err(4, "can't read master boot record");	signature = *((u_char *)mbr + DOSMBR_SIGNATURE_OFF) |	    (*((u_char *)mbr + DOSMBR_SIGNATURE_OFF + 1) << 8);	bcopy((char *)mbr+DOSPARTOFF, (char *)mbr, sizeof(*dp) * NDOSPART);			/*	 * Don't (yet) know disk geometry (BIOS), use	 * partition table to find OpenBSD partition, and obtain	 * disklabel from there.	 */	/* Check if table is valid. */	for (part = 0; part < NDOSPART; part++) {		if ((dp[part].dp_flag & ~0x80) != 0)			return (0);	}	/* Find OpenBSD partition. */	for (part = 0; part < NDOSPART; part++) {		if (get_le(&dp[part].dp_size) && dp[part].dp_typ == DOSPTYP_OPENBSD) {			fprintf(stderr, "# using MBR partition %d: "			    "type %02X off %d (0x%x) size %d (0x%x)\n", part,			    dp[part].dp_typ,			    get_le(&dp[part].dp_start), get_le(&dp[part].dp_start),			    get_le(&dp[part].dp_size), get_le(&dp[part].dp_size));			return (&dp[part]);		}	}	for (part = 0; part < NDOSPART; part++) {		if (get_le(&dp[part].dp_size) && dp[part].dp_typ == DOSPTYP_FREEBSD) {			fprintf(stderr, "# using MBR partition %d: "			    "type %02X off %d (0x%x) size %d (0x%x)\n", part,			    dp[part].dp_typ,			    get_le(&dp[part].dp_start), get_le(&dp[part].dp_start),			    get_le(&dp[part].dp_size), get_le(&dp[part].dp_size));			return (&dp[part]);		}	}	for (part = 0; part < NDOSPART; part++) {		if (get_le(&dp[part].dp_size) && dp[part].dp_typ == DOSPTYP_NETBSD) {			fprintf(stderr, "# using MBR partition %d: "			    "type %02X off %d (0x%x) size %d (0x%x)\n", part,			    dp[part].dp_typ,			    get_le(&dp[part].dp_start), get_le(&dp[part].dp_start),			    get_le(&dp[part].dp_size), get_le(&dp[part].dp_size));			return (&dp[part]);		}	}	/*	 * If there is no signature and no OpenBSD partition this is probably	 * not an MBR.	 */	if (signature != DOSMBR_SIGNATURE)		return (NULL);	/* If no OpenBSD partition, find first used partition. */	for (part = 0; part < NDOSPART; part++) {		if (get_le(&dp[part].dp_size)) {			warnx("warning, DOS partition table with no valid OpenBSD partition");			return (&dp[part]);		}	}	/* Table appears to be empty. */	return (NULL);}#endif/* * Fetch disklabel for disk. * Use ioctl to get label unless -r flag is given. */struct disklabel *readlabel(f)	int f;{	struct disklabel *lp = NULL;	if (rflag) {		char *msg;		off_t sectoffset = 0;#ifdef DOSLABEL		if (dosdp && get_le(&dosdp->dp_size) &&		    (dosdp->dp_typ == DOSPTYP_OPENBSD ||		    dosdp->dp_typ == DOSPTYP_FREEBSD ||		    dosdp->dp_typ == DOSPTYP_NETBSD))			sectoffset = (off_t)get_le(&dosdp->dp_start) *			    DEV_BSIZE;#endif		if (verbose)			printf("reading label from block %qd, offset %qd\n",			    sectoffset/DEV_BSIZE,			    sectoffset/DEV_BSIZE +			    (LABELSECTOR * DEV_BSIZE) + LABELOFFSET);		if (lseek(f, sectoffset, SEEK_SET) < 0 ||		    read(f, bootarea, BBSIZE) < BBSIZE)			err(4, "%s", specname);		lp = (struct disklabel *)(bootarea +			(LABELSECTOR * DEV_BSIZE) + LABELOFFSET);		if (lp->d_magic == DISKMAGIC &&		    lp->d_magic2 == DISKMAGIC) {			if (lp->d_npartitions <= MAXPARTITIONS &&			    dkcksum(lp) == 0)				return (lp);			msg = "disk label corrupted";		}		else {			warnx("no disklabel found. scanning.");		}		nwflag++;		msg = "no disk label";		for (lp = (struct disklabel *)bootarea;		    lp <= (struct disklabel *)(bootarea + BBSIZE - sizeof(*lp));		    lp = (struct disklabel *)((char *)lp + sizeof(long))) {			if (lp->d_magic == DISKMAGIC &&			    lp->d_magic2 == DISKMAGIC) {				if (lp->d_npartitions <= MAXPARTITIONS &&				    dkcksum(lp) == 0) {					warnx("found at 0x%x", (char *)lp					    - bootarea);					return (lp);				}				msg = "disk label corrupted";			}		}		warnx(msg);		return(NULL);	} else {		if (cflag && ioctl(f, DIOCRLDINFO) < 0)			err(4, "ioctl DIOCRLDINFO");		if (dflag) {			lp = &lab;			if (ioctl(f, DIOCGPDINFO, lp) < 0)				err(4, "ioctl DIOCGPDINFO");		} else {			lp = &lab;			if (ioctl(f, DIOCGDINFO, lp) < 0)				err(4, "ioctl DIOCGDINFO");		}	}	return (lp);}/* * Construct a bootarea (d_bbsize bytes) in the specified buffer ``boot'' * Returns a pointer to the disklabel portion of the bootarea. */struct disklabel *makebootarea(boot, dp, f)	char *boot;	struct disklabel *dp;	int f;{	struct disklabel *lp;	char *p;	int b;#if NUMBOOT > 0	char *dkbasename;#if NUMBOOT == 1	struct stat sb;#endif#endif	/* XXX */	if (dp->d_secsize == 0) {		dp->d_secsize = DEV_BSIZE;		dp->d_bbsize = BBSIZE;	}	lp = (struct disklabel *)	    (boot + (LABELSECTOR * dp->d_secsize) + LABELOFFSET);	memset(lp, 0, sizeof *lp);#if NUMBOOT > 0	/*	 * If we are not installing a boot program but we are installing a	 * label on disk then we must read the current bootarea so we don't	 * clobber the existing boot.	 */	if (!installboot) {#ifndef __i386__		if (rflag) {			if (read(f, boot, BBSIZE) < BBSIZE)				err(4, "%s", specname);			memset(lp, 0, sizeof *lp);		}#endif		return (lp);	}	/*	 * We are installing a boot program.  Determine the name(s) and	 * read them into the appropriate places in the boot area.	 */	if (!xxboot || !bootxx) {		dkbasename = np;		if ((p = strrchr(dkname, '/')) == NULL)			p = dkname;		else			p++;		while (*p && !isdigit(*p))			*np++ = *p++;		*np++ = '\0';		if (!xxboot) {			(void)sprintf(np, "%s%sboot",				      _PATH_BOOTDIR, dkbasename);			if (access(np, F_OK) < 0 && dkbasename[0] == 'r')				dkbasename++;			xxboot = np;			(void)sprintf(xxboot, "%s%sboot",				      _PATH_BOOTDIR, dkbasename);			np += strlen(xxboot) + 1;		}#if NUMBOOT > 1		if (!bootxx) {			(void)sprintf(np, "%sboot%s",				      _PATH_BOOTDIR, dkbasename);			if (access(np, F_OK) < 0 && dkbasename[0] == 'r')				dkbasename++;			bootxx = np;			(void)sprintf(bootxx, "%sboot%s",				      _PATH_BOOTDIR, dkbasename);			np += strlen(bootxx) + 1;		}#endif	}	if (verbose)		warnx("bootstraps: xxboot = %s, bootxx = %s", xxboot,		    bootxx ? bootxx : "NONE");	/*	 * Strange rules:	 * 1. One-piece bootstrap (hp300/hp800)	 *	up to d_bbsize bytes of ``xxboot'' go in bootarea, the rest	 *	is remembered and written later following the bootarea.	 * 2. Two-piece bootstraps (vax/i386?/mips?)	 *	up to d_secsize bytes of ``xxboot'' go in first d_secsize	 *	bytes of bootarea, remaining d_bbsize-d_secsize filled	 *	from ``bootxx''.	 */	b = open(xxboot, O_RDONLY);	if (b < 0)		err(4, "%s", xxboot);#if NUMBOOT > 1	if (read(b, boot, (int)dp->d_secsize) < 0)		err(4, "%s", xxboot);	(void)close(b);	b = open(bootxx, O_RDONLY);	if (b < 0)		err(4, "%s", bootxx);	if (read(b, &boot[dp->d_secsize], (int)(dp->d_bbsize-dp->d_secsize)) < 0)		err(4, "%s", bootxx);#else	if (read(b, boot, (int)dp->d_bbsize) < 0)		err(4, "%s", xxboot);	(void)fstat(b, &sb);	bootsize = (int)sb.st_size - dp->d_bbsize;	if (bootsize > 0) {		/* XXX assume d_secsize is a power of two */		bootsize = (bootsize + dp->d_secsize-1) & ~(dp->d_secsize-1);		bootbuf = (char *)malloc((size_t)bootsize);		if (bootbuf == 0)			err(4, "%s", xxboot);		if (read(b, bootbuf, bootsize) < 0) {			free(bootbuf);			err(4, "%s", xxboot);		}	}#endif	(void)close(b);#endif	/*	 * Make sure no part of the bootstrap is written in the area	 * reserved for the label.	 */	for (p = (char *)lp; p < (char *)lp + sizeof(struct disklabel); p++)		if (*p)			errx(2, "Bootstrap doesn't leave room for disk label");	return (lp);}voidmakedisktab(f, lp)	FILE *f;	struct disklabel *lp;{	int i;	char *did = "\\\n\t:";	struct partition *pp;	if (lp->d_packname[0])		(void)fprintf(f, "%.*s|", sizeof(lp->d_packname),		    lp->d_packname);	if (lp->d_typename[0])		(void)fprintf(f, "%.*s|", sizeof(lp->d_typename),		    lp->d_typename);	(void)fputs("Automatically generated label:\\\n\t:dt=", f);	if ((unsigned) lp->d_type < DKMAXTYPES)		(void)fprintf(f, "%s:", dktypenames[lp->d_type]);	else		(void)fprintf(f, "unknown%d:", lp->d_type);	(void)fprintf(f, "se#%d:", lp->d_secsize);	(void)fprintf(f, "ns#%d:", lp->d_nsectors);	(void)fprintf(f, "nt#%d:", lp->d_ntracks);	(void)fprintf(f, "sc#%d:", lp->d_secpercyl);	(void)fprintf(f, "nc#%d:", lp->d_ncylinders);	if (lp->d_rpm != 3600) {		(void)fprintf(f, "%srm#%d:", did, lp->d_rpm);		did = "";	}	if (lp->d_interleave != 1) {		(void)fprintf(f, "%sil#%d:", did, lp->d_interleave);		did = "";	}	if (lp->d_trackskew != 0) {		(void)fprintf(f, "%ssk#%d:", did, lp->d_trackskew);		did = "";	}	if (lp->d_cylskew != 0) {		(void)fprintf(f, "%scs#%d:", did, lp->d_cylskew);		did = "";	}	if (lp->d_headswitch != 0) {		(void)fprintf(f, "%shs#%d:", did, lp->d_headswitch);		did = "";	}	if (lp->d_trkseek != 0) {		(void)fprintf(f, "%sts#%d:", did, lp->d_trkseek);		did = "";	}	for (i = 0; i < NDDATA; i++)		if (lp->d_drivedata[i])			(void)fprintf(f, "d%d#%d", lp->d_drivedata[i]);	pp = lp->d_partitions;	for (i = 0; i < lp->d_npartitions; i++, pp++) {		if (pp->p_size) {			char c = 'a' + i;			(void)fprintf(f, "\\\n\t:");			(void)fprintf(f, "p%c#%d:", c, pp->p_size);			(void)fprintf(f, "o%c#%d:", c, pp->p_offset);			if (pp->p_fstype != FS_UNUSED) {				if ((unsigned) pp->p_fstype < FSMAXTYPES)					(void)fprintf(f, "t%c=%s:", c, 					    fstypenames[pp->p_fstype]);				else					(void)fprintf(f, "t%c=unknown%d:",					    c, pp->p_fstype);			}			switch (pp->p_fstype) {			case FS_UNUSED:				break;			case FS_BSDFFS:				(void)fprintf(f, "b%c#%d:", c,				    pp->p_fsize * pp->p_frag);				(void)fprintf(f, "f%c#%d:", c, pp->p_fsize);				break;			default:				break;			}		}	}	(void)fputc('\n', f);	(void)fflush(f);}intwidth_partition(lp, unit)	struct disklabel *lp;{	unit = toupper(unit);	switch (unit) {	case 'K':		return 10;	}	return 8;}/* * Display a particular partion. */voiddisplay_partition(f, lp, mp, i, unit, width)	FILE *f;	struct disklabel *lp;	char **mp;	int i;	char unit;	int width;{	struct partition *pp = &lp->d_partitions[i];	double p_size, p_offset;	if (width == 0)		width = 8;	unit = toupper(unit);	switch (unit) {	case 'B':		p_size = (double)pp->p_size * lp->d_secsize;		p_offset = (double)pp->p_offset * lp->d_secsize;		break;	case 'C':		p_size = (double)pp->p_size / lp->d_secpercyl;		p_offset = (double)pp->p_offset / lp->d_secpercyl;		break;	case 'K':		p_size = (double)pp->p_size / (1024 / lp->d_secsize);		p_offset = (double)pp->p_offset / (1024 / lp->d_secsize);		break;	case 'M':		p_size = (double)pp->p_size / ((1024*1024) / lp->d_secsize);		p_offset = (double)pp->p_offset / ((1024*1024) / lp->d_secsize);		break;	case 'G':		p_size = (double)pp->p_size / ((1024*1024*1024) / lp->d_secsize);		p_offset = (double)pp->p_offset / ((1024*1024*1024) / lp->d_secsize);		break;	default:		p_size = -1;			/* no conversion */		break;	}	if (pp->p_size) {		if (p_size < 0)			fprintf(f, "  %c: %*u %*u  ", 'a' + i,			    width, pp->p_size, width, pp->p_offset);		else			fprintf(f, "  %c: %*.1f%c %*.1f%c  ", 'a' + i,			    width-1, p_size, unit, width-1, p_offset, unit);		if ((unsigned) pp->p_fstype < FSMAXTYPES)			fprintf(f, "%8.8s", fstypenames[pp->p_fstype]);		else			fprintf(f, "%8d", pp->p_fstype);		switch (pp->p_fstype) {		case FS_UNUSED:				/* XXX */			fprintf(f, "    %5d %5d %5.5s ",			    pp->p_fsize, pp->p_fsize * pp->p_frag, "");			break;		case FS_BSDFFS:			fprintf(f, "    %5d %5d %5d ",			    pp->p_fsize, pp->p_fsize * pp->p_frag,			    pp->p_cpg);			break;		default:			fprintf(f, "%22.22s", "");			break;		}		if (mp != NULL) {			if (mp[i] != NULL)				fprintf(f, " # %s", mp[i]);		} else if (lp->d_secpercyl) {			fprintf(f, "\t# (Cyl. %4d",			    pp->p_offset / lp->d_secpercyl);			if (pp->p_offset % lp->d_secpercyl)				putc('*', f);			else				putc(' ', f);			fprintf(f, "- %d",			    (pp->p_offset + 			    pp->p_size + lp->d_secpercyl - 1) /			    lp->d_secpercyl - 1);			if ((pp->p_offset + pp->p_size) % lp->d_secpercyl)				putc('*', f);			putc(')', f);		}		putc('\n', f);	}}voiddisplay(f, lp)	FILE *f;	struct disklabel *lp;{	int i, j;	int width;	fprintf(f, "# %s:\n", specname);	if ((unsigned) lp->d_type < DKMAXTYPES)		fprintf(f, "type: %s\n", dktypenames[lp->d_type]);	else		fprintf(f, "type: %d\n", lp->d_type);	fprintf(f, "disk: %.*s\n", (int)sizeof(lp->d_typename), lp->d_typename);	fprintf(f, "label: %.*s\n", (int)sizeof(lp->d_packname), lp->d_packname);	fprintf(f, "flags:");	if (lp->d_flags & D_REMOVABLE)		fprintf(f, " removable");	if (lp->d_flags & D_ECC)		fprintf(f, " ecc");	if (lp->d_flags & D_BADSECT)		fprintf(f, " badsect");	putc('\n', f);	fprintf(f, "bytes/sector: %ld\n", (long)lp->d_secsize);	fprintf(f, "sectors/track: %ld\n", (long)lp->d_nsectors);	fprintf(f, "tracks/cylinder: %ld\n", (long)lp->d_ntracks);	fprintf(f, "sectors/cylinder: %ld\n", (long)lp->d_secpercyl);	fprintf(f, "cylinders: %ld\n", (long)lp->d_ncylinders);	fprintf(f, "total sectors: %ld\n", (long)lp->d_secperunit);	fprintf(f, "rpm: %ld\n", (long)lp->d_rpm);	fprintf(f, "interleave: %ld\n", (long)lp->d_interleave);	fprintf(f, "trackskew: %ld\n", (long)lp->d_trackskew);	fprintf(f, "cylinderskew: %ld\n", (long)lp->d_cylskew);	fprintf(f, "headswitch: %ld\t\t# microseconds\n",	    (long)lp->d_headswitch);	fprintf(f, "track-to-track seek: %ld\t# microseconds\n",	    (long)lp->d_trkseek);	fprintf(f, "drivedata: ");	for (i = NDDATA - 1; i >= 0; i--)		if (lp->d_drivedata[i])			break;	if (i < 0)		i = 0;	for (j = 0; j <= i; j++)		fprintf(f, "%d ", lp->d_drivedata[j]);	fprintf(f, "\n\n%d partitions:\n", lp->d_npartitions);	width = width_partition(lp, 0);	fprintf(f,	    "#    %*.*s %*.*s    fstype   [fsize bsize   cpg]\n",	    width, width, "size", width, width, "offset");	for (i = 0; i < lp->d_npartitions; i++)		display_partition(f, lp, NULL, i, 0, width);	fflush(f);}intedit(lp, f)	struct disklabel *lp;	int f;{	int first, ch, fd;	struct disklabel label;	FILE *fp;	if ((fd = mkstemp(tmpfil)) == -1 || (fp = fdopen(fd, "w")) == NULL) {		if (fd != -1)			close(fd);		warn("%s", tmpfil);		return (1);	}	display(fp, lp);	fprintf(fp, "\n# Notes:\n");	fprintf(fp,"# Up to 16 partitions are valid, named from 'a' to 'p'.  Partition 'a' is\n""# your root filesystem, 'b' is your swap, and 'c' should cover your whole\n""# disk. Any other partition is free for any use.  'size' and 'offset' are\n""# in 512-byte blocks. fstype should be '4.2BSD', 'swap', or 'none' or some\n""# other values.  fsize/bsize/cpg should typically be '1024 8192 16' for a\n""# 4.2BSD filesystem (or '512 4096 16' except on alpha, sun4, amiga, sun3...)\n");	fclose(fp);	for (;;) {		if (!editit())			break;		fp = fopen(tmpfil, "r");		if (fp == NULL) {			warn("%s", tmpfil);			break;		}		memset(&label, 0, sizeof(label));		if (getasciilabel(fp, &label)) {			if (cmplabel(lp, &label) == 0) {				puts("No changes.");				fclose(fp);				(void) unlink(tmpfil);				return (0);			}			*lp = label;			if (writelabel(f, bootarea, lp) == 0) {				fclose(fp);				(void) unlink(tmpfil);				return (0);			}		}		fclose(fp);		printf("re-edit the label? [y]: ");		fflush(stdout);		first = ch = getchar();		while (ch != '\n' && ch != EOF)			ch = getchar();		if (first == 'n' || first == 'N')			break;	}	(void)unlink(tmpfil);	return (1);}inteditit(){	pid_t pid, xpid;	int stat;	extern char *getenv();	char *argp[] = {"sh", "-c", NULL, NULL};	char *ed, *p;	if ((ed = getenv("EDITOR")) == NULL)		ed = _PATH_VI;	p = (char *)malloc(strlen(ed) + 1 + strlen(tmpfil) + 1);	if (!p) {		warn("failed to start editor");		return (0);	}	sprintf(p, "%s %s", ed, tmpfil);	argp[2] = p;	/* Turn off signals. */	(void)signal(SIGHUP, SIG_IGN);	(void)signal(SIGINT, SIG_IGN);	(void)signal(SIGQUIT, SIG_IGN);	while ((pid = fork()) < 0) {		if (errno != EAGAIN) {			warn("fork");			free(p);			stat = 1;			goto bail;		}		sleep(1);	}	if (pid == 0) {		execv(_PATH_BSHELL, argp);		_exit(127);	}	free(p);	for (;;) {		xpid = waitpid(pid, (int *)&stat, WUNTRACED);		if (WIFSTOPPED(stat))			raise(WSTOPSIG(stat));		else if (WIFEXITED(stat))			break;	}bail:	(void)signal(SIGHUP, SIG_DFL);	(void)signal(SIGINT, SIG_DFL);	(void)signal(SIGQUIT, SIG_DFL);	return (!stat);}char *skip(cp)	char *cp;{	cp += strspn(cp, " \t");	if (*cp == '\0')		return (NULL);	return (cp);}char *word(cp)	char *cp;{	cp += strcspn(cp, " \t");	if (*cp == '\0')		return (NULL);	*cp++ = '\0';	cp += strspn(cp, " \t");	if (*cp == '\0')		return (NULL);	return (cp);}