[BACK]Return to mbr.c CVS log [TXT][DIR] Up to [local] / src / sbin / fdisk

File: [local] / src / sbin / fdisk / mbr.c (download)

Revision 1.124, Wed May 17 12:59:37 2023 UTC (12 months, 2 weeks ago) by krw
Branch: MAIN
CVS Tags: OPENBSD_7_5_BASE, OPENBSD_7_5, OPENBSD_7_4_BASE, OPENBSD_7_4, HEAD
Changes since 1.123: +4 -4 lines

Make function and symmetry obvious by renaming PRT_make() to
PRT_prt_to_dp() and PRT_parse() to PRT_dp_to_prt().

No functional change.

/*	$OpenBSD: mbr.c,v 1.124 2023/05/17 12:59:37 krw Exp $	*/

/*
 * Copyright (c) 1997 Tobias Weingartner
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include <sys/param.h>	/* DEV_BSIZE */
#include <sys/ioctl.h>
#include <sys/disklabel.h>
#include <sys/dkio.h>

#include <err.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "part.h"
#include "disk.h"
#include "misc.h"
#include "mbr.h"
#include "gpt.h"

struct dos_mbr		default_dmbr;

void		mbr_to_dos_mbr(const struct mbr *, struct dos_mbr *);
void		dos_mbr_to_mbr(const struct dos_mbr *, const uint64_t,
    const uint64_t, struct mbr *);

void
MBR_init(struct mbr *mbr)
{
	struct dos_partition	dp;
	struct prt		bootprt, obsdprt;
	daddr_t			daddr;

	memset(&gmbr, 0, sizeof(gmbr));
	memset(&gh, 0, sizeof(gh));
	memset(&gp, 0, sizeof(gp));

	if (mbr->mbr_lba_self != 0) {
		/* Extended MBR - save lba's, set sig, zap everything else. */
		memset(mbr->mbr_code, 0, sizeof(mbr->mbr_code));
		memset(mbr->mbr_prt, 0, sizeof(mbr->mbr_prt));
		mbr->mbr_signature = DOSMBR_SIGNATURE;
		return;
	}

	memset(&obsdprt, 0, sizeof(obsdprt));
	memset(&bootprt, 0, sizeof(bootprt));

	if (disk.dk_bootprt.prt_ns > 0) {
		bootprt = disk.dk_bootprt;
	} else {
		memcpy(&dp, &default_dmbr.dmbr_parts[0], sizeof(dp));
		PRT_dp_to_prt(&dp, 0, 0, &bootprt);
	}

	if (bootprt.prt_ns > 0) {
		/* Start OpenBSD partition immediately after bootprt. */
		obsdprt.prt_bs = bootprt.prt_bs + bootprt.prt_ns;
	} else if (disk.dk_heads > 1 || disk.dk_cylinders > 1) {
		/*
		 * Start OpenBSD partition on power of 2 block number
		 * after the first track.
		 */
		daddr = 1;
		while (daddr < DL_SECTOBLK(&dl, disk.dk_sectors))
			daddr *= 2;
		obsdprt.prt_bs = DL_BLKTOSEC(&dl, daddr);
	} else {
		/* Start OpenBSD partition immediately after MBR. */
		obsdprt.prt_bs = 1;
	}

	if (obsdprt.prt_bs >= disk.dk_size) {
		memset(&obsdprt, 0, sizeof(obsdprt));
	} else {
		obsdprt.prt_ns = disk.dk_size - obsdprt.prt_bs;
		obsdprt.prt_id = DOSPTYP_OPENBSD;
		if (bootprt.prt_flag != DOSACTIVE)
			obsdprt.prt_flag = DOSACTIVE;
	}

	memset(mbr, 0, sizeof(*mbr));
	memcpy(mbr->mbr_code, default_dmbr.dmbr_boot, sizeof(mbr->mbr_code));
	mbr->mbr_prt[0] = bootprt;
	mbr->mbr_prt[3] = obsdprt;
	mbr->mbr_signature = DOSMBR_SIGNATURE;
}

