scheme.c revision 263829
1253923Smarcel/*- 2263409Smarcel * Copyright (c) 2013,2014 Juniper Networks, Inc. 3253923Smarcel * All rights reserved. 4253923Smarcel * 5253923Smarcel * Redistribution and use in source and binary forms, with or without 6253923Smarcel * modification, are permitted provided that the following conditions 7253923Smarcel * are met: 8253923Smarcel * 1. Redistributions of source code must retain the above copyright 9253923Smarcel * notice, this list of conditions and the following disclaimer. 10253923Smarcel * 2. Redistributions in binary form must reproduce the above copyright 11253923Smarcel * notice, this list of conditions and the following disclaimer in the 12253923Smarcel * documentation and/or other materials provided with the distribution. 13253923Smarcel * 14253923Smarcel * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15253923Smarcel * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16253923Smarcel * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17253923Smarcel * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18253923Smarcel * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19253923Smarcel * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20253923Smarcel * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21253923Smarcel * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22253923Smarcel * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23253923Smarcel * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24253923Smarcel * SUCH DAMAGE. 25253923Smarcel */ 26253923Smarcel 27253923Smarcel#include <sys/cdefs.h> 28253923Smarcel__FBSDID("$FreeBSD$"); 29253923Smarcel 30253923Smarcel#include <sys/types.h> 31263409Smarcel#include <sys/linker_set.h> 32263382Smarcel#include <sys/queue.h> 33263537Smarcel#include <sys/stat.h> 34253923Smarcel#include <err.h> 35253923Smarcel#include <errno.h> 36253923Smarcel#include <stdint.h> 37263537Smarcel#include <stdlib.h> 38263466Smarcel#include <string.h> 39253923Smarcel#include <unistd.h> 40253923Smarcel 41263382Smarcel#include "mkimg.h" 42253923Smarcel#include "scheme.h" 43253923Smarcel 44263487Smarcelstatic struct { 45263487Smarcel const char *name; 46263487Smarcel enum alias alias; 47263487Smarcel} scheme_alias[] = { 48263672Smarcel { "ebr", ALIAS_EBR }, 49263487Smarcel { "efi", ALIAS_EFI }, 50263672Smarcel { "fat32", ALIAS_FAT32 }, 51263487Smarcel { "freebsd", ALIAS_FREEBSD }, 52263487Smarcel { "freebsd-boot", ALIAS_FREEBSD_BOOT }, 53263487Smarcel { "freebsd-nandfs", ALIAS_FREEBSD_NANDFS }, 54263487Smarcel { "freebsd-swap", ALIAS_FREEBSD_SWAP }, 55263487Smarcel { "freebsd-ufs", ALIAS_FREEBSD_UFS }, 56263487Smarcel { "freebsd-vinum", ALIAS_FREEBSD_VINUM }, 57263487Smarcel { "freebsd-zfs", ALIAS_FREEBSD_ZFS }, 58263487Smarcel { "mbr", ALIAS_MBR }, 59263487Smarcel { NULL, ALIAS_NONE } /* Keep last! */ 60263487Smarcel}; 61263487Smarcel 62263409Smarcelstatic struct mkimg_scheme *scheme; 63263537Smarcelstatic void *bootcode; 64253923Smarcel 65263487Smarcelstatic enum alias 66263487Smarcelscheme_parse_alias(const char *name) 67263487Smarcel{ 68263487Smarcel u_int idx; 69263487Smarcel 70263487Smarcel idx = 0; 71263487Smarcel while (scheme_alias[idx].name != NULL) { 72263487Smarcel if (strcasecmp(scheme_alias[idx].name, name) == 0) 73263487Smarcel return (scheme_alias[idx].alias); 74263487Smarcel idx++; 75263487Smarcel } 76263487Smarcel return (ALIAS_NONE); 77263487Smarcel} 78263487Smarcel 79253923Smarcelint 80253923Smarcelscheme_select(const char *spec) 81253923Smarcel{ 82263409Smarcel struct mkimg_scheme *s, **iter; 83253923Smarcel 84263409Smarcel SET_FOREACH(iter, schemes) { 85263409Smarcel s = *iter; 86263409Smarcel if (strcasecmp(spec, s->name) == 0) { 87263409Smarcel scheme = s; 88253923Smarcel return (0); 89253923Smarcel } 90253923Smarcel } 91253923Smarcel return (EINVAL); 92253923Smarcel} 93253923Smarcel 94263409Smarcelstruct mkimg_scheme * 95253923Smarcelscheme_selected(void) 96253923Smarcel{ 97253923Smarcel 98253923Smarcel return (scheme); 99253923Smarcel} 100253923Smarcel 101253923Smarcelint 102263537Smarcelscheme_bootcode(int fd) 103263537Smarcel{ 104263537Smarcel struct stat sb; 105263537Smarcel int error; 106263537Smarcel 107263537Smarcel if (fd == -1) 108263537Smarcel return (0); 109263537Smarcel if (scheme->bootcode == 0) 110263537Smarcel return (ENXIO); 111263537Smarcel 112263537Smarcel error = fstat(fd, &sb); 113263537Smarcel if (error) 114263537Smarcel return (error); 115263537Smarcel if (sb.st_size > scheme->bootcode) 116263537Smarcel return (EFBIG); 117263537Smarcel 118263537Smarcel bootcode = malloc(scheme->bootcode); 119263537Smarcel if (bootcode == NULL) 120263537Smarcel return (ENOMEM); 121263537Smarcel memset(bootcode, 0, scheme->bootcode); 122263537Smarcel if (read(fd, bootcode, sb.st_size) != sb.st_size) { 123263537Smarcel free(bootcode); 124263537Smarcel bootcode = NULL; 125263537Smarcel return (errno); 126263537Smarcel } 127263537Smarcel return (0); 128263537Smarcel} 129263537Smarcel 130263537Smarcelint 131263409Smarcelscheme_check_part(struct part *p) 132253923Smarcel{ 133263487Smarcel struct mkimg_alias *iter; 134263487Smarcel enum alias alias; 135253923Smarcel 136263414Smarcel /* Check the partition type alias */ 137263487Smarcel alias = scheme_parse_alias(p->alias); 138263487Smarcel if (alias == ALIAS_NONE) 139263487Smarcel return (EINVAL); 140263487Smarcel 141263414Smarcel iter = scheme->aliases; 142263487Smarcel while (iter->alias != ALIAS_NONE) { 143263487Smarcel if (alias == iter->alias) 144263414Smarcel break; 145263414Smarcel iter++; 146263414Smarcel } 147263487Smarcel if (iter->alias == ALIAS_NONE) 148263414Smarcel return (EINVAL); 149263461Smarcel p->type = iter->type; 150263466Smarcel 151263466Smarcel /* Validate the optional label. */ 152263466Smarcel if (p->label != NULL) { 153263466Smarcel if (strlen(p->label) > scheme->labellen) 154263487Smarcel return (EINVAL); 155263466Smarcel } 156263466Smarcel 157253923Smarcel return (0); 158253923Smarcel} 159253923Smarcel 160253923Smarcelu_int 161253923Smarcelscheme_max_parts(void) 162253923Smarcel{ 163253923Smarcel 164263409Smarcel return (scheme->nparts); 165253923Smarcel} 166253923Smarcel 167263829Smarcelu_int 168263829Smarcelscheme_max_secsz(void) 169263829Smarcel{ 170263829Smarcel 171263829Smarcel return (scheme->maxsecsz); 172263829Smarcel} 173263829Smarcel 174263653Smarcellba_t 175263653Smarcelscheme_first_block(void) 176263442Smarcel{ 177263653Smarcel lba_t blks; 178263442Smarcel 179263653Smarcel blks = scheme->metadata(SCHEME_META_IMG_START) + 180263653Smarcel scheme->metadata(SCHEME_META_PART_BEFORE); 181263653Smarcel return (blks); 182263442Smarcel} 183263442Smarcel 184263653Smarcellba_t 185263653Smarcelscheme_next_block(lba_t start, lba_t size) 186253923Smarcel{ 187263653Smarcel lba_t blks; 188253923Smarcel 189263653Smarcel blks = scheme->metadata(SCHEME_META_PART_AFTER) + 190263653Smarcel scheme->metadata(SCHEME_META_PART_BEFORE); 191263653Smarcel return (start + size + blks); 192253923Smarcel} 193253923Smarcel 194263442Smarcelint 195263653Smarcelscheme_write(int fd, lba_t end) 196253923Smarcel{ 197263442Smarcel int error; 198253923Smarcel 199263653Smarcel /* Fixup block: it has an extra metadata before the partition */ 200263653Smarcel end -= scheme->metadata(SCHEME_META_PART_BEFORE); 201263653Smarcel end += scheme->metadata(SCHEME_META_IMG_END); 202263653Smarcel if (ftruncate(fd, end * secsz) == -1) 203263442Smarcel return (errno); 204263442Smarcel 205263653Smarcel error = scheme->write(fd, end, bootcode); 206263442Smarcel return (error); 207253923Smarcel} 208