1 1.1 christos /*- 2 1.1 christos * Copyright (c) 2002 Marcel Moolenaar 3 1.1 christos * All rights reserved. 4 1.1 christos * 5 1.1 christos * Redistribution and use in source and binary forms, with or without 6 1.1 christos * modification, are permitted provided that the following conditions 7 1.1 christos * are met: 8 1.1 christos * 9 1.1 christos * 1. Redistributions of source code must retain the above copyright 10 1.1 christos * notice, this list of conditions and the following disclaimer. 11 1.1 christos * 2. Redistributions in binary form must reproduce the above copyright 12 1.1 christos * notice, this list of conditions and the following disclaimer in the 13 1.1 christos * documentation and/or other materials provided with the distribution. 14 1.1 christos * 15 1.1 christos * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 1.1 christos * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 1.1 christos * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 1.1 christos * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 1.1 christos * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 1.1 christos * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 1.1 christos * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 1.1 christos * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 1.1 christos * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 1.1 christos * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 1.1 christos */ 26 1.1 christos 27 1.25 christos #if HAVE_NBTOOL_CONFIG_H 28 1.25 christos #include "nbtool_config.h" 29 1.25 christos #endif 30 1.25 christos 31 1.1 christos #include <sys/cdefs.h> 32 1.2 christos #ifdef __FBSDID 33 1.2 christos __FBSDID("$FreeBSD: src/sbin/gpt/add.c,v 1.14 2006/06/22 22:05:28 marcel Exp $"); 34 1.2 christos #endif 35 1.2 christos #ifdef __RCSID 36 1.46 christos __RCSID("$NetBSD: add.c,v 1.46 2025/02/23 20:47:19 christos Exp $"); 37 1.2 christos #endif 38 1.1 christos 39 1.1 christos #include <sys/types.h> 40 1.31 christos #include <sys/param.h> 41 1.31 christos #include <sys/stat.h> 42 1.1 christos 43 1.1 christos #include <err.h> 44 1.1 christos #include <stddef.h> 45 1.1 christos #include <stdio.h> 46 1.1 christos #include <stdlib.h> 47 1.1 christos #include <string.h> 48 1.1 christos #include <unistd.h> 49 1.1 christos 50 1.1 christos #include "map.h" 51 1.1 christos #include "gpt.h" 52 1.31 christos #include "gpt_private.h" 53 1.1 christos 54 1.32 christos static int cmd_add(gpt_t, int, char *[]); 55 1.1 christos 56 1.32 christos static const char *addhelp[] = { 57 1.38 christos "[-a alignment] [-b blocknr] [-i index] [-l label]", 58 1.38 christos "[-s size] [-t type]", 59 1.32 christos }; 60 1.32 christos 61 1.46 christos const struct gpt_cmd c_add = { 62 1.32 christos "add", 63 1.32 christos cmd_add, 64 1.32 christos addhelp, __arraycount(addhelp), 65 1.44 jnemeth GPT_SYNC, 66 1.32 christos }; 67 1.5 riz 68 1.32 christos #define usage() gpt_usage(NULL, &c_add) 69 1.1 christos 70 1.35 christos static void 71 1.35 christos ent_set(struct gpt_ent *ent, const map_t map, const gpt_uuid_t xtype, 72 1.35 christos const uint8_t *xname) 73 1.35 christos { 74 1.35 christos gpt_uuid_copy(ent->ent_type, xtype); 75 1.39 christos ent->ent_lba_start = htole64((uint64_t)map->map_start); 76 1.39 christos ent->ent_lba_end = htole64((uint64_t)(map->map_start + 77 1.39 christos map->map_size - 1LL)); 78 1.36 christos if (xname == NULL) 79 1.36 christos return; 80 1.36 christos utf8_to_utf16(xname, ent->ent_name, __arraycount(ent->ent_name)); 81 1.35 christos } 82 1.35 christos 83 1.31 christos static int 84 1.46 christos add(gpt_t gpt, off_t alignment, off_t block, off_t sectors, off_t size __unused, 85 1.38 christos u_int entry, uint8_t *name, gpt_uuid_t type) 86 1.1 christos { 87 1.31 christos map_t map; 88 1.1 christos struct gpt_hdr *hdr; 89 1.35 christos struct gpt_ent *ent; 90 1.1 christos unsigned int i; 91 1.15 jnemeth off_t alignsecs; 92 1.33 christos char buf[128]; 93 1.15 jnemeth 94 1.31 christos if ((hdr = gpt_hdr(gpt)) == NULL) 95 1.31 christos return -1; 96 1.1 christos 97 1.3 he ent = NULL; 98 1.1 christos 99 1.1 christos if (entry > le32toh(hdr->hdr_entries)) { 100 1.31 christos gpt_warnx(gpt, "index %u out of range (%u max)", 101 1.1 christos entry, le32toh(hdr->hdr_entries)); 102 1.31 christos return -1; 103 1.1 christos } 104 1.1 christos 105 1.1 christos if (entry > 0) { 106 1.1 christos i = entry - 1; 107 1.31 christos ent = gpt_ent_primary(gpt, i); 108 1.27 christos if (!gpt_uuid_is_nil(ent->ent_type)) { 109 1.31 christos gpt_warnx(gpt, "Entry at index %u is not free", entry); 110 1.31 christos return -1; 111 1.1 christos } 112 1.1 christos } else { 113 1.1 christos /* Find empty slot in GPT table. */ 114 1.1 christos for (i = 0; i < le32toh(hdr->hdr_entries); i++) { 115 1.31 christos ent = gpt_ent_primary(gpt, i); 116 1.27 christos if (gpt_uuid_is_nil(ent->ent_type)) 117 1.1 christos break; 118 1.1 christos } 119 1.1 christos if (i == le32toh(hdr->hdr_entries)) { 120 1.31 christos gpt_warnx(gpt, "No available table entries"); 121 1.31 christos return -1; 122 1.1 christos } 123 1.1 christos } 124 1.1 christos 125 1.45 kre if (gpt_uuid_is_nil(ent->ent_guid)) 126 1.45 kre if (gpt_uuid_generate(gpt, ent->ent_guid) == -1) { 127 1.45 kre gpt_warnx(gpt, "Unable to make UUID"); 128 1.45 kre return -1; 129 1.45 kre } 130 1.45 kre 131 1.15 jnemeth if (alignment > 0) { 132 1.31 christos alignsecs = alignment / gpt->secsz; 133 1.31 christos map = map_alloc(gpt, block, sectors, alignsecs); 134 1.15 jnemeth if (map == NULL) { 135 1.31 christos gpt_warnx(gpt, "Not enough space available on " 136 1.31 christos "device for an aligned partition"); 137 1.31 christos return -1; 138 1.15 jnemeth } 139 1.15 jnemeth } else { 140 1.31 christos map = map_alloc(gpt, block, sectors, 0); 141 1.15 jnemeth if (map == NULL) { 142 1.31 christos gpt_warnx(gpt, "Not enough space available on device"); 143 1.31 christos return -1; 144 1.15 jnemeth } 145 1.1 christos } 146 1.1 christos 147 1.35 christos ent_set(ent, map, type, name); 148 1.40 christos if (gpt_write_primary(gpt) == -1) 149 1.40 christos return -1; 150 1.1 christos 151 1.31 christos ent = gpt_ent_backup(gpt, i); 152 1.35 christos ent_set(ent, map, type, name); 153 1.40 christos if (gpt_write_backup(gpt) == -1) 154 1.40 christos return -1; 155 1.1 christos 156 1.33 christos gpt_uuid_snprintf(buf, sizeof(buf), "%d", type); 157 1.33 christos gpt_msg(gpt, "Partition %d added: %s %" PRIu64 " %" PRIu64, i + 1, 158 1.33 christos buf, map->map_start, map->map_size); 159 1.31 christos return 0; 160 1.1 christos } 161 1.1 christos 162 1.32 christos static int 163 1.31 christos cmd_add(gpt_t gpt, int argc, char *argv[]) 164 1.1 christos { 165 1.31 christos int ch; 166 1.38 christos off_t alignment = 0, block = 0, sectors = 0, size = 0; 167 1.38 christos unsigned int entry = 0; 168 1.38 christos uint8_t *name = NULL; 169 1.38 christos gpt_uuid_t type; 170 1.38 christos 171 1.38 christos gpt_uuid_copy(type, gpt_uuid_nil); 172 1.1 christos 173 1.37 jnemeth while ((ch = getopt(argc, argv, GPT_AIS "b:l:t:")) != -1) { 174 1.1 christos switch(ch) { 175 1.1 christos case 'b': 176 1.43 christos if (gpt_human_get(gpt, &block) == -1) 177 1.41 christos goto usage; 178 1.1 christos break; 179 1.15 jnemeth case 'l': 180 1.34 christos if (gpt_name_get(gpt, &name) == -1) 181 1.41 christos goto usage; 182 1.15 jnemeth break; 183 1.1 christos case 't': 184 1.34 christos if (gpt_uuid_get(gpt, &type) == -1) 185 1.41 christos goto usage; 186 1.1 christos break; 187 1.46 christos case 'a': 188 1.46 christos case 's': 189 1.46 christos case 'i': 190 1.33 christos if (gpt_add_ais(gpt, &alignment, &entry, &size, ch) 191 1.33 christos == -1) 192 1.41 christos goto usage; 193 1.33 christos break; 194 1.46 christos default: 195 1.46 christos goto usage; 196 1.1 christos } 197 1.1 christos } 198 1.1 christos 199 1.33 christos if (argc != optind) 200 1.32 christos return usage(); 201 1.1 christos 202 1.9 jakllsch /* Create NetBSD FFS partitions by default. */ 203 1.34 christos if (gpt_uuid_is_nil(type)) 204 1.27 christos gpt_uuid_create(GPT_TYPE_NETBSD_FFS, type, NULL, 0); 205 1.1 christos 206 1.31 christos if (optind != argc) 207 1.41 christos goto cleanup; 208 1.1 christos 209 1.39 christos if ((sectors = gpt_check_ais(gpt, alignment, ~0U, size)) == -1) 210 1.41 christos goto cleanup; 211 1.1 christos 212 1.38 christos return add(gpt, alignment, block, sectors, size, entry, name, type); 213 1.42 christos usage: 214 1.42 christos return usage(); 215 1.41 christos cleanup: 216 1.41 christos free(name); 217 1.41 christos return -1; 218 1.1 christos } 219