geom_part.c revision 172856
1/*-
2 * Copyright (c) 2007 Marcel Moolenaar
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/part/geom_part.c 172856 2007-10-21 19:38:21Z marcel $");
29
30#include <stdio.h>
31#include <stdint.h>
32#include <stdlib.h>
33#include <unistd.h>
34#include <err.h>
35#include <fcntl.h>
36#include <string.h>
37#include <strings.h>
38#include <libgeom.h>
39#include <paths.h>
40#include <errno.h>
41#include <assert.h>
42
43#include "core/geom.h"
44#include "misc/subr.h"
45
46uint32_t lib_version = G_LIB_VERSION;
47uint32_t version = 0;
48
49static char optional[] = "";
50static char flags[] = "C";
51
52static void gpart_show(struct gctl_req *, unsigned);
53
54struct g_command class_commands[] = {
55	{ "add", 0, NULL, {
56		{ 'b', "start", NULL, G_TYPE_STRING },
57		{ 's', "size", NULL, G_TYPE_STRING },
58		{ 't', "type", NULL, G_TYPE_STRING },
59		{ 'i', "index", optional, G_TYPE_STRING },
60		{ 'l', "label", optional, G_TYPE_STRING },
61		{ 'f', "flags", flags, G_TYPE_STRING },
62		G_OPT_SENTINEL },
63	  "geom", NULL,
64	},
65	{ "commit", 0, NULL, G_NULL_OPTS, "geom", NULL },
66	{ "create", 0, NULL, {
67		{ 's', "scheme", NULL, G_TYPE_STRING },
68		{ 'n', "entries", optional, G_TYPE_STRING },
69		{ 'f', "flags", flags, G_TYPE_STRING },
70		G_OPT_SENTINEL },
71	  "provider", NULL
72	},
73	{ "delete", 0, NULL, {
74		{ 'i', "index", NULL, G_TYPE_STRING },
75		{ 'f', "flags", flags, G_TYPE_STRING },
76		G_OPT_SENTINEL },
77	  "geom", NULL
78	},
79	{ "destroy", 0, NULL, {
80		{ 'f', "flags", flags, G_TYPE_STRING },
81		G_OPT_SENTINEL },
82	  "geom", NULL },
83	{ "modify", 0, NULL, {
84		{ 'i', "index", NULL, G_TYPE_STRING },
85		{ 'l', "label", optional, G_TYPE_STRING },
86		{ 't', "type", optional, G_TYPE_STRING },
87		{ 'f', "flags", flags, G_TYPE_STRING },
88		G_OPT_SENTINEL },
89	  "geom", NULL
90	},
91	{ "show", 0, gpart_show, G_NULL_OPTS, NULL, "[geom ...]" },
92	{ "undo", 0, NULL, G_NULL_OPTS, "geom", NULL },
93	G_CMD_SENTINEL
94};
95
96static struct gclass *
97find_class(struct gmesh *mesh, const char *name)
98{
99	struct gclass *classp;
100
101	LIST_FOREACH(classp, &mesh->lg_class, lg_class) {
102		if (strcmp(classp->lg_name, name) == 0)
103			return (classp);
104	}
105	return (NULL);
106}
107
108static struct ggeom *
109find_geom(struct gclass *classp, const char *name)
110{
111	struct ggeom *gp;
112
113	LIST_FOREACH(gp, &classp->lg_geom, lg_geom) {
114		if (strcmp(gp->lg_name, name) == 0)
115			return (gp);
116	}
117	return (NULL);
118}
119
120static const char *
121find_geomcfg(struct ggeom *gp, const char *cfg)
122{
123	struct gconfig *gc;
124
125	LIST_FOREACH(gc, &gp->lg_config, lg_config) {
126		if (!strcmp(gc->lg_name, cfg))
127			return (gc->lg_val);
128	}
129	return (NULL);
130}
131
132static const char *
133find_provcfg(struct gprovider *pp, const char *cfg)
134{
135	struct gconfig *gc;
136
137	LIST_FOREACH(gc, &pp->lg_config, lg_config) {
138		if (!strcmp(gc->lg_name, cfg))
139			return (gc->lg_val);
140	}
141	return (NULL);
142}
143
144static struct gprovider *
145find_provider(struct ggeom *gp, unsigned long long minsector)
146{
147	struct gprovider *pp, *bestpp;
148	unsigned long long offset;
149	unsigned long long sector, bestsector;
150
151	bestpp = NULL;
152	LIST_FOREACH(pp, &gp->lg_provider, lg_provider) {
153		offset = atoll(find_provcfg(pp, "offset"));
154		sector = offset / pp->lg_sectorsize;
155		if (sector < minsector)
156			continue;
157		if (bestpp != NULL && sector >= bestsector)
158			continue;
159		bestpp = pp;
160		bestsector = sector;
161	}
162	return (bestpp);
163}
164
165static const char *
166fmtsize(long double rawsz)
167{
168	static char buf[32];
169	static const char *sfx[] = { "B", "KB", "MB", "GB", "TB" };
170	long double sz;
171	int sfxidx;
172
173	sfxidx = 0;
174	sz = (long double)rawsz;
175	while (sfxidx < 4 && sz > 1099.0) {
176		sz /= 1000;
177		sfxidx++;
178	}
179
180	sprintf(buf, "%.1Lf%s", sz, sfx[sfxidx]);
181	return (buf);
182}
183
184static void
185gpart_show_geom(struct ggeom *gp)
186{
187	struct gprovider *pp;
188	const char *s, *scheme;
189	unsigned long long first, last, sector, end;
190	unsigned long long offset, length, secsz;
191	int idx, wblocks, wname;
192
193	scheme = find_geomcfg(gp, "scheme");
194	s = find_geomcfg(gp, "first");
195	first = atoll(s);
196	s = find_geomcfg(gp, "last");
197	last = atoll(s);
198	wblocks = strlen(s);
199	wname = strlen(gp->lg_name);
200	pp = LIST_FIRST(&gp->lg_consumer)->lg_provider;
201	secsz = pp->lg_sectorsize;
202	printf("=>%*llu  %*llu  %*s  %s  (%s)\n",
203	    wblocks, first, wblocks, (last - first + 1),
204	    wname, gp->lg_name,
205	    scheme, fmtsize(pp->lg_mediasize));
206
207	while ((pp = find_provider(gp, first)) != NULL) {
208		s = find_provcfg(pp, "offset");
209		offset = atoll(s);
210		sector = offset / secsz;
211		s = find_provcfg(pp, "length");
212		length = atoll(s);
213		s = find_provcfg(pp, "index");
214		idx = atoi(s);
215		end = sector + length / secsz;
216		if (first < sector) {
217			printf("  %*llu  %*llu  %*s  - free -  (%s)\n",
218			    wblocks, first, wblocks, sector - first,
219			    wname, "",
220			    fmtsize((sector - first) * secsz));
221		}
222		printf("  %*llu  %*llu  %*d  %s  (%s)\n",
223		    wblocks, sector, wblocks, end - sector,
224		    wname, idx,
225		    find_provcfg(pp, "type"), fmtsize(pp->lg_mediasize));
226		first = end;
227	}
228	if (first <= last) {
229		printf("  %*llu  %*llu  %*s  - free -  (%s)\n",
230		    wblocks, first, wblocks, last - first + 1,
231		    wname, "",
232		    fmtsize((last - first + 1) * secsz));
233	}
234	printf("\n");
235}
236
237static void
238gpart_show(struct gctl_req *req, unsigned fl __unused)
239{
240	struct gmesh mesh;
241	struct gclass *classp;
242	struct ggeom *gp;
243	const char *name;
244	int error, i, nargs;
245
246	name = gctl_get_ascii(req, "class");
247	if (name == NULL)
248		abort();
249	error = geom_gettree(&mesh);
250	if (error != 0)
251		errc(EXIT_FAILURE, error, "Cannot get GEOM tree");
252	classp = find_class(&mesh, name);
253	if (classp == NULL) {
254		geom_deletetree(&mesh);
255		errx(EXIT_FAILURE, "Class %s not found.", name);
256	}
257	nargs = gctl_get_int(req, "nargs");
258	if (nargs > 0) {
259		for (i = 0; i < nargs; i++) {
260			name = gctl_get_ascii(req, "arg%d", i);
261			gp = find_geom(classp, name);
262			if (gp != NULL)
263				gpart_show_geom(gp);
264			else
265				errx(EXIT_FAILURE, "No such geom: %s.", name);
266		}
267	} else {
268		LIST_FOREACH(gp, &classp->lg_geom, lg_geom) {
269			gpart_show_geom(gp);
270		}
271	}
272	geom_deletetree(&mesh);
273}
274