[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.22

1.22    ! christos    1: /*     $NetBSD: biosboot.c,v 1.21 2015/12/03 01:07:28 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.22    ! christos   40: __RCSID("$NetBSD: biosboot.c,v 1.21 2015/12/03 01:07:28 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:
1.17      christos   68: static int cmd_biosboot(gpt_t, int, char *[]);
1.1       jakllsch   69:
1.17      christos   70: static const char *biosboothelp[] = {
1.21      christos   71:        "[-c bootcode] [-i index] [-L label]",
1.20      christos   72: #if notyet
1.21      christos   73:        "[-a alignment] [-b blocknr] [-i index] [-l label]",
                     74:        "[-s size] [-t type]",
1.20      christos   75: #endif
1.17      christos   76: };
                     77:
                     78: struct gpt_cmd c_biosboot = {
                     79:        "biosboot",
                     80:        cmd_biosboot,
                     81:        biosboothelp, __arraycount(biosboothelp),
                     82:        0,
                     83: };
                     84:
                     85: #define usage() gpt_usage(NULL, &c_biosboot)
1.1       jakllsch   86:
                     87: static struct mbr*
1.21      christos   88: read_boot(gpt_t gpt, const char *bootpath)
1.1       jakllsch   89: {
1.21      christos   90:        int bfd, ret = -1;
1.1       jakllsch   91:        struct mbr *buf;
                     92:        struct stat st;
1.21      christos   93:        char *bp;
1.1       jakllsch   94:
1.16      christos   95:        buf = NULL;
                     96:        bfd = -1;
                     97:
                     98:        if (bootpath == NULL)
1.21      christos   99:                bp = strdup(DEFAULT_BOOTDIR "/" DEFAULT_BOOTCODE);
1.16      christos  100:        else if (*bootpath == '/')
1.21      christos  101:                bp = strdup(bootpath);
1.16      christos  102:        else {
1.21      christos  103:                if (asprintf(&bp, "%s/%s", DEFAULT_BOOTDIR, bootpath) < 0)
                    104:                        bp = NULL;
1.16      christos  105:        }
                    106:
1.21      christos  107:        if (bp == NULL) {
1.16      christos  108:                gpt_warn(gpt, "Can't allocate memory for bootpath");
                    109:                goto fail;
                    110:        }
                    111:
                    112:        if ((buf = malloc((size_t)gpt->secsz)) == NULL) {
                    113:                gpt_warn(gpt, "Can't allocate memory for sector");
                    114:                goto fail;
1.1       jakllsch  115:        }
                    116:
                    117:
1.21      christos  118:        if ((bfd = open(bp, O_RDONLY)) < 0 || fstat(bfd, &st) == -1) {
                    119:                gpt_warn(gpt, "Can't open `%s'", bp);
1.1       jakllsch  120:                goto fail;
                    121:        }
                    122:
1.2       jakllsch  123:        if (st.st_size != MBR_DSN_OFFSET) {
1.16      christos  124:                gpt_warnx(gpt, "The bootcode in `%s' does not match the"
1.21      christos  125:                    " expected size %u", bp, MBR_DSN_OFFSET);
1.1       jakllsch  126:                goto fail;
                    127:        }
                    128:
1.22    ! christos  129:        if (read(bfd, buf, (size_t)st.st_size) != (ssize_t)st.st_size) {
1.21      christos  130:                gpt_warn(gpt, "Error reading from `%s'", bp);
1.1       jakllsch  131:                goto fail;
                    132:        }
                    133:
1.21      christos  134:        ret = 0;
                    135: fail:
1.16      christos  136:        if (bfd != -1)
1.1       jakllsch  137:                close(bfd);
1.21      christos  138:        if (ret == -1) {
1.1       jakllsch  139:                free(buf);
                    140:                buf = NULL;
                    141:        }
1.21      christos  142:        free(bp);
1.1       jakllsch  143:        return buf;
                    144: }
                    145:
1.16      christos  146: static int
                    147: set_bootable(gpt_t gpt, map_t map, map_t tbl, unsigned int i)
1.1       jakllsch  148: {
1.16      christos  149:        unsigned int j;
                    150:        struct gpt_hdr *hdr = map->map_data;
                    151:        struct gpt_ent *ent;
                    152:        unsigned int ne = le32toh(hdr->hdr_entries);
                    153:
                    154:        for (j = 0; j < ne; j++) {
                    155:                ent = gpt_ent(map, tbl, j);
                    156:                ent->ent_attr &= ~GPT_ENT_ATTR_LEGACY_BIOS_BOOTABLE;
                    157:        }
                    158:
                    159:        ent = gpt_ent(map, tbl, i);
                    160:        ent->ent_attr |= GPT_ENT_ATTR_LEGACY_BIOS_BOOTABLE;
                    161:
                    162:        return gpt_write_crc(gpt, map, tbl);
                    163: }
                    164:
                    165: static int
1.21      christos  166: biosboot(gpt_t gpt, daddr_t start, uint64_t size, u_int entry, uint8_t *label,
                    167:     const char *bootpath)
1.16      christos  168: {
                    169:        map_t mbrmap, m;
1.1       jakllsch  170:        struct mbr *mbr, *bootcode;
1.16      christos  171:        unsigned int i;
1.2       jakllsch  172:        struct gpt_ent *ent;
1.19      christos  173:        uint8_t utfbuf[__arraycount(ent->ent_name) * 3 + 1];
1.1       jakllsch  174:
                    175:        /*
                    176:         * Parse and validate partition maps
                    177:         */
1.16      christos  178:        if (gpt_hdr(gpt) == NULL)
                    179:                return -1;
1.1       jakllsch  180:
1.16      christos  181:        mbrmap = map_find(gpt, MAP_TYPE_PMBR);
1.1       jakllsch  182:        if (mbrmap == NULL || mbrmap->map_start != 0) {
1.16      christos  183:                gpt_warnx(gpt, "No valid Protective MBR found");
                    184:                return -1;
1.1       jakllsch  185:        }
                    186:
                    187:        mbr = mbrmap->map_data;
                    188:
                    189:        /*
                    190:         * Update the boot code
                    191:         */
1.21      christos  192:        if ((bootcode = read_boot(gpt, bootpath)) == NULL) {
1.16      christos  193:                gpt_warnx(gpt, "Error reading bootcode");
                    194:                return -1;
1.1       jakllsch  195:        }
                    196:        (void)memcpy(&mbr->mbr_code, &bootcode->mbr_code,
                    197:                sizeof(mbr->mbr_code));
                    198:        free(bootcode);
                    199:
                    200:        /*
                    201:         * Walk through the GPT and see where we can boot from
                    202:         */
1.16      christos  203:        for (m = map_first(gpt); m != NULL; m = m->map_next) {
1.1       jakllsch  204:                if (m->map_type != MAP_TYPE_GPT_PART || m->map_index < 1)
                    205:                        continue;
                    206:
1.2       jakllsch  207:                ent = m->map_data;
1.1       jakllsch  208:
                    209:                /* first, prefer user selection */
                    210:                if (entry > 0 && m->map_index == entry)
                    211:                        break;
                    212:
1.19      christos  213:                if (label != NULL) {
                    214:                        utf16_to_utf8(ent->ent_name, utfbuf, sizeof(utfbuf));
                    215:                        if (strcmp((char *)label, (char *)utfbuf) == 0)
1.9       jnemeth   216:                                break;
1.19      christos  217:                }
1.9       jnemeth   218:
1.1       jakllsch  219:                /* next, partition as could be specified by wedge */
1.9       jnemeth   220:                if (entry < 1 && label == NULL && size > 0 &&
1.1       jakllsch  221:                    m->map_start == start && m->map_size == (off_t)size)
                    222:                        break;
                    223:        }
                    224:
                    225:        if (m == NULL) {
1.16      christos  226:                gpt_warnx(gpt, "No bootable partition");
                    227:                return -1;
1.2       jakllsch  228:        }
                    229:
                    230:        i = m->map_index - 1;
1.1       jakllsch  231:
                    232:
1.16      christos  233:        if (set_bootable(gpt, gpt->gpt, gpt->tbl, i) == -1)
                    234:                return -1;
1.2       jakllsch  235:
1.16      christos  236:        if (set_bootable(gpt, gpt->tpg, gpt->lbt, i) == -1)
                    237:                return -1;
1.2       jakllsch  238:
1.16      christos  239:        if (gpt_write(gpt, mbrmap) == -1) {
                    240:                gpt_warnx(gpt, "Cannot update Protective MBR");
                    241:                return -1;
1.1       jakllsch  242:        }
1.9       jnemeth   243:
1.16      christos  244:        gpt_msg(gpt, "Partition %d marked as bootable", i + 1);
                    245:        return 0;
1.1       jakllsch  246: }
                    247:
