Home | History | Annotate | Line # | Download | only in efi
      1  1.5  riastrad /* $NetBSD: gptsubr.c,v 1.5 2025/03/02 01:07:11 riastradh Exp $ */
      2  1.1  christos 
      3  1.1  christos /*
      4  1.1  christos  * Redistribution and use in source and binary forms, with or without
      5  1.1  christos  * modification, are permitted provided that the following conditions
      6  1.1  christos  * are met:
      7  1.1  christos  * 1. Redistributions of source code must retain the above copyright
      8  1.1  christos  *    notice, this list of conditions and the following disclaimer.
      9  1.1  christos  * 2. Redistributions in binary form must reproduce the above copyright
     10  1.1  christos  *    notice, this list of conditions and the following disclaimer in the
     11  1.1  christos  *    documentation and/or other materials provided with the distribution.
     12  1.1  christos  *
     13  1.1  christos  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
     14  1.1  christos  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     15  1.1  christos  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     16  1.1  christos  * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     17  1.1  christos  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     18  1.1  christos  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
     19  1.1  christos  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     20  1.1  christos  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     21  1.1  christos  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     22  1.1  christos  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     23  1.1  christos  * SUCH DAMAGE.
     24  1.1  christos  */
     25  1.1  christos 
     26  1.1  christos #include <sys/cdefs.h>
     27  1.1  christos #ifndef lint
     28  1.5  riastrad __RCSID("$NetBSD: gptsubr.c,v 1.5 2025/03/02 01:07:11 riastradh Exp $");
     29  1.1  christos #endif /* not lint */
     30  1.1  christos 
     31  1.1  christos #include <sys/param.h>
     32  1.1  christos 
     33  1.1  christos #include <sys/disk.h>
     34  1.1  christos #include <sys/disklabel.h>
     35  1.1  christos #include <sys/disklabel_gpt.h>
     36  1.1  christos #include <sys/dkio.h>
     37  1.1  christos #include <sys/ioctl.h>
     38  1.1  christos #include <sys/stat.h>
     39  1.1  christos #include <sys/statvfs.h>
     40  1.1  christos 
     41  1.1  christos #include <err.h>
     42  1.1  christos #include <fcntl.h>
     43  1.1  christos #include <libgen.h>
     44  1.1  christos #include <paths.h>
     45  1.1  christos #include <stdbool.h>
     46  1.1  christos #include <stdio.h>
     47  1.1  christos #include <stdlib.h>
     48  1.1  christos #include <unistd.h>
     49  1.1  christos #include <uuid.h>
     50  1.1  christos 
     51  1.1  christos #include "defs.h"
     52  1.1  christos #include "gpt.h"
     53  1.1  christos #include "gptsubr.h"
     54  1.1  christos #include "map.h"
     55  1.1  christos 
     56  1.1  christos #define DEBUG
     57  1.1  christos 
     58  1.1  christos #ifdef DEBUG
     59  1.1  christos #define DPRINTF(fmt, ...)	printf(fmt, __VA_ARGS__)
     60  1.1  christos #else
     61  1.1  christos #define DPRINTF(fmt, ...)	do { } while (/*CONSTCOND*/0)
     62  1.1  christos #endif
     63  1.1  christos 
     64  1.1  christos static const char *
     65  1.1  christos map_type_name(int map_type)
     66  1.1  christos {
     67  1.1  christos 	const char *xtbl[] = {
     68  1.1  christos 		"UNUSED",	// 0
     69  1.1  christos 		"MBR",		// 1
     70  1.1  christos 		"MBR_PART",	// 2
     71  1.1  christos 		"PRI_GPT_HDR",	// 3
     72  1.1  christos 		"SEC_GPT_HDR",	// 4
     73  1.1  christos 		"PRI_GPT_TBL",	// 5
     74  1.1  christos 		"SEC_GPT_TBL",	// 6
     75  1.1  christos 		"GPT_PART",	// 7
     76  1.1  christos 		"PMBR",		// 8
     77  1.1  christos 	};
     78  1.1  christos 
     79  1.1  christos 	if (map_type >= (int)__arraycount(xtbl))
     80  1.1  christos 		return "UNKNOWN";
     81  1.1  christos 
     82  1.1  christos 	return xtbl[map_type];
     83  1.1  christos }
     84  1.1  christos 
     85  1.1  christos #if 0
     86  1.1  christos struct map {
     87  1.1  christos 	off_t	map_start;
     88  1.1  christos 	off_t	map_size;
     89  1.1  christos 	struct map *map_next;
     90  1.1  christos 	struct map *map_prev;
     91  1.1  christos 	int	map_type;
     92  1.1  christos #define	MAP_TYPE_UNUSED		0
     93  1.1  christos #define	MAP_TYPE_MBR		1
     94  1.1  christos #define	MAP_TYPE_MBR_PART	2
     95  1.1  christos #define	MAP_TYPE_PRI_GPT_HDR	3
     96  1.1  christos #define	MAP_TYPE_SEC_GPT_HDR	4
     97  1.1  christos #define	MAP_TYPE_PRI_GPT_TBL	5
     98  1.1  christos #define	MAP_TYPE_SEC_GPT_TBL	6
     99  1.1  christos #define	MAP_TYPE_GPT_PART	7
    100  1.1  christos #define	MAP_TYPE_PMBR		8
    101  1.1  christos 	unsigned int map_index;
    102  1.1  christos 	void 	*map_data;
    103  1.1  christos 	int	map_alloc;
    104  1.1  christos };
    105  1.1  christos 
    106  1.1  christos struct gpt_ent {
    107  1.1  christos 	uint8_t		ent_type[16];	/* partition type GUID */
    108  1.1  christos 	uint8_t		ent_guid[16];	/* unique partition GUID */
    109  1.1  christos 	uint64_t	ent_lba_start;	/* start of partition */
    110  1.1  christos 	uint64_t	ent_lba_end;	/* end of partition */
    111  1.1  christos 	uint64_t	ent_attr;	/* partition attributes */
    112  1.1  christos 	uint16_t	ent_name[36];	/* partition name in UCS-2 */
    113  1.1  christos };
    114  1.1  christos 
    115  1.1  christos struct gpt_hdr {
    116  1.1  christos 	int8_t		hdr_sig[8];	/* identifies GUID Partition Table */
    117  1.1  christos 	uint32_t	hdr_revision;	/* GPT specification revision */
    118  1.1  christos 	uint32_t	hdr_size;	/* size of GPT Header */
    119  1.1  christos 	uint32_t	hdr_crc_self;	/* CRC32 of GPT Header */
    120  1.1  christos 	uint32_t	hdr__rsvd0;	/* must be zero */
    121  1.1  christos 	uint64_t	hdr_lba_self;	/* LBA that contains this Header */
    122  1.1  christos 	uint64_t	hdr_lba_alt;	/* LBA of backup GPT Header */
    123  1.1  christos 	uint64_t	hdr_lba_start;	/* first LBA usable for partitions */
    124  1.1  christos 	uint64_t	hdr_lba_end;	/* last LBA usable for partitions */
    125  1.1  christos 	uint8_t		hdr_guid[16];	/* GUID to identify the disk */
    126  1.1  christos 	uint64_t	hdr_lba_table;	/* first LBA of GPE array */
    127  1.1  christos 	uint32_t	hdr_entries;	/* number of entries in GPE array */
    128  1.1  christos 	uint32_t	hdr_entsz;	/* size of each GPE */
    129  1.1  christos 	uint32_t	hdr_crc_table;	/* CRC32 of GPE array */
    130  1.1  christos 	/*
    131  1.1  christos 	 * The remainder of the block that contains the GPT Header
    132  1.1  christos 	 * is reserved by EFI for future GPT Header expansion, and
    133  1.1  christos 	 * must be zero.
    134  1.1  christos 	 */
    135  1.1  christos };
    136  1.1  christos #endif
    137  1.1  christos 
    138  1.1  christos struct map_widths {
    139  1.1  christos 	uint start;
    140  1.1  christos 	uint size;
    141  1.1  christos 	uint type_name;
    142  1.1  christos };
    143  1.1  christos 
    144  1.1  christos static struct map_widths
    145  1.1  christos get_map_widths(gpt_t gpt)
    146  1.1  christos {
    147  1.1  christos 	struct map_widths w;
    148  1.1  christos 	off_t max_start = 0;
    149  1.1  christos 	off_t max_size = 0;
    150  1.1  christos 	map_t m;
    151  1.1  christos 
    152  1.1  christos 	w.type_name = 0;
    153  1.1  christos 	for (m = map_first(gpt); m != NULL; m = m->map_next) {
    154  1.1  christos 		uint n;
    155  1.1  christos 
    156  1.1  christos 		if (max_start < m->map_start)
    157  1.1  christos 			max_start = m->map_start;
    158  1.1  christos 		if (max_size < m->map_size)
    159  1.1  christos 			max_size = m->map_size;
    160  1.1  christos 		if (m->map_type == MAP_TYPE_GPT_PART) {
    161  1.1  christos 			struct gpt_ent *ent = m->map_data;
    162  1.1  christos 			gpt_uuid_t gpt_uuid;
    163  1.1  christos 			char ent_type[128];
    164  1.1  christos 
    165  1.1  christos 			memcpy(&gpt_uuid, ent->ent_type, sizeof(gpt_uuid));
    166  1.5  riastrad 			n = (uint)gpt_uuid_snprintf(ent_type, sizeof(ent_type),
    167  1.5  riastrad 			    "%s", gpt_uuid);
    168  1.1  christos 			if (w.type_name < n)
    169  1.1  christos 				w.type_name = n;
    170  1.1  christos 		}
    171  1.1  christos 
    172  1.1  christos 	}
    173  1.2    martin 	w.start = (uint)snprintf(NULL, 0, "%" PRIx64, max_start);
    174  1.2    martin 	w.size = (uint)snprintf(NULL, 0, "%" PRIx64, max_size);
    175  1.1  christos 
    176  1.1  christos #define MIN_WIDTH_OF(s)	(sizeof(s) - 1)
    177  1.1  christos 	if (w.type_name < MIN_WIDTH_OF("TYPE_NAME"))
    178  1.1  christos 		w.type_name = MIN_WIDTH_OF("TYPE_NAME");
    179  1.1  christos 	if (w.start < MIN_WIDTH_OF("START"))
    180  1.1  christos 		w.start = MIN_WIDTH_OF("START");
    181  1.1  christos 	if (w.size < MIN_WIDTH_OF("SIZE"))
    182  1.1  christos 		w.size = MIN_WIDTH_OF("SIZE");
    183  1.1  christos #undef MIN_WIDTH_OF
    184  1.1  christos 
    185  1.1  christos 	return w;
    186  1.1  christos }
    187  1.1  christos 
    188  1.1  christos static void
    189  1.1  christos show_map_banner(struct map_widths w)
    190  1.1  christos {
    191  1.1  christos 
    192  1.1  christos 	printf("IDX %*s %*s   ATTR            PARTITION_GUID"
    193  1.1  christos 	    "                         TYPE_UUID       %*s "
    194  1.1  christos 	    "TYPE_NAME ENTRY_NAME  DESCRIPTION\n",
    195  1.1  christos 	    w.start, "START",
    196  1.1  christos 	    w.size, "SIZE",
    197  1.1  christos 	    w.type_name, "");
    198  1.1  christos }
    199  1.1  christos 
    200  1.1  christos static void
    201  1.1  christos show_map(map_t m, struct map_widths w)
    202  1.1  christos {
    203  1.1  christos 	struct gpt_ent *ent;
    204  1.1  christos 	struct gpt_hdr *hdr;
    205  1.1  christos 	gpt_uuid_t gpt_uuid;
    206  1.1  christos 	uuid_t uuid;
    207  1.1  christos 	uint32_t status;
    208  1.1  christos 	char *type_uuid;
    209  1.1  christos 	char *part_guid;
    210  1.1  christos 	uint64_t ent_attr;
    211  1.1  christos 	uint8_t  ent_desc[128];
    212  1.1  christos 	char     ent_type[128];
    213  1.1  christos 
    214  1.1  christos 	ent_desc[0] = '\0';
    215  1.1  christos 	ent_type[0] = '\0';
    216  1.1  christos 	ent_attr = 0;
    217  1.1  christos 
    218  1.1  christos 	switch (m->map_type) {
    219  1.1  christos 	case MAP_TYPE_PRI_GPT_HDR:
    220  1.1  christos 	case MAP_TYPE_SEC_GPT_HDR:
    221  1.1  christos 		hdr = m->map_data;
    222  1.1  christos 		memcpy(&uuid, hdr->hdr_guid, sizeof(uuid));
    223  1.1  christos 		uuid_to_string(&uuid, &part_guid, &status);
    224  1.1  christos 		type_uuid = estrdup("");
    225  1.1  christos 		break;
    226  1.3  riastrad 
    227  1.1  christos 	case MAP_TYPE_GPT_PART:
    228  1.1  christos 		ent = m->map_data;
    229  1.1  christos 
    230  1.1  christos 		memcpy(&uuid, ent->ent_type, sizeof(uuid));
    231  1.1  christos 		uuid_to_string(&uuid, &type_uuid, &status);
    232  1.3  riastrad 
    233  1.1  christos 		memcpy(&uuid, ent->ent_guid, sizeof(uuid));
    234  1.1  christos 		uuid_to_string(&uuid, &part_guid, &status);
    235  1.3  riastrad 
    236  1.1  christos 		ent_attr = ent->ent_attr;
    237  1.1  christos 
    238  1.1  christos 		memcpy(&gpt_uuid, ent->ent_type, sizeof(uuid));
    239  1.1  christos 		gpt_uuid_snprintf(ent_type, sizeof(ent_type), "%s", gpt_uuid);
    240  1.3  riastrad 
    241  1.1  christos 		/*
    242  1.1  christos 		 * Use the gpt.c code here rather than our
    243  1.1  christos 		 * ucs2_to_utf8() as we are in their world.
    244  1.1  christos 		 */
    245  1.1  christos 		utf16_to_utf8(ent->ent_name, sizeof(ent->ent_name),
    246  1.1  christos 		    ent_desc, sizeof(ent_desc));
    247  1.1  christos 
    248  1.1  christos 		break;
    249  1.3  riastrad 
    250  1.1  christos 	case MAP_TYPE_MBR_PART:
    251  1.1  christos 		part_guid = estrdup("");
    252  1.1  christos 		type_uuid = estrdup("");
    253  1.1  christos 		break;
    254  1.1  christos 
    255  1.1  christos 	case MAP_TYPE_MBR: {
    256  1.1  christos 		struct mbr *mbr = m->map_data;
    257  1.1  christos 
    258  1.5  riastrad 		easprintf(&part_guid,
    259  1.5  riastrad 		    "%02x%02x%02x%02x-0000-0000-0000-000000000000",
    260  1.1  christos 		    mbr->mbr_code[440],
    261  1.1  christos 		    mbr->mbr_code[441],
    262  1.1  christos 		    mbr->mbr_code[442],
    263  1.1  christos 		    mbr->mbr_code[443]);
    264  1.1  christos 		uuid_to_string(&(uuid_t)GPT_ENT_TYPE_MBR, &type_uuid, &status);
    265  1.1  christos 		break;
    266  1.1  christos 	}
    267  1.1  christos 	default:
    268  1.1  christos 		part_guid = estrdup("");
    269  1.1  christos 		type_uuid = estrdup("");
    270  1.1  christos 		break;
    271  1.1  christos 	}
    272  1.1  christos 
    273  1.2    martin 	printf("%2u: %*" PRIx64 " %*" PRIx64 " %08" PRIx64
    274  1.2    martin 	    " %36s %36s %*s %-11s %s\n",
    275  1.1  christos 	    m->map_index,
    276  1.1  christos 	    w.start,
    277  1.1  christos 	    m->map_start,
    278  1.1  christos 	    w.size,
    279  1.1  christos 	    m->map_size,
    280  1.1  christos 	    ent_attr,
    281  1.1  christos 	    part_guid,
    282  1.1  christos 	    type_uuid,
    283  1.1  christos 	    w.type_name,
    284  1.1  christos 	    ent_type,
    285  1.1  christos 	    map_type_name(m->map_type),
    286  1.1  christos 	    ent_desc);
    287  1.3  riastrad 
    288  1.1  christos 	free(part_guid);
    289  1.1  christos 	free(type_uuid);
    290  1.1  christos }
    291  1.1  christos 
    292  1.1  christos PUBLIC map_t
    293  1.1  christos find_gpt_map(const char *dev, uint idx)
    294  1.1  christos {
    295  1.1  christos 	gpt_t gpt;
    296  1.1  christos 	map_t m;
    297  1.1  christos 
    298  1.1  christos 	gpt = gpt_open(dev, GPT_READONLY, 0, 0, 0, 0);
    299  1.1  christos 
    300  1.1  christos 	if (gpt == NULL)
    301  1.1  christos 		err(EXIT_FAILURE, "gpt_open");
    302  1.1  christos 
    303  1.1  christos 	if (map_find(gpt, MAP_TYPE_PRI_GPT_HDR) == NULL)
    304  1.1  christos 		printf("GPT not found, displaying data from MBR.\n");
    305  1.1  christos 
    306  1.1  christos 	for (m = map_first(gpt); m != NULL; m = m->map_next) {
    307  1.1  christos 		if (m->map_index == idx)
    308  1.1  christos 			break;
    309  1.1  christos 	}
    310  1.1  christos 	gpt_close(gpt);
    311  1.1  christos 	return m;
    312  1.1  christos }
    313  1.1  christos 
    314  1.1  christos PUBLIC char *
    315  1.1  christos parent_of_fname(const char *fname)
    316  1.1  christos {
    317  1.1  christos 	struct dkwedge_info dkinfo;
    318  1.1  christos 	struct statvfs vfsb;
    319  1.1  christos 	struct stat sb;
    320  1.1  christos 	const char *d, *b;
    321  1.1  christos 	char *p;
    322  1.1  christos 	size_t n;
    323  1.1  christos 	int fd, rv;
    324  1.1  christos 
    325  1.1  christos 	rv = stat(fname, &sb);
    326  1.1  christos 	if (rv == -1)
    327  1.1  christos 		err(EXIT_FAILURE, "stat: %s", fname);
    328  1.1  christos 
    329  1.1  christos 	if (S_ISBLK(sb.st_mode) || S_ISCHR(sb.st_mode))
    330  1.1  christos 		return estrdup(fname);
    331  1.1  christos 
    332  1.1  christos 	rv = statvfs(fname, &vfsb);
    333  1.1  christos 	if (rv == -1)
    334  1.1  christos 		err(EXIT_FAILURE, "statvfs: %s", fname);
    335  1.1  christos 
    336  1.1  christos 	b = basename(vfsb.f_mntfromname);
    337  1.1  christos 	d = dirname(vfsb.f_mntfromname);
    338  1.1  christos 	easprintf(&p, "%s/r%s", d, b);
    339  1.3  riastrad 
    340  1.1  christos 	fd = open(p, O_RDONLY);
    341  1.1  christos 	if (fd == -1)
    342  1.1  christos 		err(EXIT_FAILURE, "open");
    343  1.3  riastrad 
    344  1.1  christos 	rv = ioctl(fd, DIOCGWEDGEINFO, &dkinfo);
    345  1.1  christos 	close(fd);
    346  1.1  christos 
    347  1.1  christos 	if (rv != -1) {
    348  1.1  christos 		free(p);
    349  1.1  christos 		return estrdup(dkinfo.dkw_parent);
    350  1.1  christos 	}
    351  1.1  christos 
    352  1.1  christos 	warn("ioctl: DIOCGWEDGEINFO");
    353  1.3  riastrad 
    354  1.1  christos 	/*
    355  1.1  christos 	 * Hum.  No wedges?  Assume we have the old disklabel
    356  1.1  christos 	 * "/dev/rwd0x" syntax.  Convert it to "/dev/rwd0d".
    357  1.1  christos 	 * XXX: this probably won't work.
    358  1.1  christos 	 */
    359  1.1  christos 	n = strlen(p);
    360  1.1  christos 	p[n - 1] = 'd';
    361  1.1  christos 
    362  1.1  christos 	return p;
    363  1.1  christos }
    364  1.1  christos 
    365  1.1  christos PUBLIC int
    366  1.1  christos mbr_sig_write(const char *fname, uint32_t new_sig, bool force, int verbose)
    367  1.1  christos {
    368  1.1  christos 	gpt_t gpt;
    369  1.1  christos 	map_t m;
    370  1.1  christos 	struct mbr *mbr;
    371  1.1  christos 	const char *dev;
    372  1.1  christos 	uint32_t old_sig;
    373  1.1  christos 
    374  1.1  christos 	if (fname == NULL)
    375  1.1  christos 		errx(EXIT_FAILURE, "please specify a device");
    376  1.1  christos 
    377  1.1  christos 	dev = parent_of_fname(fname);
    378  1.1  christos 	if (dev == NULL) {
    379  1.1  christos 		warnx("unable to find parent device of %s\n", fname);
    380  1.1  christos 		return -1;
    381  1.1  christos 	}
    382  1.1  christos 
    383  1.1  christos 	gpt = gpt_open(dev, GPT_MODIFIED, verbose, 0, 0, 0);
    384  1.1  christos 
    385  1.1  christos 	if (gpt == NULL)
    386  1.1  christos 		err(EXIT_FAILURE, "gpt_open");
    387  1.1  christos 
    388  1.1  christos 	m = map_find(gpt, MAP_TYPE_MBR);
    389  1.1  christos 	if (m == NULL)
    390  1.1  christos 		printf("No MBR partition found!\n");
    391  1.1  christos 	else {
    392  1.1  christos 		mbr = m->map_data;
    393  1.1  christos 
    394  1.1  christos 		memcpy(&old_sig, &mbr->mbr_code[440], 4);
    395  1.1  christos 
    396  1.1  christos 		if (old_sig == 0)
    397  1.1  christos 			force = true;
    398  1.1  christos 
    399  1.1  christos 		if (force) {
    400  1.1  christos 			memcpy(&mbr->mbr_code[440], &new_sig, 4);
    401  1.1  christos 			if (gpt_write(gpt, m) == -1)
    402  1.1  christos 				warn("gpt_write");
    403  1.1  christos 			else if (verbose)
    404  1.1  christos 				printf("sig: 0x%08x -> 0x%08x\n",
    405  1.1  christos 				    old_sig, new_sig);
    406  1.1  christos 		}
    407  1.1  christos 		else if (verbose)
    408  1.1  christos 			printf("sig: 0x%08x (unchanged)\n", old_sig);
    409  1.1  christos 	}
    410  1.1  christos 
    411  1.1  christos 	gpt_close(gpt);
    412  1.1  christos 	return 0;
    413  1.1  christos }
    414  1.1  christos 
    415  1.1  christos PUBLIC int
    416  1.1  christos show_gpt(const char *fname, int verbose)
    417  1.1  christos {
    418  1.1  christos 	gpt_t gpt;
    419  1.1  christos 	map_t m;
    420  1.1  christos 	struct map_widths w;
    421  1.1  christos 	const char *dev;
    422  1.1  christos 
    423  1.1  christos 	dev = parent_of_fname(fname);
    424  1.1  christos 	if (dev == NULL)
    425  1.1  christos 		return -1;
    426  1.1  christos 
    427  1.1  christos 	gpt = gpt_open(dev, GPT_READONLY, verbose, 0, 0, 0);
    428  1.1  christos 
    429  1.1  christos 	if (gpt == NULL)
    430  1.1  christos 		err(EXIT_FAILURE, "gpt_open");
    431  1.1  christos 
    432  1.1  christos 	if (map_find(gpt, MAP_TYPE_PRI_GPT_HDR) == NULL)
    433  1.1  christos 		warnx("GPT not found, displaying data from MBR.");
    434  1.1  christos 
    435  1.1  christos 	w = get_map_widths(gpt);
    436  1.1  christos 	show_map_banner(w);
    437  1.1  christos 
    438  1.1  christos 	for (m = map_first(gpt); m != NULL; m = m->map_next)
    439  1.1  christos 		show_map(m, w);
    440  1.1  christos 
    441  1.1  christos 	gpt_close(gpt);
    442  1.1  christos 	return 0;
    443  1.1  christos }
    444  1.1  christos 
    445  1.1  christos #if 0 /* UNUSED */
    446  1.1  christos 
    447  1.1  christos PUBLIC char *
    448  1.1  christos wedge_of_fname(const char *fname)
    449  1.1  christos {
    450  1.1  christos 	struct statvfs vfsbuf;
    451  1.1  christos 	int rv;
    452  1.1  christos 
    453  1.1  christos 	rv = statvfs(fname, &vfsbuf);
    454  1.1  christos 	if (rv) {
    455  1.1  christos 		warn("statvfs: %s", fname);
    456  1.1  christos 		return NULL;
    457  1.1  christos 	}
    458  1.1  christos 
    459  1.1  christos 	return estrdup(vfsbuf.f_mntfromname);
    460  1.1  christos }
    461  1.1  christos 
    462  1.1  christos PUBLIC int
    463  1.1  christos find_partition_idx(const char *fname, int verbose)
    464  1.1  christos {
    465  1.1  christos 	struct dkwedge_info dkinfo;
    466  1.1  christos 	struct stat sb;
    467  1.1  christos 	struct statvfs vfsbuf;
    468  1.1  christos 	gpt_t gpt;
    469  1.1  christos 	map_t m;
    470  1.1  christos 	off_t offset;
    471  1.1  christos 	size_t size;
    472  1.1  christos 	const char *parent;
    473  1.1  christos 	char *b, *d;
    474  1.1  christos 	int rv;
    475  1.1  christos 
    476  1.1  christos 	/* the following are for gpt_open() */
    477  1.1  christos 	off_t mediasz = 0;
    478  1.1  christos 	u_int secsz = 0;
    479  1.1  christos 	time_t timestamp = 0;
    480  1.1  christos 
    481  1.1  christos 	rv = stat(fname, &sb);
    482  1.1  christos 	if (rv == -1)
    483  1.1  christos 		err(EXIT_FAILURE, "stat: %s", fname);
    484  1.1  christos 
    485  1.1  christos 	if (S_ISBLK(sb.st_mode) || S_ISCHR(sb.st_mode)) {
    486  1.1  christos 		parent = fname;
    487  1.1  christos 		offset = 0;
    488  1.1  christos 		size = 0;
    489  1.1  christos 		goto doit;
    490  1.1  christos 	}
    491  1.1  christos 
    492  1.1  christos 	rv = statvfs(fname, &vfsbuf);
    493  1.1  christos 	if (rv == -1)
    494  1.1  christos 		err(EXIT_FAILURE, "statvfs: %s", fname);
    495  1.1  christos 
    496  1.1  christos 	b = basename(vfsbuf.f_mntfromname);
    497  1.1  christos 	d = dirname(vfsbuf.f_mntfromname);
    498  1.1  christos 
    499  1.1  christos 	{
    500  1.1  christos 		char *p;
    501  1.1  christos 
    502  1.1  christos 		easprintf(&p, "%s/r%s", d, b);
    503  1.1  christos 
    504  1.1  christos 		int fd = open(p, O_RDONLY);
    505  1.1  christos 		if (fd == -1)
    506  1.1  christos 			err(EXIT_FAILURE, "open");
    507  1.3  riastrad 
    508  1.1  christos 		rv = ioctl(fd, DIOCGWEDGEINFO, &dkinfo);
    509  1.1  christos 		if (rv != -1) {
    510  1.1  christos 			parent = dkinfo.dkw_parent;
    511  1.1  christos 			offset = dkinfo.dkw_offset;
    512  1.1  christos 			size   = dkinfo.dkw_size;
    513  1.1  christos 		}
    514  1.1  christos 		else {
    515  1.1  christos 			struct disklabel dl;
    516  1.3  riastrad 
    517  1.1  christos 			warn("ioctl: DIOCGWEDGEINFO");
    518  1.3  riastrad 
    519  1.1  christos 			rv = ioctl(fd, DIOCGDINFO, &dl);
    520  1.1  christos 			if (rv == -1)
    521  1.1  christos 				err(EXIT_FAILURE, "ioctl: DIOCGDINFO");
    522  1.3  riastrad 
    523  1.1  christos 			size_t n = strlen(p);
    524  1.3  riastrad 
    525  1.1  christos 			int pnum = p[n - 1] - 'a';
    526  1.1  christos 			p[n - 1] = 'd';
    527  1.3  riastrad 
    528  1.1  christos 			printf("num_parts: %u\n", dl.d_npartitions);
    529  1.1  christos 			printf("partition %d\n", pnum);
    530  1.4  riastrad 			printf("  offset = %u (%#x)\n",
    531  1.4  riastrad 			    dl.d_partitions[pnum].p_offset,
    532  1.4  riastrad 			    dl.d_partitions[pnum].p_offset);
    533  1.4  riastrad 			printf("  size = %u (%#x)\n",
    534  1.4  riastrad 			    dl.d_partitions[pnum].p_size,
    535  1.4  riastrad 			    dl.d_partitions[pnum].p_size);
    536  1.3  riastrad 
    537  1.1  christos 			parent = p;	// vfsbuf.f_mntfromname;
    538  1.1  christos 			offset = dl.d_partitions[pnum].p_offset;
    539  1.1  christos 			size   = dl.d_partitions[pnum].p_size;
    540  1.1  christos 		}
    541  1.3  riastrad 
    542  1.1  christos 		close(fd);
    543  1.1  christos 		free(p);
    544  1.1  christos 	}
    545  1.1  christos 
    546  1.1  christos  doit:
    547  1.1  christos 	DPRINTF("parent: %s\n", parent);
    548  1.1  christos 	DPRINTF("offset: 0x%lx\n", offset);
    549  1.1  christos 	DPRINTF("size: 0x%lx\n", size);
    550  1.1  christos 
    551  1.1  christos 	gpt = gpt_open(parent, GPT_READONLY,
    552  1.1  christos 	    verbose, mediasz, secsz, timestamp);
    553  1.1  christos 
    554  1.1  christos 	if (gpt == NULL)
    555  1.1  christos 		err(EXIT_FAILURE, "gpt_open");
    556  1.1  christos 
    557  1.1  christos 	if (map_find(gpt, MAP_TYPE_PRI_GPT_HDR) == NULL)
    558  1.1  christos 		printf("GPT not found, displaying data from MBR.\n");
    559  1.1  christos 
    560  1.1  christos 	int index = -1;
    561  1.1  christos 	struct map_widths w;
    562  1.1  christos 	if (verbose) {
    563  1.1  christos 		w = get_map_widths(gpt);
    564  1.1  christos 		show_map_banner(w);
    565  1.1  christos 	}
    566  1.1  christos 	for (m = map_first(gpt); m != NULL; m = m->map_next) {
    567  1.1  christos 		if (verbose)
    568  1.1  christos 			show_map(m, w);
    569  1.1  christos 
    570  1.1  christos 		if (m->map_type != MAP_TYPE_GPT_PART || m->map_index < 1) {
    571  1.1  christos 			continue;
    572  1.1  christos 		}
    573  1.1  christos 
    574  1.1  christos 		if ((off_t)offset == m->map_start &&
    575  1.1  christos 		    (off_t)size   == m->map_size) {
    576  1.1  christos 			if (index != -1)
    577  1.1  christos 				printf("match: %u\n", index);
    578  1.1  christos 			index = (int)m->map_index;
    579  1.1  christos 		}
    580  1.1  christos 	}
    581  1.1  christos 	return index;
    582  1.1  christos }
    583  1.1  christos 
    584  1.1  christos PUBLIC char *
    585  1.1  christos find_partition_pathname(const char *fname)
    586  1.1  christos {
    587  1.1  christos 	char *pname;	/* partition name */
    588  1.1  christos 	char *rname;	/* real name */
    589  1.1  christos 	struct statvfs vfsbuf;
    590  1.1  christos 	int i, rv;
    591  1.1  christos 
    592  1.1  christos 	rname = realpath(fname, NULL);
    593  1.1  christos 
    594  1.1  christos 	DPRINTF("fname: %s\n", fname);
    595  1.1  christos 	DPRINTF("rname: %s\n", rname);
    596  1.1  christos 
    597  1.1  christos 	rv = statvfs(rname, &vfsbuf);
    598  1.1  christos 	if (rv) {
    599  1.1  christos 		warn("statvfs: %s", rname);
    600  1.1  christos 		free(rname);
    601  1.1  christos 		return NULL;
    602  1.1  christos 	}
    603  1.1  christos 
    604  1.1  christos 	DPRINTF("mount: %s\n", vfsbuf.f_mntonname);
    605  1.1  christos 
    606  1.1  christos 	i = 0;
    607  1.5  riastrad 	while (vfsbuf.f_mntonname[i] == rname[i] &&
    608  1.5  riastrad 	    vfsbuf.f_mntonname[i] != '\0')
    609  1.1  christos 		i++;
    610  1.1  christos 
    611  1.1  christos 	if (vfsbuf.f_mntonname[i] != '\0')
    612  1.1  christos 		errx(EXIT_FAILURE, "mntonname mismatch: %s",
    613  1.1  christos 		    vfsbuf.f_mntonname + i);
    614  1.3  riastrad 
    615  1.1  christos 	pname = estrdup(rname + i);
    616  1.1  christos 	free(rname);
    617  1.1  christos 
    618  1.1  christos 	return pname;
    619  1.1  christos }
    620  1.1  christos 
    621  1.1  christos #endif
    622