Home | History | Annotate | Line # | Download | only in gpt
      1 /*-
      2  * Copyright (c) 2002 Marcel Moolenaar
      3  * All rights reserved.
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions
      7  * are met:
      8  *
      9  * 1. Redistributions of source code must retain the above copyright
     10  *    notice, this list of conditions and the following disclaimer.
     11  * 2. Redistributions in binary form must reproduce the above copyright
     12  *    notice, this list of conditions and the following disclaimer in the
     13  *    documentation and/or other materials provided with the distribution.
     14  *
     15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     25  */
     26 
     27 #if HAVE_NBTOOL_CONFIG_H
     28 #include "nbtool_config.h"
     29 #endif
     30 
     31 #include <sys/cdefs.h>
     32 #ifdef __FBSDID
     33 __FBSDID("$FreeBSD: src/sbin/gpt/show.c,v 1.14 2006/06/22 22:22:32 marcel Exp $");
     34 #endif
     35 #ifdef __RCSID
     36 __RCSID("$NetBSD: backup.c,v 1.21 2025/02/23 20:47:19 christos Exp $");
     37 #endif
     38 
     39 #include <sys/bootblock.h>
     40 #include <sys/types.h>
     41 
     42 #include <assert.h>
     43 #include <err.h>
     44 #include <limits.h>
     45 #include <stddef.h>
     46 #include <stdio.h>
     47 #include <stdlib.h>
     48 #include <string.h>
     49 #include <unistd.h>
     50 #include <prop/proplib.h>
     51 
     52 #include "map.h"
     53 #include "gpt.h"
     54 #include "gpt_private.h"
     55 
     56 static const char *backuphelp[] = {
     57 	"[-o outfile]",
     58 };
     59 
     60 static int cmd_backup(gpt_t, int, char *[]);
     61 
     62 const struct gpt_cmd c_backup = {
     63 	"backup",
     64 	cmd_backup,
     65 	backuphelp, __arraycount(backuphelp),
     66 	GPT_READONLY,
     67 };
     68 
     69 #define usage() gpt_usage(NULL, &c_backup)
     70 
     71 #define PROP_ERR(x)	if (!(x)) goto cleanup
     72 
     73 static int
     74 store_mbr(gpt_t gpt, unsigned int i, const struct mbr *mbr,
     75     prop_array_t *mbr_array)
     76 {
     77 	prop_dictionary_t mbr_dict;
     78 	const struct mbr_part *par = &mbr->mbr_part[i];
     79 
     80 	if (mbr->mbr_part[i].part_typ == MBR_PTYPE_UNUSED)
     81 		return 0;
     82 
     83 	mbr_dict = prop_dictionary_create();
     84 	PROP_ERR(mbr_dict);
     85 	assert(i <= INT_MAX);
     86 	PROP_ERR(prop_dictionary_set_int(mbr_dict, "index", (int)i));
     87 	PROP_ERR(prop_dictionary_set_uint(mbr_dict, "flag", par->part_flag));
     88 	PROP_ERR(prop_dictionary_set_uint(mbr_dict, "start_head",
     89 					  par->part_shd));
     90 	PROP_ERR(prop_dictionary_set_uint(mbr_dict, "start_sector",
     91 					  par->part_ssect));
     92 	PROP_ERR(prop_dictionary_set_uint(mbr_dict, "start_cylinder",
     93 					  par->part_scyl));
     94 	PROP_ERR(prop_dictionary_set_uint(mbr_dict, "type", par->part_typ));
     95 	PROP_ERR(prop_dictionary_set_uint(mbr_dict, "end_head", par->part_ehd));
     96 	PROP_ERR(prop_dictionary_set_uint(mbr_dict, "end_sector",
     97 					  par->part_esect));
     98 	PROP_ERR(prop_dictionary_set_uint(mbr_dict, "end_cylinder",
     99 					  par->part_ecyl));
    100 	PROP_ERR(prop_dictionary_set_uint(mbr_dict, "lba_start_low",
    101 					  le16toh(par->part_start_lo)));
    102 	PROP_ERR(prop_dictionary_set_uint(mbr_dict, "lba_start_high",
    103 					  le16toh(par->part_start_hi)));
    104 	PROP_ERR(prop_dictionary_set_uint(mbr_dict, "lba_size_low",
    105 					  le16toh(par->part_size_lo)));
    106 	PROP_ERR(prop_dictionary_set_uint(mbr_dict, "lba_size_high",
    107 					  le16toh(par->part_size_hi)));
    108 
    109 	if (*mbr_array == NULL) {
    110 		*mbr_array = prop_array_create();
    111 		PROP_ERR(*mbr_array);
    112 	}
    113 	PROP_ERR(prop_array_add_and_rel(*mbr_array, mbr_dict));
    114 	return 0;
    115 cleanup:
    116 	if (mbr_dict)
    117 		prop_object_release(mbr_dict);
    118 	gpt_warnx(gpt, "proplib failure");
    119 	return -1;
    120 }
    121 
    122 static int
    123 store_gpt(gpt_t gpt __unused, const struct gpt_hdr *hdr,
    124     prop_dictionary_t *type_dict)
    125 {
    126 	char buf[128];
    127 
    128 	*type_dict = prop_dictionary_create();
    129 	PROP_ERR(type_dict);
    130 	PROP_ERR(prop_dictionary_set_uint(*type_dict, "revision",
    131 					  le32toh(hdr->hdr_revision)));
    132 	gpt_uuid_snprintf(buf, sizeof(buf), "%d", hdr->hdr_guid);
    133 	PROP_ERR(prop_dictionary_set_string(*type_dict, "guid", buf));
    134 	assert(le32toh(hdr->hdr_entries) <= INT32_MAX);
    135 	PROP_ERR(prop_dictionary_set_int32(*type_dict, "entries",
    136 					   (int32_t)le32toh(hdr->hdr_entries)));
    137 	return 0;
    138 cleanup:
    139 	if (*type_dict)
    140 		prop_object_release(*type_dict);
    141 	return -1;
    142 }
    143 
    144 static int
    145 store_tbl(gpt_t gpt, const map_t m, prop_dictionary_t *type_dict)
    146 {
    147 	const struct gpt_ent *ent;
    148 	unsigned int i;
    149 	prop_dictionary_t gpt_dict;
    150 	prop_array_t gpt_array;
    151 	char buf[128];
    152 	uint8_t utfbuf[__arraycount(ent->ent_name) * 3 + 1];
    153 	bool rc;
    154 
    155 	*type_dict = NULL;
    156 
    157 	gpt_array = prop_array_create();
    158 	PROP_ERR(gpt_array);
    159 
    160 	*type_dict = prop_dictionary_create();
    161 	PROP_ERR(*type_dict);
    162 
    163 	ent = m->map_data;
    164 	for (i = 1, ent = m->map_data;
    165 	    (const char *)ent < (const char *)(m->map_data) +
    166 	    m->map_size * gpt->secsz; i++, ent++) {
    167 		gpt_dict = prop_dictionary_create();
    168 		PROP_ERR(gpt_dict);
    169 		assert(i <= INT_MAX);
    170 		PROP_ERR(prop_dictionary_set_int(gpt_dict, "index", (int)i));
    171 		gpt_uuid_snprintf(buf, sizeof(buf), "%d", ent->ent_type);
    172 		PROP_ERR(prop_dictionary_set_string(gpt_dict, "type", buf));
    173 		gpt_uuid_snprintf(buf, sizeof(buf), "%d", ent->ent_guid);
    174 		PROP_ERR(prop_dictionary_set_string(gpt_dict, "guid", buf));
    175 		PROP_ERR(prop_dictionary_set_uint64(gpt_dict, "start",
    176 						le64toh(ent->ent_lba_start)));
    177 		PROP_ERR(prop_dictionary_set_uint64(gpt_dict, "end",
    178 						le64toh(ent->ent_lba_end)));
    179 		PROP_ERR(prop_dictionary_set_uint64(gpt_dict, "attributes",
    180 						le64toh(ent->ent_attr)));
    181 		utf16_to_utf8(ent->ent_name, __arraycount(ent->ent_name),
    182 		    utfbuf, __arraycount(utfbuf));
    183 		if (utfbuf[0] != '\0') {
    184 			PROP_ERR(prop_dictionary_set_string(gpt_dict, "name",
    185 							    (char *)utfbuf));
    186 		}
    187 		rc = prop_array_add(gpt_array, gpt_dict);
    188 		PROP_ERR(rc);
    189 	}
    190 	rc = prop_dictionary_set_and_rel(*type_dict, "gpt_array", gpt_array);
    191 	PROP_ERR(rc);
    192 	return 0;
    193 cleanup:
    194 	if (*type_dict)
    195 		prop_object_release(*type_dict);
    196 	if (gpt_array)
    197 		prop_object_release(gpt_array);
    198 	return -1;
    199 }
    200 
    201 static int
    202 backup(gpt_t gpt, const char *outfile)
    203 {
    204 	map_t m;
    205 	struct mbr *mbr;
    206 	unsigned int i;
    207 	prop_dictionary_t props, type_dict;
    208 	prop_array_t mbr_array;
    209 	char *propext;
    210 	bool rc;
    211 	FILE *fp;
    212 
    213 	props = prop_dictionary_create();
    214 	PROP_ERR(props);
    215 	assert(gpt->secsz <= INT_MAX);
    216 	PROP_ERR(prop_dictionary_set_int(props, "sector_size",
    217 					 (int)gpt->secsz));
    218 	m = map_first(gpt);
    219 	while (m != NULL) {
    220 		switch (m->map_type) {
    221 		case MAP_TYPE_MBR:
    222 		case MAP_TYPE_PMBR:
    223 			type_dict = prop_dictionary_create();
    224 			PROP_ERR(type_dict);
    225 			mbr = m->map_data;
    226 			PROP_ERR(prop_dictionary_set_data_nocopy(type_dict,
    227 			    "code", mbr->mbr_code, sizeof(mbr->mbr_code)));
    228 			mbr_array = NULL;
    229 			for (i = 0; i < 4; i++) {
    230 				if (store_mbr(gpt, i, mbr, &mbr_array) == -1)
    231 					goto cleanup;
    232 			}
    233 			if (mbr_array != NULL) {
    234 				rc = prop_dictionary_set_and_rel(type_dict,
    235 				    "mbr_array", mbr_array);
    236 				PROP_ERR(rc);
    237 			}
    238 			rc = prop_dictionary_set_and_rel(props, "MBR",
    239 							 type_dict);
    240 			PROP_ERR(rc);
    241 			break;
    242 		case MAP_TYPE_PRI_GPT_HDR:
    243 			if (store_gpt(gpt, m->map_data, &type_dict) == -1)
    244 				goto cleanup;
    245 
    246 			rc = prop_dictionary_set_and_rel(props, "GPT_HDR",
    247 							 type_dict);
    248 			PROP_ERR(rc);
    249 			break;
    250 		case MAP_TYPE_PRI_GPT_TBL:
    251 			if (store_tbl(gpt, m, &type_dict) == -1)
    252 				goto cleanup;
    253 			rc = prop_dictionary_set_and_rel(props, "GPT_TBL",
    254 							 type_dict);
    255 			PROP_ERR(rc);
    256 			break;
    257 		}
    258 		m = m->map_next;
    259 	}
    260 	propext = prop_dictionary_externalize(props);
    261 	PROP_ERR(propext);
    262 	prop_object_release(props);
    263 	fp = strcmp(outfile, "-") == 0 ? stdout : fopen(outfile, "w");
    264 	if (fp == NULL) {
    265 		gpt_warn(gpt, "Can't open `%s'", outfile);
    266 		free(propext);
    267 		goto cleanup;
    268 	}
    269 	fputs(propext, fp);
    270 	if (fp != stdout)
    271 		fclose(fp);
    272 	free(propext);
    273 	return 0;
    274 cleanup:
    275 	if (props)
    276 		prop_object_release(props);
    277 	return -1;
    278 }
    279 
    280 static int
    281 cmd_backup(gpt_t gpt, int argc, char *argv[])
    282 {
    283 	int ch;
    284 	const char *outfile = "-";
    285 
    286 	while ((ch = getopt(argc, argv, "o:")) != -1) {
    287 		switch(ch) {
    288 		case 'o':
    289 			outfile = optarg;
    290 			break;
    291 		default:
    292 			return usage();
    293 		}
    294 	}
    295 	if (argc != optind)
    296 		return usage();
    297 
    298 	return backup(gpt, outfile);
    299 }
    300