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 * $FreeBSD: src/sbin/gpt/create.c,v 1.11 2005/08/31 01:47:19 marcel Exp $ 27 * $DragonFly: src/sbin/gpt/create.c,v 1.1 2007/06/16 22:29:27 dillon Exp $ 28 */ 29 30 #include <sys/types.h> 31 32 #include <err.h> 33 #include <stddef.h> 34 #include <stdio.h> 35 #include <stdlib.h> 36 #include <string.h> 37 #include <unistd.h> 38 39 #include "map.h" 40 #include "gpt.h" 41 42 static int force; 43 static int primary_only; 44 45 static void 46 usage_create(void) 47 { 48 49 fprintf(stderr, 50 "usage: %s [-fp] device ...\n", getprogname()); 51 exit(1); 52 } 53 54 static void 55 create(int fd) 56 { 57 uuid_t uuid; 58 off_t blocks, last; 59 map_t *gpt, *tpg; 60 map_t *tbl, *lbt; 61 map_t *map; 62 struct mbr *mbr; 63 struct gpt_hdr *hdr; 64 struct gpt_ent *ent; 65 unsigned int i; 66 67 last = mediasz / secsz - 1LL; 68 69 if (map_find(MAP_TYPE_PRI_GPT_HDR) != NULL || 70 map_find(MAP_TYPE_SEC_GPT_HDR) != NULL) { 71 warnx("%s: error: device already contains a GPT", device_name); 72 return; 73 } 74 map = map_find(MAP_TYPE_MBR); 75 if (map != NULL) { 76 if (!force) { 77 warnx("%s: error: device contains a MBR", device_name); 78 return; 79 } 80 81 /* Nuke the MBR in our internal map. */ 82 map->map_type = MAP_TYPE_UNUSED; 83 } 84 85 /* 86 * Create PMBR. 87 */ 88 if (map_find(MAP_TYPE_PMBR) == NULL) { 89 if (map_free(0LL, 1LL) == 0) { 90 warnx("%s: error: no room for the PMBR", device_name); 91 return; 92 } 93 mbr = gpt_read(fd, 0LL, 1); 94 bzero(mbr, sizeof(*mbr)); 95 mbr->mbr_sig = htole16(MBR_SIG); 96 mbr->mbr_part[0].part_shd = 0xff; 97 mbr->mbr_part[0].part_ssect = 0xff; 98 mbr->mbr_part[0].part_scyl = 0xff; 99 mbr->mbr_part[0].part_typ = 0xee; 100 mbr->mbr_part[0].part_ehd = 0xff; 101 mbr->mbr_part[0].part_esect = 0xff; 102 mbr->mbr_part[0].part_ecyl = 0xff; 103 mbr->mbr_part[0].part_start_lo = htole16(1); 104 if (last > 0xffffffff) { 105 mbr->mbr_part[0].part_size_lo = htole16(0xffff); 106 mbr->mbr_part[0].part_size_hi = htole16(0xffff); 107 } else { 108 mbr->mbr_part[0].part_size_lo = htole16(last); 109 mbr->mbr_part[0].part_size_hi = htole16(last >> 16); 110 } 111 map = map_add(0LL, 1LL, MAP_TYPE_PMBR, mbr); 112 gpt_write(fd, map); 113 } 114 115 /* Get the amount of free space after the MBR */ 116 blocks = map_free(1LL, 0LL); 117 if (blocks == 0LL) { 118 warnx("%s: error: no room for the GPT header", device_name); 119 return; 120 } 121 122 /* Don't create more than parts entries. */ 123 if ((uint64_t)(blocks - 1) * secsz > parts * sizeof(struct gpt_ent)) { 124 blocks = (parts * sizeof(struct gpt_ent)) / secsz; 125 if ((parts * sizeof(struct gpt_ent)) % secsz) 126 blocks++; 127 blocks++; /* Don't forget the header itself */ 128 } 129 130 /* Never cross the median of the device. */ 131 if ((blocks + 1LL) > ((last + 1LL) >> 1)) 132 blocks = ((last + 1LL) >> 1) - 1LL; 133 134 /* 135 * Get the amount of free space at the end of the device and 136 * calculate the size for the GPT structures. 137 */ 138 map = map_last(); 139 if (map->map_type != MAP_TYPE_UNUSED) { 140 warnx("%s: error: no room for the backup header", device_name); 141 return; 142 } 143 144 if (map->map_size < blocks) 145 blocks = map->map_size; 146 if (blocks == 1LL) { 147 warnx("%s: error: no room for the GPT table", device_name); 148 return; 149 } 150 151 blocks--; /* Number of blocks in the GPT table. */ 152 gpt = map_add(1LL, 1LL, MAP_TYPE_PRI_GPT_HDR, calloc(1, secsz)); 153 tbl = map_add(2LL, blocks, MAP_TYPE_PRI_GPT_TBL, 154 calloc(blocks, secsz)); 155 if (gpt == NULL || tbl == NULL) 156 return; 157 158 hdr = gpt->map_data; 159 memcpy(hdr->hdr_sig, GPT_HDR_SIG, sizeof(hdr->hdr_sig)); 160 hdr->hdr_revision = htole32(GPT_HDR_REVISION); 161 /* 162 * XXX struct gpt_hdr is not a multiple of 8 bytes in size and thus 163 * contains padding we must not include in the size. 164 */ 165 hdr->hdr_size = htole32(offsetof(struct gpt_hdr, padding)); 166 hdr->hdr_lba_self = htole64(gpt->map_start); 167 hdr->hdr_lba_alt = htole64(last); 168 hdr->hdr_lba_start = htole64(tbl->map_start + blocks); 169 hdr->hdr_lba_end = htole64(last - blocks - 1LL); 170 uuid_create(&uuid, NULL); 171 le_uuid_enc(&hdr->hdr_uuid, &uuid); 172 hdr->hdr_lba_table = htole64(tbl->map_start); 173 hdr->hdr_entries = htole32((blocks * secsz) / sizeof(struct gpt_ent)); 174 if (le32toh(hdr->hdr_entries) > parts) 175 hdr->hdr_entries = htole32(parts); 176 hdr->hdr_entsz = htole32(sizeof(struct gpt_ent)); 177 178 ent = tbl->map_data; 179 for (i = 0; i < le32toh(hdr->hdr_entries); i++) { 180 uuid_create(&uuid, NULL); 181 le_uuid_enc(&ent[i].ent_uuid, &uuid); 182 } 183 184 hdr->hdr_crc_table = htole32(crc32(ent, le32toh(hdr->hdr_entries) * 185 le32toh(hdr->hdr_entsz))); 186 hdr->hdr_crc_self = htole32(crc32(hdr, le32toh(hdr->hdr_size))); 187 188 gpt_write(fd, gpt); 189 gpt_write(fd, tbl); 190 191 /* 192 * Create backup GPT if the user didn't suppress it. 193 */ 194 if (!primary_only) { 195 tpg = map_add(last, 1LL, MAP_TYPE_SEC_GPT_HDR, 196 calloc(1, secsz)); 197 lbt = map_add(last - blocks, blocks, MAP_TYPE_SEC_GPT_TBL, 198 tbl->map_data); 199 memcpy(tpg->map_data, gpt->map_data, secsz); 200 hdr = tpg->map_data; 201 hdr->hdr_lba_self = htole64(tpg->map_start); 202 hdr->hdr_lba_alt = htole64(gpt->map_start); 203 hdr->hdr_lba_table = htole64(lbt->map_start); 204 hdr->hdr_crc_self = 0; /* Don't ever forget this! */ 205 hdr->hdr_crc_self = htole32(crc32(hdr, le32toh(hdr->hdr_size))); 206 gpt_write(fd, lbt); 207 gpt_write(fd, tpg); 208 } 209 } 210 211 int 212 cmd_create(int argc, char *argv[]) 213 { 214 int ch, fd; 215 216 while ((ch = getopt(argc, argv, "fp")) != -1) { 217 switch(ch) { 218 case 'f': 219 force = 1; 220 break; 221 case 'p': 222 primary_only = 1; 223 break; 224 default: 225 usage_create(); 226 } 227 } 228 229 if (argc == optind) 230 usage_create(); 231 232 while (optind < argc) { 233 fd = gpt_open(argv[optind++]); 234 if (fd == -1) { 235 warn("unable to open device '%s'", device_name); 236 continue; 237 } 238 239 create(fd); 240 241 gpt_close(fd); 242 } 243 244 return (0); 245 } 246