Example #1
0
/*
 * Fetch disklabel for disk.
 * Use ioctl to get label unless -r flag is given.
 */
struct disklabel32 *
readlabel(int f)
{
	const char *msg;
	struct disklabel32 *lp;
	int r;

	if (rflag) {
		r = read(f, bootarea, BBSIZE);
		if (r < BBSIZE)
			err(4, "%s", specname);
		for (lp = (struct disklabel32 *)bootarea;
		    lp <= (struct disklabel32 *)(bootarea + BBSIZE - sizeof(*lp));
		    lp = (struct disklabel32 *)((char *)lp + 16)) {
			if (lp->d_magic == DISKMAGIC32 &&
			    lp->d_magic2 == DISKMAGIC32)
				break;
		}
		if (lp > (struct disklabel32 *)(bootarea+BBSIZE-sizeof(*lp)) ||
		    lp->d_magic != DISKMAGIC32 || lp->d_magic2 != DISKMAGIC32 ||
		    dkcksum32(lp) != 0) {
			errx(1, "bad pack magic number (label is damaged, "
				"or pack is unlabeled)");
		}
		if ((msg = fixlabel(f, lp, 0)) != NULL)
			errx(1, msg);
	} else {
		lp = &lab;
		if (ioctl(f, DIOCGDINFO32, lp) < 0) {
			l_perror("ioctl DIOCGDINFO32");
			exit(4);
		}
	}
	return (lp);
}
/*
 * Create a disklabel based on a disk_info structure, initializing
 * the appropriate fields and creating a raw partition that covers the
 * whole disk.
 *
 * If a diskslice is passed, the label is truncated to the slice
 */
static disklabel_t
l32_clone_label(struct disk_info *info, struct diskslice *sp)
{
	struct disklabel32 *lp;
	disklabel_t res;

	lp = kmalloc(sizeof *lp, M_DEVBUF, M_WAITOK | M_ZERO);
	lp->d_nsectors = info->d_secpertrack;
	lp->d_ntracks = info->d_nheads;
	lp->d_secpercyl = info->d_secpercyl;
	lp->d_secsize = info->d_media_blksize;

	if (sp)
		lp->d_secperunit = (u_int)sp->ds_size;
	else
		lp->d_secperunit = (u_int)info->d_media_blocks;

	if (lp->d_typename[0] == '\0')
		strncpy(lp->d_typename, "amnesiac", sizeof(lp->d_typename));
	if (lp->d_packname[0] == '\0')
		strncpy(lp->d_packname, "fictitious", sizeof(lp->d_packname));
	if (lp->d_nsectors == 0)
		lp->d_nsectors = 32;
	if (lp->d_ntracks == 0)
		lp->d_ntracks = 64;
	lp->d_secpercyl = lp->d_nsectors * lp->d_ntracks;
	lp->d_ncylinders = lp->d_secperunit / lp->d_secpercyl;
	if (lp->d_rpm == 0)
		lp->d_rpm = 3600;
	if (lp->d_interleave == 0)
		lp->d_interleave = 1;
	if (lp->d_npartitions < RAW_PART + 1)
		lp->d_npartitions = MAXPARTITIONS32;
	if (lp->d_bbsize == 0)
		lp->d_bbsize = BBSIZE;
	if (lp->d_sbsize == 0)
		lp->d_sbsize = SBSIZE;

	/*
	 * Used by various devices to create a compatibility slice which
	 * allows us to mount root from devices which do not have a
	 * disklabel.  Particularly: CDs.
	 */
	lp->d_partitions[RAW_PART].p_size = lp->d_secperunit;
	if (info->d_dsflags & DSO_COMPATPARTA) {
		lp->d_partitions[0].p_size = lp->d_secperunit;
		lp->d_partitions[0].p_fstype = FS_OTHER;
	}
	lp->d_magic = DISKMAGIC32;
	lp->d_magic2 = DISKMAGIC32;
	lp->d_checksum = dkcksum32(lp);
	res.lab32 = lp;
	return (res);
}
/*
 * Attempt to read a disk label from a device.  
 *
 * Returns NULL on sucess, and an error string on failure
 */
static const char *
l32_readdisklabel(cdev_t dev, struct diskslice *sp, disklabel_t *lpp,
		struct disk_info *info)
{
	disklabel_t lpx;
	struct buf *bp;
	struct disklabel32 *dlp;
	const char *msg = NULL;
	int secsize = info->d_media_blksize;

