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

1.27    ! christos    1: /*     $NetBSD: biosboot.c,v 1.26 2016/06/09 19:04:43 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.27    ! christos   40: __RCSID("$NetBSD: biosboot.c,v 1.26 2016/06/09 19:04:43 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.26      christos   71:        "[-A] [-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,
1.25      christos  167:     const char *bootpath, int active)
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:
1.25      christos  200:        for (i = 0; i < __arraycount(mbr->mbr_part); i++)
                    201:                if (mbr->mbr_part[i].part_typ == MBR_PTYPE_PMBR)
                    202:                        mbr->mbr_part[i].part_flag = active ? 0x80 : 0;
                    203:
1.1       jakllsch  204:        /*
                    205:         * Walk through the GPT and see where we can boot from
                    206:         */
1.16      christos  207:        for (m = map_first(gpt); m != NULL; m = m->map_next) {
1.1       jakllsch  208:                if (m->map_type != MAP_TYPE_GPT_PART || m->map_index < 1)
                    209:                        continue;
                    210:
1.2       jakllsch  211:                ent = m->map_data;
1.1       jakllsch  212:
                    213:                /* first, prefer user selection */
                    214:                if (entry > 0 && m->map_index == entry)
                    215:                        break;
                    216:
1.19      christos  217:                if (label != NULL) {
                    218:                        utf16_to_utf8(ent->ent_name, utfbuf, sizeof(utfbuf));
                    219:                        if (strcmp((char *)label, (char *)utfbuf) == 0)
1.9       jnemeth   220:                                break;
1.19      christos  221:                }
1.9       jnemeth   222:
1.1       jakllsch  223:                /* next, partition as could be specified by wedge */
1.9       jnemeth   224:                if (entry < 1 && label == NULL && size > 0 &&
1.1       jakllsch  225:                    m->map_start == start && m->map_size == (off_t)size)
                    226:                        break;
                    227:        }
                    228:
                    229:        if (m == NULL) {
1.16      christos  230:                gpt_warnx(gpt, "No bootable partition");
                    231:                return -1;
1.2       jakllsch  232:        }
                    233:
                    234:        i = m->map_index - 1;
1.1       jakllsch  235:
                    236:
1.16      christos  237:        if (set_bootable(gpt, gpt->gpt, gpt->tbl, i) == -1)
                    238:                return -1;
1.2       jakllsch  239:
1.16      christos  240:        if (set_bootable(gpt, gpt->tpg, gpt->lbt, i) == -1)
                    241:                return -1;
1.2       jakllsch  242:
1.16      christos  243:        if (gpt_write(gpt, mbrmap) == -1) {
                    244:                gpt_warnx(gpt, "Cannot update Protective MBR");
                    245:                return -1;
1.1       jakllsch  246:        }
1.9       jnemeth   247:
1.16      christos  248:        gpt_msg(gpt, "Partition %d marked as bootable", i + 1);
                    249:        return 0;
1.1       jakllsch  250: }
                    251:
1.17      christos  252: static int
1.16      christos  253: cmd_biosboot(gpt_t gpt, int argc, char *argv[])
1.1       jakllsch  254: {
1.12      christos  255: #ifdef DIOCGWEDGEINFO
1.1       jakllsch  256:        struct dkwedge_info dkw;
1.12      christos  257: #endif
1.16      christos  258:        int ch;
                    259:        gpt_t ngpt = gpt;
1.21      christos  260:        daddr_t start = 0;
                    261:        uint64_t size = 0;
1.25      christos  262:        int active = 0;
1.21      christos  263:        unsigned int entry = 0;
                    264:        uint8_t *label = NULL;
1.23      christos  265:        char *bootpath = NULL;
1.1       jakllsch  266:
1.26      christos  267:        while ((ch = getopt(argc, argv, "Ac:i:L:")) != -1) {
1.1       jakllsch  268:                switch(ch) {
1.26      christos  269:                case 'A':
1.25      christos  270:                        active = 1;
                    271:                        break;
1.1       jakllsch  272:                case 'c':
1.18      christos  273:                        if (gpt_name_get(gpt, &bootpath) == -1)
1.23      christos  274:                                goto usage;
1.1       jakllsch  275:                        break;
                    276:                case 'i':
1.24      christos  277:                        if (gpt_uint_get(gpt, &entry) == -1)
1.23      christos  278:                                goto usage;
1.1       jakllsch  279:                        break;
1.9       jnemeth   280:                case 'L':
1.18      christos  281:                        if (gpt_name_get(gpt, &label) == -1)
1.23      christos  282:                                goto usage;
1.9       jnemeth   283:                        break;
1.1       jakllsch  284:                default:
1.23      christos  285:                        goto usage;
1.1       jakllsch  286:                }
                    287:        }
                    288:
1.16      christos  289:        if (argc != optind)
1.17      christos  290:                return usage();
1.1       jakllsch  291:
                    292: #ifdef DIOCGWEDGEINFO
1.16      christos  293:        if ((gpt->sb.st_mode & S_IFMT) != S_IFREG &&
                    294:            ioctl(gpt->fd, DIOCGWEDGEINFO, &dkw) != -1) {
                    295:                if (entry > 0)
                    296:                        /* wedges and indexes are mutually exclusive */
1.23      christos  297:                        goto usage;
1.16      christos  298:                start = dkw.dkw_offset;
                    299:                size = dkw.dkw_size;
1.21      christos  300:                ngpt = gpt_open(dkw.dkw_parent, gpt->flags, gpt->verbose,
1.27    ! christos  301:                    gpt->mediasz, gpt->secsz, gpt->timestamp);
1.16      christos  302:                if (ngpt == NULL)
1.23      christos  303:                        goto cleanup;
1.16      christos  304:        }
1.1       jakllsch  305: #endif
1.25      christos  306:        if (biosboot(ngpt, start, size, entry, label, bootpath, active) == -1)
1.23      christos  307:                goto cleanup;
1.16      christos  308:        if (ngpt != gpt)
                    309:                gpt_close(ngpt);
                    310:        return 0;
1.23      christos  311: usage:
                    312:        usage();
                    313: cleanup:
                    314:        if (ngpt != gpt)
                    315:                gpt_close(ngpt);
                    316:        free(bootpath);
                    317:        free(label);
                    318:        return -1;
1.1       jakllsch  319: }

CVSweb <webmaster@jp.NetBSD.org>