Annotation of src/sbin/gpt/biosboot.c, Revision 1.17
1.17 ! christos 1: /* $NetBSD: biosboot.c,v 1.16 2015/12/01 09:05:33 christos Exp $ */
1.1 jakllsch 2:
3: /*
1.6 jakllsch 4: * Copyright (c) 2009 The NetBSD Foundation, Inc.
1.1 jakllsch 5: * All rights reserved.
1.6 jakllsch 6: *
1.1 jakllsch 7: * This code is derived from software contributed to the NetBSD Foundation
8: * by Mike M. Volokhov. Development of this software was supported by the
9: * Google Summer of Code program.
10: * The GSoC project was mentored by Allen Briggs and Joerg Sonnenberger.
11: *
12: * Redistribution and use in source and binary forms, with or without
13: * modification, are permitted provided that the following conditions
14: * are met:
15: * 1. Redistributions of source code must retain the above copyright
16: * notice, this list of conditions and the following disclaimer.
17: * 2. Redistributions in binary form must reproduce the above copyright
18: * notice, this list of conditions and the following disclaimer in the
19: * documentation and/or other materials provided with the distribution.
20: *
21: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
22: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
23: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
25: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31: * POSSIBILITY OF SUCH DAMAGE.
32: */
33:
1.10 christos 34: #if HAVE_NBTOOL_CONFIG_H
35: #include "nbtool_config.h"
36: #endif
37:
1.1 jakllsch 38: #include <sys/cdefs.h>
39: #ifdef __RCSID
1.17 ! christos 40: __RCSID("$NetBSD: biosboot.c,v 1.16 2015/12/01 09:05:33 christos Exp $");
1.1 jakllsch 41: #endif
42:
43: #include <sys/stat.h>
44: #include <sys/types.h>
45: #include <sys/ioctl.h>
1.14 christos 46: #ifdef DIOCGWEDGEINFO
1.1 jakllsch 47: #include <sys/disk.h>
1.13 joerg 48: #endif
1.1 jakllsch 49: #include <sys/param.h>
50: #include <sys/bootblock.h>
51:
52: #include <err.h>
53: #include <fcntl.h>
54: #include <paths.h>
55: #include <stddef.h>
56: #include <stdio.h>
57: #include <stdlib.h>
58: #include <string.h>
59: #include <unistd.h>
60:
61: #include "map.h"
62: #include "gpt.h"
1.16 christos 63: #include "gpt_private.h"
1.1 jakllsch 64:
65: #define DEFAULT_BOOTDIR "/usr/mdec"
1.3 jakllsch 66: #define DEFAULT_BOOTCODE "gptmbr.bin"
1.1 jakllsch 67:
68: static daddr_t start;
69: static uint64_t size;
70:
71: static char *bootpath;
72: static unsigned int entry;
1.9 jnemeth 73: static uint8_t *label;
1.1 jakllsch 74:
1.17 ! christos 75: static int cmd_biosboot(gpt_t, int, char *[]);
1.1 jakllsch 76:
1.17 ! christos 77: static const char *biosboothelp[] = {
! 78: "[-c bootcode] [-i index] [-L label]",
! 79: "[-a alignment] [-b blocknr] [-i index] [-l label]",
! 80: "[-s size] [-t type]",
! 81: };
! 82:
! 83: struct gpt_cmd c_biosboot = {
! 84: "biosboot",
! 85: cmd_biosboot,
! 86: biosboothelp, __arraycount(biosboothelp),
! 87: 0,
! 88: };
! 89:
! 90: #define usage() gpt_usage(NULL, &c_biosboot)
1.1 jakllsch 91:
92: static struct mbr*
1.16 christos 93: read_boot(gpt_t gpt)
1.1 jakllsch 94: {
95: int bfd, ret = 0;
96: struct mbr *buf;
97: struct stat st;
98:
1.16 christos 99: buf = NULL;
100: bfd = -1;
101:
102: if (bootpath == NULL)
103: bootpath = strdup(DEFAULT_BOOTDIR "/" DEFAULT_BOOTCODE);
104: else if (*bootpath == '/')
105: bootpath = strdup(bootpath);
106: else {
107: if (asprintf(&bootpath, "%s/%s", DEFAULT_BOOTDIR, bootpath) < 0)
108: bootpath = NULL;
109: }
110:
1.1 jakllsch 111: if (bootpath == NULL) {
1.16 christos 112: gpt_warn(gpt, "Can't allocate memory for bootpath");
113: goto fail;
114: }
115:
116: if ((buf = malloc((size_t)gpt->secsz)) == NULL) {
117: gpt_warn(gpt, "Can't allocate memory for sector");
118: goto fail;
1.1 jakllsch 119: }
120:
121:
122: if ((bfd = open(bootpath, O_RDONLY)) < 0 || fstat(bfd, &st) == -1) {
1.16 christos 123: gpt_warn(gpt, "Can't open `%s'", bootpath);
1.1 jakllsch 124: goto fail;
125: }
126:
1.2 jakllsch 127: if (st.st_size != MBR_DSN_OFFSET) {
1.16 christos 128: gpt_warnx(gpt, "The bootcode in `%s' does not match the"
129: " expected size %u", bootpath, MBR_DSN_OFFSET);
1.1 jakllsch 130: goto fail;
131: }
132:
1.2 jakllsch 133: if (read(bfd, buf, st.st_size) != st.st_size) {
1.16 christos 134: gpt_warn(gpt, "Error reading from `%s'", bootpath);
1.1 jakllsch 135: goto fail;
136: }
137:
138: ret++;
139:
140: fail:
1.16 christos 141: if (bfd != -1)
1.1 jakllsch 142: close(bfd);
143: if (ret == 0) {
144: free(buf);
145: buf = NULL;
146: }
147: return buf;
148: }
149:
1.16 christos 150: static int
151: set_bootable(gpt_t gpt, map_t map, map_t tbl, unsigned int i)
1.1 jakllsch 152: {
1.16 christos 153: unsigned int j;
154: struct gpt_hdr *hdr = map->map_data;
155: struct gpt_ent *ent;
156: unsigned int ne = le32toh(hdr->hdr_entries);
157:
158: for (j = 0; j < ne; j++) {
159: ent = gpt_ent(map, tbl, j);
160: ent->ent_attr &= ~GPT_ENT_ATTR_LEGACY_BIOS_BOOTABLE;
161: }
162:
163: ent = gpt_ent(map, tbl, i);
164: ent->ent_attr |= GPT_ENT_ATTR_LEGACY_BIOS_BOOTABLE;
165:
166: return gpt_write_crc(gpt, map, tbl);
167: }
168:
169: static int
170: biosboot(gpt_t gpt)
171: {
172: map_t mbrmap, m;
1.1 jakllsch 173: struct mbr *mbr, *bootcode;
1.16 christos 174: unsigned int i;
1.2 jakllsch 175: struct gpt_ent *ent;
1.1 jakllsch 176:
177: /*
178: * Parse and validate partition maps
179: */
1.16 christos 180: if (gpt_hdr(gpt) == NULL)
181: return -1;
1.1 jakllsch 182:
1.16 christos 183: mbrmap = map_find(gpt, MAP_TYPE_PMBR);
1.1 jakllsch 184: if (mbrmap == NULL || mbrmap->map_start != 0) {
1.16 christos 185: gpt_warnx(gpt, "No valid Protective MBR found");
186: return -1;
1.1 jakllsch 187: }
188:
189: mbr = mbrmap->map_data;
190:
191: /*
192: * Update the boot code
193: */
1.16 christos 194: if ((bootcode = read_boot(gpt)) == NULL) {
195: gpt_warnx(gpt, "Error reading bootcode");
196: return -1;
1.1 jakllsch 197: }
198: (void)memcpy(&mbr->mbr_code, &bootcode->mbr_code,
199: sizeof(mbr->mbr_code));
200: free(bootcode);
201:
202: /*
203: * Walk through the GPT and see where we can boot from
204: */
1.16 christos 205: for (m = map_first(gpt); m != NULL; m = m->map_next) {
1.1 jakllsch 206: if (m->map_type != MAP_TYPE_GPT_PART || m->map_index < 1)
207: continue;
208:
1.2 jakllsch 209: ent = m->map_data;
1.1 jakllsch 210:
211: /* first, prefer user selection */
212: if (entry > 0 && m->map_index == entry)
213: break;
214:
1.9 jnemeth 215: if (label != NULL)
216: if (strcmp((char *)label,
217: (char *)utf16_to_utf8(ent->ent_name)) == 0)
218: break;
219:
1.1 jakllsch 220: /* next, partition as could be specified by wedge */
1.9 jnemeth 221: if (entry < 1 && label == NULL && size > 0 &&
1.1 jakllsch 222: m->map_start == start && m->map_size == (off_t)size)
223: break;
224: }
225:
226: if (m == NULL) {
1.16 christos 227: gpt_warnx(gpt, "No bootable partition");
228: return -1;
1.2 jakllsch 229: }
230:
231: i = m->map_index - 1;
1.1 jakllsch 232:
233:
1.16 christos 234: if (set_bootable(gpt, gpt->gpt, gpt->tbl, i) == -1)
235: return -1;
1.2 jakllsch 236:
1.16 christos 237: if (set_bootable(gpt, gpt->tpg, gpt->lbt, i) == -1)
238: return -1;
1.2 jakllsch 239:
1.16 christos 240: if (gpt_write(gpt, mbrmap) == -1) {
241: gpt_warnx(gpt, "Cannot update Protective MBR");
242: return -1;
1.1 jakllsch 243: }
1.9 jnemeth 244:
1.16 christos 245: gpt_msg(gpt, "Partition %d marked as bootable", i + 1);
246: return 0;
1.1 jakllsch 247: }
248:
1.17 ! christos 249: static int
1.16 christos 250: cmd_biosboot(gpt_t gpt, int argc, char *argv[])
1.1 jakllsch 251: {
1.12 christos 252: #ifdef DIOCGWEDGEINFO
1.1 jakllsch 253: struct dkwedge_info dkw;
1.12 christos 254: #endif
1.1 jakllsch 255: char *dev, *p;
1.16 christos 256: int ch;
257: gpt_t ngpt = gpt;
1.1 jakllsch 258:
1.9 jnemeth 259: while ((ch = getopt(argc, argv, "c:i:L:")) != -1) {
1.1 jakllsch 260: switch(ch) {
261: case 'c':
262: if (bootpath != NULL)
1.17 ! christos 263: usage();
! 264: if ((bootpath = strdup(optarg)) == NULL) {
! 265: gpt_warn(gpt, "strdup failed");
! 266: return -1;
! 267: }
1.1 jakllsch 268: break;
269: case 'i':
270: if (entry > 0)
1.17 ! christos 271: usage();
1.1 jakllsch 272: entry = strtoul(optarg, &p, 10);
273: if (*p != 0 || entry < 1)
1.17 ! christos 274: return usage();
1.1 jakllsch 275: break;
1.9 jnemeth 276: case 'L':
277: if (label != NULL)
1.17 ! christos 278: return usage();
! 279: if ((label = (uint8_t *)strdup(optarg)) == NULL) {
! 280: gpt_warn(gpt, "strdup failed");
! 281: return -1;
! 282: }
1.9 jnemeth 283: break;
1.1 jakllsch 284: default:
1.17 ! christos 285: return usage();
1.1 jakllsch 286: }
287: }
288:
1.16 christos 289: if (argc != optind)
1.17 ! christos 290: return usage();
1.1 jakllsch 291:
1.16 christos 292: start = 0;
293: size = 0;
1.1 jakllsch 294:
295: #ifdef DIOCGWEDGEINFO
1.16 christos 296: if ((gpt->sb.st_mode & S_IFMT) != S_IFREG &&
297: ioctl(gpt->fd, DIOCGWEDGEINFO, &dkw) != -1) {
298: if (entry > 0)
299: /* wedges and indexes are mutually exclusive */
1.17 ! christos 300: return usage();
1.16 christos 301: dev = dkw.dkw_parent;
302: start = dkw.dkw_offset;
303: size = dkw.dkw_size;
304: ngpt = gpt_open(dev, gpt->flags, gpt->verbose,
305: gpt->mediasz, gpt->secsz);
306: if (ngpt == NULL)
307: return -1;
308: }
1.1 jakllsch 309: #endif
1.16 christos 310: biosboot(ngpt);
311: if (ngpt != gpt)
312: gpt_close(ngpt);
1.1 jakllsch 313:
1.16 christos 314: return 0;
1.1 jakllsch 315: }
CVSweb <webmaster@jp.NetBSD.org>