Home | History | Annotate | Line # | Download | only in gpt
backup.c revision 1.18
      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.18 2017/09/07 10:23:33 christos Exp $");
     37 #endif
     38 
     39 #include <sys/bootblock.h>
     40 #include <sys/types.h>
     41 
     42 #include <err.h>
     43 #include <stddef.h>
     44 #include <stdio.h>
     45 #include <stdlib.h>
     46 #include <string.h>
     47 #include <unistd.h>
     48 #include <prop/proplib.h>
     49 
     50 #include "map.h"
     51 #include "gpt.h"
     52 #include "gpt_private.h"
     53 
     54 static const char *backuphelp[] = {
     55 	"[-o outfile]",
     56 };
     57 
     58 static int cmd_backup(gpt_t, int, char *[]);
     59 
     60 struct gpt_cmd c_backup = {
     61 	"backup",
     62 	cmd_backup,
     63 	backuphelp, __arraycount(backuphelp),
     64 	GPT_READONLY,
     65 };
     66 
     67 #define usage() gpt_usage(NULL, &c_backup)
     68 
     69 #define PROP_ERR(x)	if (!(x)) goto cleanup
     70 
     71 #define prop_uint(a) prop_number_create_unsigned_integer(a)
     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 	prop_number_t propnum;
     79 	const struct mbr_part *par = &mbr->mbr_part[i];
     80 	bool rc;
     81 
     82 	if (mbr->mbr_part[i].part_typ == MBR_PTYPE_UNUSED)
     83 		return 0;
     84 
     85 	mbr_dict = prop_dictionary_create();
     86 	PROP_ERR(mbr_dict);
     87 	propnum = prop_number_create_integer(i);
     88 	PROP_ERR(propnum);
     89 	rc = prop_dictionary_set(mbr_dict, "index", propnum);
     90 	PROP_ERR(rc);
     91 	propnum = prop_uint(par->part_flag);
     92 	PROP_ERR(propnum);
     93 	rc = prop_dictionary_set(mbr_dict, "flag", propnum);
     94 	PROP_ERR(rc);
     95 	propnum = prop_uint(par->part_shd);
     96 	PROP_ERR(propnum);
     97 	rc = prop_dictionary_set(mbr_dict, "start_head", propnum);
     98 	PROP_ERR(rc);
     99 	propnum = prop_uint(par->part_ssect);
    100 	PROP_ERR(propnum);
    101 	rc = prop_dictionary_set(mbr_dict, "start_sector", propnum);
    102 	PROP_ERR(rc);
    103 	propnum = prop_uint(par->part_scyl);
    104 	PROP_ERR(propnum);
    105 	rc = prop_dictionary_set(mbr_dict, "start_cylinder", propnum);
    106 	PROP_ERR(rc);
    107 	propnum = prop_uint(par->part_typ);
    108 	PROP_ERR(propnum);
    109 	rc = prop_dictionary_set(mbr_dict, "type", propnum);
    110 	PROP_ERR(rc);
    111 	propnum = prop_uint(par->part_ehd);
    112 	PROP_ERR(propnum);
    113 	rc = prop_dictionary_set(mbr_dict, "end_head", propnum);
    114 	PROP_ERR(rc);
    115 	propnum = prop_uint(par->part_esect);
    116 	PROP_ERR(propnum);
    117 	rc = prop_dictionary_set(mbr_dict, "end_sector", propnum);
    118 	PROP_ERR(rc);
    119 	propnum = prop_uint(par->part_ecyl);
    120 	PROP_ERR(propnum);
    121 	rc = prop_dictionary_set(mbr_dict, "end_cylinder", propnum);
    122 	PROP_ERR(rc);
    123 	propnum = prop_uint(le16toh(par->part_start_lo));
    124 	PROP_ERR(propnum);
    125 	rc = prop_dictionary_set(mbr_dict, "lba_start_low", propnum);
    126 	PROP_ERR(rc);
    127 	propnum = prop_uint(le16toh(par->part_start_hi));
    128 	PROP_ERR(propnum);
    129 	rc = prop_dictionary_set(mbr_dict, "lba_start_high", propnum);
    130 	PROP_ERR(rc);
    131 	propnum = prop_uint(le16toh(par->part_size_lo));
    132 	PROP_ERR(propnum);
    133 	rc = prop_dictionary_set(mbr_dict, "lba_size_low", propnum);
    134 	PROP_ERR(rc);
    135 	propnum = prop_uint(le16toh(par->part_size_hi));
    136 	PROP_ERR(propnum);
    137 	rc = prop_dictionary_set(mbr_dict, "lba_size_high", propnum);
    138 	if (*mbr_array == NULL) {
    139 		*mbr_array = prop_array_create();
    140 		PROP_ERR(*mbr_array);
    141 	}
    142 	rc = prop_array_add(*mbr_array, mbr_dict);
    143 	PROP_ERR(rc);
    144 	return 0;
    145 cleanup:
    146 	if (mbr_dict)
    147 		prop_object_release(mbr_dict);
    148 	gpt_warnx(gpt, "proplib failure");
    149 	return -1;
    150 }
    151 
    152 static int
    153 store_gpt(gpt_t gpt, const struct gpt_hdr *hdr, prop_dictionary_t *type_dict)
    154 {
    155 	prop_number_t propnum;
    156 	prop_string_t propstr;
    157 	char buf[128];
    158 	bool rc;
    159 
    160 	*type_dict = prop_dictionary_create();
    161 	PROP_ERR(type_dict);
    162 	propnum = prop_uint(le32toh(hdr->hdr_revision));
    163 	PROP_ERR(propnum);
    164 	rc = prop_dictionary_set(*type_dict, "revision", propnum);
    165 	PROP_ERR(rc);
    166 	gpt_uuid_snprintf(buf, sizeof(buf), "%d", hdr->hdr_guid);
    167 	propstr = prop_string_create_cstring(buf);
    168 	PROP_ERR(propstr);
    169 	rc = prop_dictionary_set(*type_dict, "guid", propstr);
    170 	PROP_ERR(rc);
    171 	propnum = prop_number_create_integer(le32toh(hdr->hdr_entries));
    172 	PROP_ERR(propnum);
    173 	rc = prop_dictionary_set(*type_dict, "entries", propnum);
    174 	PROP_ERR(rc);
    175 	return 0;
    176 cleanup:
    177 	if (*type_dict)
    178 		prop_object_release(*type_dict);
    179 	return -1;
    180 }
    181 
    182 static int
    183 store_tbl(gpt_t gpt, const map_t m, prop_dictionary_t *type_dict)
    184 {
    185 	const struct gpt_ent *ent;
    186 	unsigned int i;
    187 	prop_dictionary_t gpt_dict;
    188 	prop_array_t gpt_array;
    189 	prop_number_t propnum;
    190 	prop_string_t propstr;
    191 	char buf[128];
    192 	uint8_t utfbuf[__arraycount(ent->ent_name) * 3 + 1];
    193 	bool rc;
    194 
    195 	*type_dict = NULL;
    196 
    197 	gpt_array = prop_array_create();
    198 	PROP_ERR(gpt_array);
    199 
    200 	*type_dict = prop_dictionary_create();
    201 	PROP_ERR(*type_dict);
    202 
    203 	ent = m->map_data;
    204 	for (i = 1, ent = m->map_data;
    205 	    (const char *)ent < (const char *)(m->map_data) +
    206 	    m->map_size * gpt->secsz; i++, ent++) {
    207 		gpt_dict = prop_dictionary_create();
    208 		PROP_ERR(gpt_dict);
    209 		propnum = prop_number_create_integer(i);
    210 		PROP_ERR(propnum);
    211 		rc = prop_dictionary_set(gpt_dict, "index", propnum);
    212 		PROP_ERR(propnum);
    213 		gpt_uuid_snprintf(buf, sizeof(buf), "%d", ent->ent_type);
    214 		propstr = prop_string_create_cstring(buf);
    215 		PROP_ERR(propstr);
    216 		rc = prop_dictionary_set(gpt_dict, "type", propstr);
    217 		gpt_uuid_snprintf(buf, sizeof(buf), "%d", ent->ent_guid);
    218 		propstr = prop_string_create_cstring(buf);
    219 		PROP_ERR(propstr);
    220 		rc = prop_dictionary_set(gpt_dict, "guid", propstr);
    221 		PROP_ERR(propstr);
    222 		propnum = prop_uint(le64toh(ent->ent_lba_start));
    223 		PROP_ERR(propnum);
    224 		rc = prop_dictionary_set(gpt_dict, "start", propnum);
    225 		PROP_ERR(rc);
    226 		propnum = prop_uint(le64toh(ent->ent_lba_end));
    227 		PROP_ERR(rc);
    228 		rc = prop_dictionary_set(gpt_dict, "end", propnum);
    229 		PROP_ERR(rc);
    230 		propnum = prop_uint(le64toh(ent->ent_attr));
    231 		PROP_ERR(propnum);
    232 		rc = prop_dictionary_set(gpt_dict, "attributes", propnum);
    233 		PROP_ERR(rc);
    234 		utf16_to_utf8(ent->ent_name, __arraycount(ent->ent_name),
    235 		    utfbuf, __arraycount(utfbuf));
    236 		if (utfbuf[0] != '\0') {
    237 			propstr = prop_string_create_cstring((char *)utfbuf);
    238 			PROP_ERR(propstr);
    239 			rc = prop_dictionary_set(gpt_dict, "name", propstr);
    240 			PROP_ERR(rc);
    241 		}
    242 		rc = prop_array_add(gpt_array, gpt_dict);
    243 		PROP_ERR(rc);
    244 	}
    245 	rc = prop_dictionary_set(*type_dict, "gpt_array", gpt_array);
    246 	PROP_ERR(rc);
    247 	prop_object_release(gpt_array);
    248 	return 0;
    249 cleanup:
    250 	if (*type_dict)
    251 		prop_object_release(*type_dict);
    252 	if (gpt_array)
    253 		prop_object_release(gpt_array);
    254 	return -1;
    255 }
    256 
    257 static int
    258 backup(gpt_t gpt, const char *outfile)
    259 {
    260 	map_t m;
    261 	struct mbr *mbr;
    262 	unsigned int i;
    263 	prop_dictionary_t props, type_dict;
    264 	prop_array_t mbr_array;
    265 	prop_data_t propdata;
    266 	prop_number_t propnum;
    267 	char *propext;
    268 	bool rc;
    269 	FILE *fp;
    270 
    271 	props = prop_dictionary_create();
    272 	PROP_ERR(props);
    273 	propnum = prop_number_create_integer(gpt->secsz);
    274 	PROP_ERR(propnum);
    275 	rc = prop_dictionary_set(props, "sector_size", propnum);
    276 	PROP_ERR(rc);
    277 	m = map_first(gpt);
    278 	while (m != NULL) {
    279 		switch (m->map_type) {
    280 		case MAP_TYPE_MBR:
    281 		case MAP_TYPE_PMBR:
    282 			type_dict = prop_dictionary_create();
    283 			PROP_ERR(type_dict);
    284 			mbr = m->map_data;
    285 			propdata = prop_data_create_data_nocopy(mbr->mbr_code,
    286 			    sizeof(mbr->mbr_code));
    287 			PROP_ERR(propdata);
    288 			rc = prop_dictionary_set(type_dict, "code", propdata);
    289 			PROP_ERR(rc);
    290 			mbr_array = NULL;
    291 			for (i = 0; i < 4; i++) {
    292 				if (store_mbr(gpt, i, mbr, &mbr_array) == -1)
    293 					goto cleanup;
    294 			}
    295 			if (mbr_array != NULL) {
    296 				rc = prop_dictionary_set(type_dict,
    297 				    "mbr_array", mbr_array);
    298 				PROP_ERR(rc);
    299 				prop_object_release(mbr_array);
    300 			}
    301 			rc = prop_dictionary_set(props, "MBR", type_dict);
    302 			PROP_ERR(rc);
    303 			prop_object_release(type_dict);
    304 			break;
    305 		case MAP_TYPE_PRI_GPT_HDR:
    306 			if (store_gpt(gpt, m->map_data, &type_dict) == -1)
    307 				goto cleanup;
    308 
    309 			rc = prop_dictionary_set(props, "GPT_HDR", type_dict);
    310 			PROP_ERR(rc);
    311 			prop_object_release(type_dict);
    312 			break;
    313 		case MAP_TYPE_PRI_GPT_TBL:
    314 			if (store_tbl(gpt, m, &type_dict) == -1)
    315 				goto cleanup;
    316 			rc = prop_dictionary_set(props, "GPT_TBL", type_dict);
    317 			PROP_ERR(rc);
    318 			prop_object_release(type_dict);
    319 			break;
    320 		}
    321 		m = m->map_next;
    322 	}
    323 	propext = prop_dictionary_externalize(props);
    324 	PROP_ERR(propext);
    325 	prop_object_release(props);
    326 	fp = strcmp(outfile, "-") == 0 ? stdout : fopen(outfile, "w");
    327 	if (fp == NULL) {
    328 		gpt_warn(gpt, "Can't open `%s'", outfile);
    329 		free(propext);
    330 		goto cleanup;
    331 	}
    332 	fputs(propext, fp);
    333 	if (fp != stdout)
    334 		fclose(fp);
    335 	free(propext);
    336 	return 0;
    337 cleanup:
    338 	if (props)
    339 		prop_object_release(props);
    340 	return -1;
    341 }
    342 
    343 static int
    344 cmd_backup(gpt_t gpt, int argc, char *argv[])
    345 {
    346 	int ch;
    347 	const char *outfile = "-";
    348 
    349 	while ((ch = getopt(argc, argv, "o:")) != -1) {
    350 		switch(ch) {
    351 		case 'o':
    352 			outfile = optarg;
    353 			break;
    354 		default:
    355 			return usage();
    356 		}
    357 	}
    358 	if (argc != optind)
    359 		return usage();
    360 
    361 	return backup(gpt, outfile);
    362 }
    363