backup.c revision 1.13 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.13 2015/12/02 12:36:53 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 *outfile = "/dev/stdout";
55
56 static const char *backuphelp[] = {
57 "[-o outfile]",
58 };
59
60 static int cmd_backup(gpt_t, int, char *[]);
61
62 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)) { \
72 gpt_warnx(gpt, "proplib failure"); \
73 return -1; \
74 }
75
76 #define prop_uint(a) prop_number_create_unsigned_integer(a)
77
78 static int
79 store_mbr(gpt_t gpt, unsigned int i, const struct mbr *mbr,
80 prop_array_t *mbr_array)
81 {
82 prop_dictionary_t mbr_dict;
83 prop_number_t propnum;
84 const struct mbr_part *par = &mbr->mbr_part[i];
85 bool rc;
86
87 if (mbr->mbr_part[i].part_typ == MBR_PTYPE_UNUSED)
88 return 0;
89
90 mbr_dict = prop_dictionary_create();
91 PROP_ERR(mbr_dict);
92 propnum = prop_number_create_integer(i);
93 PROP_ERR(propnum);
94 rc = prop_dictionary_set(mbr_dict, "index", propnum);
95 PROP_ERR(rc);
96 propnum = prop_uint(par->part_flag);
97 PROP_ERR(propnum);
98 rc = prop_dictionary_set(mbr_dict, "flag", propnum);
99 PROP_ERR(rc);
100 propnum = prop_uint(par->part_shd);
101 PROP_ERR(propnum);
102 rc = prop_dictionary_set(mbr_dict, "start_head", propnum);
103 PROP_ERR(rc);
104 propnum = prop_uint(par->part_ssect);
105 PROP_ERR(propnum);
106 rc = prop_dictionary_set(mbr_dict, "start_sector", propnum);
107 PROP_ERR(rc);
108 propnum = prop_uint(par->part_scyl);
109 PROP_ERR(propnum);
110 rc = prop_dictionary_set(mbr_dict, "start_cylinder", propnum);
111 PROP_ERR(rc);
112 propnum = prop_uint(par->part_typ);
113 PROP_ERR(propnum);
114 rc = prop_dictionary_set(mbr_dict, "type", propnum);
115 PROP_ERR(rc);
116 propnum = prop_uint(par->part_ehd);
117 PROP_ERR(propnum);
118 rc = prop_dictionary_set(mbr_dict, "end_head", propnum);
119 PROP_ERR(rc);
120 propnum = prop_uint(par->part_esect);
121 PROP_ERR(propnum);
122 rc = prop_dictionary_set(mbr_dict, "end_sector", propnum);
123 PROP_ERR(rc);
124 propnum = prop_uint(par->part_ecyl);
125 PROP_ERR(propnum);
126 rc = prop_dictionary_set(mbr_dict, "end_cylinder", propnum);
127 PROP_ERR(rc);
128 propnum = prop_uint(le16toh(par->part_start_lo));
129 PROP_ERR(propnum);
130 rc = prop_dictionary_set(mbr_dict, "lba_start_low", propnum);
131 PROP_ERR(rc);
132 propnum = prop_uint(le16toh(par->part_start_hi));
133 PROP_ERR(propnum);
134 rc = prop_dictionary_set(mbr_dict, "lba_start_high", propnum);
135 PROP_ERR(rc);
136 propnum = prop_uint(le16toh(par->part_size_lo));
137 PROP_ERR(propnum);
138 rc = prop_dictionary_set(mbr_dict, "lba_size_low", propnum);
139 PROP_ERR(rc);
140 propnum = prop_uint(le16toh(par->part_size_hi));
141 PROP_ERR(propnum);
142 rc = prop_dictionary_set(mbr_dict, "lba_size_high", propnum);
143 if (*mbr_array == NULL) {
144 *mbr_array = prop_array_create();
145 PROP_ERR(*mbr_array);
146 }
147 rc = prop_array_add(*mbr_array, mbr_dict);
148 PROP_ERR(rc);
149 return 0;
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 }
177
178 static int
179 store_tbl(gpt_t gpt, const map_t m, prop_dictionary_t *type_dict)
180 {
181 const struct gpt_ent *ent;
182 unsigned int i;
183 prop_dictionary_t gpt_dict;
184 prop_array_t gpt_array;
185 prop_number_t propnum;
186 prop_string_t propstr;
187 char buf[128];
188 uint8_t utfbuf[__arraycount(ent->ent_name) * 3 + 1];
189 bool rc;
190
191 *type_dict = prop_dictionary_create();
192 PROP_ERR(*type_dict);
193
194 ent = m->map_data;
195 gpt_array = prop_array_create();
196 PROP_ERR(gpt_array);
197 for (i = 1, ent = m->map_data;
198 (const char *)ent < (const char *)(m->map_data) +
199 m->map_size * gpt->secsz; i++, ent++) {
200 gpt_dict = prop_dictionary_create();
201 PROP_ERR(gpt_dict);
202 propnum = prop_number_create_integer(i);
203 PROP_ERR(propnum);
204 rc = prop_dictionary_set(gpt_dict, "index", propnum);
205 PROP_ERR(propnum);
206 gpt_uuid_snprintf(buf, sizeof(buf), "%d", ent->ent_type);
207 propstr = prop_string_create_cstring(buf);
208 PROP_ERR(propstr);
209 rc = prop_dictionary_set(gpt_dict, "type", propstr);
210 gpt_uuid_snprintf(buf, sizeof(buf), "%d", ent->ent_guid);
211 propstr = prop_string_create_cstring(buf);
212 PROP_ERR(propstr);
213 rc = prop_dictionary_set(gpt_dict, "guid", propstr);
214 PROP_ERR(propstr);
215 propnum = prop_uint(le64toh(ent->ent_lba_start));
216 PROP_ERR(propnum);
217 rc = prop_dictionary_set(gpt_dict, "start", propnum);
218 PROP_ERR(rc);
219 propnum = prop_uint(le64toh(ent->ent_lba_end));
220 PROP_ERR(rc);
221 rc = prop_dictionary_set(gpt_dict, "end", propnum);
222 PROP_ERR(rc);
223 propnum = prop_uint(le64toh(ent->ent_attr));
224 PROP_ERR(propnum);
225 rc = prop_dictionary_set(gpt_dict, "attributes", propnum);
226 PROP_ERR(rc);
227 utf16_to_utf8(ent->ent_name, utfbuf, sizeof(utfbuf));
228 if (utfbuf[0] != '\0') {
229 propstr = prop_string_create_cstring((char *)utfbuf);
230 PROP_ERR(propstr);
231 rc = prop_dictionary_set(gpt_dict, "name", propstr);
232 PROP_ERR(rc);
233 }
234 rc = prop_array_add(gpt_array, gpt_dict);
235 PROP_ERR(rc);
236 }
237 rc = prop_dictionary_set(*type_dict, "gpt_array", gpt_array);
238 PROP_ERR(rc);
239 prop_object_release(gpt_array);
240 return 0;
241 }
242
243 static int
244 backup(gpt_t gpt)
245 {
246 map_t m;
247 struct mbr *mbr;
248 unsigned int i;
249 prop_dictionary_t props, type_dict;
250 prop_array_t mbr_array;
251 prop_data_t propdata;
252 prop_number_t propnum;
253 char *propext;
254 bool rc;
255 FILE *fp;
256
257 props = prop_dictionary_create();
258 PROP_ERR(props);
259 propnum = prop_number_create_integer(gpt->secsz);
260 PROP_ERR(propnum);
261 rc = prop_dictionary_set(props, "sector_size", propnum);
262 PROP_ERR(rc);
263 m = map_first(gpt);
264 while (m != NULL) {
265 switch (m->map_type) {
266 case MAP_TYPE_MBR:
267 case MAP_TYPE_PMBR:
268 type_dict = prop_dictionary_create();
269 PROP_ERR(type_dict);
270 mbr = m->map_data;
271 propdata = prop_data_create_data_nocopy(mbr->mbr_code,
272 sizeof(mbr->mbr_code));
273 PROP_ERR(propdata);
274 rc = prop_dictionary_set(type_dict, "code", propdata);
275 PROP_ERR(rc);
276 mbr_array = NULL;
277 for (i = 0; i < 4; i++) {
278 if (store_mbr(gpt, i, mbr, &mbr_array) == -1)
279 return -1;
280 }
281 if (mbr_array != NULL) {
282 rc = prop_dictionary_set(type_dict,
283 "mbr_array", mbr_array);
284 PROP_ERR(rc);
285 prop_object_release(mbr_array);
286 }
287 rc = prop_dictionary_set(props, "MBR", type_dict);
288 PROP_ERR(rc);
289 prop_object_release(type_dict);
290 break;
291 case MAP_TYPE_PRI_GPT_HDR:
292 if (store_gpt(gpt, m->map_data, &type_dict) == -1)
293 return -1;
294
295 rc = prop_dictionary_set(props, "GPT_HDR", type_dict);
296 PROP_ERR(rc);
297 prop_object_release(type_dict);
298 break;
299 case MAP_TYPE_PRI_GPT_TBL:
300 if (store_tbl(gpt, m, &type_dict) == -1)
301 return -1;
302 rc = prop_dictionary_set(props, "GPT_TBL", type_dict);
303 PROP_ERR(rc);
304 prop_object_release(type_dict);
305 break;
306 }
307 m = m->map_next;
308 }
309 propext = prop_dictionary_externalize(props);
310 PROP_ERR(propext);
311 prop_object_release(props);
312 if ((fp = fopen(outfile, "w")) == NULL) {
313 gpt_warn(gpt, "Can't open `%s'", outfile);
314 return -1;
315 }
316 fputs(propext, fp);
317 fclose(fp);
318 free(propext);
319 return 0;
320 }
321
322 static int
323 cmd_backup(gpt_t gpt, int argc, char *argv[])
324 {
325 int ch;
326
327 while ((ch = getopt(argc, argv, "o:")) != -1) {
328 switch(ch) {
329 case 'o':
330 outfile = optarg;
331 break;
332 default:
333 return usage();
334 }
335 }
336 if (argc != optind)
337 return usage();
338
339 return backup(gpt);
340 }
341