xref: /netbsd/sbin/gpt/add.c (revision b61b88fb)
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 
27f0e11cd4Schristos #if HAVE_NBTOOL_CONFIG_H
28f0e11cd4Schristos #include "nbtool_config.h"
29f0e11cd4Schristos #endif
30f0e11cd4Schristos 
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*b61b88fbSjnemeth __RCSID("$NetBSD: add.c,v 1.44 2018/07/03 03:41:23 jnemeth Exp $");
379b522365Schristos #endif
385819a8c0Schristos 
395819a8c0Schristos #include <sys/types.h>
409aa3ec79Schristos #include <sys/param.h>
419aa3ec79Schristos #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"
529aa3ec79Schristos #include "gpt_private.h"
535819a8c0Schristos 
54f2c850e5Schristos static int cmd_add(gpt_t, int, char *[]);
555819a8c0Schristos 
56f2c850e5Schristos static const char *addhelp[] = {
57f2c850e5Schristos 	"[-a alignment] [-b blocknr] [-i index] [-l label]",
58f2c850e5Schristos 	"[-s size] [-t type]",
59f2c850e5Schristos };
600fac2edbSriz 
61f2c850e5Schristos struct gpt_cmd c_add = {
62f2c850e5Schristos 	"add",
63f2c850e5Schristos 	cmd_add,
64f2c850e5Schristos 	addhelp, __arraycount(addhelp),
65*b61b88fbSjnemeth 	GPT_SYNC,
66f2c850e5Schristos };
675819a8c0Schristos 
68f2c850e5Schristos #define usage() gpt_usage(NULL, &c_add)
695819a8c0Schristos 
70e7ba17aaSchristos static void
ent_set(struct gpt_ent * ent,const map_t map,const gpt_uuid_t xtype,const uint8_t * xname)71e7ba17aaSchristos ent_set(struct gpt_ent *ent, const map_t map, const gpt_uuid_t xtype,
72e7ba17aaSchristos     const uint8_t *xname)
73e7ba17aaSchristos {
74e7ba17aaSchristos 	gpt_uuid_copy(ent->ent_type, xtype);
7522a50e1aSchristos 	ent->ent_lba_start = htole64((uint64_t)map->map_start);
7622a50e1aSchristos 	ent->ent_lba_end = htole64((uint64_t)(map->map_start +
7722a50e1aSchristos 	    map->map_size - 1LL));
783aa8edceSchristos 	if (xname == NULL)
793aa8edceSchristos 		return;
803aa8edceSchristos 	utf8_to_utf16(xname, ent->ent_name, __arraycount(ent->ent_name));
81e7ba17aaSchristos }
82e7ba17aaSchristos 
839aa3ec79Schristos static int
add(gpt_t gpt,off_t alignment,off_t block,off_t sectors,off_t size,u_int entry,uint8_t * name,gpt_uuid_t type)840400ff57Schristos add(gpt_t gpt, off_t alignment, off_t block, off_t sectors, off_t size,
850400ff57Schristos     u_int entry, uint8_t *name, gpt_uuid_t type)
865819a8c0Schristos {
879aa3ec79Schristos 	map_t map;
885819a8c0Schristos 	struct gpt_hdr *hdr;
89e7ba17aaSchristos 	struct gpt_ent *ent;
905819a8c0Schristos 	unsigned int i;
91d6e6a766Sjnemeth 	off_t alignsecs;
923441a013Schristos 	char buf[128];
93d6e6a766Sjnemeth 
949aa3ec79Schristos 	if ((hdr = gpt_hdr(gpt)) == NULL)
959aa3ec79Schristos 		return -1;
965819a8c0Schristos 
97565d8259She 	ent = NULL;
985819a8c0Schristos 
995819a8c0Schristos 	if (entry > le32toh(hdr->hdr_entries)) {
1009aa3ec79Schristos 		gpt_warnx(gpt, "index %u out of range (%u max)",
1015819a8c0Schristos 		    entry, le32toh(hdr->hdr_entries));
1029aa3ec79Schristos 		return -1;
1035819a8c0Schristos 	}
1045819a8c0Schristos 
1055819a8c0Schristos 	if (entry > 0) {
1065819a8c0Schristos 		i = entry - 1;
1079aa3ec79Schristos 		ent = gpt_ent_primary(gpt, i);
1084bc60a99Schristos 		if (!gpt_uuid_is_nil(ent->ent_type)) {
1099aa3ec79Schristos 			gpt_warnx(gpt, "Entry at index %u is not free", entry);
1109aa3ec79Schristos 			return -1;
1115819a8c0Schristos 		}
1125819a8c0Schristos 	} else {
1135819a8c0Schristos 		/* Find empty slot in GPT table. */
1145819a8c0Schristos 		for (i = 0; i < le32toh(hdr->hdr_entries); i++) {
1159aa3ec79Schristos 			ent = gpt_ent_primary(gpt, i);
1164bc60a99Schristos 			if (gpt_uuid_is_nil(ent->ent_type))
1175819a8c0Schristos 				break;
1185819a8c0Schristos 		}
1195819a8c0Schristos 		if (i == le32toh(hdr->hdr_entries)) {
1209aa3ec79Schristos 			gpt_warnx(gpt, "No available table entries");
1219aa3ec79Schristos 			return -1;
1225819a8c0Schristos 		}
1235819a8c0Schristos 	}
1245819a8c0Schristos 
125d6e6a766Sjnemeth 	if (alignment > 0) {
1269aa3ec79Schristos 		alignsecs = alignment / gpt->secsz;
1279aa3ec79Schristos 		map = map_alloc(gpt, block, sectors, alignsecs);
128d6e6a766Sjnemeth 		if (map == NULL) {
1299aa3ec79Schristos 			gpt_warnx(gpt, "Not enough space available on "
1309aa3ec79Schristos 			      "device for an aligned partition");
1319aa3ec79Schristos 			return -1;
132d6e6a766Sjnemeth 		}
133d6e6a766Sjnemeth 	} else {
1349aa3ec79Schristos 		map = map_alloc(gpt, block, sectors, 0);
1355819a8c0Schristos 		if (map == NULL) {
1369aa3ec79Schristos 			gpt_warnx(gpt, "Not enough space available on device");
1379aa3ec79Schristos 			return -1;
1385819a8c0Schristos 		}
139d6e6a766Sjnemeth 	}
1405819a8c0Schristos 
141e7ba17aaSchristos 	ent_set(ent, map, type, name);
1420a90555aSchristos 	if (gpt_write_primary(gpt) == -1)
1430a90555aSchristos 		return -1;
1445819a8c0Schristos 
1459aa3ec79Schristos 	ent = gpt_ent_backup(gpt, i);
146e7ba17aaSchristos 	ent_set(ent, map, type, name);
1470a90555aSchristos 	if (gpt_write_backup(gpt) == -1)
1480a90555aSchristos 		return -1;
1495819a8c0Schristos 
1503441a013Schristos 	gpt_uuid_snprintf(buf, sizeof(buf), "%d", type);
1513441a013Schristos 	gpt_msg(gpt, "Partition %d added: %s %" PRIu64 " %" PRIu64, i + 1,
1523441a013Schristos 	    buf, map->map_start, map->map_size);
1539aa3ec79Schristos 	return 0;
1545819a8c0Schristos }
1555819a8c0Schristos 
156f2c850e5Schristos static int
cmd_add(gpt_t gpt,int argc,char * argv[])1579aa3ec79Schristos cmd_add(gpt_t gpt, int argc, char *argv[])
1585819a8c0Schristos {
1599aa3ec79Schristos 	int ch;
1600400ff57Schristos 	off_t alignment = 0, block = 0, sectors = 0, size = 0;
1610400ff57Schristos 	unsigned int entry = 0;
1620400ff57Schristos 	uint8_t *name = NULL;
1630400ff57Schristos 	gpt_uuid_t type;
1640400ff57Schristos 
1650400ff57Schristos 	gpt_uuid_copy(type, gpt_uuid_nil);
1665819a8c0Schristos 
167e8a14898Sjnemeth 	while ((ch = getopt(argc, argv, GPT_AIS "b:l:t:")) != -1) {
1685819a8c0Schristos 		switch(ch) {
1695819a8c0Schristos 		case 'b':
1709c2ffc09Schristos 			if (gpt_human_get(gpt, &block) == -1)
171f0b8ec31Schristos 				goto usage;
1725819a8c0Schristos 			break;
173d6e6a766Sjnemeth 		case 'l':
1745e89d4b2Schristos 			if (gpt_name_get(gpt, &name) == -1)
175f0b8ec31Schristos 				goto usage;
176d6e6a766Sjnemeth 			break;
1775819a8c0Schristos 		case 't':
1785e89d4b2Schristos 			if (gpt_uuid_get(gpt, &type) == -1)
179f0b8ec31Schristos 				goto usage;
1805819a8c0Schristos 			break;
1815819a8c0Schristos 		default:
1823441a013Schristos 			if (gpt_add_ais(gpt, &alignment, &entry, &size, ch)
1833441a013Schristos 			    == -1)
184f0b8ec31Schristos 				goto usage;
1853441a013Schristos 			break;
1865819a8c0Schristos 		}
1875819a8c0Schristos 	}
1885819a8c0Schristos 
1893441a013Schristos 	if (argc != optind)
190f2c850e5Schristos 		return usage();
1915819a8c0Schristos 
19200f1a564Sjakllsch 	/* Create NetBSD FFS partitions by default. */
1935e89d4b2Schristos 	if (gpt_uuid_is_nil(type))
1944bc60a99Schristos 		gpt_uuid_create(GPT_TYPE_NETBSD_FFS, type, NULL, 0);
1955819a8c0Schristos 
1969aa3ec79Schristos 	if (optind != argc)
197f0b8ec31Schristos 		goto cleanup;
1985819a8c0Schristos 
19922a50e1aSchristos 	if ((sectors = gpt_check_ais(gpt, alignment, ~0U, size)) == -1)
200f0b8ec31Schristos 		goto cleanup;
201d6e6a766Sjnemeth 
2020400ff57Schristos 	return add(gpt, alignment, block, sectors, size, entry, name, type);
20376ff2dabSchristos usage:
20476ff2dabSchristos 	return usage();
205f0b8ec31Schristos cleanup:
206f0b8ec31Schristos 	free(name);
207f0b8ec31Schristos 	return -1;
2085819a8c0Schristos }
209