geom_shsec.c revision 140074
1167802Sjkim/*-
2167802Sjkim * Copyright (c) 2004 Pawel Jakub Dawidek <pjd@FreeBSD.org>
3167802Sjkim * All rights reserved.
4167802Sjkim *
5167802Sjkim * Redistribution and use in source and binary forms, with or without
6167802Sjkim * modification, are permitted provided that the following conditions
7217365Sjkim * are met:
8217365Sjkim * 1. Redistributions of source code must retain the above copyright
9167802Sjkim *    notice, this list of conditions and the following disclaimer.
10167802Sjkim * 2. Redistributions in binary form must reproduce the above copyright
11217365Sjkim *    notice, this list of conditions and the following disclaimer in the
12217365Sjkim *    documentation and/or other materials provided with the distribution.
13217365Sjkim *
14217365Sjkim * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
15217365Sjkim * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16217365Sjkim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17217365Sjkim * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
18217365Sjkim * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19217365Sjkim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20217365Sjkim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21217365Sjkim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22217365Sjkim * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23217365Sjkim * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24217365Sjkim * SUCH DAMAGE.
25167802Sjkim */
26217365Sjkim
27217365Sjkim#include <sys/cdefs.h>
28217365Sjkim__FBSDID("$FreeBSD: head/sbin/geom/class/shsec/geom_shsec.c 140074 2005-01-11 18:06:44Z pjd $");
29167802Sjkim
30217365Sjkim#include <sys/param.h>
31217365Sjkim#include <errno.h>
32217365Sjkim#include <paths.h>
33217365Sjkim#include <stdio.h>
34217365Sjkim#include <stdlib.h>
35217365Sjkim#include <stdint.h>
36217365Sjkim#include <string.h>
37217365Sjkim#include <strings.h>
38217365Sjkim#include <assert.h>
39217365Sjkim#include <libgeom.h>
40217365Sjkim#include <geom/shsec/g_shsec.h>
41217365Sjkim
42217365Sjkim#include "core/geom.h"
43167802Sjkim#include "misc/subr.h"
44193529Sjkim
45193529Sjkim
46193529Sjkimuint32_t lib_version = G_LIB_VERSION;
47193529Sjkimuint32_t version = G_SHSEC_VERSION;
48167802Sjkim
49167802Sjkimstatic void shsec_main(struct gctl_req *req, unsigned flags);
50167802Sjkimstatic void shsec_clear(struct gctl_req *req);
51167802Sjkimstatic void shsec_dump(struct gctl_req *req);
52167802Sjkimstatic void shsec_label(struct gctl_req *req);
53167802Sjkim
54167802Sjkimstruct g_command class_commands[] = {
55218590Sjkim	{ "clear", G_FLAG_VERBOSE, shsec_main, G_NULL_OPTS },
56218590Sjkim	{ "dump", 0, shsec_main, G_NULL_OPTS },
57218590Sjkim	{ "label", G_FLAG_VERBOSE | G_FLAG_LOADKLD, shsec_main,
58218590Sjkim	    {
59218590Sjkim		{ 'h', "hardcode", NULL, G_TYPE_NONE },
60218590Sjkim		G_OPT_SENTINEL
61167802Sjkim	    }
62167802Sjkim	},
63167802Sjkim	{ "stop", G_FLAG_VERBOSE, NULL,
64167802Sjkim	    {
65167802Sjkim		{ 'f', "force", NULL, G_TYPE_NONE },
66167802Sjkim		G_OPT_SENTINEL
67209746Sjkim	    }
68209746Sjkim	},
69167802Sjkim	G_CMD_SENTINEL
70167802Sjkim};
71167802Sjkim
72167802Sjkimstatic int verbose = 0;
73167802Sjkim
74167802Sjkimvoid usage(const char *name);
75167802Sjkimvoid
76167802Sjkimusage(const char *name)
77167802Sjkim{
78209746Sjkim
79209746Sjkim	fprintf(stderr, "usage: %s label [-hv] <name> <prov> <prov> [prov [...]]\n", name);
80209746Sjkim	fprintf(stderr, "       %s stop [-fv] <name> [name [...]]\n", name);
81167802Sjkim	fprintf(stderr, "       %s clear [-v] <prov> [prov [...]]\n", name);
82167802Sjkim	fprintf(stderr, "       %s dump <prov> [prov [...]]\n", name);
83167802Sjkim}
84167802Sjkim
85167802Sjkimstatic void
86167802Sjkimshsec_main(struct gctl_req *req, unsigned flags)
87209746Sjkim{
88167802Sjkim	const char *name;
89209746Sjkim
90209746Sjkim	if ((flags & G_FLAG_VERBOSE) != 0)
91209746Sjkim		verbose = 1;
92167802Sjkim
93209746Sjkim	name = gctl_get_asciiparam(req, "verb");
94209746Sjkim	if (name == NULL) {
95209746Sjkim		gctl_error(req, "No '%s' argument.", "verb");
96209746Sjkim		return;
97209746Sjkim	}
98209746Sjkim	if (strcmp(name, "label") == 0)
99209746Sjkim		shsec_label(req);
100209746Sjkim	else if (strcmp(name, "clear") == 0)
101209746Sjkim		shsec_clear(req);
102167802Sjkim	else if (strcmp(name, "dump") == 0)
103209746Sjkim		shsec_dump(req);
104209746Sjkim	else
105209746Sjkim		gctl_error(req, "Unknown command: %s.", name);
106209746Sjkim}
107209746Sjkim
108209746Sjkimstatic void
109209746Sjkimshsec_label(struct gctl_req *req)
110209746Sjkim{
111209746Sjkim	struct g_shsec_metadata md;
112209746Sjkim	off_t compsize, msize;
113209746Sjkim	u_char sector[512];
114167802Sjkim	unsigned i, ssize, secsize;
115167802Sjkim	const char *name;
116167802Sjkim	char param[16];
117167802Sjkim	int *hardcode, *nargs, error;
118167802Sjkim
119167802Sjkim	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
120167802Sjkim	if (nargs == NULL) {
121167802Sjkim		gctl_error(req, "No '%s' argument.", "nargs");
122167802Sjkim		return;
123167802Sjkim	}
124167802Sjkim	if (*nargs <= 2) {
125167802Sjkim		gctl_error(req, "Too few arguments.");
126167802Sjkim		return;
127167802Sjkim	}
128167802Sjkim	hardcode = gctl_get_paraml(req, "hardcode", sizeof(*hardcode));
129167802Sjkim	if (hardcode == NULL) {
130167802Sjkim		gctl_error(req, "No '%s' argument.", "hardcode");
131167802Sjkim		return;
132167802Sjkim	}
133167802Sjkim
134167802Sjkim	/*
135167802Sjkim	 * Clear last sector first to spoil all components if device exists.
136167802Sjkim	 */
137167802Sjkim	compsize = 0;
138167802Sjkim	secsize = 0;
139167802Sjkim	for (i = 1; i < (unsigned)*nargs; i++) {
140167802Sjkim		snprintf(param, sizeof(param), "arg%u", i);
141167802Sjkim		name = gctl_get_asciiparam(req, param);
142167802Sjkim
143167802Sjkim		msize = g_get_mediasize(name);
144167802Sjkim		ssize = g_get_sectorsize(name);
145167802Sjkim		if (msize == 0 || ssize == 0) {
146167802Sjkim			gctl_error(req, "Can't get informations about %s: %s.",
147167802Sjkim			    name, strerror(errno));
148167802Sjkim			return;
149167802Sjkim		}
150167802Sjkim		msize -= ssize;
151167802Sjkim		if (compsize == 0 || (compsize > 0 && msize < compsize))
152167802Sjkim			compsize = msize;
153167802Sjkim		if (secsize == 0)
154167802Sjkim			secsize = ssize;
155167802Sjkim		else
156167802Sjkim			secsize = g_lcm(secsize, ssize);
157167802Sjkim
158167802Sjkim		error = g_metadata_clear(name, NULL);
159167802Sjkim		if (error != 0) {
160167802Sjkim			gctl_error(req, "Can't store metadata on %s: %s.", name,
161167802Sjkim			    strerror(error));
162167802Sjkim			return;
163167802Sjkim		}
164167802Sjkim	}
165167802Sjkim
166167802Sjkim	strlcpy(md.md_magic, G_SHSEC_MAGIC, sizeof(md.md_magic));
167167802Sjkim	md.md_version = G_SHSEC_VERSION;
168167802Sjkim	name = gctl_get_asciiparam(req, "arg0");
169167802Sjkim	if (name == NULL) {
170167802Sjkim		gctl_error(req, "No 'arg%u' argument.", 0);
171167802Sjkim		return;
172167802Sjkim	}
173167802Sjkim	strlcpy(md.md_name, name, sizeof(md.md_name));
174167802Sjkim	md.md_id = arc4random();
175167802Sjkim	md.md_all = *nargs - 1;
176167802Sjkim
177167802Sjkim	/*
178167802Sjkim	 * Ok, store metadata.
179167802Sjkim	 */
180167802Sjkim	for (i = 1; i < (unsigned)*nargs; i++) {
181167802Sjkim		snprintf(param, sizeof(param), "arg%u", i);
182167802Sjkim		name = gctl_get_asciiparam(req, param);
183167802Sjkim
184167802Sjkim		msize = g_get_mediasize(name) - g_get_sectorsize(name);
185167802Sjkim		if (compsize < msize) {
186167802Sjkim			fprintf(stderr,
187167802Sjkim			    "warning: %s: only %jd bytes from %jd bytes used.\n",
188167802Sjkim			    name, (intmax_t)compsize, (intmax_t)msize);
189167802Sjkim		}
190167802Sjkim
191167802Sjkim		md.md_no = i - 1;
192167802Sjkim		if (!*hardcode)
193167802Sjkim			bzero(md.md_provider, sizeof(md.md_provider));
194167802Sjkim		else {
195167802Sjkim			if (strncmp(name, _PATH_DEV, strlen(_PATH_DEV)) == 0)
196167802Sjkim				name += strlen(_PATH_DEV);
197167802Sjkim			strlcpy(md.md_provider, name, sizeof(md.md_provider));
198167802Sjkim		}
199167802Sjkim		shsec_metadata_encode(&md, sector);
200167802Sjkim		error = g_metadata_store(name, sector, sizeof(sector));
201167802Sjkim		if (error != 0) {
202167802Sjkim			fprintf(stderr, "Can't store metadata on %s: %s.\n",
203167802Sjkim			    name, strerror(error));
204167802Sjkim			gctl_error(req, "Not fully done.");
205167802Sjkim			continue;
206167802Sjkim		}
207167802Sjkim		if (verbose)
208167802Sjkim			printf("Metadata value stored on %s.\n", name);
209167802Sjkim	}
210218590Sjkim}
211218590Sjkim
212218590Sjkimstatic void
213218590Sjkimshsec_clear(struct gctl_req *req)
214167802Sjkim{
215167802Sjkim	const char *name;
216167802Sjkim	char param[16];
217167802Sjkim	unsigned i;
218167802Sjkim	int *nargs, error;
219167802Sjkim
220167802Sjkim	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
221218590Sjkim	if (nargs == NULL) {
222167802Sjkim		gctl_error(req, "No '%s' argument.", "nargs");
223167802Sjkim		return;
224167802Sjkim	}
225218590Sjkim	if (*nargs < 1) {
226167802Sjkim		gctl_error(req, "Too few arguments.");
227218590Sjkim		return;
228218590Sjkim	}
229167802Sjkim
230167802Sjkim	for (i = 0; i < (unsigned)*nargs; i++) {
231167802Sjkim		snprintf(param, sizeof(param), "arg%u", i);
232167802Sjkim		name = gctl_get_asciiparam(req, param);
233218590Sjkim
234193529Sjkim		error = g_metadata_clear(name, G_SHSEC_MAGIC);
235218590Sjkim		if (error != 0) {
236193529Sjkim			fprintf(stderr, "Can't clear metadata on %s: %s.\n",
237193529Sjkim			    name, strerror(error));
238193529Sjkim			gctl_error(req, "Not fully done.");
239193529Sjkim			continue;
240167802Sjkim		}
241167802Sjkim		if (verbose)
242167802Sjkim			printf("Metadata cleared on %s.\n", name);
243218590Sjkim	}
244218590Sjkim}
245218590Sjkim
246218590Sjkimstatic void
247167802Sjkimshsec_metadata_dump(const struct g_shsec_metadata *md)
248167802Sjkim{
249167802Sjkim
250167802Sjkim	printf("         Magic string: %s\n", md->md_magic);
251167802Sjkim	printf("     Metadata version: %u\n", (u_int)md->md_version);
252218590Sjkim	printf("          Device name: %s\n", md->md_name);
253218590Sjkim	printf("            Device ID: %u\n", (u_int)md->md_id);
254218590Sjkim	printf("          Disk number: %u\n", (u_int)md->md_no);
255218590Sjkim	printf("Total number of disks: %u\n", (u_int)md->md_all);
256218590Sjkim	printf("   Hardcoded provider: %s\n", md->md_provider);
257218590Sjkim}
258218590Sjkim
259218590Sjkimstatic void
260218590Sjkimshsec_dump(struct gctl_req *req)
261218590Sjkim{
262218590Sjkim	struct g_shsec_metadata md, tmpmd;
263218590Sjkim	const char *name;
264218590Sjkim	char param[16];
265218590Sjkim	int *nargs, error, i;
266218590Sjkim
267218590Sjkim	nargs = gctl_get_paraml(req, "nargs", sizeof(*nargs));
268218590Sjkim	if (nargs == NULL) {
269218590Sjkim		gctl_error(req, "No '%s' argument.", "nargs");
270218590Sjkim		return;
271218590Sjkim	}
272218590Sjkim	if (*nargs < 1) {
273218590Sjkim		gctl_error(req, "Too few arguments.");
274218590Sjkim		return;
275218590Sjkim	}
276218590Sjkim
277218590Sjkim	for (i = 0; i < *nargs; i++) {
278218590Sjkim		snprintf(param, sizeof(param), "arg%u", i);
279218590Sjkim		name = gctl_get_asciiparam(req, param);
280218590Sjkim
281218590Sjkim		error = g_metadata_read(name, (u_char *)&tmpmd, sizeof(tmpmd),
282218590Sjkim		    G_SHSEC_MAGIC);
283218590Sjkim		if (error != 0) {
284218590Sjkim			fprintf(stderr, "Can't read metadata from %s: %s.\n",
285218590Sjkim			    name, strerror(error));
286218590Sjkim			gctl_error(req, "Not fully done.");
287218590Sjkim			continue;
288218590Sjkim		}
289218590Sjkim		shsec_metadata_decode((u_char *)&tmpmd, &md);
290218590Sjkim		printf("Metadata on %s:\n", name);
291218590Sjkim		shsec_metadata_dump(&md);
292218590Sjkim		printf("\n");
293218590Sjkim	}
294218590Sjkim}
295218590Sjkim