1/*-
2 * Copyright (c) 2004 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#ifdef __FBSDID
29__FBSDID("$FreeBSD: src/sbin/gpt/remove.c,v 1.10 2006/10/04 18:20:25 marcel Exp $");
30#endif
31#ifdef __RCSID
32__RCSID("$NetBSD: remove.c,v 1.5 2009/02/07 17:21:44 uebayasi Exp $");
33#endif
34
35#include <sys/types.h>
36
37#include <err.h>
38#include <stddef.h>
39#include <stdio.h>
40#include <stdlib.h>
41#include <string.h>
42#include <unistd.h>
43
44#include "map.h"
45#include "gpt.h"
46
47static int all;
48static uuid_t type;
49static off_t block, size;
50static unsigned int entry;
51
52const char removemsg1[] = "remove -a device ...";
53const char removemsg2[] = "remove [-b lba] [-i index] [-s lba] "
54	"[-t type] device ...";
55
56__dead static void
57usage_remove(void)
58{
59
60	fprintf(stderr,
61	    "usage: %s %s\n"
62	    "       %s %s\n",
63	    getprogname(), removemsg1, getprogname(), removemsg2);
64	exit(1);
65}
66
67static void
68rem(int fd)
69{
70	uuid_t uuid;
71	map_t *gpt, *tpg;
72	map_t *tbl, *lbt;
73	map_t *m;
74	struct gpt_hdr *hdr;
75	struct gpt_ent *ent;
76	unsigned int i;
77
78	gpt = map_find(MAP_TYPE_PRI_GPT_HDR);
79	if (gpt == NULL) {
80		warnx("%s: error: no primary GPT header; run create or recover",
81		    device_name);
82		return;
83	}
84
85	tpg = map_find(MAP_TYPE_SEC_GPT_HDR);
86	if (tpg == NULL) {
87		warnx("%s: error: no secondary GPT header; run recover",
88		    device_name);
89		return;
90	}
91
92	tbl = map_find(MAP_TYPE_PRI_GPT_TBL);
93	lbt = map_find(MAP_TYPE_SEC_GPT_TBL);
94	if (tbl == NULL || lbt == NULL) {
95		warnx("%s: error: run recover -- trust me", device_name);
96		return;
97	}
98
99	/* Remove all matching entries in the map. */
100	for (m = map_first(); m != NULL; m = m->map_next) {
101		if (m->map_type != MAP_TYPE_GPT_PART || m->map_index < 1)
102			continue;
103		if (entry > 0 && entry != m->map_index)
104			continue;
105		if (block > 0 && block != m->map_start)
106			continue;
107		if (size > 0 && size != m->map_size)
108			continue;
109
110		i = m->map_index - 1;
111
112		hdr = gpt->map_data;
113		ent = (void*)((char*)tbl->map_data + i *
114		    le32toh(hdr->hdr_entsz));
115		le_uuid_dec(&ent->ent_type, &uuid);
116		if (!uuid_is_nil(&type, NULL) &&
117		    !uuid_equal(&type, &uuid, NULL))
118			continue;
119
120		/* Remove the primary entry by clearing the partition type. */
121		uuid_create_nil((uuid_t *)&ent->ent_type, NULL);
122
123		hdr->hdr_crc_table = htole32(crc32(tbl->map_data,
124		    le32toh(hdr->hdr_entries) * le32toh(hdr->hdr_entsz)));
125		hdr->hdr_crc_self = 0;
126		hdr->hdr_crc_self = htole32(crc32(hdr, le32toh(hdr->hdr_size)));
127
128		gpt_write(fd, gpt);
129		gpt_write(fd, tbl);
130
131		hdr = tpg->map_data;
132		ent = (void*)((char*)lbt->map_data + i *
133		    le32toh(hdr->hdr_entsz));
134
135		/* Remove the secundary entry. */
136		uuid_create_nil((uuid_t *)&ent->ent_type, NULL);
137
138		hdr->hdr_crc_table = htole32(crc32(lbt->map_data,
139		    le32toh(hdr->hdr_entries) * le32toh(hdr->hdr_entsz)));
140		hdr->hdr_crc_self = 0;
141		hdr->hdr_crc_self = htole32(crc32(hdr, le32toh(hdr->hdr_size)));
142
143		gpt_write(fd, lbt);
144		gpt_write(fd, tpg);
145#ifdef __FreeBSD__
146		printf("%sp%u removed\n", device_name, m->map_index);
147#endif
148#ifdef __NetBSD__
149		printf("partition %d removed from %s\n", m->map_index,
150		    device_name);
151#endif
152	}
153}
154
155int
156cmd_remove(int argc, char *argv[])
157{
158	char *p;
159	int ch, fd;
160
161	/* Get the remove options */
162	while ((ch = getopt(argc, argv, "ab:i:s:t:")) != -1) {
163		switch(ch) {
164		case 'a':
165			if (all > 0)
166				usage_remove();
167			all = 1;
168			break;
169		case 'b':
170			if (block > 0)
171				usage_remove();
172			block = strtoll(optarg, &p, 10);
173			if (*p != 0 || block < 1)
174				usage_remove();
175			break;
176		case 'i':
177			if (entry > 0)
178				usage_remove();
179			entry = strtoul(optarg, &p, 10);
180			if (*p != 0 || entry < 1)
181				usage_remove();
182			break;
183		case 's':
184			if (size > 0)
185				usage_remove();
186			size = strtoll(optarg, &p, 10);
187			if (*p != 0 || size < 1)
188				usage_remove();
189			break;
190		case 't':
191			if (!uuid_is_nil(&type, NULL))
192				usage_remove();
193			if (parse_uuid(optarg, &type) != 0)
194				usage_remove();
195			break;
196		default:
197			usage_remove();
198		}
199	}
200
201	if (!all ^
202	    (block > 0 || entry > 0 || size > 0 || !uuid_is_nil(&type, NULL)))
203		usage_remove();
204
205	if (argc == optind)
206		usage_remove();
207
208	while (optind < argc) {
209		fd = gpt_open(argv[optind++]);
210		if (fd == -1) {
211			warn("unable to open device '%s'", device_name);
212			continue;
213		}
214
215		rem(fd);
216
217		gpt_close(fd);
218	}
219
220	return (0);
221}
222