struct disklabel *makebootarea __P((char *, struct disklabel *, int)); void	display __P((FILE *, struct disklabel *)); void	display_partition __P((FILE *, struct disklabel *, int, char, int)); int	width_partition __P((struct disklabel *, int)); int	editor __P((struct disklabel *, int, char *)); int	edit __P((struct disklabel *, int)); int	editit __P((void)); char	*skip __P((char *)); 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 *));  int main(argc, argv) int argc; char *argv[]; { int ch, f, writeable, error = 0; struct disklabel *lp; FILE *t;  while ((ch = getopt(argc, argv, "BENRWb:denrs: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 'd': ++dflag; break; case 'e': if (op != UNSPEC) usage(); op = EDIT; break; case 'E': if (op != UNSPEC) usage(); op = EDITOR; 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 && dflag)) 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  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); 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); }   void makelabel(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  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  memset(lp->d_packname, 0, sizeof(lp->d_packname)); if (name) (void)strncpy(lp->d_packname, name, sizeof(lp->d_packname)); }  int writelabel(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);  } #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 (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 (!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   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); }  writeable = 1;  if (ioctl(f, DIOCWLABEL, &writeable) < 0) perror("ioctl DIOCWLABEL"); #ifdef __alpha__  { 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  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); }  void l_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  struct dos_partition * readmbr(f) int f; { static int mbr[DEV_BSIZE / sizeof(int)]; struct dos_partition *dp; int part;   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");  bcopy((char *)mbr+DOSPARTOFF, (char *)mbr, sizeof(*dp) * NDOSPART);    for (part = 0; part < NDOSPART; part++) { if ((dp[part].dp_flag & ~0x80) != 0) return (0); }  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]); } }   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]); } }  return (0); } #endif   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 (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); }   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);}