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