xref: /netbsd-src/sbin/gpt/backup.c (revision 946379e7b37692fc43f68eb0d1c10daa0a7f3b6c)
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.16 2015/12/03 21:40:32 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, utfbuf, sizeof(utfbuf));
235 		if (utfbuf[0] != '\0') {
236 			propstr = prop_string_create_cstring((char *)utfbuf);
237 			PROP_ERR(propstr);
238 			rc = prop_dictionary_set(gpt_dict, "name", propstr);
239 			PROP_ERR(rc);
240 		}
241 		rc = prop_array_add(gpt_array, gpt_dict);
242 		PROP_ERR(rc);
243 	}
244 	rc = prop_dictionary_set(*type_dict, "gpt_array", gpt_array);
245 	PROP_ERR(rc);
246 	prop_object_release(gpt_array);
247 	return 0;
248 cleanup:
249 	if (*type_dict)
250 		prop_object_release(*type_dict);
251 	if (gpt_array)
252 		prop_object_release(gpt_array);
253 	return -1;
254 }
255 
256 static int
257 backup(gpt_t gpt, const char *outfile)
258 {
259 	map_t m;
260 	struct mbr *mbr;
261 	unsigned int i;
262 	prop_dictionary_t props, type_dict;
263 	prop_array_t mbr_array;
264 	prop_data_t propdata;
265 	prop_number_t propnum;
266 	char *propext;
267 	bool rc;
268 	FILE *fp;
269 
270 	props = prop_dictionary_create();
271 	PROP_ERR(props);
272 	propnum = prop_number_create_integer(gpt->secsz);
273 	PROP_ERR(propnum);
274 	rc = prop_dictionary_set(props, "sector_size", propnum);
275 	PROP_ERR(rc);
276 	m = map_first(gpt);
277 	while (m != NULL) {
278 		switch (m->map_type) {
279 		case MAP_TYPE_MBR:
280 		case MAP_TYPE_PMBR:
281 			type_dict = prop_dictionary_create();
282 			PROP_ERR(type_dict);
283 			mbr = m->map_data;
284 			propdata = prop_data_create_data_nocopy(mbr->mbr_code,
285 			    sizeof(mbr->mbr_code));
286 			PROP_ERR(propdata);
287 			rc = prop_dictionary_set(type_dict, "code", propdata);
288 			PROP_ERR(rc);
289 			mbr_array = NULL;
290 			for (i = 0; i < 4; i++) {
291 				if (store_mbr(gpt, i, mbr, &mbr_array) == -1)
292 					goto cleanup;
293 			}
294 			if (mbr_array != NULL) {
295 				rc = prop_dictionary_set(type_dict,
296 				    "mbr_array", mbr_array);
297 				PROP_ERR(rc);
298 				prop_object_release(mbr_array);
299 			}
300 			rc = prop_dictionary_set(props, "MBR", type_dict);
301 			PROP_ERR(rc);
302 			prop_object_release(type_dict);
303 			break;
304 		case MAP_TYPE_PRI_GPT_HDR:
305 			if (store_gpt(gpt, m->map_data, &type_dict) == -1)
306 				goto cleanup;
307 
308 			rc = prop_dictionary_set(props, "GPT_HDR", type_dict);
309 			PROP_ERR(rc);
310 			prop_object_release(type_dict);
311 			break;
312 		case MAP_TYPE_PRI_GPT_TBL:
313 			if (store_tbl(gpt, m, &type_dict) == -1)
314 				goto cleanup;
315 			rc = prop_dictionary_set(props, "GPT_TBL", type_dict);
316 			PROP_ERR(rc);
317 			prop_object_release(type_dict);
318 			break;
319 		}
320 		m = m->map_next;
321 	}
322 	propext = prop_dictionary_externalize(props);
323 	PROP_ERR(propext);
324 	prop_object_release(props);
325 	fp = strcmp(outfile, "-") == 0 ? stdout : fopen(outfile, "w");
326 	if (fp == NULL) {
327 		gpt_warn(gpt, "Can't open `%s'", outfile);
328 		free(propext);
329 		goto cleanup;
330 	}
331 	fputs(propext, fp);
332 	if (fp != stdout)
333 		fclose(fp);
334 	free(propext);
335 	return 0;
336 cleanup:
337 	if (props)
338 		prop_object_release(props);
339 	return -1;
340 }
341 
342 static int
343 cmd_backup(gpt_t gpt, int argc, char *argv[])
344 {
345 	int ch;
346 	const char *outfile = "-";
347 
348 	while ((ch = getopt(argc, argv, "o:")) != -1) {
349 		switch(ch) {
350 		case 'o':
351 			outfile = optarg;
352 			break;
353 		default:
354 			return usage();
355 		}
356 	}
357 	if (argc != optind)
358 		return usage();
359 
360 	return backup(gpt, outfile);
361 }
362