geom_part.c revision 198478
1169586Smarcel/*-
2179854Smarcel * Copyright (c) 2007, 2008 Marcel Moolenaar
3169586Smarcel * All rights reserved.
4169586Smarcel *
5169586Smarcel * Redistribution and use in source and binary forms, with or without
6169586Smarcel * modification, are permitted provided that the following conditions
7169586Smarcel * are met:
8169586Smarcel * 1. Redistributions of source code must retain the above copyright
9169586Smarcel *    notice, this list of conditions and the following disclaimer.
10169586Smarcel * 2. Redistributions in binary form must reproduce the above copyright
11169586Smarcel *    notice, this list of conditions and the following disclaimer in the
12169586Smarcel *    documentation and/or other materials provided with the distribution.
13169586Smarcel *
14169586Smarcel * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
15169586Smarcel * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16169586Smarcel * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17169586Smarcel * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
18169586Smarcel * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19169586Smarcel * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20169586Smarcel * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21169586Smarcel * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22169586Smarcel * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23169586Smarcel * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24169586Smarcel * SUCH DAMAGE.
25169586Smarcel */
26169586Smarcel
27169586Smarcel#include <sys/cdefs.h>
28169586Smarcel__FBSDID("$FreeBSD: head/sbin/geom/class/part/geom_part.c 198478 2009-10-26 07:43:41Z lulf $");
29169586Smarcel
30185044Smarcel#include <sys/stat.h>
31185044Smarcel
32185044Smarcel#include <assert.h>
33185044Smarcel#include <err.h>
34185044Smarcel#include <errno.h>
35185044Smarcel#include <fcntl.h>
36185044Smarcel#include <libgeom.h>
37185046Smarcel#include <libutil.h>
38185044Smarcel#include <paths.h>
39185044Smarcel#include <stdint.h>
40169586Smarcel#include <stdio.h>
41169586Smarcel#include <stdlib.h>
42169586Smarcel#include <string.h>
43169586Smarcel#include <strings.h>
44185044Smarcel#include <unistd.h>
45169586Smarcel
46169586Smarcel#include "core/geom.h"
47169586Smarcel#include "misc/subr.h"
48169586Smarcel
49179550Smarcel#ifdef STATIC_GEOM_CLASSES
50173313Smarcel#define	PUBSYM(x)	gpart_##x
51173313Smarcel#else
52173313Smarcel#define	PUBSYM(x)	x
53173313Smarcel#endif
54169586Smarcel
55173313Smarceluint32_t PUBSYM(lib_version) = G_LIB_VERSION;
56173313Smarceluint32_t PUBSYM(version) = 0;
57173313Smarcel
58193673Smarcelstatic char autofill[] = "*";
59169586Smarcelstatic char optional[] = "";
60169586Smarcelstatic char flags[] = "C";
61169586Smarcel
62179629Smarcelstatic char bootcode_param[] = "bootcode";
63179629Smarcelstatic char index_param[] = "index";
64179629Smarcelstatic char partcode_param[] = "partcode";
65179629Smarcel
66178180Smarcelstatic void gpart_bootcode(struct gctl_req *, unsigned int);
67185454Smarcelstatic void gpart_issue(struct gctl_req *, unsigned int);
68178180Smarcelstatic void gpart_show(struct gctl_req *, unsigned int);
69172837Smarcel
70173313Smarcelstruct g_command PUBSYM(class_commands)[] = {
71185454Smarcel	{ "add", 0, gpart_issue, {
72193673Smarcel		{ 'b', "start", autofill, G_TYPE_ASCLBA },
73193673Smarcel		{ 's', "size", autofill, G_TYPE_ASCLBA },
74169586Smarcel		{ 't', "type", NULL, G_TYPE_STRING },
75193648Smarcel		{ 'i', index_param, optional, G_TYPE_ASCNUM },
76169586Smarcel		{ 'l', "label", optional, G_TYPE_STRING },
77169586Smarcel		{ 'f', "flags", flags, G_TYPE_STRING },
78169586Smarcel		G_OPT_SENTINEL },
79178180Smarcel	  "geom", NULL
80169586Smarcel	},
81178180Smarcel	{ "bootcode", 0, gpart_bootcode, {
82179629Smarcel		{ 'b', bootcode_param, optional, G_TYPE_STRING },
83179629Smarcel		{ 'p', partcode_param, optional, G_TYPE_STRING },
84193648Smarcel		{ 'i', index_param, optional, G_TYPE_ASCNUM },
85178180Smarcel		{ 'f', "flags", flags, G_TYPE_STRING },
86178180Smarcel		G_OPT_SENTINEL },
87178180Smarcel	  "geom", NULL
88178180Smarcel	},
89185454Smarcel	{ "commit", 0, gpart_issue, G_NULL_OPTS, "geom", NULL },
90185454Smarcel	{ "create", 0, gpart_issue, {
91169586Smarcel		{ 's', "scheme", NULL, G_TYPE_STRING },
92193648Smarcel		{ 'n', "entries", optional, G_TYPE_ASCNUM },
93169586Smarcel		{ 'f', "flags", flags, G_TYPE_STRING },
94169586Smarcel		G_OPT_SENTINEL },
95169586Smarcel	  "provider", NULL
96169586Smarcel	},
97185454Smarcel	{ "delete", 0, gpart_issue, {
98193648Smarcel		{ 'i', index_param, NULL, G_TYPE_ASCNUM },
99169586Smarcel		{ 'f', "flags", flags, G_TYPE_STRING },
100169586Smarcel		G_OPT_SENTINEL },
101169586Smarcel	  "geom", NULL
102169586Smarcel	},
103185454Smarcel	{ "destroy", 0, gpart_issue, {
104169586Smarcel		{ 'f', "flags", flags, G_TYPE_STRING },
105169586Smarcel		G_OPT_SENTINEL },
106169586Smarcel	  "geom", NULL },
107185454Smarcel	{ "modify", 0, gpart_issue, {
108193648Smarcel		{ 'i', index_param, NULL, G_TYPE_ASCNUM },
109169586Smarcel		{ 'l', "label", optional, G_TYPE_STRING },
110169586Smarcel		{ 't', "type", optional, G_TYPE_STRING },
111169586Smarcel		{ 'f', "flags", flags, G_TYPE_STRING },
112169586Smarcel		G_OPT_SENTINEL },
113169586Smarcel	  "geom", NULL
114169586Smarcel	},
115185454Smarcel	{ "set", 0, gpart_issue, {
116179854Smarcel		{ 'a', "attrib", NULL, G_TYPE_STRING },
117193648Smarcel		{ 'i', index_param, NULL, G_TYPE_ASCNUM },
118179854Smarcel		{ 'f', "flags", flags, G_TYPE_STRING },
119179854Smarcel		G_OPT_SENTINEL },
120179854Smarcel	  "geom", NULL
121179854Smarcel	},
122179769Smarcel	{ "show", 0, gpart_show, {
123179769Smarcel		{ 'l', "show_label", NULL, G_TYPE_BOOL },
124179769Smarcel		{ 'r', "show_rawtype", NULL, G_TYPE_BOOL },
125179769Smarcel		G_OPT_SENTINEL },
126179769Smarcel	  NULL, "[-lr] [geom ...]"
127179769Smarcel	},
128185454Smarcel	{ "undo", 0, gpart_issue, G_NULL_OPTS, "geom", NULL },
129185454Smarcel	{ "unset", 0, gpart_issue, {
130179854Smarcel		{ 'a', "attrib", NULL, G_TYPE_STRING },
131193648Smarcel		{ 'i', index_param, NULL, G_TYPE_ASCNUM },
132179854Smarcel		{ 'f', "flags", flags, G_TYPE_STRING },
133179854Smarcel		G_OPT_SENTINEL },
134179854Smarcel	  "geom", NULL
135179854Smarcel        },
136169586Smarcel	G_CMD_SENTINEL
137169586Smarcel};
138172837Smarcel
139172837Smarcelstatic struct gclass *
140172837Smarcelfind_class(struct gmesh *mesh, const char *name)
141172837Smarcel{
142172837Smarcel	struct gclass *classp;
143172837Smarcel
144172837Smarcel	LIST_FOREACH(classp, &mesh->lg_class, lg_class) {
145172837Smarcel		if (strcmp(classp->lg_name, name) == 0)
146172837Smarcel			return (classp);
147172837Smarcel	}
148172837Smarcel	return (NULL);
149172837Smarcel}
150172837Smarcel
151172837Smarcelstatic struct ggeom *
152172837Smarcelfind_geom(struct gclass *classp, const char *name)
153172837Smarcel{
154172837Smarcel	struct ggeom *gp;
155172837Smarcel
156172837Smarcel	LIST_FOREACH(gp, &classp->lg_geom, lg_geom) {
157172837Smarcel		if (strcmp(gp->lg_name, name) == 0)
158172837Smarcel			return (gp);
159172837Smarcel	}
160172837Smarcel	return (NULL);
161172837Smarcel}
162172837Smarcel
163172837Smarcelstatic const char *
164172837Smarcelfind_geomcfg(struct ggeom *gp, const char *cfg)
165172837Smarcel{
166172837Smarcel	struct gconfig *gc;
167172837Smarcel
168172837Smarcel	LIST_FOREACH(gc, &gp->lg_config, lg_config) {
169172837Smarcel		if (!strcmp(gc->lg_name, cfg))
170172837Smarcel			return (gc->lg_val);
171172837Smarcel	}
172172837Smarcel	return (NULL);
173172837Smarcel}
174172837Smarcel
175172837Smarcelstatic const char *
176172837Smarcelfind_provcfg(struct gprovider *pp, const char *cfg)
177172837Smarcel{
178172837Smarcel	struct gconfig *gc;
179172837Smarcel
180172837Smarcel	LIST_FOREACH(gc, &pp->lg_config, lg_config) {
181172837Smarcel		if (!strcmp(gc->lg_name, cfg))
182172837Smarcel			return (gc->lg_val);
183172837Smarcel	}
184172837Smarcel	return (NULL);
185172837Smarcel}
186172837Smarcel
187172837Smarcelstatic struct gprovider *
188172837Smarcelfind_provider(struct ggeom *gp, unsigned long long minsector)
189172837Smarcel{
190172837Smarcel	struct gprovider *pp, *bestpp;
191188330Smarcel	const char *s;
192172837Smarcel	unsigned long long sector, bestsector;
193172837Smarcel
194172837Smarcel	bestpp = NULL;
195198478Slulf	bestsector = 0;
196172837Smarcel	LIST_FOREACH(pp, &gp->lg_provider, lg_provider) {
197188330Smarcel		s = find_provcfg(pp, "start");
198188330Smarcel		if (s == NULL) {
199188330Smarcel			s = find_provcfg(pp, "offset");
200188330Smarcel			sector = atoll(s) / pp->lg_sectorsize;
201188330Smarcel		} else
202188330Smarcel			sector = atoll(s);
203188330Smarcel
204172837Smarcel		if (sector < minsector)
205172837Smarcel			continue;
206172837Smarcel		if (bestpp != NULL && sector >= bestsector)
207172837Smarcel			continue;
208188330Smarcel
209172837Smarcel		bestpp = pp;
210172837Smarcel		bestsector = sector;
211172837Smarcel	}
212172837Smarcel	return (bestpp);
213172837Smarcel}
214172837Smarcel
215172837Smarcelstatic const char *
216185046Smarcelfmtsize(int64_t rawsz)
217172837Smarcel{
218185046Smarcel	static char buf[5];
219172837Smarcel
220185046Smarcel	humanize_number(buf, sizeof(buf), rawsz, "", HN_AUTOSCALE,
221185046Smarcel	    HN_B | HN_NOSPACE | HN_DECIMAL);
222172837Smarcel	return (buf);
223172837Smarcel}
224172837Smarcel
225179854Smarcelstatic const char *
226179854Smarcelfmtattrib(struct gprovider *pp)
227179854Smarcel{
228184070Smarcel	static char buf[128];
229184070Smarcel	struct gconfig *gc;
230184070Smarcel	u_int idx;
231179854Smarcel
232184070Smarcel	buf[0] = '\0';
233184070Smarcel	idx = 0;
234184070Smarcel	LIST_FOREACH(gc, &pp->lg_config, lg_config) {
235184070Smarcel		if (strcmp(gc->lg_name, "attrib") != 0)
236184070Smarcel			continue;
237184070Smarcel		idx += snprintf(buf + idx, sizeof(buf) - idx, "%s%s",
238184070Smarcel		    (idx == 0) ? " [" : ",", gc->lg_val);
239184070Smarcel	}
240184070Smarcel	if (idx > 0)
241184070Smarcel		snprintf(buf + idx, sizeof(buf) - idx, "] ");
242179854Smarcel	return (buf);
243179854Smarcel}
244179854Smarcel
245193673Smarcelstatic int
246193673Smarcelgpart_autofill(struct gctl_req *req)
247193673Smarcel{
248193673Smarcel	struct gmesh mesh;
249193673Smarcel	struct gclass *cp;
250193673Smarcel	struct ggeom *gp;
251193673Smarcel	struct gprovider *pp;
252193673Smarcel	unsigned long long first, last;
253193673Smarcel	unsigned long long size, start;
254193673Smarcel	unsigned long long lba, len, grade;
255193673Smarcel	const char *s;
256193673Smarcel	char *val;
257193673Smarcel	int error, has_size, has_start;
258193673Smarcel
259193673Smarcel	s = gctl_get_ascii(req, "verb");
260193673Smarcel	if (strcmp(s, "add") != 0)
261193673Smarcel		return (0);
262193673Smarcel
263193673Smarcel	s = gctl_get_ascii(req, "size");
264193673Smarcel	has_size = (*s == '*') ? 0 : 1;
265193673Smarcel	size = (has_size) ? (unsigned long long)atoll(s) : 0ULL;
266193673Smarcel
267193673Smarcel	s = gctl_get_ascii(req, "start");
268193673Smarcel	has_start = (*s == '*') ? 0 : 1;
269193673Smarcel	start = (has_start) ? (unsigned long long)atoll(s) : ~0ULL;
270193673Smarcel
271193673Smarcel	/* No autofill necessary. */
272193673Smarcel	if (has_size && has_start)
273193673Smarcel		return (0);
274193673Smarcel
275193673Smarcel	error = geom_gettree(&mesh);
276193673Smarcel	if (error)
277193673Smarcel		return (error);
278196278Smarcel	s = gctl_get_ascii(req, "class");
279196278Smarcel	if (s == NULL)
280196278Smarcel		abort();
281196278Smarcel	cp = find_class(&mesh, s);
282196278Smarcel	if (cp == NULL)
283196278Smarcel		errx(EXIT_FAILURE, "Class %s not found.", s);
284196278Smarcel	s = gctl_get_ascii(req, "geom");
285196278Smarcel	if (s == NULL)
286196278Smarcel		abort();
287196278Smarcel	gp = find_geom(cp, s);
288196278Smarcel	if (gp == NULL)
289196278Smarcel		errx(EXIT_FAILURE, "No such geom: %s.", s);
290193673Smarcel	first = atoll(find_geomcfg(gp, "first"));
291193673Smarcel	last = atoll(find_geomcfg(gp, "last"));
292193673Smarcel	grade = ~0ULL;
293193673Smarcel	while ((pp = find_provider(gp, first)) != NULL) {
294193673Smarcel		s = find_provcfg(pp, "start");
295193673Smarcel		if (s == NULL) {
296193673Smarcel			s = find_provcfg(pp, "offset");
297193673Smarcel			lba = atoll(s) / pp->lg_sectorsize;
298193673Smarcel		} else
299193673Smarcel			lba = atoll(s);
300193673Smarcel
301193673Smarcel		if (first < lba) {
302193673Smarcel			/* Free space [first, lba> */
303193673Smarcel			len = lba - first;
304193673Smarcel			if (has_size) {
305193673Smarcel				if (len >= size && len - size < grade) {
306193673Smarcel					start = first;
307193673Smarcel					grade = len - size;
308193673Smarcel				}
309193673Smarcel			} else if (has_start) {
310193673Smarcel				if (start >= first && start < lba) {
311193673Smarcel					size = lba - start;
312193673Smarcel					grade = start - first;
313193673Smarcel				}
314193673Smarcel			} else {
315193673Smarcel				if (grade == ~0ULL || len > size) {
316193673Smarcel					start = first;
317193673Smarcel					size = len;
318193673Smarcel					grade = 0;
319193673Smarcel				}
320193673Smarcel			}
321193673Smarcel		}
322193673Smarcel
323193673Smarcel		s = find_provcfg(pp, "end");
324193673Smarcel		if (s == NULL) {
325193673Smarcel			s = find_provcfg(pp, "length");
326193673Smarcel			first = lba + atoll(s) / pp->lg_sectorsize;
327193673Smarcel		} else
328193673Smarcel			first = atoll(s) + 1;
329193673Smarcel	}
330193673Smarcel	if (first <= last) {
331193673Smarcel		/* Free space [first-last] */
332193673Smarcel		len = last - first + 1;
333193673Smarcel		if (has_size) {
334193673Smarcel			if (len >= size && len - size < grade) {
335193673Smarcel				start = first;
336193673Smarcel				grade = len - size;
337193673Smarcel			}
338193673Smarcel		} else if (has_start) {
339193673Smarcel			if (start >= first && start <= last) {
340193673Smarcel				size = last - start + 1;
341193673Smarcel				grade = start - first;
342193673Smarcel			}
343193673Smarcel		} else {
344193673Smarcel			if (grade == ~0ULL || len > size) {
345193673Smarcel				start = first;
346193673Smarcel				size = len;
347193673Smarcel				grade = 0;
348193673Smarcel			}
349193673Smarcel		}
350193673Smarcel	}
351193673Smarcel
352193673Smarcel	if (grade == ~0ULL)
353193673Smarcel		return (ENOSPC);
354193673Smarcel
355193673Smarcel	if (!has_size) {
356193728Sjhb		asprintf(&val, "%llu", size);
357193673Smarcel		if (val == NULL)
358193673Smarcel			return (ENOMEM);
359193673Smarcel		gctl_change_param(req, "size", -1, val);
360193673Smarcel	}
361193673Smarcel	if (!has_start) {
362193728Sjhb		asprintf(&val, "%llu", start);
363193673Smarcel		if (val == NULL)
364193673Smarcel			return (ENOMEM);
365193673Smarcel		gctl_change_param(req, "start", -1, val);
366193673Smarcel	}
367193673Smarcel	return (0);
368193673Smarcel}
369193673Smarcel
370172837Smarcelstatic void
371179769Smarcelgpart_show_geom(struct ggeom *gp, const char *element)
372172837Smarcel{
373172837Smarcel	struct gprovider *pp;
374172837Smarcel	const char *s, *scheme;
375172837Smarcel	unsigned long long first, last, sector, end;
376188330Smarcel	unsigned long long length, secsz;
377172837Smarcel	int idx, wblocks, wname;
378172837Smarcel
379172837Smarcel	scheme = find_geomcfg(gp, "scheme");
380172837Smarcel	s = find_geomcfg(gp, "first");
381172837Smarcel	first = atoll(s);
382172837Smarcel	s = find_geomcfg(gp, "last");
383172837Smarcel	last = atoll(s);
384172837Smarcel	wblocks = strlen(s);
385172837Smarcel	wname = strlen(gp->lg_name);
386172837Smarcel	pp = LIST_FIRST(&gp->lg_consumer)->lg_provider;
387172837Smarcel	secsz = pp->lg_sectorsize;
388172837Smarcel	printf("=>%*llu  %*llu  %*s  %s  (%s)\n",
389172837Smarcel	    wblocks, first, wblocks, (last - first + 1),
390172837Smarcel	    wname, gp->lg_name,
391172837Smarcel	    scheme, fmtsize(pp->lg_mediasize));
392172837Smarcel
393172837Smarcel	while ((pp = find_provider(gp, first)) != NULL) {
394188330Smarcel		s = find_provcfg(pp, "start");
395188330Smarcel		if (s == NULL) {
396188330Smarcel			s = find_provcfg(pp, "offset");
397188330Smarcel			sector = atoll(s) / secsz;
398188330Smarcel		} else
399188330Smarcel			sector = atoll(s);
400188330Smarcel
401188330Smarcel		s = find_provcfg(pp, "end");
402188330Smarcel		if (s == NULL) {
403188330Smarcel			s = find_provcfg(pp, "length");
404188330Smarcel			length = atoll(s) / secsz;
405188330Smarcel			end = sector + length - 1;
406188330Smarcel		} else {
407188330Smarcel			end = atoll(s);
408188330Smarcel			length = end - sector + 1;
409188330Smarcel		}
410172837Smarcel		s = find_provcfg(pp, "index");
411172837Smarcel		idx = atoi(s);
412172837Smarcel		if (first < sector) {
413172837Smarcel			printf("  %*llu  %*llu  %*s  - free -  (%s)\n",
414172837Smarcel			    wblocks, first, wblocks, sector - first,
415172837Smarcel			    wname, "",
416172837Smarcel			    fmtsize((sector - first) * secsz));
417172837Smarcel		}
418179854Smarcel		printf("  %*llu  %*llu  %*d  %s %s (%s)\n",
419188330Smarcel		    wblocks, sector, wblocks, length,
420179854Smarcel		    wname, idx, find_provcfg(pp, element),
421179854Smarcel		    fmtattrib(pp), fmtsize(pp->lg_mediasize));
422188330Smarcel		first = end + 1;
423172837Smarcel	}
424172837Smarcel	if (first <= last) {
425188330Smarcel		length = last - first + 1;
426172837Smarcel		printf("  %*llu  %*llu  %*s  - free -  (%s)\n",
427188330Smarcel		    wblocks, first, wblocks, length,
428172837Smarcel		    wname, "",
429188330Smarcel		    fmtsize(length * secsz));
430172837Smarcel	}
431172837Smarcel	printf("\n");
432172837Smarcel}
433172837Smarcel
434179769Smarcelstatic int
435179769Smarcelgpart_show_hasopt(struct gctl_req *req, const char *opt, const char *elt)
436179769Smarcel{
437179769Smarcel
438179769Smarcel	if (!gctl_get_int(req, opt))
439179769Smarcel		return (0);
440179769Smarcel
441179769Smarcel	if (elt != NULL)
442179769Smarcel		errx(EXIT_FAILURE, "-l and -r are mutually exclusive");
443179769Smarcel
444179769Smarcel	return (1);
445179769Smarcel}
446179769Smarcel
447172837Smarcelstatic void
448178180Smarcelgpart_show(struct gctl_req *req, unsigned int fl __unused)
449172837Smarcel{
450172837Smarcel	struct gmesh mesh;
451172837Smarcel	struct gclass *classp;
452172837Smarcel	struct ggeom *gp;
453179769Smarcel	const char *element, *name;
454172837Smarcel	int error, i, nargs;
455172837Smarcel
456179769Smarcel	element = NULL;
457179769Smarcel	if (gpart_show_hasopt(req, "show_label", element))
458179769Smarcel		element = "label";
459179769Smarcel	if (gpart_show_hasopt(req, "show_rawtype", element))
460179769Smarcel		element = "rawtype";
461179769Smarcel	if (element == NULL)
462179769Smarcel		element = "type";
463179769Smarcel
464172837Smarcel	name = gctl_get_ascii(req, "class");
465172837Smarcel	if (name == NULL)
466172837Smarcel		abort();
467172837Smarcel	error = geom_gettree(&mesh);
468172837Smarcel	if (error != 0)
469172837Smarcel		errc(EXIT_FAILURE, error, "Cannot get GEOM tree");
470172837Smarcel	classp = find_class(&mesh, name);
471172837Smarcel	if (classp == NULL) {
472172837Smarcel		geom_deletetree(&mesh);
473172837Smarcel		errx(EXIT_FAILURE, "Class %s not found.", name);
474172837Smarcel	}
475172837Smarcel	nargs = gctl_get_int(req, "nargs");
476172837Smarcel	if (nargs > 0) {
477172837Smarcel		for (i = 0; i < nargs; i++) {
478172837Smarcel			name = gctl_get_ascii(req, "arg%d", i);
479172837Smarcel			gp = find_geom(classp, name);
480172837Smarcel			if (gp != NULL)
481179769Smarcel				gpart_show_geom(gp, element);
482172837Smarcel			else
483172837Smarcel				errx(EXIT_FAILURE, "No such geom: %s.", name);
484172837Smarcel		}
485172837Smarcel	} else {
486172837Smarcel		LIST_FOREACH(gp, &classp->lg_geom, lg_geom) {
487179769Smarcel			gpart_show_geom(gp, element);
488172837Smarcel		}
489172837Smarcel	}
490172837Smarcel	geom_deletetree(&mesh);
491172837Smarcel}
492178180Smarcel
493179629Smarcelstatic void *
494179629Smarcelgpart_bootfile_read(const char *bootfile, ssize_t *size)
495178180Smarcel{
496178180Smarcel	struct stat sb;
497178180Smarcel	void *code;
498179629Smarcel	int fd;
499178180Smarcel
500179629Smarcel	if (stat(bootfile, &sb) == -1)
501179629Smarcel		err(EXIT_FAILURE, "%s", bootfile);
502178180Smarcel	if (!S_ISREG(sb.st_mode))
503178180Smarcel		errx(EXIT_FAILURE, "%s: not a regular file", bootfile);
504179629Smarcel	if (sb.st_size == 0)
505179629Smarcel		errx(EXIT_FAILURE, "%s: empty file", bootfile);
506179629Smarcel	if (*size > 0 && sb.st_size >= *size)
507179629Smarcel		errx(EXIT_FAILURE, "%s: file too big (%zu limit)", bootfile,
508179629Smarcel		    *size);
509178180Smarcel
510179629Smarcel	*size = sb.st_size;
511178180Smarcel
512178180Smarcel	fd = open(bootfile, O_RDONLY);
513178180Smarcel	if (fd == -1)
514179629Smarcel		err(EXIT_FAILURE, "%s", bootfile);
515179629Smarcel	code = malloc(*size);
516178180Smarcel	if (code == NULL)
517179629Smarcel		err(EXIT_FAILURE, NULL);
518179629Smarcel	if (read(fd, code, *size) != *size)
519179629Smarcel		err(EXIT_FAILURE, "%s", bootfile);
520178180Smarcel	close(fd);
521178180Smarcel
522179629Smarcel	return (code);
523178180Smarcel}
524179629Smarcel
525179629Smarcelstatic void
526179629Smarcelgpart_write_partcode(struct gctl_req *req, int idx, void *code, ssize_t size)
527179629Smarcel{
528179629Smarcel	char dsf[128];
529179629Smarcel	struct gmesh mesh;
530179629Smarcel	struct gclass *classp;
531179629Smarcel	struct ggeom *gp;
532179629Smarcel	struct gprovider *pp;
533179629Smarcel	const char *s;
534185038Smarcel	char *buf;
535185038Smarcel	off_t bsize;
536179629Smarcel	int error, fd;
537179629Smarcel
538179629Smarcel	s = gctl_get_ascii(req, "class");
539179629Smarcel	if (s == NULL)
540179629Smarcel		abort();
541179629Smarcel	error = geom_gettree(&mesh);
542179629Smarcel	if (error != 0)
543179629Smarcel		errc(EXIT_FAILURE, error, "Cannot get GEOM tree");
544179629Smarcel	classp = find_class(&mesh, s);
545179629Smarcel	if (classp == NULL) {
546179629Smarcel		geom_deletetree(&mesh);
547179629Smarcel		errx(EXIT_FAILURE, "Class %s not found.", s);
548179629Smarcel	}
549179629Smarcel	s = gctl_get_ascii(req, "geom");
550196278Smarcel	if (s == NULL)
551196278Smarcel		abort();
552179629Smarcel	gp = find_geom(classp, s);
553179629Smarcel	if (gp == NULL)
554179629Smarcel		errx(EXIT_FAILURE, "No such geom: %s.", s);
555179629Smarcel
556179629Smarcel	LIST_FOREACH(pp, &gp->lg_provider, lg_provider) {
557179629Smarcel		s = find_provcfg(pp, "index");
558179629Smarcel		if (s == NULL)
559179629Smarcel			continue;
560179629Smarcel		if (atoi(s) == idx)
561179629Smarcel			break;
562179629Smarcel	}
563179629Smarcel
564179629Smarcel	if (pp != NULL) {
565179629Smarcel		snprintf(dsf, sizeof(dsf), "/dev/%s", pp->lg_name);
566179629Smarcel		fd = open(dsf, O_WRONLY);
567179629Smarcel		if (fd == -1)
568179629Smarcel			err(EXIT_FAILURE, "%s", dsf);
569179629Smarcel		if (lseek(fd, size, SEEK_SET) != size)
570179629Smarcel			errx(EXIT_FAILURE, "%s: not enough space", dsf);
571179629Smarcel		if (lseek(fd, 0, SEEK_SET) != 0)
572179629Smarcel			err(EXIT_FAILURE, "%s", dsf);
573185038Smarcel
574185038Smarcel		/*
575185038Smarcel		 * When writing to a disk device, the write must be
576185038Smarcel		 * sector aligned and not write to any partial sectors,
577185038Smarcel		 * so round up the buffer size to the next sector and zero it.
578185038Smarcel		 */
579185038Smarcel		bsize = (size + pp->lg_sectorsize - 1) /
580185038Smarcel		    pp->lg_sectorsize * pp->lg_sectorsize;
581185038Smarcel		buf = calloc(1, bsize);
582185038Smarcel		if (buf == NULL)
583179629Smarcel			err(EXIT_FAILURE, "%s", dsf);
584185038Smarcel		bcopy(code, buf, size);
585185038Smarcel		if (write(fd, buf, bsize) != bsize)
586185038Smarcel			err(EXIT_FAILURE, "%s", dsf);
587185038Smarcel		free(buf);
588179629Smarcel		close(fd);
589179629Smarcel	} else
590179629Smarcel		errx(EXIT_FAILURE, "invalid partition index");
591179629Smarcel
592179629Smarcel	geom_deletetree(&mesh);
593179629Smarcel}
594179629Smarcel
595179629Smarcelstatic void
596185454Smarcelgpart_bootcode(struct gctl_req *req, unsigned int fl)
597179629Smarcel{
598179629Smarcel	const char *s;
599179629Smarcel	char *sp;
600179629Smarcel	void *bootcode, *partcode;
601179629Smarcel	size_t bootsize, partsize;
602179629Smarcel	int error, idx;
603179629Smarcel
604179629Smarcel	if (gctl_has_param(req, bootcode_param)) {
605179629Smarcel		s = gctl_get_ascii(req, bootcode_param);
606179629Smarcel		bootsize = 64 * 1024;		/* Arbitrary limit. */
607179629Smarcel		bootcode = gpart_bootfile_read(s, &bootsize);
608179629Smarcel		error = gctl_change_param(req, bootcode_param, bootsize,
609179629Smarcel		    bootcode);
610179629Smarcel		if (error)
611179629Smarcel			errc(EXIT_FAILURE, error, "internal error");
612179629Smarcel	} else {
613179629Smarcel		bootcode = NULL;
614179629Smarcel		bootsize = 0;
615179629Smarcel	}
616179629Smarcel
617179629Smarcel	if (gctl_has_param(req, partcode_param)) {
618179629Smarcel		s = gctl_get_ascii(req, partcode_param);
619179629Smarcel		partsize = bootsize * 1024;
620179629Smarcel		partcode = gpart_bootfile_read(s, &partsize);
621179629Smarcel		error = gctl_delete_param(req, partcode_param);
622179629Smarcel		if (error)
623179629Smarcel			errc(EXIT_FAILURE, error, "internal error");
624179629Smarcel	} else {
625179629Smarcel		partcode = NULL;
626179629Smarcel		partsize = 0;
627179629Smarcel	}
628179629Smarcel
629179629Smarcel	if (gctl_has_param(req, index_param)) {
630179629Smarcel		if (partcode == NULL)
631179629Smarcel			errx(EXIT_FAILURE, "-i is only valid with -p");
632179629Smarcel		s = gctl_get_ascii(req, index_param);
633179629Smarcel		idx = strtol(s, &sp, 10);
634179629Smarcel		if (idx < 1 || *s == '\0' || *sp != '\0')
635179629Smarcel			errx(EXIT_FAILURE, "invalid partition index");
636179629Smarcel		error = gctl_delete_param(req, index_param);
637179629Smarcel		if (error)
638179629Smarcel			errc(EXIT_FAILURE, error, "internal error");
639179629Smarcel	} else
640179629Smarcel		idx = 0;
641179629Smarcel
642179629Smarcel	if (partcode != NULL) {
643179629Smarcel		if (idx == 0)
644179629Smarcel			errx(EXIT_FAILURE, "missing -i option");
645179629Smarcel		gpart_write_partcode(req, idx, partcode, partsize);
646179629Smarcel	} else {
647179629Smarcel		if (bootcode == NULL)
648179629Smarcel			errx(EXIT_FAILURE, "no -b nor -p");
649179629Smarcel	}
650179629Smarcel
651185454Smarcel	if (bootcode != NULL)
652185454Smarcel		gpart_issue(req, fl);
653185454Smarcel}
654185454Smarcel
655185454Smarcelstatic void
656185454Smarcelgpart_issue(struct gctl_req *req, unsigned int fl __unused)
657185454Smarcel{
658185454Smarcel	char buf[4096];
659185454Smarcel	char *errmsg;
660185454Smarcel	const char *errstr;
661185495Smarcel	int error, status;
662185454Smarcel
663193673Smarcel	/* autofill parameters (if applicable). */
664193673Smarcel	error = gpart_autofill(req);
665193673Smarcel	if (error) {
666193673Smarcel		warnc(error, "autofill");
667193673Smarcel		status = EXIT_FAILURE;
668193673Smarcel		goto done;
669193673Smarcel	}
670193673Smarcel
671185454Smarcel	bzero(buf, sizeof(buf));
672185454Smarcel	gctl_rw_param(req, "output", sizeof(buf), buf);
673185454Smarcel	errstr = gctl_issue(req);
674185454Smarcel	if (errstr == NULL || errstr[0] == '\0') {
675185454Smarcel		if (buf[0] != '\0')
676185454Smarcel			printf("%s", buf);
677185495Smarcel		status = EXIT_SUCCESS;
678185495Smarcel		goto done;
679179629Smarcel	}
680185454Smarcel
681185454Smarcel	error = strtol(errstr, &errmsg, 0);
682185496Smarcel	if (errmsg != errstr) {
683185496Smarcel		while (errmsg[0] == ' ')
684185496Smarcel			errmsg++;
685185496Smarcel		if (errmsg[0] != '\0')
686185496Smarcel			warnc(error, "%s", errmsg);
687185496Smarcel		else
688185496Smarcel			warnc(error, NULL);
689185496Smarcel	} else
690185496Smarcel		warnx("%s", errmsg);
691185495Smarcel
692185495Smarcel	status = EXIT_FAILURE;
693185495Smarcel
694185495Smarcel done:
695185495Smarcel	gctl_free(req);
696185495Smarcel	exit(status);
697179629Smarcel}
698