void
dos_mbr_to_mbr(const struct dos_mbr *dmbr, const uint64_t lba_self,
    const uint64_t lba_firstembr, struct mbr *mbr)
{
	struct dos_partition	dos_parts[NDOSPART];
	uint8_t			*p;
	unsigned int		 i;

	p = (uint8_t *)dmbr;
	mbr->mbr_dmbrzeros = 0;
	for (i = 0; i < sizeof(struct dos_mbr) && *p == 0; i++, p++)
		mbr->mbr_dmbrzeros++;

	memcpy(mbr->mbr_code, dmbr->dmbr_boot, sizeof(mbr->mbr_code));
	mbr->mbr_lba_self = lba_self;
	mbr->mbr_lba_firstembr = lba_firstembr;
	mbr->mbr_signature = letoh16(dmbr->dmbr_sign);

	memcpy(dos_parts, dmbr->dmbr_parts, sizeof(dos_parts));

	for (i = 0; i < nitems(mbr->mbr_prt); i++) {
		memset(&mbr->mbr_prt[i], 0, sizeof(mbr->mbr_prt[i]));
		if (i < nitems(dmbr->dmbr_parts))
			PRT_dp_to_prt(&dos_parts[i], lba_self, lba_firstembr,
			    &mbr->mbr_prt[i]);
	}
}

void
mbr_to_dos_mbr(const struct mbr *mbr, struct dos_mbr *dos_mbr)
{
	struct dos_partition	dos_partition;
	unsigned int		i;

	memcpy(dos_mbr->dmbr_boot, mbr->mbr_code, sizeof(dos_mbr->dmbr_boot));
	dos_mbr->dmbr_sign = htole16(DOSMBR_SIGNATURE);

	for (i = 0; i < nitems(dos_mbr->dmbr_parts); i++) {
		memset(&dos_partition, 0, sizeof(dos_partition));
		if (i < nitems(mbr->mbr_prt)) {
			PRT_prt_to_dp(&mbr->mbr_prt[i], mbr->mbr_lba_self,
			    mbr->mbr_lba_firstembr, &dos_partition);
		}
		memcpy(&dos_mbr->dmbr_parts[i], &dos_partition,
		    sizeof(dos_mbr->dmbr_parts[i]));
	}
}

void
MBR_print(const struct mbr *mbr, const char *units)
{
	unsigned int		i;

	DISK_printgeometry("s");

	printf("Offset: %llu\t", mbr->mbr_lba_self);
	printf("Signature: 0x%X\n", (int)mbr->mbr_signature);
	PRT_print_parthdr();

	for (i = 0; i < nitems(mbr->mbr_prt); i++)
		PRT_print_part(i, &mbr->mbr_prt[i], units);
}

int
MBR_read(const uint64_t lba_self, const uint64_t lba_firstembr, struct mbr *mbr)
{
	struct dos_mbr		 dos_mbr;

	if (DISK_readbytes(&dos_mbr, lba_self, sizeof(dos_mbr)))
		return -1;

	dos_mbr_to_mbr(&dos_mbr, lba_self, lba_firstembr, mbr);

	return 0;
}

int
MBR_write(const struct mbr *mbr)
{
	struct dos_mbr		 dos_mbr;

	mbr_to_dos_mbr(mbr, &dos_mbr);

	if (DISK_writebytes(&dos_mbr, mbr->mbr_lba_self, sizeof(dos_mbr)))
		return -1;

	/* Refresh in-kernel disklabel from the updated disk information. */
	if (ioctl(disk.dk_fd, DIOCRLDINFO, 0) == -1)
		warn("DIOCRLDINFO");

	return 0;
}

int
MBR_valid_prt(const struct mbr *mbr)
{
	uint64_t		bs, ns;
	unsigned int		i, nprt;
	unsigned char		id;

	if (mbr->mbr_dmbrzeros == sizeof(struct dos_mbr))
		return 1;	/* All zeros struct dos_mbr is editable. */

	nprt = 0;
	for (i = 0; i < nitems(mbr->mbr_prt); i++) {
		bs = mbr->mbr_prt[i].prt_bs;
		ns = mbr->mbr_prt[i].prt_ns;
		id = mbr->mbr_prt[i].prt_id;
		if ((bs == 0 && ns == 0 && id == 0) ||
		    (bs < DL_GETDSIZE(&dl) && ns > 0 && ns <= DL_GETDSIZE(&dl)))
			nprt++;
	}

	return nprt > 0 && mbr->mbr_signature == DOSMBR_SIGNATURE;
}