	bp = geteblk(secsize);
	bp->b_bio1.bio_offset = (off_t)LABELSECTOR32 * secsize;
	bp->b_bio1.bio_done = biodone_sync;
	bp->b_bio1.bio_flags |= BIO_SYNC;
	bp->b_bcount = secsize;
	bp->b_flags &= ~B_INVAL;
	bp->b_cmd = BUF_CMD_READ;
	dev_dstrategy(dev, &bp->b_bio1);
	if (biowait(&bp->b_bio1, "labrd"))
		msg = "I/O error";
	else for (dlp = (struct disklabel32 *)bp->b_data;
	    dlp <= (struct disklabel32 *)((char *)bp->b_data +
	    secsize - sizeof(*dlp));
	    dlp = (struct disklabel32 *)((char *)dlp + sizeof(long))) {
		if (dlp->d_magic != DISKMAGIC32 ||
		    dlp->d_magic2 != DISKMAGIC32) {
			/*
			 * NOTE! dsreadandsetlabel() does a strcmp() on
			 * this string.
			 */
			if (msg == NULL) 
				msg = "no disk label";
		} else if (dlp->d_npartitions > MAXPARTITIONS32 ||
			   dkcksum32(dlp) != 0) {
			msg = "disk label corrupted";
		} else {
			lpx.lab32 = dlp;
			msg = l32_fixlabel(NULL, sp, lpx, FALSE);
			if (msg == NULL) {
				(*lpp).lab32 = kmalloc(sizeof(*dlp),
						       M_DEVBUF, M_WAITOK|M_ZERO);
				*(*lpp).lab32 = *dlp;
			}
			break;
		}
	}
	bp->b_flags |= B_INVAL | B_AGE;
	brelse(bp);
	return (msg);
}
Example #4
0
int
writelabel(int f, const char *boot, struct disklabel32 *lp)
{
	const char *msg;
	int flag;
	int r;

	if (disable_write) {
		Warning("write to disk label suppressed - label was as follows:");
		display(stdout, lp);
		return (0);
	} else {
		/* make sure we are not overwriting our boot code */
		if (checkoldboot(f, boot))
			errx(4, "Will not overwrite old bootblocks w/ label, install new boot blocks first!");
		setbootflag(lp);
		lp->d_magic = DISKMAGIC32;
		lp->d_magic2 = DISKMAGIC32;
		lp->d_checksum = 0;
		lp->d_checksum = dkcksum32(lp);
		if (rflag) {
			/*
			 * 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 (ioctl(f, DIOCSDINFO32, lp) < 0 &&
				errno != ENODEV && errno != ENOTTY) {
				l_perror("ioctl DIOCSDINFO32");
				return (1);
			}
			lseek(f, (off_t)0, SEEK_SET);

			/*
			 * write enable label sector before write
			 * (if necessary), disable after writing.
			 */
			flag = 1;
			if (ioctl(f, DIOCWLABEL, &flag) < 0)
				warn("ioctl DIOCWLABEL");
			msg = fixlabel(f, lp, 1);
			if (msg) {
				warn(msg);
				return (1);
			}
			r = write(f, boot, lp->d_bbsize);
			fixlabel(f, lp, 0);
			if (r != ((ssize_t)lp->d_bbsize)) {
				warn("write");
				return (1);
			}
#if NUMBOOT > 0
			/*
			 * Output the remainder of the disklabel
			 */
			if (bootbuf) {
				fixlabel(f, lp, 1);
				r = write(f, bootbuf, bootsize);
				fixlabel(f, lp, 0);
				if (r != bootsize) {
					warn("write");
					return(1);
				}
			}
#endif
			flag = 0;
			ioctl(f, DIOCWLABEL, &flag);
		} else if (ioctl(f, DIOCWDINFO32, lp) < 0) {
			l_perror("ioctl DIOCWDINFO32");
			return (1);
		}
	}
	return (0);
}
Example #5
0
/*
 * Traditional 32 bit disklabels actually use absolute sector numbers on
 * disk, NOT slice relative sector numbres.   The OS hides this from us
 * when we use DIOC ioctls to access the label, but newer versions of
 * Dragonfly no longer adjusts the disklabel when snooping reads or writes
 * so we have to figure it out ourselves.
 */
