g_part_apm.c revision 170362
1166551Smarcel/*-
2166551Smarcel * Copyright (c) 2006, 2007 Marcel Moolenaar
3166551Smarcel * All rights reserved.
4166551Smarcel *
5166551Smarcel * Redistribution and use in source and binary forms, with or without
6166551Smarcel * modification, are permitted provided that the following conditions
7166551Smarcel * are met:
8166551Smarcel *
9166551Smarcel * 1. Redistributions of source code must retain the above copyright
10166551Smarcel *    notice, this list of conditions and the following disclaimer.
11166551Smarcel * 2. Redistributions in binary form must reproduce the above copyright
12166551Smarcel *    notice, this list of conditions and the following disclaimer in the
13166551Smarcel *    documentation and/or other materials provided with the distribution.
14166551Smarcel *
15166551Smarcel * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16166551Smarcel * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17166551Smarcel * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18166551Smarcel * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19166551Smarcel * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20166551Smarcel * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21166551Smarcel * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22166551Smarcel * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23166551Smarcel * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24166551Smarcel * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25166551Smarcel */
26166551Smarcel
27166551Smarcel#include <sys/cdefs.h>
28166551Smarcel__FBSDID("$FreeBSD: head/sys/geom/part/g_part_apm.c 170362 2007-06-06 05:06:14Z marcel $");
29166551Smarcel
30166551Smarcel#include <sys/param.h>
31166551Smarcel#include <sys/apm.h>
32166551Smarcel#include <sys/bio.h>
33166551Smarcel#include <sys/diskmbr.h>
34166551Smarcel#include <sys/endian.h>
35166551Smarcel#include <sys/kernel.h>
36166551Smarcel#include <sys/kobj.h>
37166551Smarcel#include <sys/limits.h>
38166551Smarcel#include <sys/lock.h>
39166551Smarcel#include <sys/malloc.h>
40166551Smarcel#include <sys/mutex.h>
41166551Smarcel#include <sys/queue.h>
42166551Smarcel#include <sys/sbuf.h>
43166551Smarcel#include <sys/systm.h>
44166551Smarcel#include <geom/geom.h>
45166551Smarcel#include <geom/part/g_part.h>
46166551Smarcel
47166551Smarcel#include "g_part_if.h"
48166551Smarcel
49166551Smarcelstruct g_part_apm_table {
50166551Smarcel	struct g_part_table	base;
51166551Smarcel	struct apm_ddr		ddr;
52166551Smarcel	struct apm_ent		self;
53166551Smarcel};
54166551Smarcel
55166551Smarcelstruct g_part_apm_entry {
56166551Smarcel	struct g_part_entry	base;
57166551Smarcel	struct apm_ent		ent;
58166551Smarcel};
59166551Smarcel
60166551Smarcelstatic int g_part_apm_add(struct g_part_table *, struct g_part_entry *,
61166551Smarcel    struct g_part_parms *);
62166551Smarcelstatic int g_part_apm_create(struct g_part_table *, struct g_part_parms *);
63166551Smarcelstatic int g_part_apm_destroy(struct g_part_table *, struct g_part_parms *);
64166551Smarcelstatic int g_part_apm_dumpto(struct g_part_table *, struct g_part_entry *);
65166551Smarcelstatic int g_part_apm_modify(struct g_part_table *, struct g_part_entry *,
66166551Smarcel    struct g_part_parms *);
67166551Smarcelstatic char *g_part_apm_name(struct g_part_table *, struct g_part_entry *,
68166551Smarcel    char *, size_t);
69166551Smarcelstatic int g_part_apm_probe(struct g_part_table *, struct g_consumer *);
70166551Smarcelstatic int g_part_apm_read(struct g_part_table *, struct g_consumer *);
71166551Smarcelstatic const char *g_part_apm_type(struct g_part_table *, struct g_part_entry *,
72166551Smarcel    char *, size_t);
73166551Smarcelstatic int g_part_apm_write(struct g_part_table *, struct g_consumer *);
74166551Smarcel
75166551Smarcelstatic kobj_method_t g_part_apm_methods[] = {
76166551Smarcel	KOBJMETHOD(g_part_add,		g_part_apm_add),
77166551Smarcel	KOBJMETHOD(g_part_create,	g_part_apm_create),
78166551Smarcel	KOBJMETHOD(g_part_destroy,	g_part_apm_destroy),
79166551Smarcel	KOBJMETHOD(g_part_dumpto,	g_part_apm_dumpto),
80166551Smarcel	KOBJMETHOD(g_part_modify,	g_part_apm_modify),
81166551Smarcel	KOBJMETHOD(g_part_name,		g_part_apm_name),
82166551Smarcel	KOBJMETHOD(g_part_probe,	g_part_apm_probe),
83166551Smarcel	KOBJMETHOD(g_part_read,		g_part_apm_read),
84166551Smarcel	KOBJMETHOD(g_part_type,		g_part_apm_type),
85166551Smarcel	KOBJMETHOD(g_part_write,	g_part_apm_write),
86166551Smarcel	{ 0, 0 }
87166551Smarcel};
88166551Smarcel
89166551Smarcelstatic struct g_part_scheme g_part_apm_scheme = {
90166551Smarcel	"APM",
91166551Smarcel	g_part_apm_methods,
92166551Smarcel	sizeof(struct g_part_apm_table),
93166551Smarcel	.gps_entrysz = sizeof(struct g_part_apm_entry),
94166551Smarcel	.gps_minent = 16,
95166551Smarcel	.gps_maxent = INT_MAX,
96166551Smarcel};
97166551SmarcelG_PART_SCHEME_DECLARE(g_part_apm_scheme);
98166551Smarcel
99166551Smarcelstatic int
100166551Smarcelapm_parse_type(const char *type, char *buf, size_t bufsz)
101166551Smarcel{
102169389Smarcel	const char *alias;
103166551Smarcel
104169389Smarcel	if (type[0] == '!') {
105169389Smarcel		type++;
106166551Smarcel		if (strlen(type) > bufsz)
107166551Smarcel			return (EINVAL);
108166551Smarcel		if (!strcmp(type, APM_ENT_TYPE_SELF) ||
109166551Smarcel		    !strcmp(type, APM_ENT_TYPE_UNUSED))
110166551Smarcel			return (EINVAL);
111166551Smarcel		strncpy(buf, type, bufsz);
112166551Smarcel		return (0);
113166551Smarcel	}
114169389Smarcel	alias = g_part_alias_name(G_PART_ALIAS_FREEBSD);
115169389Smarcel	if (!strcasecmp(type, alias)) {
116166551Smarcel		strcpy(buf, APM_ENT_TYPE_FREEBSD);
117169389Smarcel		return (0);
118169389Smarcel	}
119169389Smarcel	alias = g_part_alias_name(G_PART_ALIAS_FREEBSD_SWAP);
120169389Smarcel	if (!strcasecmp(type, alias)) {
121166551Smarcel		strcpy(buf, APM_ENT_TYPE_FREEBSD_SWAP);
122169389Smarcel		return (0);
123169389Smarcel	}
124169389Smarcel	alias = g_part_alias_name(G_PART_ALIAS_FREEBSD_UFS);
125169389Smarcel	if (!strcasecmp(type, alias)) {
126166551Smarcel		strcpy(buf, APM_ENT_TYPE_FREEBSD_UFS);
127169389Smarcel		return (0);
128169389Smarcel	}
129169389Smarcel	alias = g_part_alias_name(G_PART_ALIAS_FREEBSD_VINUM);
130169389Smarcel	if (!strcasecmp(type, alias)) {
131166551Smarcel		strcpy(buf, APM_ENT_TYPE_FREEBSD_VINUM);
132169389Smarcel		return (0);
133169389Smarcel	}
134169389Smarcel	return (EINVAL);
135166551Smarcel}
136166551Smarcel
137166551Smarcelstatic int
138166551Smarcelapm_read_ent(struct g_consumer *cp, uint32_t blk, struct apm_ent *ent)
139166551Smarcel{
140166551Smarcel	struct g_provider *pp;
141166551Smarcel	char *buf;
142166551Smarcel	int error;
143166551Smarcel
144166551Smarcel	pp = cp->provider;
145166551Smarcel	buf = g_read_data(cp, pp->sectorsize * blk, pp->sectorsize, &error);
146166551Smarcel	if (buf == NULL)
147166551Smarcel		return (error);
148166551Smarcel	ent->ent_sig = be16dec(buf);
149166551Smarcel	ent->ent_pmblkcnt = be32dec(buf + 4);
150166551Smarcel	ent->ent_start = be32dec(buf + 8);
151166551Smarcel	ent->ent_size = be32dec(buf + 12);
152166551Smarcel	bcopy(buf + 16, ent->ent_name, sizeof(ent->ent_name));
153166551Smarcel	bcopy(buf + 48, ent->ent_type, sizeof(ent->ent_type));
154166551Smarcel	g_free(buf);
155166551Smarcel	return (0);
156166551Smarcel}
157166551Smarcel
158166551Smarcelstatic int
159166551Smarcelg_part_apm_add(struct g_part_table *basetable, struct g_part_entry *baseentry,
160166551Smarcel    struct g_part_parms *gpp)
161166551Smarcel{
162166551Smarcel	struct g_part_apm_entry *entry;
163166551Smarcel	struct g_part_apm_table *table;
164166551Smarcel	int error;
165166551Smarcel
166166551Smarcel	entry = (struct g_part_apm_entry *)baseentry;
167166551Smarcel	table = (struct g_part_apm_table *)basetable;
168166551Smarcel	entry->ent.ent_sig = APM_ENT_SIG;
169166551Smarcel	entry->ent.ent_pmblkcnt = table->self.ent_pmblkcnt;
170166551Smarcel	entry->ent.ent_start = gpp->gpp_start;
171166551Smarcel	entry->ent.ent_size = gpp->gpp_size;
172166551Smarcel	if (baseentry->gpe_deleted) {
173166551Smarcel		bzero(entry->ent.ent_type, sizeof(entry->ent.ent_type));
174166551Smarcel		bzero(entry->ent.ent_name, sizeof(entry->ent.ent_name));
175166551Smarcel	}
176166551Smarcel	error = apm_parse_type(gpp->gpp_type, entry->ent.ent_type,
177166551Smarcel	    sizeof(entry->ent.ent_type));
178166551Smarcel	if (error)
179166551Smarcel		return (error);
180166551Smarcel	if (gpp->gpp_parms & G_PART_PARM_LABEL) {
181166551Smarcel		if (strlen(gpp->gpp_label) > sizeof(entry->ent.ent_name))
182166551Smarcel			return (EINVAL);
183166551Smarcel		strncpy(entry->ent.ent_name, gpp->gpp_label,
184166551Smarcel		    sizeof(entry->ent.ent_name));
185166551Smarcel	}
186166551Smarcel	return (0);
187166551Smarcel}
188166551Smarcel
189166551Smarcelstatic int
190166551Smarcelg_part_apm_create(struct g_part_table *basetable, struct g_part_parms *gpp)
191166551Smarcel{
192166551Smarcel	struct g_provider *pp;
193166551Smarcel	struct g_part_apm_table *table;
194166551Smarcel
195166551Smarcel	table = (struct g_part_apm_table *)basetable;
196166551Smarcel	pp = gpp->gpp_provider;
197166551Smarcel	if (pp->sectorsize != 512 ||
198166551Smarcel	    pp->mediasize < (2 + 2 * basetable->gpt_entries) * pp->sectorsize)
199166551Smarcel		return (ENOSPC);
200166551Smarcel
201166551Smarcel	basetable->gpt_first = 2 + basetable->gpt_entries;
202166551Smarcel	basetable->gpt_last = (pp->mediasize / pp->sectorsize) - 1;
203166551Smarcel
204166551Smarcel	table->ddr.ddr_sig = APM_DDR_SIG;
205166551Smarcel	table->ddr.ddr_blksize = pp->sectorsize;
206166551Smarcel	table->ddr.ddr_blkcount = basetable->gpt_last + 1;
207166551Smarcel
208166551Smarcel	table->self.ent_sig = APM_ENT_SIG;
209166551Smarcel	table->self.ent_pmblkcnt = basetable->gpt_entries + 1;
210166551Smarcel	table->self.ent_start = 1;
211166551Smarcel	table->self.ent_size = table->self.ent_pmblkcnt;
212166551Smarcel	strcpy(table->self.ent_name, "Apple");
213166551Smarcel	strcpy(table->self.ent_type, APM_ENT_TYPE_SELF);
214166551Smarcel	return (0);
215166551Smarcel}
216166551Smarcel
217166551Smarcelstatic int
218166551Smarcelg_part_apm_destroy(struct g_part_table *basetable, struct g_part_parms *gpp)
219166551Smarcel{
220166551Smarcel
221166551Smarcel	/* Wipe the first 2 sectors to clear the partitioning. */
222166551Smarcel	basetable->gpt_smhead |= 3;
223166551Smarcel	return (0);
224166551Smarcel}
225166551Smarcel
226166551Smarcelstatic int
227166551Smarcelg_part_apm_dumpto(struct g_part_table *table, struct g_part_entry *baseentry)
228166551Smarcel{
229166551Smarcel	struct g_part_apm_entry *entry;
230166551Smarcel
231166551Smarcel	entry = (struct g_part_apm_entry *)baseentry;
232166551Smarcel	return ((!strcmp(entry->ent.ent_type, APM_ENT_TYPE_FREEBSD_SWAP))
233166551Smarcel	    ? 1 : 0);
234166551Smarcel}
235166551Smarcel
236166551Smarcelstatic int
237166551Smarcelg_part_apm_modify(struct g_part_table *basetable,
238166551Smarcel    struct g_part_entry *baseentry, struct g_part_parms *gpp)
239166551Smarcel{
240166551Smarcel	struct g_part_apm_entry *entry;
241166551Smarcel	int error;
242166551Smarcel
243166551Smarcel	entry = (struct g_part_apm_entry *)baseentry;
244166551Smarcel	if (gpp->gpp_parms & G_PART_PARM_LABEL) {
245166551Smarcel		if (strlen(gpp->gpp_label) > sizeof(entry->ent.ent_name))
246166551Smarcel			return (EINVAL);
247166551Smarcel	}
248166551Smarcel	if (gpp->gpp_parms & G_PART_PARM_TYPE) {
249166551Smarcel		error = apm_parse_type(gpp->gpp_type, entry->ent.ent_type,
250166551Smarcel		    sizeof(entry->ent.ent_type));
251166551Smarcel		if (error)
252166551Smarcel			return (error);
253166551Smarcel	}
254166551Smarcel	if (gpp->gpp_parms & G_PART_PARM_LABEL) {
255166551Smarcel		strncpy(entry->ent.ent_name, gpp->gpp_label,
256166551Smarcel		    sizeof(entry->ent.ent_name));
257166551Smarcel	}
258166551Smarcel	return (0);
259166551Smarcel}
260166551Smarcel
261166551Smarcelstatic char *
262166551Smarcelg_part_apm_name(struct g_part_table *table, struct g_part_entry *baseentry,
263166551Smarcel    char *buf, size_t bufsz)
264166551Smarcel{
265166551Smarcel
266166551Smarcel	snprintf(buf, bufsz, "s%d", baseentry->gpe_index + 1);
267166551Smarcel	return (buf);
268166551Smarcel}
269166551Smarcel
270166551Smarcelstatic int
271166551Smarcelg_part_apm_probe(struct g_part_table *basetable, struct g_consumer *cp)
272166551Smarcel{
273166551Smarcel	struct g_provider *pp;
274166551Smarcel	struct g_part_apm_table *table;
275166551Smarcel	char *buf;
276166551Smarcel	int error;
277166551Smarcel
278166551Smarcel	/* We don't nest, which means that our depth should be 0. */
279166551Smarcel	if (basetable->gpt_depth != 0)
280166551Smarcel		return (ENXIO);
281166551Smarcel
282166551Smarcel	table = (struct g_part_apm_table *)basetable;
283166551Smarcel	pp = cp->provider;
284166551Smarcel
285166551Smarcel	/* Sanity-check the provider. */
286166551Smarcel	if (pp->mediasize < 4 * pp->sectorsize)
287166551Smarcel		return (ENOSPC);
288166551Smarcel
289166551Smarcel	/* Check that there's a Driver Descriptor Record (DDR). */
290166551Smarcel	buf = g_read_data(cp, 0L, pp->sectorsize, &error);
291166551Smarcel	if (buf == NULL)
292166551Smarcel		return (error);
293166551Smarcel	table->ddr.ddr_sig = be16dec(buf);
294166551Smarcel	table->ddr.ddr_blksize = be16dec(buf + 2);
295166551Smarcel	table->ddr.ddr_blkcount = be32dec(buf + 4);
296166551Smarcel	g_free(buf);
297166551Smarcel	if (table->ddr.ddr_sig != APM_DDR_SIG)
298166551Smarcel		return (ENXIO);
299166551Smarcel	if (table->ddr.ddr_blksize != pp->sectorsize)
300166551Smarcel		return (ENXIO);
301166551Smarcel
302166551Smarcel	/* Check that there's a Partition Map. */
303166551Smarcel	error = apm_read_ent(cp, 1, &table->self);
304166551Smarcel	if (error)
305166551Smarcel		return (error);
306166551Smarcel	if (table->self.ent_sig != APM_ENT_SIG)
307166551Smarcel		return (ENXIO);
308166551Smarcel	if (strcmp(table->self.ent_type, APM_ENT_TYPE_SELF))
309166551Smarcel		return (ENXIO);
310166551Smarcel	if (table->self.ent_pmblkcnt >= table->ddr.ddr_blkcount)
311166551Smarcel		return (ENXIO);
312166551Smarcel	return (G_PART_PROBE_PRI_NORM);
313166551Smarcel}
314166551Smarcel
315166551Smarcelstatic int
316166551Smarcelg_part_apm_read(struct g_part_table *basetable, struct g_consumer *cp)
317166551Smarcel{
318166551Smarcel	struct apm_ent ent;
319166551Smarcel	struct g_part_apm_entry *entry;
320166551Smarcel	struct g_part_apm_table *table;
321166551Smarcel	int error, index;
322166551Smarcel
323166551Smarcel	table = (struct g_part_apm_table *)basetable;
324166551Smarcel
325166551Smarcel	basetable->gpt_first = table->self.ent_pmblkcnt + 1;
326166551Smarcel	basetable->gpt_last = table->ddr.ddr_blkcount - 1;
327166551Smarcel	basetable->gpt_entries = table->self.ent_pmblkcnt - 1;
328166551Smarcel
329166551Smarcel	for (index = table->self.ent_pmblkcnt - 1; index > 0; index--) {
330166551Smarcel		error = apm_read_ent(cp, index + 1, &ent);
331166551Smarcel		if (error)
332166551Smarcel			continue;
333166551Smarcel		if (!strcmp(ent.ent_type, APM_ENT_TYPE_UNUSED))
334166551Smarcel			continue;
335166551Smarcel		entry = (struct g_part_apm_entry *)g_part_new_entry(basetable,
336166551Smarcel		    index, ent.ent_start, ent.ent_start + ent.ent_size - 1);
337166551Smarcel		entry->ent = ent;
338166551Smarcel	}
339166551Smarcel
340166551Smarcel	return (0);
341166551Smarcel}
342166551Smarcel
343166551Smarcelstatic const char *
344166551Smarcelg_part_apm_type(struct g_part_table *basetable, struct g_part_entry *baseentry,
345166551Smarcel    char *buf, size_t bufsz)
346166551Smarcel{
347166551Smarcel	struct g_part_apm_entry *entry;
348166551Smarcel	const char *type;
349166551Smarcel	size_t len;
350166551Smarcel
351166551Smarcel	entry = (struct g_part_apm_entry *)baseentry;
352166551Smarcel	type = entry->ent.ent_type;
353166551Smarcel	if (!strcmp(type, APM_ENT_TYPE_FREEBSD))
354166551Smarcel		return (g_part_alias_name(G_PART_ALIAS_FREEBSD));
355166551Smarcel	if (!strcmp(type, APM_ENT_TYPE_FREEBSD_SWAP))
356166551Smarcel		return (g_part_alias_name(G_PART_ALIAS_FREEBSD_SWAP));
357166551Smarcel	if (!strcmp(type, APM_ENT_TYPE_FREEBSD_UFS))
358166551Smarcel		return (g_part_alias_name(G_PART_ALIAS_FREEBSD_UFS));
359166551Smarcel	if (!strcmp(type, APM_ENT_TYPE_FREEBSD_VINUM))
360166551Smarcel		return (g_part_alias_name(G_PART_ALIAS_FREEBSD_VINUM));
361170362Smarcel	buf[0] = '!';
362170362Smarcel	len = MIN(sizeof(entry->ent.ent_type), bufsz - 2);
363170362Smarcel	bcopy(type, buf + 1, len);
364170362Smarcel	buf[len + 1] = '\0';
365166551Smarcel	return (buf);
366166551Smarcel}
367166551Smarcel
368166551Smarcelstatic int
369166551Smarcelg_part_apm_write(struct g_part_table *basetable, struct g_consumer *cp)
370166551Smarcel{
371166551Smarcel	char buf[512];
372166551Smarcel	struct g_part_entry *baseentry;
373166551Smarcel	struct g_part_apm_entry *entry;
374166551Smarcel	struct g_part_apm_table *table;
375166551Smarcel	int error, index;
376166551Smarcel
377166551Smarcel	table = (struct g_part_apm_table *)basetable;
378166551Smarcel	bzero(buf, sizeof(buf));
379166551Smarcel
380166551Smarcel	/* Write the DDR and 'self' entry only when we're newly created. */
381166551Smarcel	if (basetable->gpt_created) {
382166551Smarcel		be16enc(buf, table->ddr.ddr_sig);
383166551Smarcel		be16enc(buf + 2, table->ddr.ddr_blksize);
384166551Smarcel		be32enc(buf + 4, table->ddr.ddr_blkcount);
385166551Smarcel		error = g_write_data(cp, 0, buf, sizeof(buf));
386166551Smarcel		if (error)
387166551Smarcel			return (error);
388166551Smarcel	}
389166551Smarcel
390166551Smarcel	be16enc(buf, table->self.ent_sig);
391166551Smarcel	be16enc(buf + 2, 0);
392166551Smarcel	be32enc(buf + 4, table->self.ent_pmblkcnt);
393166551Smarcel
394166551Smarcel	if (basetable->gpt_created) {
395166551Smarcel		be32enc(buf + 8, table->self.ent_start);
396166551Smarcel		be32enc(buf + 12, table->self.ent_size);
397166551Smarcel		bcopy(table->self.ent_name, buf + 16,
398166551Smarcel		    sizeof(table->self.ent_name));
399166551Smarcel		bcopy(table->self.ent_type, buf + 48,
400166551Smarcel		    sizeof(table->self.ent_type));
401166551Smarcel		error = g_write_data(cp, 512, buf, sizeof(buf));
402166551Smarcel		if (error)
403166551Smarcel			return (error);
404166551Smarcel	}
405166551Smarcel
406166551Smarcel	baseentry = LIST_FIRST(&basetable->gpt_entry);
407166551Smarcel	for (index = 1; index <= basetable->gpt_entries; index++) {
408169389Smarcel		entry = (baseentry != NULL && index == baseentry->gpe_index)
409169389Smarcel		    ? (struct g_part_apm_entry *)baseentry : NULL;
410169389Smarcel		if (entry != NULL && !baseentry->gpe_deleted) {
411166551Smarcel			be32enc(buf + 8, entry->ent.ent_start);
412166551Smarcel			be32enc(buf + 12, entry->ent.ent_size);
413166551Smarcel			bcopy(entry->ent.ent_name, buf + 16,
414166551Smarcel			    sizeof(entry->ent.ent_name));
415166551Smarcel			bcopy(entry->ent.ent_type, buf + 48,
416166551Smarcel			    sizeof(entry->ent.ent_type));
417166551Smarcel		} else {
418166551Smarcel			bzero(buf + 8, 4 + 4 + 32 + 32);
419166551Smarcel			strcpy(buf + 48, APM_ENT_TYPE_UNUSED);
420166551Smarcel		}
421166551Smarcel		error = g_write_data(cp, (index + 1) * 512, buf, sizeof(buf));
422166551Smarcel		if (error)
423166551Smarcel			return (error);
424169389Smarcel		if (entry != NULL)
425169389Smarcel			baseentry = LIST_NEXT(baseentry, gpe_entry);
426166551Smarcel	}
427166551Smarcel
428166551Smarcel	return (0);
429166551Smarcel}
430