geom_shsec.c revision 140074
1/*-
2 * Copyright (c) 2004 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 140074 2005-01-11 18:06:44Z 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	{ "dump", 0, shsec_main, G_NULL_OPTS },
57	{ "label", G_FLAG_VERBOSE | G_FLAG_LOADKLD, shsec_main,
58	    {
59		{ 'h', "hardcode", NULL, G_TYPE_NONE },
60		G_OPT_SENTINEL
61	    }
62	},
63	{ "stop", G_FLAG_VERBOSE, NULL,
64	    {
65		{ 'f', "force", NULL, G_TYPE_NONE },
66		G_OPT_SENTINEL
67	    }
68	},
69	G_CMD_SENTINEL
70};
71
72static int verbose = 0;
73
74void usage(const char *name);
75void
76usage(const char *name)
77{
78
79	fprintf(stderr, "usage: %s label [-hv] <name> <prov> <prov> [prov [...]]\n", name);
80	fprintf(stderr, "       %s stop [-fv] <name> [name [...]]\n", name);
81	fprintf(stderr, "       %s clear [-v] <prov> [prov [...]]\n", name);
82	fprintf(stderr, "       %s dump <prov> [prov [...]]\n", name);
83}
84
85static void
86shsec_main(struct gctl_req *req, unsigned flags)
87{
88	const char *name;
89
90	if ((flags & G_FLAG_VERBOSE) != 0)
91		verbose = 1;
92
93	name = gctl_get_asciiparam(req, "verb");
94	if (name == NULL) {
95		gctl_error(req, "No '%s' argument.", "verb");
96		return;
97	}
98	if (strcmp(name, "label") == 0)
99		shsec_label(req);
100	else if (strcmp(name, "clear") == 0)
101		shsec_clear(req);
102	else if (strcmp(name, "dump") == 0)
103		shsec_dump(req);
104	else
105		gctl_error(req, "Unknown command: %s.", name);
106}
107
108static void
109shsec_label(struct gctl_req *req)
110{
111	struct g_shsec_metadata md;
112	off_t compsize, msize;
113	u_char sector[512];
114	unsigned i, ssize, secsize;
115	const char *name;
116	char param[16];
117	int *hardcode, *nargs, error;
118
119	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
120	if (nargs == NULL) {
121		gctl_error(req, "No '%s' argument.", "nargs");
122		return;
123	}
124	if (*nargs <= 2) {
125		gctl_error(req, "Too few arguments.");
126		return;
127	}
128	hardcode = gctl_get_paraml(req, "hardcode", sizeof(*hardcode));
129	if (hardcode == NULL) {
130		gctl_error(req, "No '%s' argument.", "hardcode");
131		return;
132	}
133
134	/*
135	 * Clear last sector first to spoil all components if device exists.
136	 */
137	compsize = 0;
138	secsize = 0;
139	for (i = 1; i < (unsigned)*nargs; i++) {
140		snprintf(param, sizeof(param), "arg%u", i);
141		name = gctl_get_asciiparam(req, param);
142
143		msize = g_get_mediasize(name);
144		ssize = g_get_sectorsize(name);
145		if (msize == 0 || ssize == 0) {
146			gctl_error(req, "Can't get informations about %s: %s.",
147			    name, strerror(errno));
148			return;
149		}
150		msize -= ssize;
151		if (compsize == 0 || (compsize > 0 && msize < compsize))
152			compsize = msize;
153		if (secsize == 0)
154			secsize = ssize;
155		else
156			secsize = g_lcm(secsize, ssize);
157
158		error = g_metadata_clear(name, NULL);
159		if (error != 0) {
160			gctl_error(req, "Can't store metadata on %s: %s.", name,
161			    strerror(error));
162			return;
163		}
164	}
165
166	strlcpy(md.md_magic, G_SHSEC_MAGIC, sizeof(md.md_magic));
167	md.md_version = G_SHSEC_VERSION;
168	name = gctl_get_asciiparam(req, "arg0");
169	if (name == NULL) {
170		gctl_error(req, "No 'arg%u' argument.", 0);
171		return;
172	}
173	strlcpy(md.md_name, name, sizeof(md.md_name));
174	md.md_id = arc4random();
175	md.md_all = *nargs - 1;
176
177	/*
178	 * Ok, store metadata.
179	 */
180	for (i = 1; i < (unsigned)*nargs; i++) {
181		snprintf(param, sizeof(param), "arg%u", i);
182		name = gctl_get_asciiparam(req, param);
183
184		msize = g_get_mediasize(name) - g_get_sectorsize(name);
185		if (compsize < msize) {
186			fprintf(stderr,
187			    "warning: %s: only %jd bytes from %jd bytes used.\n",
188			    name, (intmax_t)compsize, (intmax_t)msize);
189		}
190
191		md.md_no = i - 1;
192		if (!*hardcode)
193			bzero(md.md_provider, sizeof(md.md_provider));
194		else {
195			if (strncmp(name, _PATH_DEV, strlen(_PATH_DEV)) == 0)
196				name += strlen(_PATH_DEV);
197			strlcpy(md.md_provider, name, sizeof(md.md_provider));
198		}
199		shsec_metadata_encode(&md, sector);
200		error = g_metadata_store(name, sector, sizeof(sector));
201		if (error != 0) {
202			fprintf(stderr, "Can't store metadata on %s: %s.\n",
203			    name, strerror(error));
204			gctl_error(req, "Not fully done.");
205			continue;
206		}
207		if (verbose)
208			printf("Metadata value stored on %s.\n", name);
209	}
210}
211
212static void
213shsec_clear(struct gctl_req *req)
214{
215	const char *name;
216	char param[16];
217	unsigned i;
218	int *nargs, error;
219
220	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
221	if (nargs == NULL) {
222		gctl_error(req, "No '%s' argument.", "nargs");
223		return;
224	}
225	if (*nargs < 1) {
226		gctl_error(req, "Too few arguments.");
227		return;
228	}
229
230	for (i = 0; i < (unsigned)*nargs; i++) {
231		snprintf(param, sizeof(param), "arg%u", i);
232		name = gctl_get_asciiparam(req, param);
233
234		error = g_metadata_clear(name, G_SHSEC_MAGIC);
235		if (error != 0) {
236			fprintf(stderr, "Can't clear metadata on %s: %s.\n",
237			    name, strerror(error));
238			gctl_error(req, "Not fully done.");
239			continue;
240		}
241		if (verbose)
242			printf("Metadata cleared on %s.\n", name);
243	}
244}
245
246static void
247shsec_metadata_dump(const struct g_shsec_metadata *md)
248{
249
250	printf("         Magic string: %s\n", md->md_magic);
251	printf("     Metadata version: %u\n", (u_int)md->md_version);
252	printf("          Device name: %s\n", md->md_name);
253	printf("            Device ID: %u\n", (u_int)md->md_id);
254	printf("          Disk number: %u\n", (u_int)md->md_no);
255	printf("Total number of disks: %u\n", (u_int)md->md_all);
256	printf("   Hardcoded provider: %s\n", md->md_provider);
257}
258
259static void
260shsec_dump(struct gctl_req *req)
261{
262	struct g_shsec_metadata md, tmpmd;
263	const char *name;
264	char param[16];
265	int *nargs, error, i;
266
267	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
268	if (nargs == NULL) {
269		gctl_error(req, "No '%s' argument.", "nargs");
270		return;
271	}
272	if (*nargs < 1) {
273		gctl_error(req, "Too few arguments.");
274		return;
275	}
276
277	for (i = 0; i < *nargs; i++) {
278		snprintf(param, sizeof(param), "arg%u", i);
279		name = gctl_get_asciiparam(req, param);
280
281		error = g_metadata_read(name, (u_char *)&tmpmd, sizeof(tmpmd),
282		    G_SHSEC_MAGIC);
283		if (error != 0) {
284			fprintf(stderr, "Can't read metadata from %s: %s.\n",
285			    name, strerror(error));
286			gctl_error(req, "Not fully done.");
287			continue;
288		}
289		shsec_metadata_decode((u_char *)&tmpmd, &md);
290		printf("Metadata on %s:\n", name);
291		shsec_metadata_dump(&md);
292		printf("\n");
293	}
294}
295