const char *
fixlabel(int f, struct disklabel32 *lp, int writeadj)
{
	const char *msg = NULL;
	struct partinfo info;
	struct partition32 *pp;
	u_int64_t start;
	u_int64_t end;
	u_int64_t offset;
	int part;
	int rev;
	size_t rev_len = sizeof(rev);

	if (sysctlbyname("kern.osrevision", &rev, &rev_len, NULL, 0) < 0) {
		errx(1, "Cannot use raw mode on non-DragonFly systems\n");
	}
	if (rev < 200701) {
		warnx("Warning running new disklabel on old DragonFly systems,\n"
		      "assuming the disk layer will fixup the label.\n");
		sleep(3);
		return(NULL);
	}

	pp = &lp->d_partitions[RAW_PART];

	if (forceflag) {
		info.media_offset = slice_start_lba * lp->d_secsize;
		info.media_blocks = pp->p_size;
		info.media_blksize = lp->d_secsize;
	} else if (ioctl(f, DIOCGPART, &info) < 0) {
		msg = "Unable to extract the slice starting LBA, "
		      "you must use the -f <slice_start_lba> option\n"
		      "to specify it manually, or perhaps try without "
		      "using -r and let the kernel deal with it\n";
		return(msg);
	}

	if (lp->d_magic != DISKMAGIC32 || lp->d_magic2 != DISKMAGIC32)
		return ("fixlabel: invalid magic");
	if (dkcksum32(lp) != 0)
		return ("fixlabel: invalid checksum");

	/*
	 * What a mess.  For ages old backwards compatibility the disklabel
	 * on-disk stores absolute offsets instead of slice-relative offsets.
	 * So fix it up when reading, writing, or snooping.
	 *
	 * The in-core label is always slice-relative.
	 */
	if (writeadj) {
		/*
		 * incore -> disk
		 */
		start = 0;
		offset = info.media_offset / info.media_blksize;
	} else {
		/*
		 * disk -> incore
		 */
		start = info.media_offset / info.media_blksize;
		offset = -info.media_offset / info.media_blksize;
	}
	if (pp->p_offset != start)
		return ("fixlabel: raw partition offset != slice offset");
	if (pp->p_size != info.media_blocks) {
		if (pp->p_size > info.media_blocks)
			return ("fixlabel: raw partition size > slice size");
	}
	end = start + info.media_blocks;
	if (start > end)
		return ("fixlabel: slice wraps");
	if (lp->d_secpercyl <= 0)
		return ("fixlabel: d_secpercyl <= 0");
	pp -= RAW_PART;
	for (part = 0; part < lp->d_npartitions; part++, pp++) {
		if (pp->p_offset != 0 || pp->p_size != 0) {
			if (pp->p_offset < start
			    || pp->p_offset + pp->p_size > end
			    || pp->p_offset + pp->p_size < pp->p_offset) {
				/* XXX else silently discard junk. */
				bzero(pp, sizeof *pp);
			} else {
				pp->p_offset += offset;
			}
		}
	}
	lp->d_checksum = 0;
	lp->d_checksum = dkcksum32(lp);
	return (NULL);
}
/*
 * Write disk label back to device after modification.
 */
