15819a8c0Schristos /*- 25819a8c0Schristos * Copyright (c) 2002 Marcel Moolenaar 35819a8c0Schristos * All rights reserved. 45819a8c0Schristos * 55819a8c0Schristos * Redistribution and use in source and binary forms, with or without 65819a8c0Schristos * modification, are permitted provided that the following conditions 75819a8c0Schristos * are met: 85819a8c0Schristos * 95819a8c0Schristos * 1. Redistributions of source code must retain the above copyright 105819a8c0Schristos * notice, this list of conditions and the following disclaimer. 115819a8c0Schristos * 2. Redistributions in binary form must reproduce the above copyright 125819a8c0Schristos * notice, this list of conditions and the following disclaimer in the 135819a8c0Schristos * documentation and/or other materials provided with the distribution. 145819a8c0Schristos * 155819a8c0Schristos * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 165819a8c0Schristos * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 175819a8c0Schristos * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 185819a8c0Schristos * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 195819a8c0Schristos * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 205819a8c0Schristos * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 215819a8c0Schristos * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 225819a8c0Schristos * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 235819a8c0Schristos * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 245819a8c0Schristos * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 255819a8c0Schristos */ 265819a8c0Schristos 27a50708a1Schristos #if HAVE_NBTOOL_CONFIG_H 28a50708a1Schristos #include "nbtool_config.h" 29a50708a1Schristos #endif 30a50708a1Schristos 315819a8c0Schristos #include <sys/cdefs.h> 329b522365Schristos #ifdef __FBSDID 339b522365Schristos __FBSDID("$FreeBSD: src/sbin/gpt/add.c,v 1.14 2006/06/22 22:05:28 marcel Exp $"); 349b522365Schristos #endif 359b522365Schristos #ifdef __RCSID 36*808dcc6fSkre __RCSID("$NetBSD: add.c,v 1.45 2024/11/02 12:46:49 kre Exp $"); 379b522365Schristos #endif 385819a8c0Schristos 395819a8c0Schristos #include <sys/types.h> 400b43d398Schristos #include <sys/param.h> 410b43d398Schristos #include <sys/stat.h> 425819a8c0Schristos 435819a8c0Schristos #include <err.h> 445819a8c0Schristos #include <stddef.h> 455819a8c0Schristos #include <stdio.h> 465819a8c0Schristos #include <stdlib.h> 475819a8c0Schristos #include <string.h> 485819a8c0Schristos #include <unistd.h> 495819a8c0Schristos 505819a8c0Schristos #include "map.h" 515819a8c0Schristos #include "gpt.h" 520b43d398Schristos #include "gpt_private.h" 535819a8c0Schristos 548ca93e46Schristos static int cmd_add(gpt_t, int, char *[]); 555819a8c0Schristos 568ca93e46Schristos static const char *addhelp[] = { 578ca93e46Schristos "[-a alignment] [-b blocknr] [-i index] [-l label]", 588ca93e46Schristos "[-s size] [-t type]", 598ca93e46Schristos }; 600fac2edbSriz 618ca93e46Schristos struct gpt_cmd c_add = { 628ca93e46Schristos "add", 638ca93e46Schristos cmd_add, 648ca93e46Schristos addhelp, __arraycount(addhelp), 65aa3b5bb2Sjnemeth GPT_SYNC, 668ca93e46Schristos }; 675819a8c0Schristos 688ca93e46Schristos #define usage() gpt_usage(NULL, &c_add) 695819a8c0Schristos 70b7322311Schristos static void 71b7322311Schristos ent_set(struct gpt_ent *ent, const map_t map, const gpt_uuid_t xtype, 72b7322311Schristos const uint8_t *xname) 73b7322311Schristos { 74b7322311Schristos gpt_uuid_copy(ent->ent_type, xtype); 755c1ccc6eSchristos ent->ent_lba_start = htole64((uint64_t)map->map_start); 765c1ccc6eSchristos ent->ent_lba_end = htole64((uint64_t)(map->map_start + 775c1ccc6eSchristos map->map_size - 1LL)); 78cdf86847Schristos if (xname == NULL) 79cdf86847Schristos return; 80cdf86847Schristos utf8_to_utf16(xname, ent->ent_name, __arraycount(ent->ent_name)); 81b7322311Schristos } 82b7322311Schristos 830b43d398Schristos static int 84da0a3b4cSchristos add(gpt_t gpt, off_t alignment, off_t block, off_t sectors, off_t size, 85da0a3b4cSchristos u_int entry, uint8_t *name, gpt_uuid_t type) 865819a8c0Schristos { 870b43d398Schristos map_t map; 885819a8c0Schristos struct gpt_hdr *hdr; 89b7322311Schristos struct gpt_ent *ent; 905819a8c0Schristos unsigned int i; 91650728b4Sjnemeth off_t alignsecs; 92bbb4a8abSchristos char buf[128]; 93650728b4Sjnemeth 940b43d398Schristos if ((hdr = gpt_hdr(gpt)) == NULL) 950b43d398Schristos return -1; 965819a8c0Schristos 97565d8259She ent = NULL; 985819a8c0Schristos 995819a8c0Schristos if (entry > le32toh(hdr->hdr_entries)) { 1000b43d398Schristos gpt_warnx(gpt, "index %u out of range (%u max)", 1015819a8c0Schristos entry, le32toh(hdr->hdr_entries)); 1020b43d398Schristos return -1; 1035819a8c0Schristos } 1045819a8c0Schristos 1055819a8c0Schristos if (entry > 0) { 1065819a8c0Schristos i = entry - 1; 1070b43d398Schristos ent = gpt_ent_primary(gpt, i); 10821c34dbbSchristos if (!gpt_uuid_is_nil(ent->ent_type)) { 1090b43d398Schristos gpt_warnx(gpt, "Entry at index %u is not free", entry); 1100b43d398Schristos return -1; 1115819a8c0Schristos } 1125819a8c0Schristos } else { 1135819a8c0Schristos /* Find empty slot in GPT table. */ 1145819a8c0Schristos for (i = 0; i < le32toh(hdr->hdr_entries); i++) { 1150b43d398Schristos ent = gpt_ent_primary(gpt, i); 11621c34dbbSchristos if (gpt_uuid_is_nil(ent->ent_type)) 1175819a8c0Schristos break; 1185819a8c0Schristos } 1195819a8c0Schristos if (i == le32toh(hdr->hdr_entries)) { 1200b43d398Schristos gpt_warnx(gpt, "No available table entries"); 1210b43d398Schristos return -1; 1225819a8c0Schristos } 1235819a8c0Schristos } 1245819a8c0Schristos 125*808dcc6fSkre if (gpt_uuid_is_nil(ent->ent_guid)) 126*808dcc6fSkre if (gpt_uuid_generate(gpt, ent->ent_guid) == -1) { 127*808dcc6fSkre gpt_warnx(gpt, "Unable to make UUID"); 128*808dcc6fSkre return -1; 129*808dcc6fSkre } 130*808dcc6fSkre 131650728b4Sjnemeth if (alignment > 0) { 1320b43d398Schristos alignsecs = alignment / gpt->secsz; 1330b43d398Schristos map = map_alloc(gpt, block, sectors, alignsecs); 134650728b4Sjnemeth if (map == NULL) { 1350b43d398Schristos gpt_warnx(gpt, "Not enough space available on " 1360b43d398Schristos "device for an aligned partition"); 1370b43d398Schristos return -1; 138650728b4Sjnemeth } 139650728b4Sjnemeth } else { 1400b43d398Schristos map = map_alloc(gpt, block, sectors, 0); 1415819a8c0Schristos if (map == NULL) { 1420b43d398Schristos gpt_warnx(gpt, "Not enough space available on device"); 1430b43d398Schristos return -1; 1445819a8c0Schristos } 145650728b4Sjnemeth } 1465819a8c0Schristos 147b7322311Schristos ent_set(ent, map, type, name); 148d293a8ecSchristos if (gpt_write_primary(gpt) == -1) 149d293a8ecSchristos return -1; 1505819a8c0Schristos 1510b43d398Schristos ent = gpt_ent_backup(gpt, i); 152b7322311Schristos ent_set(ent, map, type, name); 153d293a8ecSchristos if (gpt_write_backup(gpt) == -1) 154d293a8ecSchristos return -1; 1555819a8c0Schristos 156bbb4a8abSchristos gpt_uuid_snprintf(buf, sizeof(buf), "%d", type); 157bbb4a8abSchristos gpt_msg(gpt, "Partition %d added: %s %" PRIu64 " %" PRIu64, i + 1, 158bbb4a8abSchristos buf, map->map_start, map->map_size); 1590b43d398Schristos return 0; 1605819a8c0Schristos } 1615819a8c0Schristos 1628ca93e46Schristos static int 1630b43d398Schristos cmd_add(gpt_t gpt, int argc, char *argv[]) 1645819a8c0Schristos { 1650b43d398Schristos int ch; 166da0a3b4cSchristos off_t alignment = 0, block = 0, sectors = 0, size = 0; 167da0a3b4cSchristos unsigned int entry = 0; 168da0a3b4cSchristos uint8_t *name = NULL; 169da0a3b4cSchristos gpt_uuid_t type; 170da0a3b4cSchristos 171da0a3b4cSchristos gpt_uuid_copy(type, gpt_uuid_nil); 1725819a8c0Schristos 173de2c104cSjnemeth while ((ch = getopt(argc, argv, GPT_AIS "b:l:t:")) != -1) { 1745819a8c0Schristos switch(ch) { 1755819a8c0Schristos case 'b': 176f9db7548Schristos if (gpt_human_get(gpt, &block) == -1) 177560e3b65Schristos goto usage; 1785819a8c0Schristos break; 179650728b4Sjnemeth case 'l': 1800f004afeSchristos if (gpt_name_get(gpt, &name) == -1) 181560e3b65Schristos goto usage; 182650728b4Sjnemeth break; 1835819a8c0Schristos case 't': 1840f004afeSchristos if (gpt_uuid_get(gpt, &type) == -1) 185560e3b65Schristos goto usage; 1865819a8c0Schristos break; 1875819a8c0Schristos default: 188bbb4a8abSchristos if (gpt_add_ais(gpt, &alignment, &entry, &size, ch) 189bbb4a8abSchristos == -1) 190560e3b65Schristos goto usage; 191bbb4a8abSchristos break; 1925819a8c0Schristos } 1935819a8c0Schristos } 1945819a8c0Schristos 195bbb4a8abSchristos if (argc != optind) 1968ca93e46Schristos return usage(); 1975819a8c0Schristos 1985da707b8Sjakllsch /* Create NetBSD FFS partitions by default. */ 1990f004afeSchristos if (gpt_uuid_is_nil(type)) 20021c34dbbSchristos gpt_uuid_create(GPT_TYPE_NETBSD_FFS, type, NULL, 0); 2015819a8c0Schristos 2020b43d398Schristos if (optind != argc) 203560e3b65Schristos goto cleanup; 2045819a8c0Schristos 2055c1ccc6eSchristos if ((sectors = gpt_check_ais(gpt, alignment, ~0U, size)) == -1) 206560e3b65Schristos goto cleanup; 207650728b4Sjnemeth 208da0a3b4cSchristos return add(gpt, alignment, block, sectors, size, entry, name, type); 209e37a2a95Schristos usage: 210e37a2a95Schristos return usage(); 211560e3b65Schristos cleanup: 212560e3b65Schristos free(name); 213560e3b65Schristos return -1; 2145819a8c0Schristos } 215