if (partno >= lp->d_npartitions) lp->d_npartitions = partno + 1;
char	*getstring __P((struct disklabel *, char *, char *, char *));u_int32_t getuint __P((struct disklabel *, int, char *, char *, u_int32_t, u_int32_t, int));int	has_overlap __P((struct disklabel *, u_int32_t *, int));void	make_contiguous __P((struct disklabel *));u_int32_t next_offset __P((struct disklabel *));int	partition_cmp __P((const void *, const void *));struct partition **sort_partitions __P((struct disklabel *, u_int16_t *));void	getdisktype __P((struct disklabel *, char *));/* from disklabel.c */int	checklabel __P((struct disklabel *));void	display __P((FILE *, struct disklabel *));void	display_partition __P((FILE *, struct disklabel *, int, char));struct disklabel *readlabel __P((int));struct disklabel *makebootarea __P((char *, struct disklabel *, int));int	writelabel __P((int, char *, struct disklabel *));extern	char *bootarea, *specname;extern	int donothing;/* * Simple partition editor.  Primarily intended for new labels. */inteditor(lp, f)	struct disklabel *lp;	int f;{	struct disklabel lastlabel, tmplabel, label = *lp;	u_int32_t freeblocks;	FILE *fp;	char buf[BUFSIZ], *cmd, *arg;	int i;	/* Set freeblocks based on initial label */	freeblocks = label.d_secperunit;	for (i = 0; i < label.d_npartitions; i++)		if (label.d_partitions[i].p_fstype != FS_UNUSED &&		    label.d_partitions[i].p_fstype != FS_BOOT &&		    label.d_partitions[i].p_size > 0)			freeblocks -= label.d_partitions[i].p_size;	puts("Initial label editor (enter '?' for help at any prompt)");	if (has_overlap(&label, &freeblocks, 1))		errx(1, "can't run when there is partition overlap.");	getdisktype(&label, "You need to specify a disk type for this disk.");#ifdef CYLCHECK	puts("This platform requires that partition offsets/sizes be on cylinder boundaries.\nPartition offsets/sizes will be rounded to the nearest cylinder automatically.");#endif	lastlabel = label;	for (;;) {		fputs("> ", stdout);		fflush(stdout);		rewind(stdin);		if (fgets(buf, sizeof(buf), stdin) == NULL) {			putchar('\n');			buf[0] = 'q';			buf[1] = '\0';		}		if ((cmd = strtok(buf, " \t\r\n")) == NULL)			continue;		arg = strtok(NULL, " \t\r\n");		switch (*cmd) {		case '?':		case 'h':			puts("Available commands:");			puts("\tp [unit]   - print label.");			puts("\tM          - show entire OpenBSD man page for disklabel.");			puts("\te          - edit drive parameters.");			puts("\ta [part]   - add new partition.");			puts("\tc [part]   - change partition size.");			puts("\td [part]   - delete partition.");			puts("\tm [part]   - modify existing partition.");			puts("\tu          - undo last change.");			puts("\ts [path]   - save label to file.");			puts("\tw          - write label to disk.");			puts("\tq          - quit and save changes.");			puts("\tx          - exit without saving changes.");			puts("\t?          - this message.");			puts("Numeric parameters may use suffixes to indicate units:\n\t'b' for bytes, 'c' for cylinders, 'k' for kilobytes, 'm' for megabytes,\n\t'g' for gigabytes or no suffix for blocks (usually 512 bytes).\n\tNon-block units will be rounded to the nearest cylinder.");			break;		case 'a':			tmplabel = lastlabel;			lastlabel = label;			editor_add(&label, &freeblocks, arg);			if (memcmp(&label, &lastlabel, sizeof(label)) == 0)				lastlabel = tmplabel;			break;		case 'c':			tmplabel = lastlabel;			lastlabel = label;			editor_change(&label, &freeblocks, arg);			if (memcmp(&label, &lastlabel, sizeof(label)) == 0)				lastlabel = tmplabel;			break;		case 'd':			tmplabel = lastlabel;			lastlabel = label;			editor_delete(&label, &freeblocks, arg);			if (memcmp(&label, &lastlabel, sizeof(label)) == 0)				lastlabel = tmplabel;			break;		case 'm':			tmplabel = lastlabel;			lastlabel = label;			editor_modify(&label, &freeblocks, arg);			if (memcmp(&label, &lastlabel, sizeof(label)) == 0)				lastlabel = tmplabel;			break;		case 'p':			editor_display(&label, &freeblocks, arg ? *arg : 0);			break;		case 'M':			fp = popen("/usr/bin/less", "w");			if (fp) {				extern char manpage[];				(void) fwrite(manpage, strlen(manpage), 1, fp);				pclose(fp);			}			break;		case 'q':			if (donothing) {				puts("In no change mode, not writing label.");				return(1);			}			if (memcmp(lp, &label, sizeof(label)) == 0) {				puts("No changes.");				return(1);			}			do {				arg = getstring(lp, "Save changes?",				    "Save changes you have made to the label?",				    "n");			} while (tolower(*arg) != 'y' && tolower(*arg) != 'n');			if (tolower(*arg) == 'y') {				*lp = label;				if (writelabel(f, bootarea, lp) == 0)					return(0);			}			return(1);			/* NOTREACHED */			break;		case 's':			if (arg == NULL) {				arg = getstring(lp, "Filename",				    "Name of the file to save label into.",				    NULL);				if (*arg == '\0')					break;			}			if ((fp = fopen(arg, "w")) == NULL) {				warn("cannot open %s", arg);			} else {				display(fp, &label);				(void)fclose(fp);			}			break;		case 'u':			if (memcmp(&label, &lastlabel, sizeof(label)) == 0) {				puts("Nothing to undo!");			} else {				tmplabel = label;				label = lastlabel;				lastlabel = tmplabel;				puts("Last change undone.");			}			break;		case 'w':			if (donothing)				puts("In no change mode, not writing label.");			else if (memcmp(lp, &label, sizeof(label)) == 0)				puts("No changes.");			else if (writelabel(f, bootarea, &label) != 0)				warnx("unable to write label");			else				*lp = label;			break;		case 'x':			return(1);			break;		case '\n':			break;		case 'e':			tmplabel = lastlabel;			lastlabel = label;			edit_parms(&label, &freeblocks);			if (memcmp(&label, &lastlabel, sizeof(label)) == 0)				lastlabel = tmplabel;			break;		default:			printf("Unknown option: %c ('?' for help)\n", *cmd);			break;		}	}}/* * Add a new partition. */voideditor_add(lp, freep, p)	struct disklabel *lp;	u_int32_t *freep;	char *p;{	struct partition origpart, *pp;	char buf[BUFSIZ];	int i, partno;	u_int32_t ui;	/* XXX - prompt user to steal space from another partition instead */	if (*freep == 0) {		fputs("No space left, you need to shrink a partition\n",		    stderr);		return;	}	/* XXX - make more like other editor_* */	if (p != NULL) {		partno = p[0] - 'a';		if (partno < 0 || partno >= MAXPARTITIONS) {			fprintf(stderr,			    "Partition must be between 'a' and '%c'.\n",			    'a' + MAXPARTITIONS - 1);			return;		} else if (lp->d_partitions[partno].p_fstype != FS_UNUSED ||		    lp->d_partitions[partno].p_size != 0) {			fprintf(stderr,			    "Partition '%c' exists.  Delete it first.\n",			    p[0]);			return;		}	} else {		/* Find first unused partition that is not 'b' or 'c' */		for (partno = 0; partno < MAXPARTITIONS; partno++, p++) {			if (lp->d_partitions[partno].p_size == 0 &&			    partno != 1 && partno != 2)				break;		}		if (partno < MAXPARTITIONS) {			buf[0] = partno + 'a';			buf[1] = '\0';			p = &buf[0];		} else			p = NULL;		for (;;) {			p = getstring(lp, "partition",			    "The letter of the new partition, a - p.", p);			partno = p[0] - 'a';			if (partno >= 0 && partno < MAXPARTITIONS)				break;			fprintf(stderr,			    "Partition must be between 'a' and '%c'.\n",			    'a' + MAXPARTITIONS - 1);		}	}	/* Increase d_npartitions and set defaults if necesary */	pp = &lp->d_partitions[partno];	if (partno >= lp->d_npartitions || pp->p_fstype == FS_UNUSED) {		if (partno >= lp->d_npartitions)			lp->d_npartitions = partno + 1;		memset(pp, 0, sizeof(*pp));		pp->p_offset = next_offset(lp);		pp->p_size = *freep;		if (partno == 1)			pp->p_fstype = FS_SWAP;		else			pp->p_fstype = FS_BSDFFS;		pp->p_fsize = 1024;		pp->p_frag = 8;		pp->p_cpg = 16;	}	origpart = *pp;	/* Get fstype */	if (pp->p_fstype < FSMAXTYPES) {		p = getstring(lp, "FS type",		    "Filesystem type (usually 4.2BSD or swap)",		    fstypenames[pp->p_fstype]);		for (i = 0; i < FSMAXTYPES; i++) {			if (!strcasecmp(p, fstypenames[i])) {				pp->p_fstype = i;				break;			}		}		if (i >= FSMAXTYPES) {			printf("Unrecognized filesystem type '%s', treating as 'unknown'\n", p);			pp->p_fstype = FS_OTHER;		}	} else {		for (;;) {			ui = getuint(lp, partno, "FS type (decimal)",			    "Filesystem type as a decimal number; usually 7 (4.2BSD) or 1 (swap).",			    pp->p_fstype, pp->p_fstype, 0);			if (ui == UINT_MAX)				fputs("Invalid entry\n", stderr);			else				break;		}		pp->p_fstype = ui;	}getoff1:	/* Get offset */	for (;;) {		ui = getuint(lp, partno, "offset",		   "Starting sector for this partition.", pp->p_offset,		   pp->p_offset, DO_CONVERSIONS |		   (pp->p_fstype == FS_BSDFFS ? DO_ROUNDING : 0));		if (ui == UINT_MAX)			fputs("Invalid entry\n", stderr);		else			break;	}	pp->p_offset = ui;	/* Get size */	for (;;) {		ui = getuint(lp, partno, "size", "Size of the partition.",		    pp->p_size, *freep, DO_CONVERSIONS |		    (pp->p_fstype == FS_BSDFFS ? DO_ROUNDING : 0));		if (ui + pp->p_offset > lp->d_partitions[2].p_size +		    lp->d_partitions[2].p_offset)			fputs("Partition must not extend past 'c'\n", stderr);		else if (ui > *freep)			/* XXX - prompt user to steal space from another partition */			fprintf(stderr,"Sorry, there are only %u blocks left\n",			    *freep);		else			break;	}	pp->p_size = ui;	if (pp->p_size == 0)		return;	/* Check for overlap and restore if not resolved */	if (has_overlap(lp, freep, 0)) {		puts("\nPlease re-enter an offset and size");		pp->p_offset = origpart.p_offset;		pp->p_size = origpart.p_size;		goto getoff1;		/* Yeah, I know... */	}	if (pp->p_fstype == FS_BSDFFS || pp->p_fstype == FS_UNUSED) {		/* get fsize */		for (;;) {			ui = getuint(lp, partno, "fragment size",			    "Size of fs block fragments.  Usually 1024 or 512.",			    pp->p_fsize, pp->p_fsize, 0);			if (ui == UINT_MAX)				fputs("Invalid entry\n", stderr);			else				break;		}		pp->p_fsize = ui;		if (pp->p_fsize == 0)			puts("Zero fragment size implies zero block size");		/* get bsize */		/* XXX - do before frag size? */		for (; pp->p_fsize > 0;) {			ui = getuint(lp, partno, "block size",			    "Size of filesystem blocks.  Usually 8192 or 4096.",			    pp->p_fsize * pp->p_frag, pp->p_fsize * pp->p_frag,			    0);			/* sanity checks */			if (ui == UINT_MAX)				fputs("Invalid entry\n", stderr);			else if (ui < getpagesize())				fprintf(stderr,				    "Error: block size must be at least as big "				    "as page size (%d).\n", getpagesize());			else if (ui % pp->p_fsize != 0)				fputs("Error: block size must be a multiple of the fragment size.\n", stderr);			else if (ui / pp->p_fsize < 1)				fputs("Error: block size must be at least as big as fragment size.\n", stderr);			else				break;		}		pp->p_frag = ui / pp->p_fsize;		if (pp->p_fstype == FS_BSDFFS) {			/* get cpg */			for (;;) {				ui = getuint(lp, partno, "cpg",				    "Number of filesystem cylinders per group.  Usually 16 or 8.",				    pp->p_cpg, pp->p_cpg, 0);				if (ui == UINT_MAX)					fputs("Invalid entry\n", stderr);				else					break;			}			pp->p_cpg = ui;		}	}	/* Update free block count and make sure things stay contiguous. */	*freep -= pp->p_size;	make_contiguous(lp);}/* * Change an existing partition. */voideditor_modify(lp, freep, p)	struct disklabel *lp;	u_int32_t *freep;	char *p;{	struct partition origpart, *pp;	u_int32_t ui;	int partno;	/* Change which partition? */	if (p == NULL) {		p = getstring(lp, "partition to modify",		    "The letter of the partition to modify, a - p.", NULL);	}	partno = p[0] - 'a';	pp = &lp->d_partitions[partno];	origpart = lp->d_partitions[partno];	if (partno < 0 || partno >= lp->d_npartitions) {		fprintf(stderr, "Partition must be between 'a' and '%c'.\n",		    'a' + lp->d_npartitions - 1);		return;	} else if (partno >= lp->d_npartitions ||	    (pp->p_fstype == FS_UNUSED && pp->p_size == 0)) {		fprintf(stderr, "Partition '%c' is not in use.\n", 'a' + partno);		return;	}		/* Get filesystem type */	if (pp->p_fstype < FSMAXTYPES) {		p = getstring(lp, "FS type",		    "Filesystem type (usually 4.2BSD or swap)",		    fstypenames[pp->p_fstype]);		for (ui = 0; ui < FSMAXTYPES; ui++) {			if (!strcasecmp(p, fstypenames[ui])) {				pp->p_fstype = ui;				break;			}		}		if (ui >= FSMAXTYPES) {			printf("Unrecognized filesystem type '%s', treating as 'unknown'\n", p);			pp->p_fstype = FS_OTHER;		}	} else {		for (;;) {			ui = getuint(lp, partno, "FS type (decimal)",			    "Filesystem type as a decimal number; usually 7 (4.2BSD) or 1 (swap).",			    pp->p_fstype, pp->p_fstype, 0);			if (ui == UINT_MAX)				fputs("Invalid entry\n", stderr);			else				break;		}		pp->p_fstype = ui;	}	/* Did they disable/enable the partition? */	if ((pp->p_fstype == FS_UNUSED || pp->p_fstype == FS_BOOT) &&	    origpart.p_fstype != FS_UNUSED && origpart.p_fstype != FS_BOOT)		*freep += origpart.p_size;	else if (pp->p_fstype != FS_UNUSED && pp->p_fstype != FS_BOOT &&	    (origpart.p_fstype == FS_UNUSED || origpart.p_fstype == FS_BOOT)) {		if (pp->p_size > *freep) {			fprintf(stderr,			    "Warning, need %u blocks but there are only %u "			    "free.  Setting size to %u.\n", pp->p_size, *freep,			    *freep);			pp->p_fstype = *freep;			*freep = 0;		} else			*freep -= pp->p_size;		/* have enough space */	}getoff2:	/* Get offset */	for (;;) {		ui = getuint(lp, partno, "offset",		    "Starting sector for this partition.", pp->p_offset,		    pp->p_offset, DO_CONVERSIONS |		    (pp->p_fstype == FS_BSDFFS ? DO_ROUNDING : 0));		if (ui == UINT_MAX)			fputs("Invalid entry\n", stderr);		else			break;	}	pp->p_offset = ui;	/* Get size */	/* XXX - this loop sucks */	for (;;) {		ui = getuint(lp, partno, "size", "Size of the partition.",		    pp->p_size, *freep, 1);		if (ui == pp->p_size)			break;			/* no change */		if (ui == UINT_MAX) {			fputs("Invalid entry\n", stderr);			continue;		} else if (partno != 2 && ui + pp->p_offset >		    lp->d_partitions[2].p_size + lp->d_partitions[2].p_offset) {			fputs("Partition must not extend past 'c'\n", stderr);			continue;		} else if (partno == 2 && ui + pp->p_offset > lp->d_secperunit) {			fputs("'c' partition may not be larger than the disk\n",			    stderr);			continue;		}		if (pp->p_fstype == FS_UNUSED || pp->p_fstype == FS_BOOT) {			pp->p_size = ui;	/* don't care what's free */			break;		} else {			if (ui > pp->p_size + *freep)				/* XXX - prompt user to steal space from another partition */				fprintf(stderr,				    "Size may not be larger than %u blocks\n",				    pp->p_size + *freep);			else {				*freep += pp->p_size - ui;				pp->p_size = ui;				break;			}		}	}	if (pp->p_size == 0)		return;	/* Check for overlap and restore if not resolved */	if (has_overlap(lp, freep, 0)) {		puts("\nPlease re-enter an offset and size");		pp->p_offset = origpart.p_offset;		pp->p_size = origpart.p_size;		goto getoff2;		/* Yeah, I know... */	}	if (pp->p_fstype == FS_BSDFFS || pp->p_fstype == FS_UNUSED) {		/* get fsize */		for (;;) {			ui = getuint(lp, partno, "fragment size",			    "Size of fs block fragments.  Usually 1024 or 512.",			    pp->p_fsize, 1024, 0);			if (ui == UINT_MAX)				fputs("Invalid entry\n", stderr);			else				break;		}		pp->p_fsize = ui;		if (pp->p_fsize == 0)			puts("Zero fragment size implies zero block size");		/* get bsize */		for (; pp->p_fsize > 0;) {			ui = getuint(lp, partno, "block size",			    "Size of filesystem blocks.  Usually 8192 or 4096.",			    pp->p_fsize * pp->p_frag, pp->p_fsize * pp->p_frag,			    0);			/* sanity check */			if (ui == UINT_MAX)				fputs("Invalid entry\n", stderr);			else if (ui % pp->p_fsize != 0)				puts("Error: block size must be a multiple of the fragment size.");			else if (ui / pp->p_fsize < 1)				puts("Error: block size must be at least as big as fragment size.");			else {				pp->p_frag = ui / pp->p_fsize;				break;			}		}		if (pp->p_fstype == FS_BSDFFS) {			/* get cpg */			for (;;) {				ui = getuint(lp, partno, "cpg",				    "Number of filesystem cylinders per group."				    "  Usually 16 or 8.", pp->p_cpg, pp->p_cpg,				    0);				if (ui == UINT_MAX)					fputs("Invalid entry\n", stderr);				else					break;			}			pp->p_cpg = ui;		}	}	/* Make sure things stay contiguous. */	make_contiguous(lp);}/* * Delete an existing partition. */voideditor_delete(lp, freep, p)	struct disklabel *lp;	u_int32_t *freep;	char *p;{	int c;	if (p == NULL) {		p = getstring(lp, "partition to delete",		    "The letter of the partition to delete, a - p.", NULL);	}	c = p[0] - 'a';	if (c < 0 || c >= lp->d_npartitions)		fprintf(stderr, "Partition must be between 'a' and '%c'.\n",		    'a' + lp->d_npartitions - 1);	else if (c >= lp->d_npartitions || (lp->d_partitions[c].p_fstype ==	    FS_UNUSED && lp->d_partitions[c].p_size == 0))		fprintf(stderr, "Partition '%c' is not in use.\n", 'a' + c);	else if (c == 2)		fputs("You may not delete the 'c' partition.\n", stderr);	else {		/* Update free block count. */		if (lp->d_partitions[c].p_fstype != FS_UNUSED &&		    lp->d_partitions[c].p_fstype != FS_BOOT &&		    lp->d_partitions[c].p_size != 0)			*freep += lp->d_partitions[c].p_size;		/* Really delete it (as opposed to just setting to "unused") */		(void)memset(&lp->d_partitions[c], 0,		    sizeof(lp->d_partitions[c]));		/* Fill in the gap we just made */		make_contiguous(lp);	}}/* * Simplified display() for use with the builtin editor. */voideditor_display(lp, freep, unit)	struct disklabel *lp;	u_int32_t *freep;	char unit;{	int i;	printf("device: %s\n", specname);	printf("type: %s\n", dktypenames[lp->d_type]);	printf("disk: %.*s\n", (int)sizeof(lp->d_typename), lp->d_typename);	printf("label: %.*s\n", (int)sizeof(lp->d_packname), lp->d_packname);	printf("bytes/sector: %ld\n", (long)lp->d_secsize);	printf("sectors/track: %ld\n", (long)lp->d_nsectors);	printf("tracks/cylinder: %ld\n", (long)lp->d_ntracks);	printf("sectors/cylinder: %ld\n", (long)lp->d_secpercyl);	printf("cylinders: %ld\n", (long)lp->d_ncylinders);	printf("total sectors: %ld\n", (long)lp->d_secperunit);	printf("free sectors: %u\n", *freep);	printf("rpm: %ld\n", (long)lp->d_rpm);	printf("\n%d partitions:\n", lp->d_npartitions);	printf("#        size   offset    fstype   [fsize bsize   cpg]\n");	for (i = 0; i < lp->d_npartitions; i++)		display_partition(stdout, lp, i, unit);}/* * Find the next reasonable starting offset and returns it. * Assumes there is a least one free block left (returns 0 if not). */u_int32_tnext_offset(lp)	struct disklabel *lp;{	struct partition **spp;	u_int16_t npartitions;	u_int32_t new_offset = 0;	int i;	/* Get a sorted list of the partitions */	spp = sort_partitions(lp, &npartitions);	for (i = 0; i < npartitions; i++ ) {		/*		 * Is new_offset inside this partition?  If so,		 * make it the next block after the partition ends.		 */		if (new_offset >= spp[i]->p_offset &&		    new_offset < spp[i]->p_offset + spp[i]->p_size)			new_offset = spp[i]->p_offset + spp[i]->p_size;	}	(void)free(spp);	return(new_offset);}/* * Change the size of an existing partition. */voideditor_change(lp, freep, p)	struct disklabel *lp;	u_int32_t *freep;	char *p;{	int partno;	u_int32_t newsize;	if (p == NULL) {		p = getstring(lp, "partition to change size",		    "The letter of the partition to change size, a - p.", NULL);	}	partno = p[0] - 'a';	if (partno < 0 || partno >= lp->d_npartitions) {		fprintf(stderr, "Partition must be between 'a' and '%c'.\n",		    'a' + lp->d_npartitions - 1);		return;	} else if (partno >= lp->d_npartitions ||	    lp->d_partitions[partno].p_size == 0) {		fprintf(stderr, "Partition '%c' is not in use.\n", 'a' + partno);		return;	}	printf("Partition %c is currently %u sectors in size (%u free).\n",	    partno + 'a', lp->d_partitions[partno].p_size, *freep);	/* XXX - make maxsize lp->d_secperunit if FS_UNUSED/FS_BOOT? */	newsize = getuint(lp, partno, "new size", "Size of the partition.  "	    "You may also say +/- amount for a relative change.",	    lp->d_partitions[partno].p_size,	    lp->d_partitions[partno].p_size + *freep, DO_CONVERSIONS |	    (lp->d_partitions[partno].p_fstype == FS_BSDFFS ? DO_ROUNDING : 0));	if (newsize == UINT_MAX) {		fputs("Invalid entry\n", stderr);		return;	} else if (newsize == lp->d_partitions[partno].p_size)		return;	if (lp->d_partitions[partno].p_fstype != FS_UNUSED &&	    lp->d_partitions[partno].p_fstype != FS_BOOT) {		if (newsize > lp->d_partitions[partno].p_size) {			if (newsize - lp->d_partitions[partno].p_size > *freep) {				fprintf(stderr,				    "Only %u sectors free, you asked for %u\n",				    *freep,				    newsize - lp->d_partitions[partno].p_size);				return;			}			*freep -= newsize - lp->d_partitions[partno].p_size;		} else if (newsize < lp->d_partitions[partno].p_size) {			*freep += lp->d_partitions[partno].p_size - newsize;		}	} else {		if (partno != 2 && newsize + lp->d_partitions[partno].p_offset >		    lp->d_partitions[2].p_size) {			fputs("Partition must not extend past 'c'\n", stderr);			return;		} else if (partno == 2 && newsize +		    lp->d_partitions[partno].p_offset > lp->d_secperunit) {			fputs("'c' partition may not be larger than the disk\n",			    stderr);			return;		}	}	lp->d_partitions[partno].p_size = newsize;	make_contiguous(lp);}voidmake_contiguous(lp)	struct disklabel *lp;{	struct partition **spp;	u_int16_t npartitions;	int i;	/* Get a sorted list of the partitions */	spp = sort_partitions(lp, &npartitions);	/*	 * Make everything contiguous but don't muck with start of the first one	 */	for (i = 1; i < npartitions; i++)		spp[i]->p_offset = spp[i - 1]->p_offset + spp[i - 1]->p_size;	(void)free(spp);}/* * Sort the partitions based on starting offset. * This assumes there can be no overlap. */intpartition_cmp(e1, e2)	const void *e1, *e2;{	struct partition *p1 = *(struct partition **)e1;	struct partition *p2 = *(struct partition **)e2;	return((int)(p1->p_offset - p2->p_offset));}char *getstring(lp, prompt, helpstring, oval)	struct disklabel *lp;	char *prompt;	char *helpstring;	char *oval;{	static char buf[BUFSIZ];	int n;	buf[0] = '\0';	do {		printf("%s: [%s] ", prompt, oval ? oval : "");		fflush(stdout);		rewind(stdin);		if (fgets(buf, sizeof(buf), stdin) == NULL) {			putchar('\n');			buf[0] = '\0';		}		n = strlen(buf);		if (n > 0 && buf[n-1] == '\n')			buf[--n] = '\0';		if (buf[0] == '?')			puts(helpstring);		else if (oval != NULL && buf[0] == '\0') {			(void)strncpy(buf, oval, sizeof(buf) - 1);			buf[sizeof(buf) - 1] = '\0';		}	} while (buf[0] == '?');	return(&buf[0]);}