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#include <sys/cdefs.h> 28__FBSDID("$FreeBSD: src/sbin/gpt/add.c,v 1.15.2.1.6.1 2010/02/10 00:26:20 kensmith Exp $"); 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 42static uuid_t add_type; 43static off_t add_block, add_size; 44static unsigned int add_entry; 45 46static void 47usage_add(void) 48{ 49 50 fprintf(stderr, 51 "usage: %s [-b lba] [-i index] [-s lba] [-t uuid] device ...\n", 52 getprogname()); 53 exit(1); 54} 55 56map_t * 57gpt_add_part(int fd, uuid_t *type, off_t start, off_t size, unsigned int *entry) 58{ 59 uuid_t uuid; 60 map_t *gpt, *tpg; 61 map_t *tbl, *lbt; 62 map_t *map; 63 struct gpt_hdr *hdr; 64 struct gpt_ent *ent; 65 unsigned int i; 66 67 gpt = map_find(MAP_TYPE_PRI_GPT_HDR); 68 ent = NULL; 69 if (gpt == NULL) { 70 warnx("%s: error: no primary GPT header; run create or recover", 71 device_name); 72 return (NULL); 73 } 74 75 tpg = map_find(MAP_TYPE_SEC_GPT_HDR); 76 if (tpg == NULL) { 77 warnx("%s: error: no secondary GPT header; run recover", 78 device_name); 79 return (NULL); 80 } 81 82 tbl = map_find(MAP_TYPE_PRI_GPT_TBL); 83 lbt = map_find(MAP_TYPE_SEC_GPT_TBL); 84 if (tbl == NULL || lbt == NULL) { 85 warnx("%s: error: run recover -- trust me", device_name); 86 return (NULL); 87 } 88 89 hdr = gpt->map_data; 90 if (*entry > le32toh(hdr->hdr_entries)) { 91 warnx("%s: error: index %u out of range (%u max)", device_name, 92 *entry, le32toh(hdr->hdr_entries)); 93 return (NULL); 94 } 95 96 if (*entry > 0) { 97 i = *entry - 1; 98 ent = (void*)((char*)tbl->map_data + i * 99 le32toh(hdr->hdr_entsz)); 100 if (!uuid_is_nil(&ent->ent_type, NULL)) { 101 warnx("%s: error: entry at index %u is not free", 102 device_name, *entry); 103 return (NULL); 104 } 105 } else { 106 /* Find empty slot in GPT table. */ 107 for (i = 0; i < le32toh(hdr->hdr_entries); i++) { 108 ent = (void*)((char*)tbl->map_data + i * 109 le32toh(hdr->hdr_entsz)); 110 if (uuid_is_nil(&ent->ent_type, NULL)) 111 break; 112 } 113 if (i == le32toh(hdr->hdr_entries)) { 114 warnx("%s: error: no available table entries", 115 device_name); 116 return (NULL); 117 } 118 } 119 120 map = map_alloc(start, size); 121 if (map == NULL) { 122 warnx("%s: error: no space available on device", device_name); 123 return (NULL); 124 } 125 126 le_uuid_dec(&ent->ent_uuid, &uuid); 127 if (uuid_is_nil(&uuid, NULL)) { 128 uuid_create(&uuid, NULL); 129 } 130 131 le_uuid_enc(&ent->ent_type, type); 132 le_uuid_enc(&ent->ent_uuid, &uuid); 133 ent->ent_lba_start = htole64(map->map_start); 134 ent->ent_lba_end = htole64(map->map_start + map->map_size - 1LL); 135 136 hdr->hdr_crc_table = htole32(crc32(tbl->map_data, 137 le32toh(hdr->hdr_entries) * le32toh(hdr->hdr_entsz))); 138 hdr->hdr_crc_self = 0; 139 hdr->hdr_crc_self = htole32(crc32(hdr, le32toh(hdr->hdr_size))); 140 141 gpt_write(fd, gpt); 142 gpt_write(fd, tbl); 143 144 hdr = tpg->map_data; 145 ent = (void*)((char*)lbt->map_data + i * le32toh(hdr->hdr_entsz)); 146 147 le_uuid_enc(&ent->ent_type, type); 148 le_uuid_enc(&ent->ent_uuid, &uuid); 149 ent->ent_lba_start = htole64(map->map_start); 150 ent->ent_lba_end = htole64(map->map_start + map->map_size - 1LL); 151 152 hdr->hdr_crc_table = htole32(crc32(lbt->map_data, 153 le32toh(hdr->hdr_entries) * le32toh(hdr->hdr_entsz))); 154 hdr->hdr_crc_self = 0; 155 hdr->hdr_crc_self = htole32(crc32(hdr, le32toh(hdr->hdr_size))); 156 157 gpt_write(fd, lbt); 158 gpt_write(fd, tpg); 159 160 *entry = i + 1; 161 162 return (map); 163} 164 165static void 166add(int fd) 167{ 168 169 if (!gpt_add_part(fd, &add_type, add_block, add_size, &add_entry)) 170 return; 171 172#ifdef __APPLE__ 173 printf("%ss%u added\n", device_name, add_entry); 174#else 175 printf("%sp%u added\n", device_name, add_entry); 176#endif 177} 178 179int 180cmd_add(int argc, char *argv[]) 181{ 182 char *p; 183 int ch, fd; 184 185 /* Get the migrate options */ 186 while ((ch = getopt(argc, argv, "b:i:s:t:")) != -1) { 187 switch(ch) { 188 case 'b': 189 if (add_block > 0) 190 usage_add(); 191 add_block = strtoll(optarg, &p, 10); 192 if (*p != 0 || add_block < 1) 193 usage_add(); 194 break; 195 case 'i': 196 if (add_entry > 0) 197 usage_add(); 198 add_entry = strtol(optarg, &p, 10); 199 if (*p != 0 || add_entry < 1) 200 usage_add(); 201 break; 202 case 's': 203 if (add_size > 0) 204 usage_add(); 205 add_size = strtoll(optarg, &p, 10); 206 if (*p != 0 || add_size < 1) 207 usage_add(); 208 break; 209 case 't': 210 if (!uuid_is_nil(&add_type, NULL)) 211 usage_add(); 212 if (parse_uuid(optarg, &add_type) != 0) 213 usage_add(); 214 break; 215 default: 216 usage_add(); 217 } 218 } 219 220 if (argc == optind) 221 usage_add(); 222 223#ifdef __APPLE__ 224 /* Create HFS partitions by default. */ 225 if (uuid_is_null(add_type)) 226 uuid_copy(add_type, GPT_ENT_TYPE_APPLE_HFS); 227#else 228 /* Create UFS partitions by default. */ 229 if (uuid_is_nil(&add_type, NULL)) { 230 uuid_t ufs = GPT_ENT_TYPE_FREEBSD_UFS; 231 add_type = ufs; 232 } 233#endif 234 235 while (optind < argc) { 236 fd = gpt_open(argv[optind++]); 237 if (fd == -1) { 238 warn("unable to open device '%s'", device_name); 239 return (1); 240 } 241 242 add(fd); 243 244 gpt_close(fd); 245 } 246 247 return (0); 248} 249