Home | History | Annotate | Line # | Download | only in gpt
backup.c revision 1.19
      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.19 2020/06/07 05:42:25 thorpej 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 static int
     72 store_mbr(gpt_t gpt, unsigned int i, const struct mbr *mbr,
     73     prop_array_t *mbr_array)
     74 {
     75 	prop_dictionary_t mbr_dict;
     76 	const struct mbr_part *par = &mbr->mbr_part[i];
     77 
     78 	if (mbr->mbr_part[i].part_typ == MBR_PTYPE_UNUSED)
     79 		return 0;
     80 
     81 	mbr_dict = prop_dictionary_create();
     82 	PROP_ERR(mbr_dict);
     83 	PROP_ERR(prop_dictionary_set_uint(mbr_dict, "index", i));
     84 	PROP_ERR(prop_dictionary_set_uint(mbr_dict, "flag", par->part_flag));
     85 	PROP_ERR(prop_dictionary_set_uint(mbr_dict, "start_head",
     86 					  par->part_shd));
     87 	PROP_ERR(prop_dictionary_set_uint(mbr_dict, "start_sector",
     88 					  par->part_ssect));
     89 	PROP_ERR(prop_dictionary_set_uint(mbr_dict, "start_cylinder",
     90 					  par->part_scyl));
     91 	PROP_ERR(prop_dictionary_set_uint(mbr_dict, "type", par->part_typ));
     92 	PROP_ERR(prop_dictionary_set_uint(mbr_dict, "end_head", par->part_ehd));
     93 	PROP_ERR(prop_dictionary_set_uint(mbr_dict, "end_sector",
     94 					  par->part_esect));
     95 	PROP_ERR(prop_dictionary_set_uint(mbr_dict, "end_cylinder",
     96 					  par->part_ecyl));
     97 	PROP_ERR(prop_dictionary_set_uint(mbr_dict, "lba_start_low",
     98 					  le16toh(par->part_start_lo)));
     99 	PROP_ERR(prop_dictionary_set_uint(mbr_dict, "lba_start_high",
    100 					  le16toh(par->part_start_hi)));
    101 	PROP_ERR(prop_dictionary_set_uint(mbr_dict, "lba_size_low",
    102 					  le16toh(par->part_size_lo)));
    103 	PROP_ERR(prop_dictionary_set_uint(mbr_dict, "lba_size_high",
    104 					  le16toh(par->part_size_hi)));
    105 
    106 	if (*mbr_array == NULL) {
    107 		*mbr_array = prop_array_create();
    108 		PROP_ERR(*mbr_array);
    109 	}
    110 	PROP_ERR(prop_array_add_and_rel(*mbr_array, mbr_dict));
    111 	return 0;
    112 cleanup:
    113 	if (mbr_dict)
    114 		prop_object_release(mbr_dict);
    115 	gpt_warnx(gpt, "proplib failure");
    116 	return -1;
    117 }
    118 
    119 static int
    120 store_gpt(gpt_t gpt, const struct gpt_hdr *hdr, prop_dictionary_t *type_dict)
    121 {
    122 	char buf[128];
    123 
    124 	*type_dict = prop_dictionary_create();
    125 	PROP_ERR(type_dict);
    126 	PROP_ERR(prop_dictionary_set_uint(*type_dict, "revision",
    127 					  le32toh(hdr->hdr_revision)));
    128 	gpt_uuid_snprintf(buf, sizeof(buf), "%d", hdr->hdr_guid);
    129 	PROP_ERR(prop_dictionary_set_string(*type_dict, "guid", buf));
    130 	PROP_ERR(prop_dictionary_set_uint(*type_dict, "entries",
    131 					  le32toh(hdr->hdr_entries)));
    132 	return 0;
    133 cleanup:
    134 	if (*type_dict)
    135 		prop_object_release(*type_dict);
    136 	return -1;
    137 }
    138 
    139 static int
    140 store_tbl(gpt_t gpt, const map_t m, prop_dictionary_t *type_dict)
    141 {
    142 	const struct gpt_ent *ent;
    143 	unsigned int i;
    144 	prop_dictionary_t gpt_dict;
    145 	prop_array_t gpt_array;
    146 	char buf[128];
    147 	uint8_t utfbuf[__arraycount(ent->ent_name) * 3 + 1];
    148 	bool rc;
    149 
    150 	*type_dict = NULL;
    151 
    152 	gpt_array = prop_array_create();
    153 	PROP_ERR(gpt_array);
    154 
    155 	*type_dict = prop_dictionary_create();
    156 	PROP_ERR(*type_dict);
    157 
    158 	ent = m->map_data;
    159 	for (i = 1, ent = m->map_data;
    160 	    (const char *)ent < (const char *)(m->map_data) +
    161 	    m->map_size * gpt->secsz; i++, ent++) {
    162 		gpt_dict = prop_dictionary_create();
    163 		PROP_ERR(gpt_dict);
    164 		PROP_ERR(prop_dictionary_set_uint(gpt_dict, "index", i));
    165 		gpt_uuid_snprintf(buf, sizeof(buf), "%d", ent->ent_type);
    166 		PROP_ERR(prop_dictionary_set_string(gpt_dict, "type", buf));
    167 		gpt_uuid_snprintf(buf, sizeof(buf), "%d", ent->ent_guid);
    168 		PROP_ERR(prop_dictionary_set_string(gpt_dict, "guid", buf));
    169 		PROP_ERR(prop_dictionary_set_uint64(gpt_dict, "start",
    170 						le64toh(ent->ent_lba_start)));
    171 		PROP_ERR(prop_dictionary_set_uint64(gpt_dict, "end",
    172 						le64toh(ent->ent_lba_end)));
    173 		PROP_ERR(prop_dictionary_set_uint64(gpt_dict, "attributes",
    174 						le64toh(ent->ent_attr)));
    175 		utf16_to_utf8(ent->ent_name, __arraycount(ent->ent_name),
    176 		    utfbuf, __arraycount(utfbuf));
    177 		if (utfbuf[0] != '\0') {
    178 			PROP_ERR(prop_dictionary_set_string(gpt_dict, "name",
    179 							    (char *)utfbuf));
    180 		}
    181 		rc = prop_array_add(gpt_array, gpt_dict);
    182 		PROP_ERR(rc);
    183 	}
    184 	rc = prop_dictionary_set_and_rel(*type_dict, "gpt_array", gpt_array);
    185 	PROP_ERR(rc);
    186 	return 0;
    187 cleanup:
    188 	if (*type_dict)
    189 		prop_object_release(*type_dict);
    190 	if (gpt_array)
    191 		prop_object_release(gpt_array);
    192 	return -1;
    193 }
    194 
    195 static int
    196 backup(gpt_t gpt, const char *outfile)
    197 {
    198 	map_t m;
    199 	struct mbr *mbr;
    200 	unsigned int i;
    201 	prop_dictionary_t props, type_dict;
    202 	prop_array_t mbr_array;
    203 	char *propext;
    204 	bool rc;
    205 	FILE *fp;
    206 
    207 	props = prop_dictionary_create();
    208 	PROP_ERR(props);
    209 	PROP_ERR(prop_dictionary_set_uint(props, "sector_size", gpt->secsz));
    210 	m = map_first(gpt);
    211 	while (m != NULL) {
    212 		switch (m->map_type) {
    213 		case MAP_TYPE_MBR:
    214 		case MAP_TYPE_PMBR:
    215 			type_dict = prop_dictionary_create();
    216 			PROP_ERR(type_dict);
    217 			mbr = m->map_data;
    218 			PROP_ERR(prop_dictionary_set_data_nocopy(type_dict,
    219 			    "code", mbr->mbr_code, sizeof(mbr->mbr_code)));
    220 			mbr_array = NULL;
    221 			for (i = 0; i < 4; i++) {
    222 				if (store_mbr(gpt, i, mbr, &mbr_array) == -1)
    223 					goto cleanup;
    224 			}
    225 			if (mbr_array != NULL) {
    226 				rc = prop_dictionary_set_and_rel(type_dict,
    227 				    "mbr_array", mbr_array);
    228 				PROP_ERR(rc);
    229 			}
    230 			rc = prop_dictionary_set_and_rel(props, "MBR",
    231 							 type_dict);
    232 			PROP_ERR(rc);
    233 			break;
    234 		case MAP_TYPE_PRI_GPT_HDR:
    235 			if (store_gpt(gpt, m->map_data, &type_dict) == -1)
    236 				goto cleanup;
    237 
    238 			rc = prop_dictionary_set_and_rel(props, "GPT_HDR",
    239 							 type_dict);
    240 			PROP_ERR(rc);
    241 			break;
    242 		case MAP_TYPE_PRI_GPT_TBL:
    243 			if (store_tbl(gpt, m, &type_dict) == -1)
    244 				goto cleanup;
    245 			rc = prop_dictionary_set_and_rel(props, "GPT_TBL",
    246 							 type_dict);
    247 			PROP_ERR(rc);
    248 			break;
    249 		}
    250 		m = m->map_next;
    251 	}
    252 	propext = prop_dictionary_externalize(props);
    253 	PROP_ERR(propext);
    254 	prop_object_release(props);
    255 	fp = strcmp(outfile, "-") == 0 ? stdout : fopen(outfile, "w");
    256 	if (fp == NULL) {
    257 		gpt_warn(gpt, "Can't open `%s'", outfile);
    258 		free(propext);
    259 		goto cleanup;
    260 	}
    261 	fputs(propext, fp);
    262 	if (fp != stdout)
    263 		fclose(fp);
    264 	free(propext);
    265 	return 0;
    266 cleanup:
    267 	if (props)
    268 		prop_object_release(props);
    269 	return -1;
    270 }
    271 
    272 static int
    273 cmd_backup(gpt_t gpt, int argc, char *argv[])
    274 {
    275 	int ch;
    276 	const char *outfile = "-";
    277 
    278 	while ((ch = getopt(argc, argv, "o:")) != -1) {
    279 		switch(ch) {
    280 		case 'o':
    281 			outfile = optarg;
    282 			break;
    283 		default:
    284 			return usage();
    285 		}
    286 	}
    287 	if (argc != optind)
    288 		return usage();
    289 
    290 	return backup(gpt, outfile);
    291 }
    292