[BACK]Return to biosboot.c CVS log [TXT][DIR] Up to [cvs.NetBSD.org] / src / sbin / gpt

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>