xref: /freebsd/sbin/geom/misc/subr.c (revision 79d89bb0aba0ca54d28e7a881f0b78bed7d65c7b)
105c91076SPawel Jakub Dawidek /*-
205c91076SPawel Jakub Dawidek  * Copyright (c) 2004 Pawel Jakub Dawidek <pjd@FreeBSD.org>
305c91076SPawel Jakub Dawidek  * All rights reserved.
405c91076SPawel Jakub Dawidek  *
505c91076SPawel Jakub Dawidek  * Redistribution and use in source and binary forms, with or without
605c91076SPawel Jakub Dawidek  * modification, are permitted provided that the following conditions
705c91076SPawel Jakub Dawidek  * are met:
805c91076SPawel Jakub Dawidek  * 1. Redistributions of source code must retain the above copyright
905c91076SPawel Jakub Dawidek  *    notice, this list of conditions and the following disclaimer.
1005c91076SPawel Jakub Dawidek  * 2. Redistributions in binary form must reproduce the above copyright
1105c91076SPawel Jakub Dawidek  *    notice, this list of conditions and the following disclaimer in the
1205c91076SPawel Jakub Dawidek  *    documentation and/or other materials provided with the distribution.
1305c91076SPawel Jakub Dawidek  *
1405c91076SPawel Jakub Dawidek  * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
1505c91076SPawel Jakub Dawidek  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1605c91076SPawel Jakub Dawidek  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1705c91076SPawel Jakub Dawidek  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
1805c91076SPawel Jakub Dawidek  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1905c91076SPawel Jakub Dawidek  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2005c91076SPawel Jakub Dawidek  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2105c91076SPawel Jakub Dawidek  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2205c91076SPawel Jakub Dawidek  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2305c91076SPawel Jakub Dawidek  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2405c91076SPawel Jakub Dawidek  * SUCH DAMAGE.
2505c91076SPawel Jakub Dawidek  */
2605c91076SPawel Jakub Dawidek 
2705c91076SPawel Jakub Dawidek #include <sys/cdefs.h>
2805c91076SPawel Jakub Dawidek __FBSDID("$FreeBSD$");
2905c91076SPawel Jakub Dawidek 
3005c91076SPawel Jakub Dawidek #include <sys/param.h>
3105c91076SPawel Jakub Dawidek #include <sys/disk.h>
3205c91076SPawel Jakub Dawidek #include <sys/endian.h>
3305c91076SPawel Jakub Dawidek #include <sys/uio.h>
3405c91076SPawel Jakub Dawidek #include <errno.h>
3505c91076SPawel Jakub Dawidek #include <fcntl.h>
3605c91076SPawel Jakub Dawidek #include <paths.h>
3705c91076SPawel Jakub Dawidek #include <stdio.h>
3805c91076SPawel Jakub Dawidek #include <stdlib.h>
39*79d89bb0SAndrey V. Elsukov #include <limits.h>
40*79d89bb0SAndrey V. Elsukov #include <inttypes.h>
4105c91076SPawel Jakub Dawidek #include <stdarg.h>
4205c91076SPawel Jakub Dawidek #include <string.h>
4305c91076SPawel Jakub Dawidek #include <strings.h>
4405c91076SPawel Jakub Dawidek #include <unistd.h>
4505c91076SPawel Jakub Dawidek #include <assert.h>
4605c91076SPawel Jakub Dawidek #include <libgeom.h>
4705c91076SPawel Jakub Dawidek 
4805c91076SPawel Jakub Dawidek #include "misc/subr.h"
4905c91076SPawel Jakub Dawidek 
5005c91076SPawel Jakub Dawidek 
5105c91076SPawel Jakub Dawidek struct std_metadata {
5205c91076SPawel Jakub Dawidek 	char		md_magic[16];
5305c91076SPawel Jakub Dawidek 	uint32_t	md_version;
5405c91076SPawel Jakub Dawidek };
5505c91076SPawel Jakub Dawidek 
5605c91076SPawel Jakub Dawidek static void
5705c91076SPawel Jakub Dawidek std_metadata_decode(const u_char *data, struct std_metadata *md)
5805c91076SPawel Jakub Dawidek {
5905c91076SPawel Jakub Dawidek 
6005c91076SPawel Jakub Dawidek         bcopy(data, md->md_magic, sizeof(md->md_magic));
6105c91076SPawel Jakub Dawidek         md->md_version = le32dec(data + 16);
6205c91076SPawel Jakub Dawidek }
6305c91076SPawel Jakub Dawidek 
6405c91076SPawel Jakub Dawidek static void
6505c91076SPawel Jakub Dawidek pathgen(const char *name, char *path, size_t size)
6605c91076SPawel Jakub Dawidek {
6705c91076SPawel Jakub Dawidek 
6805c91076SPawel Jakub Dawidek 	if (strncmp(name, _PATH_DEV, strlen(_PATH_DEV)) != 0)
6905c91076SPawel Jakub Dawidek 		snprintf(path, size, "%s%s", _PATH_DEV, name);
7005c91076SPawel Jakub Dawidek 	else
7105c91076SPawel Jakub Dawidek 		strlcpy(path, name, size);
7205c91076SPawel Jakub Dawidek }
7305c91076SPawel Jakub Dawidek 
7409cc9ab6SPawel Jakub Dawidek /*
7509cc9ab6SPawel Jakub Dawidek  * Greatest Common Divisor.
7609cc9ab6SPawel Jakub Dawidek  */
7709cc9ab6SPawel Jakub Dawidek static unsigned
7809cc9ab6SPawel Jakub Dawidek gcd(unsigned a, unsigned b)
7909cc9ab6SPawel Jakub Dawidek {
8009cc9ab6SPawel Jakub Dawidek 	u_int c;
8109cc9ab6SPawel Jakub Dawidek 
8209cc9ab6SPawel Jakub Dawidek 	while (b != 0) {
8309cc9ab6SPawel Jakub Dawidek 		c = a;
8409cc9ab6SPawel Jakub Dawidek 		a = b;
8509cc9ab6SPawel Jakub Dawidek 		b = (c % b);
8609cc9ab6SPawel Jakub Dawidek 	}
8709cc9ab6SPawel Jakub Dawidek 	return (a);
8809cc9ab6SPawel Jakub Dawidek }
8909cc9ab6SPawel Jakub Dawidek 
9009cc9ab6SPawel Jakub Dawidek /*
9109cc9ab6SPawel Jakub Dawidek  * Least Common Multiple.
9209cc9ab6SPawel Jakub Dawidek  */
9309cc9ab6SPawel Jakub Dawidek unsigned
9409cc9ab6SPawel Jakub Dawidek g_lcm(unsigned a, unsigned b)
9509cc9ab6SPawel Jakub Dawidek {
9609cc9ab6SPawel Jakub Dawidek 
9709cc9ab6SPawel Jakub Dawidek 	return ((a * b) / gcd(a, b));
9809cc9ab6SPawel Jakub Dawidek }
9909cc9ab6SPawel Jakub Dawidek 
10082978104SPawel Jakub Dawidek uint32_t
10182978104SPawel Jakub Dawidek bitcount32(uint32_t x)
10282978104SPawel Jakub Dawidek {
10382978104SPawel Jakub Dawidek 
10482978104SPawel Jakub Dawidek 	x = (x & 0x55555555) + ((x & 0xaaaaaaaa) >> 1);
10582978104SPawel Jakub Dawidek 	x = (x & 0x33333333) + ((x & 0xcccccccc) >> 2);
10682978104SPawel Jakub Dawidek 	x = (x & 0x0f0f0f0f) + ((x & 0xf0f0f0f0) >> 4);
10782978104SPawel Jakub Dawidek 	x = (x & 0x00ff00ff) + ((x & 0xff00ff00) >> 8);
10882978104SPawel Jakub Dawidek 	x = (x & 0x0000ffff) + ((x & 0xffff0000) >> 16);
10982978104SPawel Jakub Dawidek 	return (x);
11082978104SPawel Jakub Dawidek }
11182978104SPawel Jakub Dawidek 
112*79d89bb0SAndrey V. Elsukov /*
113*79d89bb0SAndrey V. Elsukov  * The size of a sector is context specific (i.e. determined by the
114*79d89bb0SAndrey V. Elsukov  * media). But when users enter a value with a SI unit, they really
115*79d89bb0SAndrey V. Elsukov  * mean the byte-size or byte-offset and not the size or offset in
116*79d89bb0SAndrey V. Elsukov  * sectors. We should map the byte-oriented value into a sector-oriented
117*79d89bb0SAndrey V. Elsukov  * value when we already know the sector size in bytes. At this time
118*79d89bb0SAndrey V. Elsukov  * we can use g_parse_lba() function. It converts user specified
119*79d89bb0SAndrey V. Elsukov  * value into sectors with following conditions:
120*79d89bb0SAndrey V. Elsukov  * o  Sectors size taken as argument from caller.
121*79d89bb0SAndrey V. Elsukov  * o  When no SI unit is specified the value is in sectors.
122*79d89bb0SAndrey V. Elsukov  * o  With an SI unit the value is in bytes.
123*79d89bb0SAndrey V. Elsukov  * o  The 'b' suffix forces byte interpretation and the 's'
124*79d89bb0SAndrey V. Elsukov  *    suffix forces sector interpretation.
125*79d89bb0SAndrey V. Elsukov  *
126*79d89bb0SAndrey V. Elsukov  * Thus:
127*79d89bb0SAndrey V. Elsukov  * o  2 and 2s mean 2 sectors, and 2b means 2 bytes.
128*79d89bb0SAndrey V. Elsukov  * o  4k and 4kb mean 4096 bytes, and 4ks means 4096 sectors.
129*79d89bb0SAndrey V. Elsukov  *
130*79d89bb0SAndrey V. Elsukov  */
131*79d89bb0SAndrey V. Elsukov int
132*79d89bb0SAndrey V. Elsukov g_parse_lba(const char *lbastr, unsigned sectorsize, off_t *sectors)
133*79d89bb0SAndrey V. Elsukov {
134*79d89bb0SAndrey V. Elsukov 	off_t number, mult, unit;
135*79d89bb0SAndrey V. Elsukov 	char *s;
136*79d89bb0SAndrey V. Elsukov 
137*79d89bb0SAndrey V. Elsukov 	assert(lbastr != NULL);
138*79d89bb0SAndrey V. Elsukov 	assert(sectorsize > 0);
139*79d89bb0SAndrey V. Elsukov 	assert(sectors != NULL);
140*79d89bb0SAndrey V. Elsukov 
141*79d89bb0SAndrey V. Elsukov 	number = (off_t)strtoimax(lbastr, &s, 0);
142*79d89bb0SAndrey V. Elsukov 	if (s == lbastr)
143*79d89bb0SAndrey V. Elsukov 		return (EINVAL);
144*79d89bb0SAndrey V. Elsukov 
145*79d89bb0SAndrey V. Elsukov 	mult = 1;
146*79d89bb0SAndrey V. Elsukov 	unit = sectorsize;
147*79d89bb0SAndrey V. Elsukov 	if (*s == '\0')
148*79d89bb0SAndrey V. Elsukov 		goto done;
149*79d89bb0SAndrey V. Elsukov 	switch (*s) {
150*79d89bb0SAndrey V. Elsukov 	case 'e': case 'E':
151*79d89bb0SAndrey V. Elsukov 		mult *= 1024;
152*79d89bb0SAndrey V. Elsukov 		/* FALLTHROUGH */
153*79d89bb0SAndrey V. Elsukov 	case 'p': case 'P':
154*79d89bb0SAndrey V. Elsukov 		mult *= 1024;
155*79d89bb0SAndrey V. Elsukov 		/* FALLTHROUGH */
156*79d89bb0SAndrey V. Elsukov 	case 't': case 'T':
157*79d89bb0SAndrey V. Elsukov 		mult *= 1024;
158*79d89bb0SAndrey V. Elsukov 		/* FALLTHROUGH */
159*79d89bb0SAndrey V. Elsukov 	case 'g': case 'G':
160*79d89bb0SAndrey V. Elsukov 		mult *= 1024;
161*79d89bb0SAndrey V. Elsukov 		/* FALLTHROUGH */
162*79d89bb0SAndrey V. Elsukov 	case 'm': case 'M':
163*79d89bb0SAndrey V. Elsukov 		mult *= 1024;
164*79d89bb0SAndrey V. Elsukov 		/* FALLTHROUGH */
165*79d89bb0SAndrey V. Elsukov 	case 'k': case 'K':
166*79d89bb0SAndrey V. Elsukov 		mult *= 1024;
167*79d89bb0SAndrey V. Elsukov 		break;
168*79d89bb0SAndrey V. Elsukov 	default:
169*79d89bb0SAndrey V. Elsukov 		goto sfx;
170*79d89bb0SAndrey V. Elsukov 	}
171*79d89bb0SAndrey V. Elsukov 	unit = 1;	/* bytes */
172*79d89bb0SAndrey V. Elsukov 	s++;
173*79d89bb0SAndrey V. Elsukov 	if (*s == '\0')
174*79d89bb0SAndrey V. Elsukov 		goto done;
175*79d89bb0SAndrey V. Elsukov sfx:
176*79d89bb0SAndrey V. Elsukov 	switch (*s) {
177*79d89bb0SAndrey V. Elsukov 	case 's': case 'S':
178*79d89bb0SAndrey V. Elsukov 		unit = sectorsize;	/* sector */
179*79d89bb0SAndrey V. Elsukov 		break;
180*79d89bb0SAndrey V. Elsukov 	case 'b': case 'B':
181*79d89bb0SAndrey V. Elsukov 		unit = 1;		/* bytes */
182*79d89bb0SAndrey V. Elsukov 		break;
183*79d89bb0SAndrey V. Elsukov 	default:
184*79d89bb0SAndrey V. Elsukov 		return (EINVAL);
185*79d89bb0SAndrey V. Elsukov 	}
186*79d89bb0SAndrey V. Elsukov 	s++;
187*79d89bb0SAndrey V. Elsukov 	if (*s != '\0')
188*79d89bb0SAndrey V. Elsukov 		return (EINVAL);
189*79d89bb0SAndrey V. Elsukov done:
190*79d89bb0SAndrey V. Elsukov 	if (mult * unit < mult || number * mult * unit < number)
191*79d89bb0SAndrey V. Elsukov 		return (ERANGE);
192*79d89bb0SAndrey V. Elsukov 	number *= mult * unit;
193*79d89bb0SAndrey V. Elsukov 	if (number % sectorsize)
194*79d89bb0SAndrey V. Elsukov 		return (EINVAL);
195*79d89bb0SAndrey V. Elsukov 	number /= sectorsize;
196*79d89bb0SAndrey V. Elsukov 	*sectors = number;
197*79d89bb0SAndrey V. Elsukov 	return (0);
198*79d89bb0SAndrey V. Elsukov }
199*79d89bb0SAndrey V. Elsukov 
20009cc9ab6SPawel Jakub Dawidek off_t
20109cc9ab6SPawel Jakub Dawidek g_get_mediasize(const char *name)
20209cc9ab6SPawel Jakub Dawidek {
20309cc9ab6SPawel Jakub Dawidek 	char path[MAXPATHLEN];
20409cc9ab6SPawel Jakub Dawidek 	off_t mediasize;
20509cc9ab6SPawel Jakub Dawidek 	int fd;
20609cc9ab6SPawel Jakub Dawidek 
20709cc9ab6SPawel Jakub Dawidek 	pathgen(name, path, sizeof(path));
20809cc9ab6SPawel Jakub Dawidek 	fd = open(path, O_RDONLY);
20909cc9ab6SPawel Jakub Dawidek 	if (fd == -1)
21009cc9ab6SPawel Jakub Dawidek 		return (0);
21109cc9ab6SPawel Jakub Dawidek 	if (ioctl(fd, DIOCGMEDIASIZE, &mediasize) < 0) {
21209cc9ab6SPawel Jakub Dawidek 		close(fd);
21309cc9ab6SPawel Jakub Dawidek 		return (0);
21409cc9ab6SPawel Jakub Dawidek 	}
21509cc9ab6SPawel Jakub Dawidek 	close(fd);
21609cc9ab6SPawel Jakub Dawidek 	return (mediasize);
21709cc9ab6SPawel Jakub Dawidek }
21809cc9ab6SPawel Jakub Dawidek 
21909cc9ab6SPawel Jakub Dawidek unsigned
22009cc9ab6SPawel Jakub Dawidek g_get_sectorsize(const char *name)
22109cc9ab6SPawel Jakub Dawidek {
22209cc9ab6SPawel Jakub Dawidek 	char path[MAXPATHLEN];
22309cc9ab6SPawel Jakub Dawidek 	unsigned sectorsize;
22409cc9ab6SPawel Jakub Dawidek 	int fd;
22509cc9ab6SPawel Jakub Dawidek 
22609cc9ab6SPawel Jakub Dawidek 	pathgen(name, path, sizeof(path));
22709cc9ab6SPawel Jakub Dawidek 	fd = open(path, O_RDONLY);
22809cc9ab6SPawel Jakub Dawidek 	if (fd == -1)
22909cc9ab6SPawel Jakub Dawidek 		return (0);
23009cc9ab6SPawel Jakub Dawidek 	if (ioctl(fd, DIOCGSECTORSIZE, &sectorsize) < 0) {
23109cc9ab6SPawel Jakub Dawidek 		close(fd);
23209cc9ab6SPawel Jakub Dawidek 		return (0);
23309cc9ab6SPawel Jakub Dawidek 	}
23409cc9ab6SPawel Jakub Dawidek 	close(fd);
23509cc9ab6SPawel Jakub Dawidek 	return (sectorsize);
23609cc9ab6SPawel Jakub Dawidek }
23709cc9ab6SPawel Jakub Dawidek 
23805c91076SPawel Jakub Dawidek int
23910fa0ebeSPawel Jakub Dawidek g_metadata_read(const char *name, u_char *md, size_t size, const char *magic)
24010fa0ebeSPawel Jakub Dawidek {
24110fa0ebeSPawel Jakub Dawidek 	struct std_metadata stdmd;
24210fa0ebeSPawel Jakub Dawidek 	char path[MAXPATHLEN];
24310fa0ebeSPawel Jakub Dawidek 	unsigned sectorsize;
24410fa0ebeSPawel Jakub Dawidek 	off_t mediasize;
24510fa0ebeSPawel Jakub Dawidek 	u_char *sector;
24610fa0ebeSPawel Jakub Dawidek 	int error, fd;
24710fa0ebeSPawel Jakub Dawidek 
24810fa0ebeSPawel Jakub Dawidek 	pathgen(name, path, sizeof(path));
24910fa0ebeSPawel Jakub Dawidek 	sector = NULL;
25010fa0ebeSPawel Jakub Dawidek 	error = 0;
25110fa0ebeSPawel Jakub Dawidek 
25210fa0ebeSPawel Jakub Dawidek 	fd = open(path, O_RDONLY);
25310fa0ebeSPawel Jakub Dawidek 	if (fd == -1)
25410fa0ebeSPawel Jakub Dawidek 		return (errno);
25510fa0ebeSPawel Jakub Dawidek 	mediasize = g_get_mediasize(name);
25610fa0ebeSPawel Jakub Dawidek 	if (mediasize == 0) {
25710fa0ebeSPawel Jakub Dawidek 		error = errno;
25810fa0ebeSPawel Jakub Dawidek 		goto out;
25910fa0ebeSPawel Jakub Dawidek 	}
26010fa0ebeSPawel Jakub Dawidek 	sectorsize = g_get_sectorsize(name);
26110fa0ebeSPawel Jakub Dawidek 	if (sectorsize == 0) {
26210fa0ebeSPawel Jakub Dawidek 		error = errno;
26310fa0ebeSPawel Jakub Dawidek 		goto out;
26410fa0ebeSPawel Jakub Dawidek 	}
26510fa0ebeSPawel Jakub Dawidek 	assert(sectorsize >= size);
26610fa0ebeSPawel Jakub Dawidek 	sector = malloc(sectorsize);
26710fa0ebeSPawel Jakub Dawidek 	if (sector == NULL) {
26810fa0ebeSPawel Jakub Dawidek 		error = ENOMEM;
26910fa0ebeSPawel Jakub Dawidek 		goto out;
27010fa0ebeSPawel Jakub Dawidek 	}
27110fa0ebeSPawel Jakub Dawidek 	if (pread(fd, sector, sectorsize, mediasize - sectorsize) !=
27210fa0ebeSPawel Jakub Dawidek 	    (ssize_t)sectorsize) {
27310fa0ebeSPawel Jakub Dawidek 		error = errno;
27410fa0ebeSPawel Jakub Dawidek 		goto out;
27510fa0ebeSPawel Jakub Dawidek 	}
27610fa0ebeSPawel Jakub Dawidek 	if (magic != NULL) {
27710fa0ebeSPawel Jakub Dawidek 		std_metadata_decode(sector, &stdmd);
27810fa0ebeSPawel Jakub Dawidek 		if (strcmp(stdmd.md_magic, magic) != 0) {
27910fa0ebeSPawel Jakub Dawidek 			error = EINVAL;
28010fa0ebeSPawel Jakub Dawidek 			goto out;
28110fa0ebeSPawel Jakub Dawidek 		}
28210fa0ebeSPawel Jakub Dawidek 	}
28310fa0ebeSPawel Jakub Dawidek 	bcopy(sector, md, size);
28410fa0ebeSPawel Jakub Dawidek out:
28510fa0ebeSPawel Jakub Dawidek 	if (sector != NULL)
28610fa0ebeSPawel Jakub Dawidek 		free(sector);
28710fa0ebeSPawel Jakub Dawidek 	close(fd);
28810fa0ebeSPawel Jakub Dawidek 	return (error);
28910fa0ebeSPawel Jakub Dawidek }
29010fa0ebeSPawel Jakub Dawidek 
29110fa0ebeSPawel Jakub Dawidek int
29205c91076SPawel Jakub Dawidek g_metadata_store(const char *name, u_char *md, size_t size)
29305c91076SPawel Jakub Dawidek {
29405c91076SPawel Jakub Dawidek 	char path[MAXPATHLEN];
29505c91076SPawel Jakub Dawidek 	unsigned sectorsize;
29605c91076SPawel Jakub Dawidek 	off_t mediasize;
29705c91076SPawel Jakub Dawidek 	u_char *sector;
29805c91076SPawel Jakub Dawidek 	int error, fd;
29905c91076SPawel Jakub Dawidek 
30005c91076SPawel Jakub Dawidek 	pathgen(name, path, sizeof(path));
30105c91076SPawel Jakub Dawidek 	sector = NULL;
30205c91076SPawel Jakub Dawidek 	error = 0;
30305c91076SPawel Jakub Dawidek 
304db2bf4b0SUlf Lilleengen 	fd = open(path, O_WRONLY);
30505c91076SPawel Jakub Dawidek 	if (fd == -1)
30605c91076SPawel Jakub Dawidek 		return (errno);
30709cc9ab6SPawel Jakub Dawidek 	mediasize = g_get_mediasize(name);
30809cc9ab6SPawel Jakub Dawidek 	if (mediasize == 0) {
30905c91076SPawel Jakub Dawidek 		error = errno;
31005c91076SPawel Jakub Dawidek 		goto out;
31105c91076SPawel Jakub Dawidek 	}
31209cc9ab6SPawel Jakub Dawidek 	sectorsize = g_get_sectorsize(name);
31309cc9ab6SPawel Jakub Dawidek 	if (sectorsize == 0) {
31405c91076SPawel Jakub Dawidek 		error = errno;
31505c91076SPawel Jakub Dawidek 		goto out;
31605c91076SPawel Jakub Dawidek 	}
31705c91076SPawel Jakub Dawidek 	assert(sectorsize >= size);
31805c91076SPawel Jakub Dawidek 	sector = malloc(sectorsize);
31905c91076SPawel Jakub Dawidek 	if (sector == NULL) {
32005c91076SPawel Jakub Dawidek 		error = ENOMEM;
32105c91076SPawel Jakub Dawidek 		goto out;
32205c91076SPawel Jakub Dawidek 	}
32305c91076SPawel Jakub Dawidek 	bcopy(md, sector, size);
32405c91076SPawel Jakub Dawidek 	if (pwrite(fd, sector, sectorsize, mediasize - sectorsize) !=
32505c91076SPawel Jakub Dawidek 	    (ssize_t)sectorsize) {
32605c91076SPawel Jakub Dawidek 		error = errno;
32705c91076SPawel Jakub Dawidek 		goto out;
32805c91076SPawel Jakub Dawidek 	}
32954ddff9dSPawel Jakub Dawidek 	(void)ioctl(fd, DIOCGFLUSH, NULL);
33005c91076SPawel Jakub Dawidek out:
33105c91076SPawel Jakub Dawidek 	if (sector != NULL)
33205c91076SPawel Jakub Dawidek 		free(sector);
33305c91076SPawel Jakub Dawidek 	close(fd);
33405c91076SPawel Jakub Dawidek 	return (error);
33505c91076SPawel Jakub Dawidek }
33605c91076SPawel Jakub Dawidek 
33705c91076SPawel Jakub Dawidek int
33805c91076SPawel Jakub Dawidek g_metadata_clear(const char *name, const char *magic)
33905c91076SPawel Jakub Dawidek {
34005c91076SPawel Jakub Dawidek 	struct std_metadata md;
34105c91076SPawel Jakub Dawidek 	char path[MAXPATHLEN];
34205c91076SPawel Jakub Dawidek 	unsigned sectorsize;
34305c91076SPawel Jakub Dawidek 	off_t mediasize;
34405c91076SPawel Jakub Dawidek 	u_char *sector;
34505c91076SPawel Jakub Dawidek 	int error, fd;
34605c91076SPawel Jakub Dawidek 
34705c91076SPawel Jakub Dawidek 	pathgen(name, path, sizeof(path));
34805c91076SPawel Jakub Dawidek 	sector = NULL;
34905c91076SPawel Jakub Dawidek 	error = 0;
35005c91076SPawel Jakub Dawidek 
35105c91076SPawel Jakub Dawidek 	fd = open(path, O_RDWR);
35205c91076SPawel Jakub Dawidek 	if (fd == -1)
35305c91076SPawel Jakub Dawidek 		return (errno);
35409cc9ab6SPawel Jakub Dawidek 	mediasize = g_get_mediasize(name);
35509cc9ab6SPawel Jakub Dawidek 	if (mediasize == 0) {
35605c91076SPawel Jakub Dawidek 		error = errno;
35705c91076SPawel Jakub Dawidek 		goto out;
35805c91076SPawel Jakub Dawidek 	}
35909cc9ab6SPawel Jakub Dawidek 	sectorsize = g_get_sectorsize(name);
36009cc9ab6SPawel Jakub Dawidek 	if (sectorsize == 0) {
36105c91076SPawel Jakub Dawidek 		error = errno;
36205c91076SPawel Jakub Dawidek 		goto out;
36305c91076SPawel Jakub Dawidek 	}
36405c91076SPawel Jakub Dawidek 	sector = malloc(sectorsize);
36505c91076SPawel Jakub Dawidek 	if (sector == NULL) {
36605c91076SPawel Jakub Dawidek 		error = ENOMEM;
36705c91076SPawel Jakub Dawidek 		goto out;
36805c91076SPawel Jakub Dawidek 	}
36905c91076SPawel Jakub Dawidek 	if (magic != NULL) {
37005c91076SPawel Jakub Dawidek 		if (pread(fd, sector, sectorsize, mediasize - sectorsize) !=
37105c91076SPawel Jakub Dawidek 		    (ssize_t)sectorsize) {
37205c91076SPawel Jakub Dawidek 			error = errno;
37305c91076SPawel Jakub Dawidek 			goto out;
37405c91076SPawel Jakub Dawidek 		}
37505c91076SPawel Jakub Dawidek 		std_metadata_decode(sector, &md);
37605c91076SPawel Jakub Dawidek 		if (strcmp(md.md_magic, magic) != 0) {
37705c91076SPawel Jakub Dawidek 			error = EINVAL;
37805c91076SPawel Jakub Dawidek 			goto out;
37905c91076SPawel Jakub Dawidek 		}
38005c91076SPawel Jakub Dawidek 	}
38105c91076SPawel Jakub Dawidek 	bzero(sector, sectorsize);
38205c91076SPawel Jakub Dawidek 	if (pwrite(fd, sector, sectorsize, mediasize - sectorsize) !=
38305c91076SPawel Jakub Dawidek 	    (ssize_t)sectorsize) {
38405c91076SPawel Jakub Dawidek 		error = errno;
38505c91076SPawel Jakub Dawidek 		goto out;
38605c91076SPawel Jakub Dawidek 	}
38754ddff9dSPawel Jakub Dawidek 	(void)ioctl(fd, DIOCGFLUSH, NULL);
38805c91076SPawel Jakub Dawidek out:
38905c91076SPawel Jakub Dawidek 	if (sector != NULL)
39005c91076SPawel Jakub Dawidek 		free(sector);
39105c91076SPawel Jakub Dawidek 	close(fd);
39205c91076SPawel Jakub Dawidek 	return (error);
39305c91076SPawel Jakub Dawidek }
39405c91076SPawel Jakub Dawidek 
39505c91076SPawel Jakub Dawidek /*
39605c91076SPawel Jakub Dawidek  * Set an error message, if one does not already exist.
39705c91076SPawel Jakub Dawidek  */
39805c91076SPawel Jakub Dawidek void
39905c91076SPawel Jakub Dawidek gctl_error(struct gctl_req *req, const char *error, ...)
40005c91076SPawel Jakub Dawidek {
40105c91076SPawel Jakub Dawidek 	va_list ap;
40205c91076SPawel Jakub Dawidek 
40305c91076SPawel Jakub Dawidek 	if (req->error != NULL)
40405c91076SPawel Jakub Dawidek 		return;
40505c91076SPawel Jakub Dawidek 	va_start(ap, error);
40605c91076SPawel Jakub Dawidek 	vasprintf(&req->error, error, ap);
40705c91076SPawel Jakub Dawidek 	va_end(ap);
40805c91076SPawel Jakub Dawidek }
40905c91076SPawel Jakub Dawidek 
410f13942a7SPawel Jakub Dawidek static void *
411f13942a7SPawel Jakub Dawidek gctl_get_param(struct gctl_req *req, size_t len, const char *pfmt, va_list ap)
41205c91076SPawel Jakub Dawidek {
413f13942a7SPawel Jakub Dawidek 	struct gctl_req_arg *argp;
414f13942a7SPawel Jakub Dawidek 	char param[256];
41505c91076SPawel Jakub Dawidek 	void *p;
41605c91076SPawel Jakub Dawidek 	unsigned i;
41705c91076SPawel Jakub Dawidek 
418f13942a7SPawel Jakub Dawidek 	vsnprintf(param, sizeof(param), pfmt, ap);
41905c91076SPawel Jakub Dawidek 	for (i = 0; i < req->narg; i++) {
420f13942a7SPawel Jakub Dawidek 		argp = &req->arg[i];
421f13942a7SPawel Jakub Dawidek 		if (strcmp(param, argp->name))
42205c91076SPawel Jakub Dawidek 			continue;
423f13942a7SPawel Jakub Dawidek 		if (!(argp->flag & GCTL_PARAM_RD))
42405c91076SPawel Jakub Dawidek 			continue;
425f13942a7SPawel Jakub Dawidek 		p = argp->value;
426f13942a7SPawel Jakub Dawidek 		if (len == 0) {
427f13942a7SPawel Jakub Dawidek 			/* We are looking for a string. */
428f13942a7SPawel Jakub Dawidek 			if (argp->len < 1) {
429f13942a7SPawel Jakub Dawidek 				fprintf(stderr, "No length argument (%s).\n",
430f13942a7SPawel Jakub Dawidek 				    param);
431f13942a7SPawel Jakub Dawidek 				abort();
43205c91076SPawel Jakub Dawidek 			}
433f13942a7SPawel Jakub Dawidek 			if (((char *)p)[argp->len - 1] != '\0') {
434f13942a7SPawel Jakub Dawidek 				fprintf(stderr, "Unterminated argument (%s).\n",
435f13942a7SPawel Jakub Dawidek 				    param);
436f13942a7SPawel Jakub Dawidek 				abort();
437f13942a7SPawel Jakub Dawidek 			}
438f13942a7SPawel Jakub Dawidek 		} else if ((int)len != argp->len) {
439f13942a7SPawel Jakub Dawidek 			fprintf(stderr, "Wrong length %s argument.\n", param);
440f13942a7SPawel Jakub Dawidek 			abort();
44105c91076SPawel Jakub Dawidek 		}
44205c91076SPawel Jakub Dawidek 		return (p);
44305c91076SPawel Jakub Dawidek 	}
444f13942a7SPawel Jakub Dawidek 	fprintf(stderr, "No such argument (%s).\n", param);
445f13942a7SPawel Jakub Dawidek 	abort();
44605c91076SPawel Jakub Dawidek }
44705c91076SPawel Jakub Dawidek 
448f13942a7SPawel Jakub Dawidek int
449f13942a7SPawel Jakub Dawidek gctl_get_int(struct gctl_req *req, const char *pfmt, ...)
45005c91076SPawel Jakub Dawidek {
451f13942a7SPawel Jakub Dawidek 	int *p;
452f13942a7SPawel Jakub Dawidek 	va_list ap;
45305c91076SPawel Jakub Dawidek 
454f13942a7SPawel Jakub Dawidek 	va_start(ap, pfmt);
455f13942a7SPawel Jakub Dawidek 	p = gctl_get_param(req, sizeof(int), pfmt, ap);
456f13942a7SPawel Jakub Dawidek 	va_end(ap);
457f13942a7SPawel Jakub Dawidek 	return (*p);
45805c91076SPawel Jakub Dawidek }
459f13942a7SPawel Jakub Dawidek 
460f13942a7SPawel Jakub Dawidek intmax_t
461f13942a7SPawel Jakub Dawidek gctl_get_intmax(struct gctl_req *req, const char *pfmt, ...)
462f13942a7SPawel Jakub Dawidek {
463f13942a7SPawel Jakub Dawidek 	intmax_t *p;
464f13942a7SPawel Jakub Dawidek 	va_list ap;
465f13942a7SPawel Jakub Dawidek 
466f13942a7SPawel Jakub Dawidek 	va_start(ap, pfmt);
467f13942a7SPawel Jakub Dawidek 	p = gctl_get_param(req, sizeof(intmax_t), pfmt, ap);
468f13942a7SPawel Jakub Dawidek 	va_end(ap);
469f13942a7SPawel Jakub Dawidek 	return (*p);
470f13942a7SPawel Jakub Dawidek }
471f13942a7SPawel Jakub Dawidek 
472f13942a7SPawel Jakub Dawidek const char *
473f13942a7SPawel Jakub Dawidek gctl_get_ascii(struct gctl_req *req, const char *pfmt, ...)
474f13942a7SPawel Jakub Dawidek {
475f13942a7SPawel Jakub Dawidek 	const char *p;
476f13942a7SPawel Jakub Dawidek 	va_list ap;
477f13942a7SPawel Jakub Dawidek 
478f13942a7SPawel Jakub Dawidek 	va_start(ap, pfmt);
479f13942a7SPawel Jakub Dawidek 	p = gctl_get_param(req, 0, pfmt, ap);
480f13942a7SPawel Jakub Dawidek 	va_end(ap);
48105c91076SPawel Jakub Dawidek 	return (p);
48205c91076SPawel Jakub Dawidek }
4831378624cSPawel Jakub Dawidek 
4841378624cSPawel Jakub Dawidek int
4851378624cSPawel Jakub Dawidek gctl_change_param(struct gctl_req *req, const char *name, int len,
4861378624cSPawel Jakub Dawidek     const void *value)
4871378624cSPawel Jakub Dawidek {
4881378624cSPawel Jakub Dawidek 	struct gctl_req_arg *ap;
4891378624cSPawel Jakub Dawidek 	unsigned i;
4901378624cSPawel Jakub Dawidek 
4911378624cSPawel Jakub Dawidek 	if (req == NULL || req->error != NULL)
4921378624cSPawel Jakub Dawidek 		return (EDOOFUS);
4931378624cSPawel Jakub Dawidek 	for (i = 0; i < req->narg; i++) {
4941378624cSPawel Jakub Dawidek 		ap = &req->arg[i];
4951378624cSPawel Jakub Dawidek 		if (strcmp(ap->name, name) != 0)
4961378624cSPawel Jakub Dawidek 			continue;
4971378624cSPawel Jakub Dawidek 		ap->value = __DECONST(void *, value);
4981378624cSPawel Jakub Dawidek 		if (len >= 0) {
4991378624cSPawel Jakub Dawidek 			ap->flag &= ~GCTL_PARAM_ASCII;
5001378624cSPawel Jakub Dawidek 			ap->len = len;
5011378624cSPawel Jakub Dawidek 		} else if (len < 0) {
5021378624cSPawel Jakub Dawidek 			ap->flag |= GCTL_PARAM_ASCII;
5031378624cSPawel Jakub Dawidek 			ap->len = strlen(value) + 1;
5041378624cSPawel Jakub Dawidek 		}
5051378624cSPawel Jakub Dawidek 		return (0);
5061378624cSPawel Jakub Dawidek 	}
5071378624cSPawel Jakub Dawidek 	return (ENOENT);
5081378624cSPawel Jakub Dawidek }
50959458bafSMarcel Moolenaar 
51059458bafSMarcel Moolenaar int
51159458bafSMarcel Moolenaar gctl_delete_param(struct gctl_req *req, const char *name)
51259458bafSMarcel Moolenaar {
51359458bafSMarcel Moolenaar 	struct gctl_req_arg *ap;
51459458bafSMarcel Moolenaar 	unsigned int i;
51559458bafSMarcel Moolenaar 
51659458bafSMarcel Moolenaar 	if (req == NULL || req->error != NULL)
51759458bafSMarcel Moolenaar 		return (EDOOFUS);
51859458bafSMarcel Moolenaar 
51959458bafSMarcel Moolenaar 	i = 0;
52059458bafSMarcel Moolenaar 	while (i < req->narg) {
52159458bafSMarcel Moolenaar 		ap = &req->arg[i];
52259458bafSMarcel Moolenaar 		if (strcmp(ap->name, name) == 0)
52359458bafSMarcel Moolenaar 			break;
52459458bafSMarcel Moolenaar 		i++;
52559458bafSMarcel Moolenaar 	}
52659458bafSMarcel Moolenaar 	if (i == req->narg)
52759458bafSMarcel Moolenaar 		return (ENOENT);
52859458bafSMarcel Moolenaar 
52924609c49SAndrey V. Elsukov 	free(ap->name);
53059458bafSMarcel Moolenaar 	req->narg--;
53159458bafSMarcel Moolenaar 	while (i < req->narg) {
53259458bafSMarcel Moolenaar 		req->arg[i] = req->arg[i + 1];
53359458bafSMarcel Moolenaar 		i++;
53459458bafSMarcel Moolenaar 	}
53559458bafSMarcel Moolenaar 	return (0);
53659458bafSMarcel Moolenaar }
53759458bafSMarcel Moolenaar 
53859458bafSMarcel Moolenaar int
53959458bafSMarcel Moolenaar gctl_has_param(struct gctl_req *req, const char *name)
54059458bafSMarcel Moolenaar {
54159458bafSMarcel Moolenaar 	struct gctl_req_arg *ap;
54259458bafSMarcel Moolenaar 	unsigned int i;
54359458bafSMarcel Moolenaar 
54459458bafSMarcel Moolenaar 	if (req == NULL || req->error != NULL)
54559458bafSMarcel Moolenaar 		return (0);
54659458bafSMarcel Moolenaar 
54759458bafSMarcel Moolenaar 	for (i = 0; i < req->narg; i++) {
54859458bafSMarcel Moolenaar 		ap = &req->arg[i];
54959458bafSMarcel Moolenaar 		if (strcmp(ap->name, name) == 0)
55059458bafSMarcel Moolenaar 			return (1);
55159458bafSMarcel Moolenaar 	}
55259458bafSMarcel Moolenaar 	return (0);
55359458bafSMarcel Moolenaar }
554