1 /*- 2 * Copyright (c) 2002 Marcel Moolenaar 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27 #if HAVE_NBTOOL_CONFIG_H 28 #include "nbtool_config.h" 29 #endif 30 31 #include <sys/cdefs.h> 32 #ifdef __FBSDID 33 __FBSDID("$FreeBSD: src/sbin/gpt/create.c,v 1.11 2005/08/31 01:47:19 marcel Exp $"); 34 #endif 35 #ifdef __RCSID 36 __RCSID("$NetBSD: create.c,v 1.12 2014/10/03 20:30:06 christos Exp $"); 37 #endif 38 39 #include <sys/types.h> 40 #include <sys/bootblock.h> 41 42 #include <err.h> 43 #include <stddef.h> 44 #include <stdio.h> 45 #include <stdlib.h> 46 #include <string.h> 47 #include <unistd.h> 48 49 #include "map.h" 50 #include "gpt.h" 51 52 static int force; 53 static int primary_only; 54 55 const char createmsg[] = "create [-fp] device ..."; 56 57 __dead static void 58 usage_create(void) 59 { 60 61 fprintf(stderr, 62 "usage: %s %s\n", getprogname(), createmsg); 63 exit(1); 64 } 65 66 static void 67 create(int fd) 68 { 69 off_t blocks, last; 70 map_t *gpt, *tpg; 71 map_t *tbl, *lbt; 72 map_t *map; 73 struct mbr *mbr; 74 struct gpt_hdr *hdr; 75 struct gpt_ent *ent; 76 unsigned int i; 77 78 last = mediasz / secsz - 1LL; 79 80 if (map_find(MAP_TYPE_PRI_GPT_HDR) != NULL || 81 map_find(MAP_TYPE_SEC_GPT_HDR) != NULL) { 82 warnx("%s: error: device already contains a GPT", device_name); 83 return; 84 } 85 map = map_find(MAP_TYPE_MBR); 86 if (map != NULL) { 87 if (!force) { 88 warnx("%s: error: device contains a MBR", device_name); 89 return; 90 } 91 92 /* Nuke the MBR in our internal map. */ 93 map->map_type = MAP_TYPE_UNUSED; 94 } 95 96 /* 97 * Create PMBR. 98 */ 99 if (map_find(MAP_TYPE_PMBR) == NULL) { 100 if (map_free(0LL, 1LL) == 0) { 101 warnx("%s: error: no room for the PMBR", device_name); 102 return; 103 } 104 mbr = gpt_read(fd, 0LL, 1); 105 memset(mbr, 0, sizeof(*mbr)); 106 mbr->mbr_sig = htole16(MBR_SIG); 107 mbr->mbr_part[0].part_shd = 0x00; 108 mbr->mbr_part[0].part_ssect = 0x02; 109 mbr->mbr_part[0].part_scyl = 0x00; 110 mbr->mbr_part[0].part_typ = MBR_PTYPE_PMBR; 111 mbr->mbr_part[0].part_ehd = 0xfe; 112 mbr->mbr_part[0].part_esect = 0xff; 113 mbr->mbr_part[0].part_ecyl = 0xff; 114 mbr->mbr_part[0].part_start_lo = htole16(1); 115 if (last > 0xffffffff) { 116 mbr->mbr_part[0].part_size_lo = htole16(0xffff); 117 mbr->mbr_part[0].part_size_hi = htole16(0xffff); 118 } else { 119 mbr->mbr_part[0].part_size_lo = htole16(last); 120 mbr->mbr_part[0].part_size_hi = htole16(last >> 16); 121 } 122 map = map_add(0LL, 1LL, MAP_TYPE_PMBR, mbr); 123 gpt_write(fd, map); 124 } 125 126 /* Get the amount of free space after the MBR */ 127 blocks = map_free(1LL, 0LL); 128 if (blocks == 0LL) { 129 warnx("%s: error: no room for the GPT header", device_name); 130 return; 131 } 132 133 /* Don't create more than parts entries. */ 134 if ((uint64_t)(blocks - 1) * secsz > parts * sizeof(struct gpt_ent)) { 135 blocks = (parts * sizeof(struct gpt_ent)) / secsz; 136 if ((parts * sizeof(struct gpt_ent)) % secsz) 137 blocks++; 138 blocks++; /* Don't forget the header itself */ 139 } 140 141 /* Never cross the median of the device. */ 142 if ((blocks + 1LL) > ((last + 1LL) >> 1)) 143 blocks = ((last + 1LL) >> 1) - 1LL; 144 145 /* 146 * Get the amount of free space at the end of the device and 147 * calculate the size for the GPT structures. 148 */ 149 map = map_last(); 150 if (map->map_type != MAP_TYPE_UNUSED) { 151 warnx("%s: error: no room for the backup header", device_name); 152 return; 153 } 154 155 if (map->map_size < blocks) 156 blocks = map->map_size; 157 if (blocks == 1LL) { 158 warnx("%s: error: no room for the GPT table", device_name); 159 return; 160 } 161 162 blocks--; /* Number of blocks in the GPT table. */ 163 gpt = map_add(1LL, 1LL, MAP_TYPE_PRI_GPT_HDR, calloc(1, secsz)); 164 tbl = map_add(2LL, blocks, MAP_TYPE_PRI_GPT_TBL, 165 calloc(blocks, secsz)); 166 if (gpt == NULL || tbl == NULL) 167 return; 168 169 hdr = gpt->map_data; 170 memcpy(hdr->hdr_sig, GPT_HDR_SIG, sizeof(hdr->hdr_sig)); 171 hdr->hdr_revision = htole32(GPT_HDR_REVISION); 172 hdr->hdr_size = htole32(GPT_HDR_SIZE); 173 hdr->hdr_lba_self = htole64(gpt->map_start); 174 hdr->hdr_lba_alt = htole64(last); 175 hdr->hdr_lba_start = htole64(tbl->map_start + blocks); 176 hdr->hdr_lba_end = htole64(last - blocks - 1LL); 177 gpt_uuid_generate(hdr->hdr_guid); 178 hdr->hdr_lba_table = htole64(tbl->map_start); 179 hdr->hdr_entries = htole32((blocks * secsz) / sizeof(struct gpt_ent)); 180 if (le32toh(hdr->hdr_entries) > parts) 181 hdr->hdr_entries = htole32(parts); 182 hdr->hdr_entsz = htole32(sizeof(struct gpt_ent)); 183 184 ent = tbl->map_data; 185 for (i = 0; i < le32toh(hdr->hdr_entries); i++) { 186 gpt_uuid_generate(ent[i].ent_guid); 187 } 188 189 hdr->hdr_crc_table = htole32(crc32(ent, le32toh(hdr->hdr_entries) * 190 le32toh(hdr->hdr_entsz))); 191 hdr->hdr_crc_self = htole32(crc32(hdr, le32toh(hdr->hdr_size))); 192 193 gpt_write(fd, gpt); 194 gpt_write(fd, tbl); 195 196 /* 197 * Create backup GPT if the user didn't suppress it. 198 */ 199 if (!primary_only) { 200 tpg = map_add(last, 1LL, MAP_TYPE_SEC_GPT_HDR, 201 calloc(1, secsz)); 202 lbt = map_add(last - blocks, blocks, MAP_TYPE_SEC_GPT_TBL, 203 tbl->map_data); 204 memcpy(tpg->map_data, gpt->map_data, secsz); 205 hdr = tpg->map_data; 206 hdr->hdr_lba_self = htole64(tpg->map_start); 207 hdr->hdr_lba_alt = htole64(gpt->map_start); 208 hdr->hdr_lba_table = htole64(lbt->map_start); 209 hdr->hdr_crc_self = 0; /* Don't ever forget this! */ 210 hdr->hdr_crc_self = htole32(crc32(hdr, le32toh(hdr->hdr_size))); 211 gpt_write(fd, lbt); 212 gpt_write(fd, tpg); 213 } 214 } 215 216 int 217 cmd_create(int argc, char *argv[]) 218 { 219 int ch, fd; 220 221 while ((ch = getopt(argc, argv, "fp")) != -1) { 222 switch(ch) { 223 case 'f': 224 force = 1; 225 break; 226 case 'p': 227 primary_only = 1; 228 break; 229 default: 230 usage_create(); 231 } 232 } 233 234 if (argc == optind) 235 usage_create(); 236 237 while (optind < argc) { 238 fd = gpt_open(argv[optind++]); 239 if (fd == -1) { 240 warn("unable to open device '%s'", device_name); 241 continue; 242 } 243 244 create(fd); 245 246 gpt_close(fd); 247 } 248 249 return (0); 250 } 251