geom_shsec.c revision 143586
1/*-
2 * Copyright (c) 2004-2005 Pawel Jakub Dawidek <pjd@FreeBSD.org>
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 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27#include <sys/cdefs.h>
28__FBSDID("$FreeBSD: head/sbin/geom/class/shsec/geom_shsec.c 143586 2005-03-14 14:25:47Z pjd $");
29
30#include <sys/param.h>
31#include <errno.h>
32#include <paths.h>
33#include <stdio.h>
34#include <stdlib.h>
35#include <stdint.h>
36#include <string.h>
37#include <strings.h>
38#include <assert.h>
39#include <libgeom.h>
40#include <geom/shsec/g_shsec.h>
41
42#include "core/geom.h"
43#include "misc/subr.h"
44
45
46uint32_t lib_version = G_LIB_VERSION;
47uint32_t version = G_SHSEC_VERSION;
48
49static void shsec_main(struct gctl_req *req, unsigned flags);
50static void shsec_clear(struct gctl_req *req);
51static void shsec_dump(struct gctl_req *req);
52static void shsec_label(struct gctl_req *req);
53
54struct g_command class_commands[] = {
55	{ "clear", G_FLAG_VERBOSE, shsec_main, G_NULL_OPTS,
56	    "clear [-v] prov ..."
57	},
58	{ "dump", 0, shsec_main, G_NULL_OPTS,
59	    "dump prov ..."
60	},
61	{ "label", G_FLAG_VERBOSE | G_FLAG_LOADKLD, shsec_main,
62	    {
63		{ 'h', "hardcode", NULL, G_TYPE_NONE },
64		G_OPT_SENTINEL
65	    },
66	    "[-hv] name prov prov ..."
67	},
68	{ "stop", G_FLAG_VERBOSE, NULL,
69	    {
70		{ 'f', "force", NULL, G_TYPE_NONE },
71		G_OPT_SENTINEL
72	    },
73	    "[-fv] name ..."
74	},
75	G_CMD_SENTINEL
76};
77
78static int verbose = 0;
79
80static void
81shsec_main(struct gctl_req *req, unsigned flags)
82{
83	const char *name;
84
85	if ((flags & G_FLAG_VERBOSE) != 0)
86		verbose = 1;
87
88	name = gctl_get_asciiparam(req, "verb");
89	if (name == NULL) {
90		gctl_error(req, "No '%s' argument.", "verb");
91		return;
92	}
93	if (strcmp(name, "label") == 0)
94		shsec_label(req);
95	else if (strcmp(name, "clear") == 0)
96		shsec_clear(req);
97	else if (strcmp(name, "dump") == 0)
98		shsec_dump(req);
99	else
100		gctl_error(req, "Unknown command: %s.", name);
101}
102
103static void
104shsec_label(struct gctl_req *req)
105{
106	struct g_shsec_metadata md;
107	off_t compsize, msize;
108	u_char sector[512];
109	unsigned i, ssize, secsize;
110	const char *name;
111	char param[16];
112	int *hardcode, *nargs, error;
113
114	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
115	if (nargs == NULL) {
116		gctl_error(req, "No '%s' argument.", "nargs");
117		return;
118	}
119	if (*nargs <= 2) {
120		gctl_error(req, "Too few arguments.");
121		return;
122	}
123	hardcode = gctl_get_paraml(req, "hardcode", sizeof(*hardcode));
124	if (hardcode == NULL) {
125		gctl_error(req, "No '%s' argument.", "hardcode");
126		return;
127	}
128
129	/*
130	 * Clear last sector first to spoil all components if device exists.
131	 */
132	compsize = 0;
133	secsize = 0;
134	for (i = 1; i < (unsigned)*nargs; i++) {
135		snprintf(param, sizeof(param), "arg%u", i);
136		name = gctl_get_asciiparam(req, param);
137
138		msize = g_get_mediasize(name);
139		ssize = g_get_sectorsize(name);
140		if (msize == 0 || ssize == 0) {
141			gctl_error(req, "Can't get informations about %s: %s.",
142			    name, strerror(errno));
143			return;
144		}
145		msize -= ssize;
146		if (compsize == 0 || (compsize > 0 && msize < compsize))
147			compsize = msize;
148		if (secsize == 0)
149			secsize = ssize;
150		else
151			secsize = g_lcm(secsize, ssize);
152
153		error = g_metadata_clear(name, NULL);
154		if (error != 0) {
155			gctl_error(req, "Can't store metadata on %s: %s.", name,
156			    strerror(error));
157			return;
158		}
159	}
160
161	strlcpy(md.md_magic, G_SHSEC_MAGIC, sizeof(md.md_magic));
162	md.md_version = G_SHSEC_VERSION;
163	name = gctl_get_asciiparam(req, "arg0");
164	if (name == NULL) {
165		gctl_error(req, "No 'arg%u' argument.", 0);
166		return;
167	}
168	strlcpy(md.md_name, name, sizeof(md.md_name));
169	md.md_id = arc4random();
170	md.md_all = *nargs - 1;
171
172	/*
173	 * Ok, store metadata.
174	 */
175	for (i = 1; i < (unsigned)*nargs; i++) {
176		snprintf(param, sizeof(param), "arg%u", i);
177		name = gctl_get_asciiparam(req, param);
178
179		msize = g_get_mediasize(name);
180		ssize = g_get_sectorsize(name);
181		if (compsize < msize - ssize) {
182			fprintf(stderr,
183			    "warning: %s: only %jd bytes from %jd bytes used.\n",
184			    name, (intmax_t)compsize, (intmax_t)(msize - ssize));
185		}
186
187		md.md_no = i - 1;
188		md.md_provsize = msize;
189		if (!*hardcode)
190			bzero(md.md_provider, sizeof(md.md_provider));
191		else {
192			if (strncmp(name, _PATH_DEV, strlen(_PATH_DEV)) == 0)
193				name += strlen(_PATH_DEV);
194			strlcpy(md.md_provider, name, sizeof(md.md_provider));
195		}
196		shsec_metadata_encode(&md, sector);
197		error = g_metadata_store(name, sector, sizeof(sector));
198		if (error != 0) {
199			fprintf(stderr, "Can't store metadata on %s: %s.\n",
200			    name, strerror(error));
201			gctl_error(req, "Not fully done.");
202			continue;
203		}
204		if (verbose)
205			printf("Metadata value stored on %s.\n", name);
206	}
207}
208
209static void
210shsec_clear(struct gctl_req *req)
211{
212	const char *name;
213	char param[16];
214	unsigned i;
215	int *nargs, error;
216
217	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
218	if (nargs == NULL) {
219		gctl_error(req, "No '%s' argument.", "nargs");
220		return;
221	}
222	if (*nargs < 1) {
223		gctl_error(req, "Too few arguments.");
224		return;
225	}
226
227	for (i = 0; i < (unsigned)*nargs; i++) {
228		snprintf(param, sizeof(param), "arg%u", i);
229		name = gctl_get_asciiparam(req, param);
230
231		error = g_metadata_clear(name, G_SHSEC_MAGIC);
232		if (error != 0) {
233			fprintf(stderr, "Can't clear metadata on %s: %s.\n",
234			    name, strerror(error));
235			gctl_error(req, "Not fully done.");
236			continue;
237		}
238		if (verbose)
239			printf("Metadata cleared on %s.\n", name);
240	}
241}
242
243static void
244shsec_metadata_dump(const struct g_shsec_metadata *md)
245{
246
247	printf("         Magic string: %s\n", md->md_magic);
248	printf("     Metadata version: %u\n", (u_int)md->md_version);
249	printf("          Device name: %s\n", md->md_name);
250	printf("            Device ID: %u\n", (u_int)md->md_id);
251	printf("          Disk number: %u\n", (u_int)md->md_no);
252	printf("Total number of disks: %u\n", (u_int)md->md_all);
253	printf("   Hardcoded provider: %s\n", md->md_provider);
254}
255
256static void
257shsec_dump(struct gctl_req *req)
258{
259	struct g_shsec_metadata md, tmpmd;
260	const char *name;
261	char param[16];
262	int *nargs, error, i;
263
264	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
265	if (nargs == NULL) {
266		gctl_error(req, "No '%s' argument.", "nargs");
267		return;
268	}
269	if (*nargs < 1) {
270		gctl_error(req, "Too few arguments.");
271		return;
272	}
273
274	for (i = 0; i < *nargs; i++) {
275		snprintf(param, sizeof(param), "arg%u", i);
276		name = gctl_get_asciiparam(req, param);
277
278		error = g_metadata_read(name, (u_char *)&tmpmd, sizeof(tmpmd),
279		    G_SHSEC_MAGIC);
280		if (error != 0) {
281			fprintf(stderr, "Can't read metadata from %s: %s.\n",
282			    name, strerror(error));
283			gctl_error(req, "Not fully done.");
284			continue;
285		}
286		shsec_metadata_decode((u_char *)&tmpmd, &md);
287		printf("Metadata on %s:\n", name);
288		shsec_metadata_dump(&md);
289		printf("\n");
290	}
291}
292