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.20 2020/06/08 22:52:09 thorpej 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 56static const char *backuphelp[] = { 57 "[-o outfile]", 58}; 59 60static int cmd_backup(gpt_t, int, char *[]); 61 62struct 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 73static int 74store_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; 115cleanup: 116 if (mbr_dict) 117 prop_object_release(mbr_dict); 118 gpt_warnx(gpt, "proplib failure"); 119 return -1; 120} 121 122static int 123store_gpt(gpt_t gpt, const struct gpt_hdr *hdr, prop_dictionary_t *type_dict) 124{ 125 char buf[128]; 126 127 *type_dict = prop_dictionary_create(); 128 PROP_ERR(type_dict); 129 PROP_ERR(prop_dictionary_set_uint(*type_dict, "revision", 130 le32toh(hdr->hdr_revision))); 131 gpt_uuid_snprintf(buf, sizeof(buf), "%d", hdr->hdr_guid); 132 PROP_ERR(prop_dictionary_set_string(*type_dict, "guid", buf)); 133 assert(le32toh(hdr->hdr_entries) <= INT32_MAX); 134 PROP_ERR(prop_dictionary_set_int32(*type_dict, "entries", 135 (int32_t)le32toh(hdr->hdr_entries))); 136 return 0; 137cleanup: 138 if (*type_dict) 139 prop_object_release(*type_dict); 140 return -1; 141} 142 143static int 144store_tbl(gpt_t gpt, const map_t m, prop_dictionary_t *type_dict) 145{ 146 const struct gpt_ent *ent; 147 unsigned int i; 148 prop_dictionary_t gpt_dict; 149 prop_array_t gpt_array; 150 char buf[128]; 151 uint8_t utfbuf[__arraycount(ent->ent_name) * 3 + 1]; 152 bool rc; 153 154 *type_dict = NULL; 155 156 gpt_array = prop_array_create(); 157 PROP_ERR(gpt_array); 158 159 *type_dict = prop_dictionary_create(); 160 PROP_ERR(*type_dict); 161 162 ent = m->map_data; 163 for (i = 1, ent = m->map_data; 164 (const char *)ent < (const char *)(m->map_data) + 165 m->map_size * gpt->secsz; i++, ent++) { 166 gpt_dict = prop_dictionary_create(); 167 PROP_ERR(gpt_dict); 168 assert(i <= INT_MAX); 169 PROP_ERR(prop_dictionary_set_int(gpt_dict, "index", (int)i)); 170 gpt_uuid_snprintf(buf, sizeof(buf), "%d", ent->ent_type); 171 PROP_ERR(prop_dictionary_set_string(gpt_dict, "type", buf)); 172 gpt_uuid_snprintf(buf, sizeof(buf), "%d", ent->ent_guid); 173 PROP_ERR(prop_dictionary_set_string(gpt_dict, "guid", buf)); 174 PROP_ERR(prop_dictionary_set_uint64(gpt_dict, "start", 175 le64toh(ent->ent_lba_start))); 176 PROP_ERR(prop_dictionary_set_uint64(gpt_dict, "end", 177 le64toh(ent->ent_lba_end))); 178 PROP_ERR(prop_dictionary_set_uint64(gpt_dict, "attributes", 179 le64toh(ent->ent_attr))); 180 utf16_to_utf8(ent->ent_name, __arraycount(ent->ent_name), 181 utfbuf, __arraycount(utfbuf)); 182 if (utfbuf[0] != '\0') { 183 PROP_ERR(prop_dictionary_set_string(gpt_dict, "name", 184 (char *)utfbuf)); 185 } 186 rc = prop_array_add(gpt_array, gpt_dict); 187 PROP_ERR(rc); 188 } 189 rc = prop_dictionary_set_and_rel(*type_dict, "gpt_array", gpt_array); 190 PROP_ERR(rc); 191 return 0; 192cleanup: 193 if (*type_dict) 194 prop_object_release(*type_dict); 195 if (gpt_array) 196 prop_object_release(gpt_array); 197 return -1; 198} 199 200static int 201backup(gpt_t gpt, const char *outfile) 202{ 203 map_t m; 204 struct mbr *mbr; 205 unsigned int i; 206 prop_dictionary_t props, type_dict; 207 prop_array_t mbr_array; 208 char *propext; 209 bool rc; 210 FILE *fp; 211 212 props = prop_dictionary_create(); 213 PROP_ERR(props); 214 assert(gpt->secsz <= INT_MAX); 215 PROP_ERR(prop_dictionary_set_int(props, "sector_size", 216 (int)gpt->secsz)); 217 m = map_first(gpt); 218 while (m != NULL) { 219 switch (m->map_type) { 220 case MAP_TYPE_MBR: 221 case MAP_TYPE_PMBR: 222 type_dict = prop_dictionary_create(); 223 PROP_ERR(type_dict); 224 mbr = m->map_data; 225 PROP_ERR(prop_dictionary_set_data_nocopy(type_dict, 226 "code", mbr->mbr_code, sizeof(mbr->mbr_code))); 227 mbr_array = NULL; 228 for (i = 0; i < 4; i++) { 229 if (store_mbr(gpt, i, mbr, &mbr_array) == -1) 230 goto cleanup; 231 } 232 if (mbr_array != NULL) { 233 rc = prop_dictionary_set_and_rel(type_dict, 234 "mbr_array", mbr_array); 235 PROP_ERR(rc); 236 } 237 rc = prop_dictionary_set_and_rel(props, "MBR", 238 type_dict); 239 PROP_ERR(rc); 240 break; 241 case MAP_TYPE_PRI_GPT_HDR: 242 if (store_gpt(gpt, m->map_data, &type_dict) == -1) 243 goto cleanup; 244 245 rc = prop_dictionary_set_and_rel(props, "GPT_HDR", 246 type_dict); 247 PROP_ERR(rc); 248 break; 249 case MAP_TYPE_PRI_GPT_TBL: 250 if (store_tbl(gpt, m, &type_dict) == -1) 251 goto cleanup; 252 rc = prop_dictionary_set_and_rel(props, "GPT_TBL", 253 type_dict); 254 PROP_ERR(rc); 255 break; 256 } 257 m = m->map_next; 258 } 259 propext = prop_dictionary_externalize(props); 260 PROP_ERR(propext); 261 prop_object_release(props); 262 fp = strcmp(outfile, "-") == 0 ? stdout : fopen(outfile, "w"); 263 if (fp == NULL) { 264 gpt_warn(gpt, "Can't open `%s'", outfile); 265 free(propext); 266 goto cleanup; 267 } 268 fputs(propext, fp); 269 if (fp != stdout) 270 fclose(fp); 271 free(propext); 272 return 0; 273cleanup: 274 if (props) 275 prop_object_release(props); 276 return -1; 277} 278 279static int 280cmd_backup(gpt_t gpt, int argc, char *argv[]) 281{ 282 int ch; 283 const char *outfile = "-"; 284 285 while ((ch = getopt(argc, argv, "o:")) != -1) { 286 switch(ch) { 287 case 'o': 288 outfile = optarg; 289 break; 290 default: 291 return usage(); 292 } 293 } 294 if (argc != optind) 295 return usage(); 296 297 return backup(gpt, outfile); 298} 299