xref: /trueos/sys/geom/geom_bsd.c (revision 94d2b7f64912987093f1a98573737a32e4e5d8d1)
1 /*-
2  * Copyright (c) 2002 Poul-Henning Kamp
3  * Copyright (c) 2002 Networks Associates Technology, Inc.
4  * All rights reserved.
5  *
6  * This software was developed for the FreeBSD Project by Poul-Henning Kamp
7  * and NAI Labs, the Security Research Division of Network Associates, Inc.
8  * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the
9  * DARPA CHATS research program.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  * 3. The names of the authors may not be used to endorse or promote
20  *    products derived from this software without specific prior written
21  *    permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  */
35 
36 /*
37  * This is the method for dealing with BSD disklabels.  It has been
38  * extensively (by my standards at least) commented, in the vain hope that
39  * it will serve as the source in future copy&paste operations.
40  */
41 
42 #include <sys/cdefs.h>
43 __FBSDID("$FreeBSD$");
44 
45 #include <sys/param.h>
46 #include <sys/endian.h>
47 #include <sys/systm.h>
48 #include <sys/sysctl.h>
49 #include <sys/kernel.h>
50 #include <sys/fcntl.h>
51 #include <sys/conf.h>
52 #include <sys/bio.h>
53 #include <sys/malloc.h>
54 #include <sys/lock.h>
55 #include <sys/mutex.h>
56 #include <sys/md5.h>
57 #include <sys/errno.h>
58 #include <sys/disklabel.h>
59 #include <sys/gpt.h>
60 #include <sys/proc.h>
61 #include <sys/sbuf.h>
62 #include <sys/uuid.h>
63 #include <geom/geom.h>
64 #include <geom/geom_slice.h>
65 
66 FEATURE(geom_bsd, "GEOM BSD disklabels support");
67 
68 #define	BSD_CLASS_NAME "BSD"
69 
70 #define ALPHA_LABEL_OFFSET	64
71 #define HISTORIC_LABEL_OFFSET	512
72 
73 #define LABELSIZE (148 + 16 * MAXPARTITIONS)
74 
75 static void g_bsd_hotwrite(void *arg, int flag);
76 /*
77  * Our private data about one instance.  All the rest is handled by the
78  * slice code and stored in its softc, so this is just the stuff
79  * specific to BSD disklabels.
80  */
81 struct g_bsd_softc {
82 	off_t	labeloffset;
83 	off_t	mbroffset;
84 	off_t	rawoffset;
85 	struct disklabel ondisk;
86 	u_char	label[LABELSIZE];
87 	u_char	labelsum[16];
88 };
89 
90 /*
91  * Modify our slicer to match proposed disklabel, if possible.
92  * This is where we make sure we don't do something stupid.
93  */
94 static int
g_bsd_modify(struct g_geom * gp,u_char * label)95 g_bsd_modify(struct g_geom *gp, u_char *label)
96 {
97 	int i, error;
98 	struct partition *ppp;
99 	struct g_slicer *gsp;
100 	struct g_consumer *cp;
101 	struct g_bsd_softc *ms;
102 	u_int secsize, u;
103 	off_t rawoffset, o;
104 	struct disklabel dl;
105 	MD5_CTX md5sum;
106 
107 	g_topology_assert();
108 	gsp = gp->softc;
109 	ms = gsp->softc;
110 
111 	error = bsd_disklabel_le_dec(label, &dl, MAXPARTITIONS);
112 	if (error) {
113 		return (error);
114 	}
115 
116 	/* Get dimensions of our device. */
117 	cp = LIST_FIRST(&gp->consumer);
118 	secsize = cp->provider->sectorsize;
119 
120 	/* ... or a smaller sector size. */
121 	if (dl.d_secsize < secsize) {
122 		return (EINVAL);
123 	}
124 
125 	/* ... or a non-multiple sector size. */
126 	if (dl.d_secsize % secsize != 0) {
127 		return (EINVAL);
128 	}
129 
130 	/* Historical braindamage... */
131 	rawoffset = (off_t)dl.d_partitions[RAW_PART].p_offset * dl.d_secsize;
132 
133 	for (i = 0; i < dl.d_npartitions; i++) {
134 		ppp = &dl.d_partitions[i];
135 		if (ppp->p_size == 0)
136 			continue;
137 	        o = (off_t)ppp->p_offset * dl.d_secsize;
138 
139 		if (o < rawoffset)
140 			rawoffset = 0;
141 	}
142 
143 	if (rawoffset != 0 && (off_t)rawoffset != ms->mbroffset)
144 		printf("WARNING: %s expected rawoffset %jd, found %jd\n",
145 		    gp->name,
146 		    (intmax_t)ms->mbroffset/dl.d_secsize,
147 		    (intmax_t)rawoffset/dl.d_secsize);
148 
149 	/* Don't munge open partitions. */
150 	for (i = 0; i < dl.d_npartitions; i++) {
151 		ppp = &dl.d_partitions[i];
152 
153 	        o = (off_t)ppp->p_offset * dl.d_secsize;
154 		if (o == 0)
155 			o = rawoffset;
156 		error = g_slice_config(gp, i, G_SLICE_CONFIG_CHECK,
157 		    o - rawoffset,
158 		    (off_t)ppp->p_size * dl.d_secsize,
159 		     dl.d_secsize,
160 		    "%s%c", gp->name, 'a' + i);
161 		if (error)
162 			return (error);
163 	}
164 
165 	/* Look good, go for it... */
166 	for (u = 0; u < gsp->nslice; u++) {
167 		ppp = &dl.d_partitions[u];
168 	        o = (off_t)ppp->p_offset * dl.d_secsize;
169 		if (o == 0)
170 			o = rawoffset;
171 		g_slice_config(gp, u, G_SLICE_CONFIG_SET,
172 		    o - rawoffset,
173 		    (off_t)ppp->p_size * dl.d_secsize,
174 		     dl.d_secsize,
175 		    "%s%c", gp->name, 'a' + u);
176 	}
177 
178 	/* Update our softc */
179 	ms->ondisk = dl;
180 	if (label != ms->label)
181 		bcopy(label, ms->label, LABELSIZE);
182 	ms->rawoffset = rawoffset;
183 
184 	/*
185 	 * In order to avoid recursively attaching to the same
186 	 * on-disk label (it's usually visible through the 'c'
187 	 * partition) we calculate an MD5 and ask if other BSD's
188 	 * below us love that label.  If they do, we don't.
189 	 */
190 	MD5Init(&md5sum);
191 	MD5Update(&md5sum, ms->label, sizeof(ms->label));
192 	MD5Final(ms->labelsum, &md5sum);
193 
194 	return (0);
195 }
196 
197 /*
198  * This is an internal helper function, called multiple times from the taste
199  * function to try to locate a disklabel on the disk.  More civilized formats
200  * will not need this, as there is only one possible place on disk to look
201  * for the magic spot.
202  */
203 
204 static int
g_bsd_try(struct g_geom * gp,struct g_slicer * gsp,struct g_consumer * cp,int secsize,struct g_bsd_softc * ms,off_t offset)205 g_bsd_try(struct g_geom *gp, struct g_slicer *gsp, struct g_consumer *cp, int secsize, struct g_bsd_softc *ms, off_t offset)
206 {
207 	int error;
208 	u_char *buf;
209 	struct disklabel *dl;
210 	off_t secoff;
211 
212 	/*
213 	 * We need to read entire aligned sectors, and we assume that the
214 	 * disklabel does not span sectors, so one sector is enough.
215 	 */
216 	secoff = offset % secsize;
217 	buf = g_read_data(cp, offset - secoff, secsize, NULL);
218 	if (buf == NULL)
219 		return (ENOENT);
220 
221 	/* Decode into our native format. */
222 	dl = &ms->ondisk;
223 	error = bsd_disklabel_le_dec(buf + secoff, dl, MAXPARTITIONS);
224 	if (!error)
225 		bcopy(buf + secoff, ms->label, LABELSIZE);
226 
227 	/* Remember to free the buffer g_read_data() gave us. */
228 	g_free(buf);
229 
230 	ms->labeloffset = offset;
231 	return (error);
232 }
233 
234 /*
235  * This function writes the current label to disk, possibly updating
236  * the alpha SRM checksum.
237  */
238 
239 static int
g_bsd_writelabel(struct g_geom * gp,u_char * bootcode)240 g_bsd_writelabel(struct g_geom *gp, u_char *bootcode)
241 {
242 	off_t secoff;
243 	u_int secsize;
244 	struct g_consumer *cp;
245 	struct g_slicer *gsp;
246 	struct g_bsd_softc *ms;
247 	u_char *buf;
248 	uint64_t sum;
249 	int error, i;
250 
251 	gsp = gp->softc;
252 	ms = gsp->softc;
253 	cp = LIST_FIRST(&gp->consumer);
254 	/* Get sector size, we need it to read data. */
255 	secsize = cp->provider->sectorsize;
256 	secoff = ms->labeloffset % secsize;
257 	if (bootcode == NULL) {
258 		buf = g_read_data(cp, ms->labeloffset - secoff, secsize, &error);
259 		if (buf == NULL)
260 			return (error);
261 		bcopy(ms->label, buf + secoff, sizeof(ms->label));
262 	} else {
263 		buf = bootcode;
264 		bcopy(ms->label, buf + ms->labeloffset, sizeof(ms->label));
265 	}
266 	if (ms->labeloffset == ALPHA_LABEL_OFFSET) {
267 		sum = 0;
268 		for (i = 0; i < 63; i++)
269 			sum += le64dec(buf + i * 8);
270 		le64enc(buf + 504, sum);
271 	}
272 	if (bootcode == NULL) {
273 		error = g_write_data(cp, ms->labeloffset - secoff, buf, secsize);
274 		g_free(buf);
275 	} else {
276 		error = g_write_data(cp, 0, bootcode, BBSIZE);
277 	}
278 	return(error);
279 }
280 
281 /*
282  * If the user tries to overwrite our disklabel through an open partition
283  * or via a magicwrite config call, we end up here and try to prevent
284  * footshooting as best we can.
285  */
286 static void
g_bsd_hotwrite(void * arg,int flag)287 g_bsd_hotwrite(void *arg, int flag)
288 {
289 	struct bio *bp;
290 	struct g_geom *gp;
291 	struct g_slicer *gsp;
292 	struct g_slice *gsl;
293 	struct g_bsd_softc *ms;
294 	u_char *p;
295 	int error;
296 
297 	g_topology_assert();
298 	/*
299 	 * We should never get canceled, because that would amount to a removal
300 	 * of the geom while there was outstanding I/O requests.
301 	 */
302 	KASSERT(flag != EV_CANCEL, ("g_bsd_hotwrite cancelled"));
303 	bp = arg;
304 	gp = bp->bio_to->geom;
305 	gsp = gp->softc;
306 	ms = gsp->softc;
307 	gsl = &gsp->slices[bp->bio_to->index];
308 	p = (u_char*)bp->bio_data + ms->labeloffset
309 	    - (bp->bio_offset + gsl->offset);
310 	error = g_bsd_modify(gp, p);
311 	if (error) {
312 		g_io_deliver(bp, EPERM);
313 		return;
314 	}
315 	g_slice_finish_hot(bp);
316 }
317 
318 /*-
319  * This start routine is only called for non-trivial requests, all the
320  * trivial ones are handled autonomously by the slice code.
321  * For requests we handle here, we must call the g_io_deliver() on the
322  * bio, and return non-zero to indicate to the slice code that we did so.
323  * This code executes in the "DOWN" I/O path, this means:
324  *    * No sleeping.
325  *    * Don't grab the topology lock.
326  *    * Don't call biowait, g_getattr(), g_setattr() or g_read_data()
327  */
328 static int
g_bsd_ioctl(struct g_provider * pp,u_long cmd,void * data,int fflag,struct thread * td)329 g_bsd_ioctl(struct g_provider *pp, u_long cmd, void *data, int fflag, struct thread *td)
330 {
331 	struct g_geom *gp;
332 	struct g_bsd_softc *ms;
333 	struct g_slicer *gsp;
334 	u_char *label;
335 	int error;
336 
337 	gp = pp->geom;
338 	gsp = gp->softc;
339 	ms = gsp->softc;
340 
341 	switch(cmd) {
342 	case DIOCGDINFO:
343 		/* Return a copy of the disklabel to userland. */
344 		bsd_disklabel_le_dec(ms->label, data, MAXPARTITIONS);
345 		return(0);
346 	case DIOCBSDBB: {
347 		struct g_consumer *cp;
348 		u_char *buf;
349 		void *p;
350 		int error, i;
351 		uint64_t sum;
352 
353 		if (!(fflag & FWRITE))
354 			return (EPERM);
355 		/* The disklabel to set is the ioctl argument. */
356 		buf = g_malloc(BBSIZE, M_WAITOK);
357 		p = *(void **)data;
358 		error = copyin(p, buf, BBSIZE);
359 		if (!error) {
360 			/* XXX: Rude, but supposedly safe */
361 			DROP_GIANT();
362 			g_topology_lock();
363 			/* Validate and modify our slice instance to match. */
364 			error = g_bsd_modify(gp, buf + ms->labeloffset);
365 			if (!error) {
366 				cp = LIST_FIRST(&gp->consumer);
367 				if (ms->labeloffset == ALPHA_LABEL_OFFSET) {
368 					sum = 0;
369 					for (i = 0; i < 63; i++)
370 						sum += le64dec(buf + i * 8);
371 					le64enc(buf + 504, sum);
372 				}
373 				error = g_write_data(cp, 0, buf, BBSIZE);
374 			}
375 			g_topology_unlock();
376 			PICKUP_GIANT();
377 		}
378 		g_free(buf);
379 		return (error);
380 	}
381 	case DIOCSDINFO:
382 	case DIOCWDINFO: {
383 		if (!(fflag & FWRITE))
384 			return (EPERM);
385 		label = g_malloc(LABELSIZE, M_WAITOK);
386 		/* The disklabel to set is the ioctl argument. */
387 		bsd_disklabel_le_enc(label, data);
388 
389 		DROP_GIANT();
390 		g_topology_lock();
391 		/* Validate and modify our slice instance to match. */
392 		error = g_bsd_modify(gp, label);
393 		if (error == 0 && cmd == DIOCWDINFO)
394 			error = g_bsd_writelabel(gp, NULL);
395 		g_topology_unlock();
396 		PICKUP_GIANT();
397 		g_free(label);
398 		return(error);
399 	}
400 	default:
401 		return (ENOIOCTL);
402 	}
403 }
404 
405 static int
g_bsd_start(struct bio * bp)406 g_bsd_start(struct bio *bp)
407 {
408 	struct g_geom *gp;
409 	struct g_bsd_softc *ms;
410 	struct g_slicer *gsp;
411 
412 	gp = bp->bio_to->geom;
413 	gsp = gp->softc;
414 	ms = gsp->softc;
415 	if (bp->bio_cmd == BIO_GETATTR) {
416 		if (g_handleattr(bp, "BSD::labelsum", ms->labelsum,
417 		    sizeof(ms->labelsum)))
418 			return (1);
419 	}
420 	return (0);
421 }
422 
423 /*
424  * Dump configuration information in XML format.
425  * Notice that the function is called once for the geom and once for each
426  * consumer and provider.  We let g_slice_dumpconf() do most of the work.
427  */
428 static void
g_bsd_dumpconf(struct sbuf * sb,const char * indent,struct g_geom * gp,struct g_consumer * cp,struct g_provider * pp)429 g_bsd_dumpconf(struct sbuf *sb, const char *indent, struct g_geom *gp, struct g_consumer *cp, struct g_provider *pp)
430 {
431 	struct g_bsd_softc *ms;
432 	struct g_slicer *gsp;
433 
434 	gsp = gp->softc;
435 	ms = gsp->softc;
436 	g_slice_dumpconf(sb, indent, gp, cp, pp);
437 	if (indent != NULL && pp == NULL && cp == NULL) {
438 		sbuf_printf(sb, "%s<labeloffset>%jd</labeloffset>\n",
439 		    indent, (intmax_t)ms->labeloffset);
440 		sbuf_printf(sb, "%s<rawoffset>%jd</rawoffset>\n",
441 		    indent, (intmax_t)ms->rawoffset);
442 		sbuf_printf(sb, "%s<mbroffset>%jd</mbroffset>\n",
443 		    indent, (intmax_t)ms->mbroffset);
444 	} else if (pp != NULL) {
445 		if (indent == NULL)
446 			sbuf_printf(sb, " ty %d",
447 			    ms->ondisk.d_partitions[pp->index].p_fstype);
448 		else
449 			sbuf_printf(sb, "%s<type>%d</type>\n", indent,
450 			    ms->ondisk.d_partitions[pp->index].p_fstype);
451 	}
452 }
453 
454 /*
455  * The taste function is called from the event-handler, with the topology
456  * lock already held and a provider to examine.  The flags are unused.
457  *
458  * If flags == G_TF_NORMAL, the idea is to take a bite of the provider and
459  * if we find valid, consistent magic on it, build a geom on it.
460  *
461  * There may be cases where the operator would like to put a BSD-geom on
462  * providers which do not meet all of the requirements.  This can be done
463  * by instead passing the G_TF_INSIST flag, which will override these
464  * checks.
465  *
466  * The final flags value is G_TF_TRANSPARENT, which instructs the method
467  * to put a geom on top of the provider and configure it to be as transparent
468  * as possible.  This is not really relevant to the BSD method and therefore
469  * not implemented here.
470  */
471 
472 static struct uuid freebsd_slice = GPT_ENT_TYPE_FREEBSD;
473 
474 static struct g_geom *
g_bsd_taste(struct g_class * mp,struct g_provider * pp,int flags)475 g_bsd_taste(struct g_class *mp, struct g_provider *pp, int flags)
476 {
477 	struct g_geom *gp;
478 	struct g_consumer *cp;
479 	int error, i;
480 	struct g_bsd_softc *ms;
481 	u_int secsize;
482 	struct g_slicer *gsp;
483 	u_char hash[16];
484 	MD5_CTX md5sum;
485 	struct uuid uuid;
486 
487 	g_trace(G_T_TOPOLOGY, "bsd_taste(%s,%s)", mp->name, pp->name);
488 	g_topology_assert();
489 
490 	/* We don't implement transparent inserts. */
491 	if (flags == G_TF_TRANSPARENT)
492 		return (NULL);
493 
494 	/*
495 	 * BSD labels are a subclass of the general "slicing" topology so
496 	 * a lot of the work can be done by the common "slice" code.
497 	 * Create a geom with space for MAXPARTITIONS providers, one consumer
498 	 * and a softc structure for us.  Specify the provider to attach
499 	 * the consumer to and our "start" routine for special requests.
500 	 * The provider is opened with mode (1,0,0) so we can do reads
501 	 * from it.
502 	 */
503 	gp = g_slice_new(mp, MAXPARTITIONS, pp, &cp, &ms,
504 	     sizeof(*ms), g_bsd_start);
505 	if (gp == NULL)
506 		return (NULL);
507 
508 	/* Get the geom_slicer softc from the geom. */
509 	gsp = gp->softc;
510 
511 	/*
512 	 * The do...while loop here allows us to have multiple escapes
513 	 * using a simple "break".  This improves code clarity without
514 	 * ending up in deep nesting and without using goto or come from.
515 	 */
516 	do {
517 		/*
518 		 * If the provider is an MBR we will only auto attach
519 		 * to type 165 slices in the G_TF_NORMAL case.  We will
520 		 * attach to any other type.
521 		 */
522 		error = g_getattr("MBR::type", cp, &i);
523 		if (!error) {
524 			if (i != 165 && flags == G_TF_NORMAL)
525 				break;
526 			error = g_getattr("MBR::offset", cp, &ms->mbroffset);
527 			if (error)
528 				break;
529 		}
530 
531 		/* Same thing if we are inside a PC98 */
532 		error = g_getattr("PC98::type", cp, &i);
533 		if (!error) {
534 			if (i != 0xc494 && flags == G_TF_NORMAL)
535 				break;
536 			error = g_getattr("PC98::offset", cp, &ms->mbroffset);
537 			if (error)
538 				break;
539 		}
540 
541 		/* Same thing if we are inside a GPT */
542 		error = g_getattr("GPT::type", cp, &uuid);
543 		if (!error) {
544 			if (memcmp(&uuid, &freebsd_slice, sizeof(uuid)) != 0 &&
545 			    flags == G_TF_NORMAL)
546 				break;
547 		}
548 
549 		/* Get sector size, we need it to read data. */
550 		secsize = cp->provider->sectorsize;
551 		if (secsize < 512)
552 			break;
553 
554 		/* First look for a label at the start of the second sector. */
555 		error = g_bsd_try(gp, gsp, cp, secsize, ms, secsize);
556 
557 		/*
558 		 * If sector size is not 512 the label still can be at
559 		 * offset 512, not at the start of the second sector. At least
560 		 * it's true for labels created by the FreeBSD's bsdlabel(8).
561 		 */
562 		if (error && secsize != HISTORIC_LABEL_OFFSET)
563 			error = g_bsd_try(gp, gsp, cp, secsize, ms,
564 			    HISTORIC_LABEL_OFFSET);
565 
566 		/* Next, look for alpha labels */
567 		if (error)
568 			error = g_bsd_try(gp, gsp, cp, secsize, ms,
569 			    ALPHA_LABEL_OFFSET);
570 
571 		/* If we didn't find a label, punt. */
572 		if (error)
573 			break;
574 
575 		/*
576 		 * In order to avoid recursively attaching to the same
577 		 * on-disk label (it's usually visible through the 'c'
578 		 * partition) we calculate an MD5 and ask if other BSD's
579 		 * below us love that label.  If they do, we don't.
580 		 */
581 		MD5Init(&md5sum);
582 		MD5Update(&md5sum, ms->label, sizeof(ms->label));
583 		MD5Final(ms->labelsum, &md5sum);
584 
585 		error = g_getattr("BSD::labelsum", cp, &hash);
586 		if (!error && !bcmp(ms->labelsum, hash, sizeof(hash)))
587 			break;
588 
589 		/*
590 		 * Process the found disklabel, and modify our "slice"
591 		 * instance to match it, if possible.
592 		 */
593 		error = g_bsd_modify(gp, ms->label);
594 	} while (0);
595 
596 	/* Success or failure, we can close our provider now. */
597 	g_access(cp, -1, 0, 0);
598 
599 	/* If we have configured any providers, return the new geom. */
600 	if (gsp->nprovider > 0) {
601 		g_slice_conf_hot(gp, 0, ms->labeloffset, LABELSIZE,
602 		    G_SLICE_HOT_ALLOW, G_SLICE_HOT_DENY, G_SLICE_HOT_CALL);
603 		gsp->hot = g_bsd_hotwrite;
604 		return (gp);
605 	}
606 	/*
607 	 * ...else push the "self-destruct" button, by spoiling our own
608 	 * consumer.  This triggers a call to g_slice_spoiled which will
609 	 * dismantle what was setup.
610 	 */
611 	g_slice_spoiled(cp);
612 	return (NULL);
613 }
614 
615 struct h0h0 {
616 	struct g_geom *gp;
617 	struct g_bsd_softc *ms;
618 	u_char *label;
619 	int error;
620 };
621 
622 static void
g_bsd_callconfig(void * arg,int flag)623 g_bsd_callconfig(void *arg, int flag)
624 {
625 	struct h0h0 *hp;
626 
627 	hp = arg;
628 	hp->error = g_bsd_modify(hp->gp, hp->label);
629 	if (!hp->error)
630 		hp->error = g_bsd_writelabel(hp->gp, NULL);
631 }
632 
633 /*
634  * NB! curthread is user process which GCTL'ed.
635  */
636 static void
g_bsd_config(struct gctl_req * req,struct g_class * mp,char const * verb)637 g_bsd_config(struct gctl_req *req, struct g_class *mp, char const *verb)
638 {
639 	u_char *label;
640 	int error;
641 	struct h0h0 h0h0;
642 	struct g_geom *gp;
643 	struct g_slicer *gsp;
644 	struct g_consumer *cp;
645 	struct g_bsd_softc *ms;
646 
647 	g_topology_assert();
648 	gp = gctl_get_geom(req, mp, "geom");
649 	if (gp == NULL)
650 		return;
651 	cp = LIST_FIRST(&gp->consumer);
652 	gsp = gp->softc;
653 	ms = gsp->softc;
654 	if (!strcmp(verb, "read mbroffset")) {
655 		gctl_set_param_err(req, "mbroffset", &ms->mbroffset,
656 		    sizeof(ms->mbroffset));
657 		return;
658 	} else if (!strcmp(verb, "write label")) {
659 		label = gctl_get_paraml(req, "label", LABELSIZE);
660 		if (label == NULL)
661 			return;
662 		h0h0.gp = gp;
663 		h0h0.ms = gsp->softc;
664 		h0h0.label = label;
665 		h0h0.error = -1;
666 		/* XXX: Does this reference register with our selfdestruct code ? */
667 		error = g_access(cp, 1, 1, 1);
668 		if (error) {
669 			gctl_error(req, "could not access consumer");
670 			return;
671 		}
672 		g_bsd_callconfig(&h0h0, 0);
673 		error = h0h0.error;
674 		g_access(cp, -1, -1, -1);
675 	} else if (!strcmp(verb, "write bootcode")) {
676 		label = gctl_get_paraml(req, "bootcode", BBSIZE);
677 		if (label == NULL)
678 			return;
679 		/* XXX: Does this reference register with our selfdestruct code ? */
680 		error = g_access(cp, 1, 1, 1);
681 		if (error) {
682 			gctl_error(req, "could not access consumer");
683 			return;
684 		}
685 		error = g_bsd_writelabel(gp, label);
686 		g_access(cp, -1, -1, -1);
687 	} else {
688 		gctl_error(req, "Unknown verb parameter");
689 	}
690 
691 	return;
692 }
693 
694 /* Finally, register with GEOM infrastructure. */
695 static struct g_class g_bsd_class = {
696 	.name = BSD_CLASS_NAME,
697 	.version = G_VERSION,
698 	.taste = g_bsd_taste,
699 	.ctlreq = g_bsd_config,
700 	.dumpconf = g_bsd_dumpconf,
701 	.ioctl = g_bsd_ioctl,
702 };
703 
704 DECLARE_GEOM_CLASS(g_bsd_class, g_bsd);
705