xref: /netbsd-src/sbin/gpt/add.c (revision 808dcc6ff47b701a9f47fad30f4fa823494300ca)
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