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