static int
l32_writedisklabel(cdev_t dev, struct diskslices *ssp, struct diskslice *sp,
		   disklabel_t lpx)
{
	struct disklabel32 *lp;
	struct disklabel32 *dlp;
	struct buf *bp;
	const char *msg;
	int error = 0;

	lp = lpx.lab32;

	if (lp->d_partitions[RAW_PART].p_offset != 0)
		return (EXDEV);			/* not quite right */

	bp = geteblk((int)lp->d_secsize);
	bp->b_bio1.bio_offset = (off_t)LABELSECTOR32 * lp->d_secsize;
	bp->b_bio1.bio_done = biodone_sync;
	bp->b_bio1.bio_flags |= BIO_SYNC;
	bp->b_bcount = lp->d_secsize;

#if 1
	/*
	 * We read the label first to see if it's there,
	 * in which case we will put ours at the same offset into the block..
	 * (I think this is stupid [Julian])
	 * Note that you can't write a label out over a corrupted label!
	 * (also stupid.. how do you write the first one? by raw writes?)
	 */
	bp->b_flags &= ~B_INVAL;
	bp->b_cmd = BUF_CMD_READ;
	KKASSERT(dkpart(dev) == WHOLE_SLICE_PART);
	dev_dstrategy(dev, &bp->b_bio1);
	error = biowait(&bp->b_bio1, "labrd");
	if (error)
		goto done;
	for (dlp = (struct disklabel32 *)bp->b_data;
	    dlp <= (struct disklabel32 *)
	      ((char *)bp->b_data + lp->d_secsize - sizeof(*dlp));
	    dlp = (struct disklabel32 *)((char *)dlp + sizeof(long))) {
		if (dlp->d_magic == DISKMAGIC32 &&
		    dlp->d_magic2 == DISKMAGIC32 && dkcksum32(dlp) == 0) {
			*dlp = *lp;
			lpx.lab32 = dlp;
			msg = l32_fixlabel(NULL, sp, lpx, TRUE);
			if (msg) {
				error = EINVAL;
			} else {
				bp->b_cmd = BUF_CMD_WRITE;
				bp->b_bio1.bio_done = biodone_sync;
				bp->b_bio1.bio_flags |= BIO_SYNC;
				KKASSERT(dkpart(dev) == WHOLE_SLICE_PART);
				dev_dstrategy(dev, &bp->b_bio1);
				error = biowait(&bp->b_bio1, "labwr");
			}
			goto done;
		}
	}
	error = ESRCH;
done:
#else
	bzero(bp->b_data, lp->d_secsize);
	dlp = (struct disklabel32 *)bp->b_data;
	*dlp = *lp;
	bp->b_flags &= ~B_INVAL;
	bp->b_cmd = BUF_CMD_WRITE;
	bp->b_bio1.bio_done = biodone_sync;
	bp->b_bio1.bio_flags |= BIO_SYNC;
	BUF_STRATEGY(bp, 1);
	error = biowait(&bp->b_bio1, "labwr");
#endif
	bp->b_flags |= B_INVAL | B_AGE;
	brelse(bp);
	return (error);
}
/*
 * Check new disk label for sensibility before setting it.
 */
static int
l32_setdisklabel(disklabel_t olpx, disklabel_t nlpx, struct diskslices *ssp,
		 struct diskslice *sp, u_int32_t *openmask)
{
	struct disklabel32 *olp, *nlp;
	struct partition32 *opp, *npp;
	int part;
	int i;

	olp = olpx.lab32;
	nlp = nlpx.lab32;

	/*
	 * Check it is actually a disklabel we are looking at.
	 */
	if (nlp->d_magic != DISKMAGIC32 || nlp->d_magic2 != DISKMAGIC32 ||
	    dkcksum32(nlp) != 0)
		return (EINVAL);

	/*
	 * For each partition that we think is open, check the new disklabel
	 * for compatibility.  Ignore special partitions (>= 128).
	 */
	i = 0;
	while (i < 128) {
		if (openmask[i >> 5] == 0) {
			i += 32;
			continue;
		}
		if ((openmask[i >> 5] & (1 << (i & 31))) == 0) {
			++i;
			continue;
		}
		if (nlp->d_npartitions <= i)
			return (EBUSY);
		opp = &olp->d_partitions[i];
		npp = &nlp->d_partitions[i];
		if (npp->p_offset != opp->p_offset || npp->p_size < opp->p_size)
			return (EBUSY);
		/*
		 * Copy internally-set partition information
		 * if new label doesn't include it.		XXX
		 * (If we are using it then we had better stay the same type)
		 * This is possibly dubious, as someone else noted (XXX)
		 */
		if (npp->p_fstype == FS_UNUSED && opp->p_fstype != FS_UNUSED) {
			npp->p_fstype = opp->p_fstype;
			npp->p_fsize = opp->p_fsize;
			npp->p_frag = opp->p_frag;
			npp->p_cpg = opp->p_cpg;
		}
		++i;
	}
 	nlp->d_checksum = 0;
 	nlp->d_checksum = dkcksum32(nlp);
	*olp = *nlp;

	if (olp->d_partitions[RAW_PART].p_offset)
		return (EXDEV);
	if (olp->d_secperunit > sp->ds_size)
		return (ENOSPC);
	for (part = 0; part < olp->d_npartitions; ++part) {
		if (olp->d_partitions[part].p_size > sp->ds_size)
			return(ENOSPC);
	}
	return (0);
}