xref: /dragonfly/sbin/gpt/label.c (revision 36a3d1d6)
1 /*-
2  * Copyright (c) 2005 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  * $FreeBSD: src/sbin/gpt/label.c,v 1.3 2006/10/04 18:20:25 marcel Exp $
27  * $DragonFly: src/sbin/gpt/label.c,v 1.2 2007/06/17 08:34:59 dillon Exp $
28  */
29 
30 #include <sys/types.h>
31 
32 #include <err.h>
33 #include <stddef.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <unistd.h>
38 
39 #include "map.h"
40 #include "gpt.h"
41 
42 static int all;
43 static uuid_t type;
44 static off_t block, size;
45 static unsigned int entry = NOENTRY;
46 static uint8_t *name;
47 
48 static void
49 usage_label(void)
50 {
51 	const char *common = "<-l label | -f file> device ...";
52 
53 	fprintf(stderr,
54 	    "usage: %s -a %s\n"
55 	    "       %s [-b lba] [-i index] [-s lba] [-t uuid] %s\n",
56 	    getprogname(), common, getprogname(), common);
57 	exit(1);
58 }
59 
60 static void
61 label(int fd)
62 {
63 	uuid_t uuid;
64 	map_t *gpt, *tpg;
65 	map_t *tbl, *lbt;
66 	map_t *m;
67 	struct gpt_hdr *hdr;
68 	struct gpt_ent *ent;
69 	unsigned int i;
70 
71 	gpt = map_find(MAP_TYPE_PRI_GPT_HDR);
72 	if (gpt == NULL) {
73 		warnx("%s: error: no primary GPT header; run create or recover",
74 		    device_name);
75 		return;
76 	}
77 
78 	tpg = map_find(MAP_TYPE_SEC_GPT_HDR);
79 	if (tpg == NULL) {
80 		warnx("%s: error: no secondary GPT header; run recover",
81 		    device_name);
82 		return;
83 	}
84 
85 	tbl = map_find(MAP_TYPE_PRI_GPT_TBL);
86 	lbt = map_find(MAP_TYPE_SEC_GPT_TBL);
87 	if (tbl == NULL || lbt == NULL) {
88 		warnx("%s: error: run recover -- trust me", device_name);
89 		return;
90 	}
91 
92 	/* Relabel all matching entries in the map. */
93 	for (m = map_first(); m != NULL; m = m->map_next) {
94 		if (m->map_type != MAP_TYPE_GPT_PART || m->map_index == NOENTRY)
95 			continue;
96 		if (entry != NOENTRY && entry != m->map_index)
97 			continue;
98 		if (block > 0 && block != m->map_start)
99 			continue;
100 		if (size > 0 && size != m->map_size)
101 			continue;
102 
103 		i = m->map_index;
104 
105 		hdr = gpt->map_data;
106 		ent = (void*)((char*)tbl->map_data + i *
107 		    le32toh(hdr->hdr_entsz));
108 		le_uuid_dec(&ent->ent_type, &uuid);
109 		if (!uuid_is_nil(&type, NULL) &&
110 		    !uuid_equal(&type, &uuid, NULL))
111 			continue;
112 
113 		/* Label the primary entry. */
114 		utf8_to_utf16(name, ent->ent_name, 36);
115 
116 		hdr->hdr_crc_table = htole32(crc32(tbl->map_data,
117 		    le32toh(hdr->hdr_entries) * le32toh(hdr->hdr_entsz)));
118 		hdr->hdr_crc_self = 0;
119 		hdr->hdr_crc_self = htole32(crc32(hdr, le32toh(hdr->hdr_size)));
120 
121 		gpt_write(fd, gpt);
122 		gpt_write(fd, tbl);
123 
124 		hdr = tpg->map_data;
125 		ent = (void*)((char*)lbt->map_data + i *
126 		    le32toh(hdr->hdr_entsz));
127 
128 		/* Label the secundary entry. */
129 		utf8_to_utf16(name, ent->ent_name, 36);
130 
131 		hdr->hdr_crc_table = htole32(crc32(lbt->map_data,
132 		    le32toh(hdr->hdr_entries) * le32toh(hdr->hdr_entsz)));
133 		hdr->hdr_crc_self = 0;
134 		hdr->hdr_crc_self = htole32(crc32(hdr, le32toh(hdr->hdr_size)));
135 
136 		gpt_write(fd, lbt);
137 		gpt_write(fd, tpg);
138 
139 		printf("%ss%u labeled\n", device_name, m->map_index);
140 	}
141 }
142 
143 static void
144 name_from_file(const char *fn)
145 {
146 	FILE *f;
147 	char *p;
148 	size_t maxlen = 1024;
149 	size_t len;
150 
151 	if (strcmp(fn, "-") != 0) {
152 		f = fopen(fn, "r");
153 		if (f == NULL)
154 			err(1, "unable to open file %s", fn);
155 	} else
156 		f = stdin;
157 	name = malloc(maxlen);
158 	len = fread(name, 1, maxlen - 1, f);
159 	if (ferror(f))
160 		err(1, "unable to read label from file %s", fn);
161 	if (f != stdin)
162 		fclose(f);
163 	name[len] = '\0';
164 	/* Only keep the first line, excluding the newline character. */
165 	p = strchr(name, '\n');
166 	if (p != NULL)
167 		*p = '\0';
168 }
169 
170 int
171 cmd_label(int argc, char *argv[])
172 {
173 	char *p;
174 	int ch, fd;
175 
176 	/* Get the label options */
177 	while ((ch = getopt(argc, argv, "ab:f:i:l:s:t:")) != -1) {
178 		switch(ch) {
179 		case 'a':
180 			if (all > 0)
181 				usage_label();
182 			all = 1;
183 			break;
184 		case 'b':
185 			if (block > 0)
186 				usage_label();
187 			block = strtoll(optarg, &p, 10);
188 			if (*p != 0 || block < 1)
189 				usage_label();
190 			break;
191 		case 'f':
192 			if (name != NULL)
193 				usage_label();
194 			name_from_file(optarg);
195 			break;
196 		case 'i':
197 			if (entry != NOENTRY)
198 				usage_label();
199 			entry = strtoul(optarg, &p, 10);
200 			if (*p != 0 || entry == NOENTRY)
201 				usage_label();
202 			break;
203 		case 'l':
204 			if (name != NULL)
205 				usage_label();
206 			name = strdup(optarg);
207 			break;
208 		case 's':
209 			if (size > 0)
210 				usage_label();
211 			size = strtoll(optarg, &p, 10);
212 			if (*p != 0 || size < 1)
213 				usage_label();
214 			break;
215 		case 't':
216 			if (!uuid_is_nil(&type, NULL))
217 				usage_label();
218 			if (parse_uuid(optarg, &type) != 0)
219 				usage_label();
220 			break;
221 		default:
222 			usage_label();
223 		}
224 	}
225 
226 	if (!all ^
227 	    (block > 0 || entry != NOENTRY || size > 0 ||
228 	     !uuid_is_nil(&type, NULL)))
229 		usage_label();
230 
231 	if (name == NULL || argc == optind)
232 		usage_label();
233 
234 	while (optind < argc) {
235 		fd = gpt_open(argv[optind++]);
236 		if (fd == -1) {
237 			warn("unable to open device '%s'", device_name);
238 			continue;
239 		}
240 
241 		label(fd);
242 
243 		gpt_close(fd);
244 	}
245 
246 	return (0);
247 }
248