1.17      christos  248: static int
1.16      christos  249: cmd_biosboot(gpt_t gpt, int argc, char *argv[])
1.1       jakllsch  250: {
1.12      christos  251: #ifdef DIOCGWEDGEINFO
1.1       jakllsch  252:        struct dkwedge_info dkw;
1.12      christos  253: #endif
1.16      christos  254:        int ch;
                    255:        gpt_t ngpt = gpt;
1.21      christos  256:        daddr_t start = 0;
                    257:        uint64_t size = 0;
                    258:        unsigned int entry = 0;
                    259:        uint8_t *label = NULL;
                    260:        const char *bootpath = NULL;
1.1       jakllsch  261:
1.9       jnemeth   262:        while ((ch = getopt(argc, argv, "c:i:L:")) != -1) {
1.1       jakllsch  263:                switch(ch) {
                    264:                case 'c':
1.18      christos  265:                        if (gpt_name_get(gpt, &bootpath) == -1)
                    266:                                return usage();
1.1       jakllsch  267:                        break;
                    268:                case 'i':
1.22    ! christos  269:                        if (gpt_uint_get(&entry) == -1)
1.17      christos  270:                                return usage();
1.1       jakllsch  271:                        break;
1.9       jnemeth   272:                case 'L':
1.18      christos  273:                        if (gpt_name_get(gpt, &label) == -1)
1.17      christos  274:                                return usage();
1.9       jnemeth   275:                        break;
1.1       jakllsch  276:                default:
1.17      christos  277:                        return usage();
1.1       jakllsch  278:                }
                    279:        }
                    280:
1.16      christos  281:        if (argc != optind)
1.17      christos  282:                return usage();
1.1       jakllsch  283:
                    284: #ifdef DIOCGWEDGEINFO
1.16      christos  285:        if ((gpt->sb.st_mode & S_IFMT) != S_IFREG &&
                    286:            ioctl(gpt->fd, DIOCGWEDGEINFO, &dkw) != -1) {
                    287:                if (entry > 0)
                    288:                        /* wedges and indexes are mutually exclusive */
1.17      christos  289:                        return usage();
1.16      christos  290:                start = dkw.dkw_offset;
                    291:                size = dkw.dkw_size;
1.21      christos  292:                ngpt = gpt_open(dkw.dkw_parent, gpt->flags, gpt->verbose,
1.16      christos  293:                    gpt->mediasz, gpt->secsz);
                    294:                if (ngpt == NULL)
                    295:                        return -1;
                    296:        }
1.1       jakllsch  297: #endif
1.21      christos  298:        biosboot(ngpt, start, size, entry, label, bootpath);
1.16      christos  299:        if (ngpt != gpt)
                    300:                gpt_close(ngpt);
1.1       jakllsch  301:
1.16      christos  302:        return 0;
1.1       jakllsch  303: }

CVSweb <webmaster@jp.NetBSD.org>