1163048Sru/*-
2163048Sru * Copyright (c) 2006 Ruslan Ermilov <ru@FreeBSD.org>
3163048Sru * All rights reserved.
4163048Sru *
5163048Sru * Redistribution and use in source and binary forms, with or without
6163048Sru * modification, are permitted provided that the following conditions
7163048Sru * are met:
8163048Sru * 1. Redistributions of source code must retain the above copyright
9163048Sru *    notice, this list of conditions and the following disclaimer.
10163048Sru * 2. Redistributions in binary form must reproduce the above copyright
11163048Sru *    notice, this list of conditions and the following disclaimer in the
12163048Sru *    documentation and/or other materials provided with the distribution.
13163048Sru *
14163048Sru * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15163048Sru * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16163048Sru * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17163048Sru * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18163048Sru * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19163048Sru * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20163048Sru * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21163048Sru * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22163048Sru * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23163048Sru * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24163048Sru * SUCH DAMAGE.
25163048Sru */
26163048Sru
27163048Sru#include <sys/cdefs.h>
28163048Sru__FBSDID("$FreeBSD: releng/10.2/sbin/geom/class/cache/geom_cache.c 212554 2010-09-13 13:48:18Z pjd $");
29163048Sru
30163048Sru#include <errno.h>
31163048Sru#include <stdio.h>
32163048Sru#include <stdint.h>
33163048Sru#include <string.h>
34163048Sru#include <strings.h>
35163048Sru#include <libgeom.h>
36163048Sru#include <geom/cache/g_cache.h>
37163048Sru
38163048Sru#include "core/geom.h"
39163048Sru#include "misc/subr.h"
40163048Sru
41163048Sru
42163048Sruuint32_t lib_version = G_LIB_VERSION;
43163048Sruuint32_t version = G_CACHE_VERSION;
44163048Sru
45212554Spjd#define	GCACHE_BLOCKSIZE	"65536"
46212554Spjd#define	GCACHE_SIZE		"100"
47163048Sru
48163048Srustatic void cache_main(struct gctl_req *req, unsigned flags);
49163048Srustatic void cache_clear(struct gctl_req *req);
50163048Srustatic void cache_dump(struct gctl_req *req);
51163048Srustatic void cache_label(struct gctl_req *req);
52163048Sru
53163048Srustruct g_command class_commands[] = {
54212554Spjd	{ "clear", G_FLAG_VERBOSE, cache_main, G_NULL_OPTS,
55163048Sru	    "[-v] prov ..."
56163048Sru	},
57163048Sru	{ "configure", G_FLAG_VERBOSE, NULL,
58163048Sru	    {
59212554Spjd		{ 'b', "blocksize", "0", G_TYPE_NUMBER },
60212554Spjd		{ 's', "size", "0", G_TYPE_NUMBER },
61163048Sru		G_OPT_SENTINEL
62163048Sru	    },
63212554Spjd	    "[-v] [-b blocksize] [-s size] name"
64163048Sru	},
65163048Sru	{ "create", G_FLAG_VERBOSE | G_FLAG_LOADKLD, NULL,
66163048Sru	    {
67212554Spjd		{ 'b', "blocksize", GCACHE_BLOCKSIZE, G_TYPE_NUMBER },
68212554Spjd		{ 's', "size", GCACHE_SIZE, G_TYPE_NUMBER },
69163048Sru		G_OPT_SENTINEL
70163048Sru	    },
71212554Spjd	    "[-v] [-b blocksize] [-s size] name prov"
72163048Sru	},
73163048Sru	{ "destroy", G_FLAG_VERBOSE, NULL,
74163048Sru	    {
75163887Spjd		{ 'f', "force", NULL, G_TYPE_BOOL },
76163048Sru		G_OPT_SENTINEL
77163048Sru	    },
78212554Spjd	    "[-fv] name ..."
79163048Sru	},
80212554Spjd	{ "dump", 0, cache_main, G_NULL_OPTS,
81163048Sru	    "prov ..."
82163048Sru	},
83163048Sru	{ "label", G_FLAG_VERBOSE | G_FLAG_LOADKLD, cache_main,
84163048Sru	    {
85212554Spjd		{ 'b', "blocksize", GCACHE_BLOCKSIZE, G_TYPE_NUMBER },
86212554Spjd		{ 's', "size", GCACHE_SIZE, G_TYPE_NUMBER },
87163048Sru		G_OPT_SENTINEL
88163048Sru	    },
89212554Spjd	    "[-v] [-b blocksize] [-s size] name prov"
90163048Sru	},
91212554Spjd	{ "reset", G_FLAG_VERBOSE, NULL, G_NULL_OPTS,
92163048Sru	    "[-v] name ..."
93163048Sru	},
94163048Sru	{ "stop", G_FLAG_VERBOSE, NULL,
95163048Sru	    {
96163887Spjd		{ 'f', "force", NULL, G_TYPE_BOOL },
97163048Sru		G_OPT_SENTINEL
98163048Sru	    },
99212554Spjd	    "[-fv] name ..."
100163048Sru	},
101163048Sru	G_CMD_SENTINEL
102163048Sru};
103163048Sru
104163048Srustatic int verbose = 0;
105163048Sru
106163048Srustatic void
107163048Srucache_main(struct gctl_req *req, unsigned flags)
108163048Sru{
109163048Sru	const char *name;
110163048Sru
111163048Sru	if ((flags & G_FLAG_VERBOSE) != 0)
112163048Sru		verbose = 1;
113163048Sru
114163048Sru	name = gctl_get_ascii(req, "verb");
115163048Sru	if (name == NULL) {
116163048Sru		gctl_error(req, "No '%s' argument.", "verb");
117163048Sru		return;
118163048Sru	}
119163048Sru	if (strcmp(name, "label") == 0)
120163048Sru		cache_label(req);
121163048Sru	else if (strcmp(name, "clear") == 0)
122163048Sru		cache_clear(req);
123163048Sru	else if (strcmp(name, "dump") == 0)
124163048Sru		cache_dump(req);
125163048Sru	else
126163048Sru		gctl_error(req, "Unknown command: %s.", name);
127163048Sru}
128163048Sru
129163048Srustatic void
130163048Srucache_label(struct gctl_req *req)
131163048Sru{
132163048Sru	struct g_cache_metadata md;
133163048Sru	u_char sector[512];
134163048Sru	const char *name;
135163048Sru	int error, nargs;
136163048Sru	intmax_t val;
137163048Sru
138163048Sru	nargs = gctl_get_int(req, "nargs");
139163048Sru	if (nargs != 2) {
140163048Sru		gctl_error(req, "Invalid number of arguments.");
141163048Sru		return;
142163048Sru	}
143163048Sru
144163048Sru	strlcpy(md.md_magic, G_CACHE_MAGIC, sizeof(md.md_magic));
145163048Sru	md.md_version = G_CACHE_VERSION;
146163048Sru	name = gctl_get_ascii(req, "arg0");
147163048Sru	strlcpy(md.md_name, name, sizeof(md.md_name));
148163048Sru	val = gctl_get_intmax(req, "blocksize");
149163048Sru	md.md_bsize = val;
150163048Sru	val = gctl_get_intmax(req, "size");
151163048Sru	md.md_size = val;
152163048Sru
153163048Sru	name = gctl_get_ascii(req, "arg1");
154163048Sru	md.md_provsize = g_get_mediasize(name);
155163048Sru	if (md.md_provsize == 0) {
156163048Sru		fprintf(stderr, "Can't get mediasize of %s: %s.\n",
157163048Sru		    name, strerror(errno));
158163048Sru		gctl_error(req, "Not fully done.");
159163048Sru		return;
160163048Sru	}
161163048Sru	cache_metadata_encode(&md, sector);
162163048Sru	error = g_metadata_store(name, sector, sizeof(sector));
163163048Sru	if (error != 0) {
164163048Sru		fprintf(stderr, "Can't store metadata on %s: %s.\n",
165163048Sru		    name, strerror(error));
166163048Sru		gctl_error(req, "Not fully done.");
167163048Sru		return;
168163048Sru	}
169163048Sru	if (verbose)
170163048Sru		printf("Metadata value stored on %s.\n", name);
171163048Sru}
172163048Sru
173163048Srustatic void
174163048Srucache_clear(struct gctl_req *req)
175163048Sru{
176163048Sru	const char *name;
177163048Sru	int error, i, nargs;
178163048Sru
179163048Sru	nargs = gctl_get_int(req, "nargs");
180163048Sru	if (nargs < 1) {
181163048Sru		gctl_error(req, "Too few arguments.");
182163048Sru		return;
183163048Sru	}
184163048Sru
185163048Sru	for (i = 0; i < nargs; i++) {
186163048Sru		name = gctl_get_ascii(req, "arg%d", i);
187163048Sru		error = g_metadata_clear(name, G_CACHE_MAGIC);
188163048Sru		if (error != 0) {
189163048Sru			fprintf(stderr, "Can't clear metadata on %s: %s.\n",
190163048Sru			    name, strerror(error));
191163048Sru			gctl_error(req, "Not fully done.");
192163048Sru			continue;
193163048Sru		}
194163048Sru		if (verbose)
195163048Sru			printf("Metadata cleared on %s.\n", name);
196163048Sru	}
197163048Sru}
198163048Sru
199163048Srustatic void
200163048Srucache_metadata_dump(const struct g_cache_metadata *md)
201163048Sru{
202163048Sru
203163048Sru	printf("         Magic string: %s\n", md->md_magic);
204163048Sru	printf("     Metadata version: %u\n", (u_int)md->md_version);
205163048Sru	printf("          Device name: %s\n", md->md_name);
206163048Sru	printf("           Block size: %u\n", (u_int)md->md_bsize);
207163048Sru	printf("           Cache size: %u\n", (u_int)md->md_size);
208163048Sru	printf("        Provider size: %ju\n", (uintmax_t)md->md_provsize);
209163048Sru}
210163048Sru
211163048Srustatic void
212163048Srucache_dump(struct gctl_req *req)
213163048Sru{
214163048Sru	struct g_cache_metadata md, tmpmd;
215163048Sru	const char *name;
216163048Sru	int error, i, nargs;
217163048Sru
218163048Sru	nargs = gctl_get_int(req, "nargs");
219163048Sru	if (nargs < 1) {
220163048Sru		gctl_error(req, "Too few arguments.");
221163048Sru		return;
222163048Sru	}
223163048Sru
224163048Sru	for (i = 0; i < nargs; i++) {
225163048Sru		name = gctl_get_ascii(req, "arg%d", i);
226163048Sru		error = g_metadata_read(name, (u_char *)&tmpmd, sizeof(tmpmd),
227163048Sru		    G_CACHE_MAGIC);
228163048Sru		if (error != 0) {
229163048Sru			fprintf(stderr, "Can't read metadata from %s: %s.\n",
230163048Sru			    name, strerror(error));
231163048Sru			gctl_error(req, "Not fully done.");
232163048Sru			continue;
233163048Sru		}
234163048Sru		cache_metadata_decode((u_char *)&tmpmd, &md);
235163048Sru		printf("Metadata on %s:\n", name);
236163048Sru		cache_metadata_dump(&md);
237163048Sru		printf("\n");
238163048Sru	}
239163048Sru}
240