xref: /dflybsd-src/sbin/gpt/label.c (revision 86d7f5d305c6adaa56ff4582ece9859d73106103)
1*86d7f5d3SJohn Marino /*-
2*86d7f5d3SJohn Marino  * Copyright (c) 2005 Marcel Moolenaar
3*86d7f5d3SJohn Marino  * All rights reserved.
4*86d7f5d3SJohn Marino  *
5*86d7f5d3SJohn Marino  * Redistribution and use in source and binary forms, with or without
6*86d7f5d3SJohn Marino  * modification, are permitted provided that the following conditions
7*86d7f5d3SJohn Marino  * are met:
8*86d7f5d3SJohn Marino  *
9*86d7f5d3SJohn Marino  * 1. Redistributions of source code must retain the above copyright
10*86d7f5d3SJohn Marino  *    notice, this list of conditions and the following disclaimer.
11*86d7f5d3SJohn Marino  * 2. Redistributions in binary form must reproduce the above copyright
12*86d7f5d3SJohn Marino  *    notice, this list of conditions and the following disclaimer in the
13*86d7f5d3SJohn Marino  *    documentation and/or other materials provided with the distribution.
14*86d7f5d3SJohn Marino  *
15*86d7f5d3SJohn Marino  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16*86d7f5d3SJohn Marino  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17*86d7f5d3SJohn Marino  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18*86d7f5d3SJohn Marino  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19*86d7f5d3SJohn Marino  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20*86d7f5d3SJohn Marino  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21*86d7f5d3SJohn Marino  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22*86d7f5d3SJohn Marino  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23*86d7f5d3SJohn Marino  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24*86d7f5d3SJohn Marino  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25*86d7f5d3SJohn Marino  *
26*86d7f5d3SJohn Marino  * $FreeBSD: src/sbin/gpt/label.c,v 1.3 2006/10/04 18:20:25 marcel Exp $
27*86d7f5d3SJohn Marino  * $DragonFly: src/sbin/gpt/label.c,v 1.2 2007/06/17 08:34:59 dillon Exp $
28*86d7f5d3SJohn Marino  */
29*86d7f5d3SJohn Marino 
30*86d7f5d3SJohn Marino #include <sys/types.h>
31*86d7f5d3SJohn Marino 
32*86d7f5d3SJohn Marino #include <err.h>
33*86d7f5d3SJohn Marino #include <stddef.h>
34*86d7f5d3SJohn Marino #include <stdio.h>
35*86d7f5d3SJohn Marino #include <stdlib.h>
36*86d7f5d3SJohn Marino #include <string.h>
37*86d7f5d3SJohn Marino #include <unistd.h>
38*86d7f5d3SJohn Marino 
39*86d7f5d3SJohn Marino #include "map.h"
40*86d7f5d3SJohn Marino #include "gpt.h"
41*86d7f5d3SJohn Marino 
42*86d7f5d3SJohn Marino static int all;
43*86d7f5d3SJohn Marino static uuid_t type;
44*86d7f5d3SJohn Marino static off_t block, size;
45*86d7f5d3SJohn Marino static unsigned int entry = NOENTRY;
46*86d7f5d3SJohn Marino static uint8_t *name;
47*86d7f5d3SJohn Marino 
48*86d7f5d3SJohn Marino static void
usage_label(void)49*86d7f5d3SJohn Marino usage_label(void)
50*86d7f5d3SJohn Marino {
51*86d7f5d3SJohn Marino 	const char *common = "<-l label | -f file> device ...";
52*86d7f5d3SJohn Marino 
53*86d7f5d3SJohn Marino 	fprintf(stderr,
54*86d7f5d3SJohn Marino 	    "usage: %s -a %s\n"
55*86d7f5d3SJohn Marino 	    "       %s [-b lba] [-i index] [-s lba] [-t uuid] %s\n",
56*86d7f5d3SJohn Marino 	    getprogname(), common, getprogname(), common);
57*86d7f5d3SJohn Marino 	exit(1);
58*86d7f5d3SJohn Marino }
59*86d7f5d3SJohn Marino 
60*86d7f5d3SJohn Marino static void
label(int fd)61*86d7f5d3SJohn Marino label(int fd)
62*86d7f5d3SJohn Marino {
63*86d7f5d3SJohn Marino 	uuid_t uuid;
64*86d7f5d3SJohn Marino 	map_t *gpt, *tpg;
65*86d7f5d3SJohn Marino 	map_t *tbl, *lbt;
66*86d7f5d3SJohn Marino 	map_t *m;
67*86d7f5d3SJohn Marino 	struct gpt_hdr *hdr;
68*86d7f5d3SJohn Marino 	struct gpt_ent *ent;
69*86d7f5d3SJohn Marino 	unsigned int i;
70*86d7f5d3SJohn Marino 
71*86d7f5d3SJohn Marino 	gpt = map_find(MAP_TYPE_PRI_GPT_HDR);
72*86d7f5d3SJohn Marino 	if (gpt == NULL) {
73*86d7f5d3SJohn Marino 		warnx("%s: error: no primary GPT header; run create or recover",
74*86d7f5d3SJohn Marino 		    device_name);
75*86d7f5d3SJohn Marino 		return;
76*86d7f5d3SJohn Marino 	}
77*86d7f5d3SJohn Marino 
78*86d7f5d3SJohn Marino 	tpg = map_find(MAP_TYPE_SEC_GPT_HDR);
79*86d7f5d3SJohn Marino 	if (tpg == NULL) {
80*86d7f5d3SJohn Marino 		warnx("%s: error: no secondary GPT header; run recover",
81*86d7f5d3SJohn Marino 		    device_name);
82*86d7f5d3SJohn Marino 		return;
83*86d7f5d3SJohn Marino 	}
84*86d7f5d3SJohn Marino 
85*86d7f5d3SJohn Marino 	tbl = map_find(MAP_TYPE_PRI_GPT_TBL);
86*86d7f5d3SJohn Marino 	lbt = map_find(MAP_TYPE_SEC_GPT_TBL);
87*86d7f5d3SJohn Marino 	if (tbl == NULL || lbt == NULL) {
88*86d7f5d3SJohn Marino 		warnx("%s: error: run recover -- trust me", device_name);
89*86d7f5d3SJohn Marino 		return;
90*86d7f5d3SJohn Marino 	}
91*86d7f5d3SJohn Marino 
92*86d7f5d3SJohn Marino 	/* Relabel all matching entries in the map. */
93*86d7f5d3SJohn Marino 	for (m = map_first(); m != NULL; m = m->map_next) {
94*86d7f5d3SJohn Marino 		if (m->map_type != MAP_TYPE_GPT_PART || m->map_index == NOENTRY)
95*86d7f5d3SJohn Marino 			continue;
96*86d7f5d3SJohn Marino 		if (entry != NOENTRY && entry != m->map_index)
97*86d7f5d3SJohn Marino 			continue;
98*86d7f5d3SJohn Marino 		if (block > 0 && block != m->map_start)
99*86d7f5d3SJohn Marino 			continue;
100*86d7f5d3SJohn Marino 		if (size > 0 && size != m->map_size)
101*86d7f5d3SJohn Marino 			continue;
102*86d7f5d3SJohn Marino 
103*86d7f5d3SJohn Marino 		i = m->map_index;
104*86d7f5d3SJohn Marino 
105*86d7f5d3SJohn Marino 		hdr = gpt->map_data;
106*86d7f5d3SJohn Marino 		ent = (void*)((char*)tbl->map_data + i *
107*86d7f5d3SJohn Marino 		    le32toh(hdr->hdr_entsz));
108*86d7f5d3SJohn Marino 		le_uuid_dec(&ent->ent_type, &uuid);
109*86d7f5d3SJohn Marino 		if (!uuid_is_nil(&type, NULL) &&
110*86d7f5d3SJohn Marino 		    !uuid_equal(&type, &uuid, NULL))
111*86d7f5d3SJohn Marino 			continue;
112*86d7f5d3SJohn Marino 
113*86d7f5d3SJohn Marino 		/* Label the primary entry. */
114*86d7f5d3SJohn Marino 		utf8_to_utf16(name, ent->ent_name, 36);
115*86d7f5d3SJohn Marino 
116*86d7f5d3SJohn Marino 		hdr->hdr_crc_table = htole32(crc32(tbl->map_data,
117*86d7f5d3SJohn Marino 		    le32toh(hdr->hdr_entries) * le32toh(hdr->hdr_entsz)));
118*86d7f5d3SJohn Marino 		hdr->hdr_crc_self = 0;
119*86d7f5d3SJohn Marino 		hdr->hdr_crc_self = htole32(crc32(hdr, le32toh(hdr->hdr_size)));
120*86d7f5d3SJohn Marino 
121*86d7f5d3SJohn Marino 		gpt_write(fd, gpt);
122*86d7f5d3SJohn Marino 		gpt_write(fd, tbl);
123*86d7f5d3SJohn Marino 
124*86d7f5d3SJohn Marino 		hdr = tpg->map_data;
125*86d7f5d3SJohn Marino 		ent = (void*)((char*)lbt->map_data + i *
126*86d7f5d3SJohn Marino 		    le32toh(hdr->hdr_entsz));
127*86d7f5d3SJohn Marino 
128*86d7f5d3SJohn Marino 		/* Label the secundary entry. */
129*86d7f5d3SJohn Marino 		utf8_to_utf16(name, ent->ent_name, 36);
130*86d7f5d3SJohn Marino 
131*86d7f5d3SJohn Marino 		hdr->hdr_crc_table = htole32(crc32(lbt->map_data,
132*86d7f5d3SJohn Marino 		    le32toh(hdr->hdr_entries) * le32toh(hdr->hdr_entsz)));
133*86d7f5d3SJohn Marino 		hdr->hdr_crc_self = 0;
134*86d7f5d3SJohn Marino 		hdr->hdr_crc_self = htole32(crc32(hdr, le32toh(hdr->hdr_size)));
135*86d7f5d3SJohn Marino 
136*86d7f5d3SJohn Marino 		gpt_write(fd, lbt);
137*86d7f5d3SJohn Marino 		gpt_write(fd, tpg);
138*86d7f5d3SJohn Marino 
139*86d7f5d3SJohn Marino 		printf("%ss%u labeled\n", device_name, m->map_index);
140*86d7f5d3SJohn Marino 	}
141*86d7f5d3SJohn Marino }
142*86d7f5d3SJohn Marino 
143*86d7f5d3SJohn Marino static void
name_from_file(const char * fn)144*86d7f5d3SJohn Marino name_from_file(const char *fn)
145*86d7f5d3SJohn Marino {
146*86d7f5d3SJohn Marino 	FILE *f;
147*86d7f5d3SJohn Marino 	char *p;
148*86d7f5d3SJohn Marino 	size_t maxlen = 1024;
149*86d7f5d3SJohn Marino 	size_t len;
150*86d7f5d3SJohn Marino 
151*86d7f5d3SJohn Marino 	if (strcmp(fn, "-") != 0) {
152*86d7f5d3SJohn Marino 		f = fopen(fn, "r");
153*86d7f5d3SJohn Marino 		if (f == NULL)
154*86d7f5d3SJohn Marino 			err(1, "unable to open file %s", fn);
155*86d7f5d3SJohn Marino 	} else
156*86d7f5d3SJohn Marino 		f = stdin;
157*86d7f5d3SJohn Marino 	name = malloc(maxlen);
158*86d7f5d3SJohn Marino 	len = fread(name, 1, maxlen - 1, f);
159*86d7f5d3SJohn Marino 	if (ferror(f))
160*86d7f5d3SJohn Marino 		err(1, "unable to read label from file %s", fn);
161*86d7f5d3SJohn Marino 	if (f != stdin)
162*86d7f5d3SJohn Marino 		fclose(f);
163*86d7f5d3SJohn Marino 	name[len] = '\0';
164*86d7f5d3SJohn Marino 	/* Only keep the first line, excluding the newline character. */
165*86d7f5d3SJohn Marino 	p = strchr(name, '\n');
166*86d7f5d3SJohn Marino 	if (p != NULL)
167*86d7f5d3SJohn Marino 		*p = '\0';
168*86d7f5d3SJohn Marino }
169*86d7f5d3SJohn Marino 
170*86d7f5d3SJohn Marino int
cmd_label(int argc,char * argv[])171*86d7f5d3SJohn Marino cmd_label(int argc, char *argv[])
172*86d7f5d3SJohn Marino {
173*86d7f5d3SJohn Marino 	char *p;
174*86d7f5d3SJohn Marino 	int ch, fd;
175*86d7f5d3SJohn Marino 
176*86d7f5d3SJohn Marino 	/* Get the label options */
177*86d7f5d3SJohn Marino 	while ((ch = getopt(argc, argv, "ab:f:i:l:s:t:")) != -1) {
178*86d7f5d3SJohn Marino 		switch(ch) {
179*86d7f5d3SJohn Marino 		case 'a':
180*86d7f5d3SJohn Marino 			if (all > 0)
181*86d7f5d3SJohn Marino 				usage_label();
182*86d7f5d3SJohn Marino 			all = 1;
183*86d7f5d3SJohn Marino 			break;
184*86d7f5d3SJohn Marino 		case 'b':
185*86d7f5d3SJohn Marino 			if (block > 0)
186*86d7f5d3SJohn Marino 				usage_label();
187*86d7f5d3SJohn Marino 			block = strtoll(optarg, &p, 10);
188*86d7f5d3SJohn Marino 			if (*p != 0 || block < 1)
189*86d7f5d3SJohn Marino 				usage_label();
190*86d7f5d3SJohn Marino 			break;
191*86d7f5d3SJohn Marino 		case 'f':
192*86d7f5d3SJohn Marino 			if (name != NULL)
193*86d7f5d3SJohn Marino 				usage_label();
194*86d7f5d3SJohn Marino 			name_from_file(optarg);
195*86d7f5d3SJohn Marino 			break;
196*86d7f5d3SJohn Marino 		case 'i':
197*86d7f5d3SJohn Marino 			if (entry != NOENTRY)
198*86d7f5d3SJohn Marino 				usage_label();
199*86d7f5d3SJohn Marino 			entry = strtoul(optarg, &p, 10);
200*86d7f5d3SJohn Marino 			if (*p != 0 || entry == NOENTRY)
201*86d7f5d3SJohn Marino 				usage_label();
202*86d7f5d3SJohn Marino 			break;
203*86d7f5d3SJohn Marino 		case 'l':
204*86d7f5d3SJohn Marino 			if (name != NULL)
205*86d7f5d3SJohn Marino 				usage_label();
206*86d7f5d3SJohn Marino 			name = strdup(optarg);
207*86d7f5d3SJohn Marino 			break;
208*86d7f5d3SJohn Marino 		case 's':
209*86d7f5d3SJohn Marino 			if (size > 0)
210*86d7f5d3SJohn Marino 				usage_label();
211*86d7f5d3SJohn Marino 			size = strtoll(optarg, &p, 10);
212*86d7f5d3SJohn Marino 			if (*p != 0 || size < 1)
213*86d7f5d3SJohn Marino 				usage_label();
214*86d7f5d3SJohn Marino 			break;
215*86d7f5d3SJohn Marino 		case 't':
216*86d7f5d3SJohn Marino 			if (!uuid_is_nil(&type, NULL))
217*86d7f5d3SJohn Marino 				usage_label();
218*86d7f5d3SJohn Marino 			if (parse_uuid(optarg, &type) != 0)
219*86d7f5d3SJohn Marino 				usage_label();
220*86d7f5d3SJohn Marino 			break;
221*86d7f5d3SJohn Marino 		default:
222*86d7f5d3SJohn Marino 			usage_label();
223*86d7f5d3SJohn Marino 		}
224*86d7f5d3SJohn Marino 	}
225*86d7f5d3SJohn Marino 
226*86d7f5d3SJohn Marino 	if (!all ^
227*86d7f5d3SJohn Marino 	    (block > 0 || entry != NOENTRY || size > 0 ||
228*86d7f5d3SJohn Marino 	     !uuid_is_nil(&type, NULL)))
229*86d7f5d3SJohn Marino 		usage_label();
230*86d7f5d3SJohn Marino 
231*86d7f5d3SJohn Marino 	if (name == NULL || argc == optind)
232*86d7f5d3SJohn Marino 		usage_label();
233*86d7f5d3SJohn Marino 
234*86d7f5d3SJohn Marino 	while (optind < argc) {
235*86d7f5d3SJohn Marino 		fd = gpt_open(argv[optind++]);
236*86d7f5d3SJohn Marino 		if (fd == -1) {
237*86d7f5d3SJohn Marino 			warn("unable to open device '%s'", device_name);
238*86d7f5d3SJohn Marino 			continue;
239*86d7f5d3SJohn Marino 		}
240*86d7f5d3SJohn Marino 
241*86d7f5d3SJohn Marino 		label(fd);
242*86d7f5d3SJohn Marino 
243*86d7f5d3SJohn Marino 		gpt_close(fd);
244*86d7f5d3SJohn Marino 	}
245*86d7f5d3SJohn Marino 
246*86d7f5d3SJohn Marino 	return (0);
247*86d7f5d3SJohn Marino }
248