1 1.1 jnemeth /*- 2 1.1 jnemeth * Copyright (c) 2002 Marcel Moolenaar 3 1.1 jnemeth * All rights reserved. 4 1.1 jnemeth * 5 1.1 jnemeth * Redistribution and use in source and binary forms, with or without 6 1.1 jnemeth * modification, are permitted provided that the following conditions 7 1.1 jnemeth * are met: 8 1.1 jnemeth * 9 1.1 jnemeth * 1. Redistributions of source code must retain the above copyright 10 1.1 jnemeth * notice, this list of conditions and the following disclaimer. 11 1.1 jnemeth * 2. Redistributions in binary form must reproduce the above copyright 12 1.1 jnemeth * notice, this list of conditions and the following disclaimer in the 13 1.1 jnemeth * documentation and/or other materials provided with the distribution. 14 1.1 jnemeth * 15 1.1 jnemeth * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 1.1 jnemeth * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 1.1 jnemeth * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 1.1 jnemeth * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 1.1 jnemeth * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 1.1 jnemeth * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 1.1 jnemeth * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 1.1 jnemeth * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 1.1 jnemeth * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 1.1 jnemeth * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 1.1 jnemeth */ 26 1.1 jnemeth 27 1.4 christos #if HAVE_NBTOOL_CONFIG_H 28 1.4 christos #include "nbtool_config.h" 29 1.4 christos #endif 30 1.4 christos 31 1.1 jnemeth #include <sys/cdefs.h> 32 1.1 jnemeth #ifdef __FBSDID 33 1.1 jnemeth __FBSDID("$FreeBSD: src/sbin/gpt/create.c,v 1.11 2005/08/31 01:47:19 marcel Exp $"); 34 1.1 jnemeth #endif 35 1.1 jnemeth #ifdef __RCSID 36 1.21 christos __RCSID("$NetBSD: restore.c,v 1.21 2025/02/23 20:47:19 christos Exp $"); 37 1.1 jnemeth #endif 38 1.1 jnemeth 39 1.1 jnemeth #include <sys/types.h> 40 1.1 jnemeth #include <sys/bootblock.h> 41 1.2 jnemeth #include <sys/disklabel_gpt.h> 42 1.1 jnemeth 43 1.1 jnemeth #include <err.h> 44 1.1 jnemeth #include <stddef.h> 45 1.1 jnemeth #include <stdio.h> 46 1.1 jnemeth #include <stdlib.h> 47 1.1 jnemeth #include <string.h> 48 1.1 jnemeth #include <unistd.h> 49 1.2 jnemeth #include <prop/proplib.h> 50 1.1 jnemeth 51 1.1 jnemeth #include "map.h" 52 1.1 jnemeth #include "gpt.h" 53 1.10 christos #include "gpt_private.h" 54 1.1 jnemeth 55 1.11 christos static int cmd_restore(gpt_t, int, char *[]); 56 1.1 jnemeth 57 1.11 christos static const char *restorehelp[] = { 58 1.15 christos "[-F] [-i infile]", 59 1.11 christos }; 60 1.11 christos 61 1.21 christos const struct gpt_cmd c_restore = { 62 1.11 christos "restore", 63 1.11 christos cmd_restore, 64 1.11 christos restorehelp, __arraycount(restorehelp), 65 1.18 jnemeth GPT_SYNC, 66 1.11 christos }; 67 1.1 jnemeth 68 1.11 christos #define usage() gpt_usage(NULL, &c_restore) 69 1.1 jnemeth 70 1.10 christos #define PROP_ERR(x) if (!(x)) { \ 71 1.10 christos gpt_warnx(gpt, "proplib failure"); \ 72 1.10 christos return -1; \ 73 1.10 christos } 74 1.2 jnemeth 75 1.14 christos static int 76 1.14 christos restore_mbr(gpt_t gpt, struct mbr *mbr, prop_dictionary_t mbr_dict, off_t last) 77 1.14 christos { 78 1.14 christos unsigned int i; 79 1.14 christos struct mbr_part *part; 80 1.14 christos 81 1.20 thorpej PROP_ERR(prop_dictionary_get_uint(mbr_dict, "index", &i)); 82 1.20 thorpej part = &mbr->mbr_part[i]; 83 1.14 christos 84 1.20 thorpej PROP_ERR(prop_dictionary_get_uint8(mbr_dict, "flag", &part->part_flag)); 85 1.20 thorpej PROP_ERR(prop_dictionary_get_uint8(mbr_dict, "start_head", 86 1.20 thorpej &part->part_shd)); 87 1.20 thorpej PROP_ERR(prop_dictionary_get_uint8(mbr_dict, "start_sector", 88 1.20 thorpej &part->part_ssect )); 89 1.20 thorpej PROP_ERR(prop_dictionary_get_uint8(mbr_dict, "start_cylinder", 90 1.20 thorpej &part->part_scyl)); 91 1.20 thorpej PROP_ERR(prop_dictionary_get_uint8(mbr_dict, "type", 92 1.20 thorpej &part->part_typ)); 93 1.20 thorpej PROP_ERR(prop_dictionary_get_uint8(mbr_dict, "end_head", 94 1.20 thorpej &part->part_ehd)); 95 1.20 thorpej PROP_ERR(prop_dictionary_get_uint8(mbr_dict, "end_sector", 96 1.20 thorpej &part->part_esect)); 97 1.20 thorpej PROP_ERR(prop_dictionary_get_uint8(mbr_dict, "end_cylinder", 98 1.20 thorpej &part->part_ecyl)); 99 1.20 thorpej PROP_ERR(prop_dictionary_get_uint16(mbr_dict, "lba_start_low", 100 1.20 thorpej &part->part_start_lo)); 101 1.20 thorpej part->part_start_lo = htole16(part->part_start_lo); 102 1.20 thorpej PROP_ERR(prop_dictionary_get_uint16(mbr_dict, "lba_start_high", 103 1.20 thorpej &part->part_start_hi)); 104 1.20 thorpej part->part_start_hi = htole16(part->part_start_hi); 105 1.14 christos 106 1.14 christos /* adjust PMBR size to size of device */ 107 1.14 christos if (part->part_typ == MBR_PTYPE_PMBR) { 108 1.14 christos if (last > 0xffffffff) { 109 1.14 christos mbr->mbr_part[0].part_size_lo = htole16(0xffff); 110 1.14 christos mbr->mbr_part[0].part_size_hi = htole16(0xffff); 111 1.14 christos } else { 112 1.16 christos mbr->mbr_part[0].part_size_lo = htole16((uint16_t)last); 113 1.16 christos mbr->mbr_part[0].part_size_hi = htole16( 114 1.21 christos (uint16_t)((uint64_t)last >> 16)); 115 1.14 christos } 116 1.14 christos } else { 117 1.20 thorpej PROP_ERR(prop_dictionary_get_uint16(mbr_dict, "lba_size_low", 118 1.20 thorpej &part->part_size_lo)); 119 1.20 thorpej part->part_size_lo = htole16(part->part_size_lo); 120 1.20 thorpej PROP_ERR(prop_dictionary_get_uint16(mbr_dict, "lba_size_high", 121 1.20 thorpej &part->part_size_hi)); 122 1.20 thorpej part->part_size_hi = htole16(part->part_size_hi); 123 1.14 christos } 124 1.14 christos return 0; 125 1.14 christos } 126 1.14 christos 127 1.14 christos static int 128 1.21 christos restore_ent(gpt_t gpt, prop_dictionary_t gpt_dict, void *secbuf, 129 1.21 christos u_int gpt_size __unused, u_int entries) 130 1.14 christos { 131 1.14 christos unsigned int i; 132 1.14 christos struct gpt_ent ent; 133 1.14 christos const char *s; 134 1.14 christos 135 1.14 christos memset(&ent, 0, sizeof(ent)); 136 1.20 thorpej PROP_ERR(prop_dictionary_get_string(gpt_dict, "type", &s)); 137 1.14 christos if (gpt_uuid_parse(s, ent.ent_type) != 0) { 138 1.14 christos gpt_warnx(gpt, "%s: not able to convert to an UUID", s); 139 1.14 christos return -1; 140 1.14 christos } 141 1.20 thorpej PROP_ERR(prop_dictionary_get_string(gpt_dict, "guid", &s)); 142 1.14 christos if (gpt_uuid_parse(s, ent.ent_guid) != 0) { 143 1.14 christos gpt_warnx(gpt, "%s: not able to convert to an UUID", s); 144 1.14 christos return -1; 145 1.14 christos } 146 1.20 thorpej PROP_ERR(prop_dictionary_get_uint64(gpt_dict, "start", 147 1.20 thorpej &ent.ent_lba_start)); 148 1.20 thorpej ent.ent_lba_start = htole64(ent.ent_lba_start); 149 1.20 thorpej PROP_ERR(prop_dictionary_get_uint64(gpt_dict, "end", 150 1.20 thorpej &ent.ent_lba_end)); 151 1.20 thorpej ent.ent_lba_end = htole64(ent.ent_lba_end); 152 1.20 thorpej PROP_ERR(prop_dictionary_get_uint64(gpt_dict, "attributes", 153 1.20 thorpej &ent.ent_attr)); 154 1.20 thorpej ent.ent_attr = htole64(ent.ent_attr); 155 1.20 thorpej 156 1.20 thorpej if (prop_dictionary_get_string(gpt_dict, "name", &s)) { 157 1.14 christos utf8_to_utf16((const uint8_t *)s, ent.ent_name, 158 1.17 christos __arraycount(ent.ent_name)); 159 1.14 christos } 160 1.20 thorpej PROP_ERR(prop_dictionary_get_uint(gpt_dict, "index", &i)); 161 1.14 christos if (i > entries) { 162 1.14 christos gpt_warnx(gpt, "Entity index out of bounds %u > %u\n", 163 1.14 christos i, entries); 164 1.14 christos return -1; 165 1.14 christos } 166 1.14 christos memcpy((char *)secbuf + gpt->secsz + ((i - 1) * sizeof(ent)), 167 1.14 christos &ent, sizeof(ent)); 168 1.14 christos return 0; 169 1.14 christos } 170 1.14 christos 171 1.10 christos static int 172 1.15 christos restore(gpt_t gpt, const char *infile, int force) 173 1.1 jnemeth { 174 1.7 jnemeth gpt_uuid_t gpt_guid, uuid; 175 1.2 jnemeth off_t firstdata, last, lastdata, gpe_start, gpe_end; 176 1.10 christos map_t map; 177 1.1 jnemeth struct mbr *mbr; 178 1.1 jnemeth struct gpt_hdr *hdr; 179 1.14 christos unsigned int i, gpt_size; 180 1.2 jnemeth prop_dictionary_t props, gpt_dict, mbr_dict, type_dict; 181 1.2 jnemeth prop_object_iterator_t propiter; 182 1.2 jnemeth prop_data_t propdata; 183 1.2 jnemeth prop_array_t mbr_array, gpt_array; 184 1.2 jnemeth prop_number_t propnum; 185 1.14 christos unsigned int entries; 186 1.2 jnemeth const char *s; 187 1.19 msaitoh void *secbuf = NULL; 188 1.14 christos int rv = -1; 189 1.1 jnemeth 190 1.10 christos last = gpt->mediasz / gpt->secsz - 1LL; 191 1.1 jnemeth 192 1.10 christos if (map_find(gpt, MAP_TYPE_PRI_GPT_HDR) != NULL || 193 1.10 christos map_find(gpt, MAP_TYPE_SEC_GPT_HDR) != NULL) { 194 1.2 jnemeth if (!force) { 195 1.10 christos gpt_warnx(gpt, "Device contains a GPT"); 196 1.10 christos return -1; 197 1.2 jnemeth } 198 1.1 jnemeth } 199 1.10 christos map = map_find(gpt, MAP_TYPE_MBR); 200 1.1 jnemeth if (map != NULL) { 201 1.1 jnemeth if (!force) { 202 1.10 christos gpt_warnx(gpt, "Device contains an MBR"); 203 1.10 christos return -1; 204 1.1 jnemeth } 205 1.1 jnemeth /* Nuke the MBR in our internal map. */ 206 1.1 jnemeth map->map_type = MAP_TYPE_UNUSED; 207 1.1 jnemeth } 208 1.1 jnemeth 209 1.15 christos props = prop_dictionary_internalize_from_file( 210 1.15 christos strcmp(infile, "-") == 0 ? "/dev/stdin" : infile); 211 1.3 jnemeth if (props == NULL) { 212 1.10 christos gpt_warnx(gpt, "Unable to read/parse backup file"); 213 1.10 christos return -1; 214 1.3 jnemeth } 215 1.2 jnemeth 216 1.2 jnemeth propnum = prop_dictionary_get(props, "sector_size"); 217 1.2 jnemeth PROP_ERR(propnum); 218 1.20 thorpej if (!prop_number_equals_signed(propnum, gpt->secsz)) { 219 1.10 christos gpt_warnx(gpt, "Sector size does not match backup"); 220 1.2 jnemeth prop_object_release(props); 221 1.10 christos return -1; 222 1.1 jnemeth } 223 1.1 jnemeth 224 1.2 jnemeth gpt_dict = prop_dictionary_get(props, "GPT_HDR"); 225 1.2 jnemeth PROP_ERR(gpt_dict); 226 1.2 jnemeth 227 1.2 jnemeth propnum = prop_dictionary_get(gpt_dict, "revision"); 228 1.2 jnemeth PROP_ERR(propnum); 229 1.20 thorpej if (!prop_number_equals_unsigned(propnum, 0x10000)) { 230 1.10 christos gpt_warnx(gpt, "backup is not revision 1.0"); 231 1.2 jnemeth prop_object_release(gpt_dict); 232 1.2 jnemeth prop_object_release(props); 233 1.10 christos return -1; 234 1.1 jnemeth } 235 1.1 jnemeth 236 1.20 thorpej PROP_ERR(prop_dictionary_get_uint(gpt_dict, "entries", &entries)); 237 1.20 thorpej 238 1.16 christos gpt_size = (u_int)(entries * sizeof(struct gpt_ent) / gpt->secsz); 239 1.10 christos if (gpt_size * sizeof(struct gpt_ent) % gpt->secsz) 240 1.3 jnemeth gpt_size++; 241 1.3 jnemeth 242 1.20 thorpej PROP_ERR(prop_dictionary_get_string(gpt_dict, "guid", &s)); 243 1.7 jnemeth if (gpt_uuid_parse(s, gpt_guid) != 0) { 244 1.10 christos gpt_warnx(gpt, "%s: not able to convert to an UUID", s); 245 1.14 christos goto out; 246 1.1 jnemeth } 247 1.2 jnemeth firstdata = gpt_size + 2; /* PMBR and GPT header */ 248 1.2 jnemeth lastdata = last - gpt_size - 1; /* alt. GPT table and header */ 249 1.2 jnemeth 250 1.2 jnemeth type_dict = prop_dictionary_get(props, "GPT_TBL"); 251 1.2 jnemeth PROP_ERR(type_dict); 252 1.2 jnemeth gpt_array = prop_dictionary_get(type_dict, "gpt_array"); 253 1.2 jnemeth PROP_ERR(gpt_array); 254 1.2 jnemeth propiter = prop_array_iterator(gpt_array); 255 1.2 jnemeth PROP_ERR(propiter); 256 1.2 jnemeth while ((gpt_dict = prop_object_iterator_next(propiter)) != NULL) { 257 1.20 thorpej PROP_ERR(prop_dictionary_get_string(gpt_dict, "type", &s)); 258 1.6 christos if (gpt_uuid_parse(s, uuid) != 0) { 259 1.10 christos gpt_warnx(gpt, "%s: not able to convert to an UUID", s); 260 1.14 christos goto out; 261 1.2 jnemeth } 262 1.6 christos if (gpt_uuid_is_nil(uuid)) 263 1.2 jnemeth continue; 264 1.20 thorpej PROP_ERR(prop_dictionary_get_int64(gpt_dict, "start", 265 1.20 thorpej &gpe_start)); 266 1.20 thorpej PROP_ERR(prop_dictionary_get_int64(gpt_dict, "end", 267 1.20 thorpej &gpe_end)); 268 1.2 jnemeth if (gpe_start < firstdata || gpe_end > lastdata) { 269 1.10 christos gpt_warnx(gpt, "Backup GPT doesn't fit"); 270 1.14 christos goto out; 271 1.2 jnemeth } 272 1.2 jnemeth } 273 1.2 jnemeth prop_object_iterator_release(propiter); 274 1.2 jnemeth 275 1.14 christos /* GPT TABLE + GPT HEADER */ 276 1.14 christos if ((secbuf = calloc(gpt_size + 1, gpt->secsz)) == NULL) { 277 1.14 christos gpt_warn(gpt, "not enough memory to create a sector buffer"); 278 1.14 christos goto out; 279 1.2 jnemeth } 280 1.3 jnemeth 281 1.10 christos if (lseek(gpt->fd, 0LL, SEEK_SET) == -1) { 282 1.14 christos gpt_warn(gpt, "Can't seek to beginning"); 283 1.14 christos goto out; 284 1.3 jnemeth } 285 1.3 jnemeth for (i = 0; i < firstdata; i++) { 286 1.14 christos if (write(gpt->fd, secbuf, gpt->secsz) != (ssize_t)gpt->secsz) { 287 1.14 christos gpt_warn(gpt, "Error writing"); 288 1.14 christos goto out; 289 1.3 jnemeth } 290 1.3 jnemeth } 291 1.10 christos if (lseek(gpt->fd, (lastdata + 1) * gpt->secsz, SEEK_SET) == -1) { 292 1.14 christos gpt_warn(gpt, "Can't seek to end"); 293 1.14 christos goto out; 294 1.3 jnemeth } 295 1.16 christos for (i = (u_int)(lastdata + 1); i <= (u_int)last; i++) { 296 1.14 christos if (write(gpt->fd, secbuf, gpt->secsz) != (ssize_t)gpt->secsz) { 297 1.14 christos gpt_warn(gpt, "Error writing"); 298 1.14 christos goto out; 299 1.3 jnemeth } 300 1.3 jnemeth } 301 1.2 jnemeth 302 1.14 christos mbr = secbuf; 303 1.2 jnemeth type_dict = prop_dictionary_get(props, "MBR"); 304 1.2 jnemeth PROP_ERR(type_dict); 305 1.2 jnemeth propdata = prop_dictionary_get(type_dict, "code"); 306 1.2 jnemeth PROP_ERR(propdata); 307 1.20 thorpej memcpy(mbr->mbr_code, prop_data_value(propdata), 308 1.2 jnemeth sizeof(mbr->mbr_code)); 309 1.2 jnemeth mbr_array = prop_dictionary_get(type_dict, "mbr_array"); 310 1.2 jnemeth PROP_ERR(mbr_array); 311 1.2 jnemeth propiter = prop_array_iterator(mbr_array); 312 1.2 jnemeth PROP_ERR(propiter); 313 1.2 jnemeth while ((mbr_dict = prop_object_iterator_next(propiter)) != NULL) { 314 1.14 christos if (restore_mbr(gpt, mbr, mbr_dict, last) == -1) 315 1.14 christos goto out; 316 1.2 jnemeth } 317 1.14 christos 318 1.2 jnemeth prop_object_iterator_release(propiter); 319 1.2 jnemeth mbr->mbr_sig = htole16(MBR_SIG); 320 1.10 christos if (lseek(gpt->fd, 0LL, SEEK_SET) == -1 || 321 1.14 christos write(gpt->fd, mbr, gpt->secsz) != (ssize_t)gpt->secsz) { 322 1.14 christos gpt_warn(gpt, "Unable to seek/write MBR"); 323 1.10 christos return -1; 324 1.3 jnemeth } 325 1.20 thorpej 326 1.2 jnemeth propiter = prop_array_iterator(gpt_array); 327 1.2 jnemeth PROP_ERR(propiter); 328 1.14 christos 329 1.2 jnemeth while ((gpt_dict = prop_object_iterator_next(propiter)) != NULL) { 330 1.14 christos if (restore_ent(gpt, gpt_dict, secbuf, gpt_size, entries) == -1) 331 1.14 christos goto out; 332 1.2 jnemeth } 333 1.2 jnemeth prop_object_iterator_release(propiter); 334 1.14 christos 335 1.14 christos size_t len = gpt_size * gpt->secsz; 336 1.10 christos if (lseek(gpt->fd, 2 * gpt->secsz, SEEK_SET) == -1 || 337 1.14 christos write(gpt->fd, (char *)secbuf + gpt->secsz, len) != (ssize_t) len) { 338 1.14 christos gpt_warn(gpt, "Unable to write primary GPT"); 339 1.14 christos goto out; 340 1.10 christos } 341 1.14 christos 342 1.10 christos if (lseek(gpt->fd, (lastdata + 1) * gpt->secsz, SEEK_SET) == -1 || 343 1.14 christos write(gpt->fd, (char *)secbuf + gpt->secsz, len) != (ssize_t) len) { 344 1.14 christos gpt_warn(gpt, "Unable to write secondary GPT"); 345 1.14 christos goto out; 346 1.3 jnemeth } 347 1.1 jnemeth 348 1.10 christos memset(secbuf, 0, gpt->secsz); 349 1.14 christos hdr = secbuf; 350 1.1 jnemeth memcpy(hdr->hdr_sig, GPT_HDR_SIG, sizeof(hdr->hdr_sig)); 351 1.1 jnemeth hdr->hdr_revision = htole32(GPT_HDR_REVISION); 352 1.2 jnemeth hdr->hdr_size = htole32(GPT_HDR_SIZE); 353 1.2 jnemeth hdr->hdr_lba_self = htole64(GPT_HDR_BLKNO); 354 1.16 christos hdr->hdr_lba_alt = htole64((uint64_t)last); 355 1.16 christos hdr->hdr_lba_start = htole64((uint64_t)firstdata); 356 1.16 christos hdr->hdr_lba_end = htole64((uint64_t)lastdata); 357 1.7 jnemeth gpt_uuid_copy(hdr->hdr_guid, gpt_guid); 358 1.2 jnemeth hdr->hdr_lba_table = htole64(2); 359 1.2 jnemeth hdr->hdr_entries = htole32(entries); 360 1.1 jnemeth hdr->hdr_entsz = htole32(sizeof(struct gpt_ent)); 361 1.14 christos hdr->hdr_crc_table = htole32(crc32((char *)secbuf + gpt->secsz, len)); 362 1.2 jnemeth hdr->hdr_crc_self = htole32(crc32(hdr, GPT_HDR_SIZE)); 363 1.14 christos if (lseek(gpt->fd, gpt->secsz, SEEK_SET) == -1 || 364 1.14 christos write(gpt->fd, hdr, gpt->secsz) != (ssize_t)gpt->secsz) { 365 1.14 christos gpt_warn(gpt, "Unable to write primary header"); 366 1.14 christos goto out; 367 1.3 jnemeth } 368 1.3 jnemeth 369 1.16 christos hdr->hdr_lba_self = htole64((uint64_t)last); 370 1.2 jnemeth hdr->hdr_lba_alt = htole64(GPT_HDR_BLKNO); 371 1.16 christos hdr->hdr_lba_table = htole64((uint64_t)(lastdata + 1)); 372 1.2 jnemeth hdr->hdr_crc_self = 0; 373 1.2 jnemeth hdr->hdr_crc_self = htole32(crc32(hdr, GPT_HDR_SIZE)); 374 1.10 christos if (lseek(gpt->fd, last * gpt->secsz, SEEK_SET) == -1 || 375 1.14 christos write(gpt->fd, hdr, gpt->secsz) != (ssize_t)gpt->secsz) { 376 1.14 christos gpt_warn(gpt, "Unable to write secondary header"); 377 1.14 christos goto out; 378 1.3 jnemeth } 379 1.14 christos rv = 0; 380 1.1 jnemeth 381 1.14 christos out: 382 1.14 christos free(secbuf); 383 1.3 jnemeth prop_object_release(props); 384 1.14 christos return rv; 385 1.1 jnemeth } 386 1.1 jnemeth 387 1.11 christos static int 388 1.10 christos cmd_restore(gpt_t gpt, int argc, char *argv[]) 389 1.1 jnemeth { 390 1.10 christos int ch; 391 1.15 christos int force = 0; 392 1.15 christos const char *infile = "-"; 393 1.1 jnemeth 394 1.13 christos while ((ch = getopt(argc, argv, "Fi:")) != -1) { 395 1.1 jnemeth switch(ch) { 396 1.13 christos case 'i': 397 1.13 christos infile = optarg; 398 1.13 christos break; 399 1.1 jnemeth case 'F': 400 1.1 jnemeth force = 1; 401 1.1 jnemeth break; 402 1.1 jnemeth default: 403 1.11 christos return usage(); 404 1.1 jnemeth } 405 1.1 jnemeth } 406 1.1 jnemeth 407 1.10 christos if (argc != optind) 408 1.11 christos return usage(); 409 1.1 jnemeth 410 1.15 christos return restore(gpt, infile, force); 411 1.1 jnemeth } 412