subr.c revision 155175
118334Speter/*-
252284Sobrien * Copyright (c) 2004 Pawel Jakub Dawidek <pjd@FreeBSD.org>
318334Speter * All rights reserved.
418334Speter *
518334Speter * Redistribution and use in source and binary forms, with or without
618334Speter * modification, are permitted provided that the following conditions
718334Speter * are met:
818334Speter * 1. Redistributions of source code must retain the above copyright
918334Speter *    notice, this list of conditions and the following disclaimer.
1018334Speter * 2. Redistributions in binary form must reproduce the above copyright
1118334Speter *    notice, this list of conditions and the following disclaimer in the
1218334Speter *    documentation and/or other materials provided with the distribution.
1318334Speter *
1418334Speter * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
1518334Speter * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1618334Speter * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1718334Speter * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
1818334Speter * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1918334Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2018334Speter * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2118334Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2218334Speter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2318334Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2418334Speter * SUCH DAMAGE.
2518334Speter */
2618334Speter
2718334Speter#include <sys/cdefs.h>
2818334Speter__FBSDID("$FreeBSD: head/sbin/geom/misc/subr.c 155175 2006-02-01 12:11:37Z pjd $");
2918334Speter
3018334Speter#include <sys/param.h>
3118334Speter#include <sys/disk.h>
3218334Speter#include <sys/endian.h>
3318334Speter#include <sys/uio.h>
3418334Speter#include <errno.h>
3518334Speter#include <fcntl.h>
3618334Speter#include <paths.h>
3718334Speter#include <stdio.h>
3818334Speter#include <stdlib.h>
3918334Speter#include <stdarg.h>
4018334Speter#include <string.h>
4118334Speter#include <strings.h>
4218334Speter#include <unistd.h>
4318334Speter#include <assert.h>
4418334Speter#include <libgeom.h>
4518334Speter
4618334Speter#include "misc/subr.h"
4718334Speter
4818334Speter
4918334Speterstruct std_metadata {
5018334Speter	char		md_magic[16];
5118334Speter	uint32_t	md_version;
5218334Speter};
5318334Speter
5418334Speterstatic void
5518334Speterstd_metadata_decode(const u_char *data, struct std_metadata *md)
5618334Speter{
5718334Speter
5818334Speter        bcopy(data, md->md_magic, sizeof(md->md_magic));
5918334Speter        md->md_version = le32dec(data + 16);
6018334Speter}
6118334Speter
6218334Speterstatic void
6318334Speterpathgen(const char *name, char *path, size_t size)
6418334Speter{
6518334Speter
6618334Speter	if (strncmp(name, _PATH_DEV, strlen(_PATH_DEV)) != 0)
6718334Speter		snprintf(path, size, "%s%s", _PATH_DEV, name);
6818334Speter	else
6918334Speter		strlcpy(path, name, size);
7018334Speter}
7118334Speter
7218334Speter/*
7318334Speter * Greatest Common Divisor.
7418334Speter */
7518334Speterstatic unsigned
7618334Spetergcd(unsigned a, unsigned b)
7718334Speter{
7818334Speter	u_int c;
7918334Speter
8018334Speter	while (b != 0) {
8118334Speter		c = a;
8218334Speter		a = b;
8318334Speter		b = (c % b);
8418334Speter	}
8518334Speter	return (a);
8618334Speter}
8718334Speter
8818334Speter/*
8918334Speter * Least Common Multiple.
9018334Speter */
9118334Speterunsigned
9218334Speterg_lcm(unsigned a, unsigned b)
9318334Speter{
9418334Speter
9518334Speter	return ((a * b) / gcd(a, b));
9618334Speter}
9718334Speter
9818334Speteruint32_t
9918334Speterbitcount32(uint32_t x)
10018334Speter{
10118334Speter
10218334Speter	x = (x & 0x55555555) + ((x & 0xaaaaaaaa) >> 1);
10318334Speter	x = (x & 0x33333333) + ((x & 0xcccccccc) >> 2);
10418334Speter	x = (x & 0x0f0f0f0f) + ((x & 0xf0f0f0f0) >> 4);
10518334Speter	x = (x & 0x00ff00ff) + ((x & 0xff00ff00) >> 8);
10618334Speter	x = (x & 0x0000ffff) + ((x & 0xffff0000) >> 16);
10718334Speter	return (x);
10818334Speter}
10918334Speter
11018334Speteroff_t
11118334Speterg_get_mediasize(const char *name)
11218334Speter{
11318334Speter	char path[MAXPATHLEN];
11418334Speter	off_t mediasize;
11518334Speter	int fd;
11618334Speter
11718334Speter	pathgen(name, path, sizeof(path));
11818334Speter	fd = open(path, O_RDONLY);
11918334Speter	if (fd == -1)
12018334Speter		return (0);
12118334Speter	if (ioctl(fd, DIOCGMEDIASIZE, &mediasize) < 0) {
12218334Speter		close(fd);
12318334Speter		return (0);
12418334Speter	}
12518334Speter	close(fd);
12618334Speter	return (mediasize);
12718334Speter}
12818334Speter
12918334Speterunsigned
13018334Speterg_get_sectorsize(const char *name)
13118334Speter{
13218334Speter	char path[MAXPATHLEN];
13318334Speter	unsigned sectorsize;
13418334Speter	int fd;
13518334Speter
13618334Speter	pathgen(name, path, sizeof(path));
13718334Speter	fd = open(path, O_RDONLY);
13818334Speter	if (fd == -1)
13918334Speter		return (0);
14018334Speter	if (ioctl(fd, DIOCGSECTORSIZE, &sectorsize) < 0) {
14118334Speter		close(fd);
14218334Speter		return (0);
14318334Speter	}
14418334Speter	close(fd);
14518334Speter	return (sectorsize);
14618334Speter}
14718334Speter
14818334Speterint
14918334Speterg_metadata_read(const char *name, u_char *md, size_t size, const char *magic)
15018334Speter{
15118334Speter	struct std_metadata stdmd;
15218334Speter	char path[MAXPATHLEN];
15318334Speter	unsigned sectorsize;
15450397Sobrien	off_t mediasize;
15518334Speter	u_char *sector;
15618334Speter	int error, fd;
15718334Speter
15818334Speter	pathgen(name, path, sizeof(path));
15918334Speter	sector = NULL;
16018334Speter	error = 0;
16150397Sobrien
16252284Sobrien	fd = open(path, O_RDONLY);
16350397Sobrien	if (fd == -1)
16452284Sobrien		return (errno);
16518334Speter	mediasize = g_get_mediasize(name);
16618334Speter	if (mediasize == 0) {
16718334Speter		error = errno;
16818334Speter		goto out;
16918334Speter	}
17018334Speter	sectorsize = g_get_sectorsize(name);
17118334Speter	if (sectorsize == 0) {
17218334Speter		error = errno;
17318334Speter		goto out;
17418334Speter	}
17518334Speter	assert(sectorsize >= size);
17618334Speter	sector = malloc(sectorsize);
17718334Speter	if (sector == NULL) {
17818334Speter		error = ENOMEM;
17918334Speter		goto out;
18018334Speter	}
18118334Speter	if (pread(fd, sector, sectorsize, mediasize - sectorsize) !=
18218334Speter	    (ssize_t)sectorsize) {
18318334Speter		error = errno;
18418334Speter		goto out;
18518334Speter	}
18618334Speter	if (magic != NULL) {
18718334Speter		std_metadata_decode(sector, &stdmd);
18818334Speter		if (strcmp(stdmd.md_magic, magic) != 0) {
18918334Speter			error = EINVAL;
19018334Speter			goto out;
19118334Speter		}
19218334Speter	}
19318334Speter	bcopy(sector, md, size);
19418334Speterout:
19518334Speter	if (sector != NULL)
19618334Speter		free(sector);
19718334Speter	close(fd);
19818334Speter	return (error);
19918334Speter}
20018334Speter
20118334Speterint
20218334Speterg_metadata_store(const char *name, u_char *md, size_t size)
20318334Speter{
20418334Speter	char path[MAXPATHLEN];
20518334Speter	unsigned sectorsize;
20618334Speter	off_t mediasize;
20718334Speter	u_char *sector;
20818334Speter	int error, fd;
20918334Speter
21018334Speter	pathgen(name, path, sizeof(path));
21118334Speter	sector = NULL;
21218334Speter	error = 0;
21350397Sobrien
21418334Speter	fd = open(path, O_WRONLY);
21518334Speter	if (fd == -1)
21652284Sobrien		return (errno);
21752284Sobrien	mediasize = g_get_mediasize(name);
21852284Sobrien	if (mediasize == 0) {
21952284Sobrien		error = errno;
22052284Sobrien		goto out;
22152284Sobrien	}
22252284Sobrien	sectorsize = g_get_sectorsize(name);
22352284Sobrien	if (sectorsize == 0) {
22418334Speter		error = errno;
22518334Speter		goto out;
22618334Speter	}
22718334Speter	assert(sectorsize >= size);
22818334Speter	sector = malloc(sectorsize);
22918334Speter	if (sector == NULL) {
23018334Speter		error = ENOMEM;
23118334Speter		goto out;
23250397Sobrien	}
23318334Speter	bcopy(md, sector, size);
23452284Sobrien	if (pwrite(fd, sector, sectorsize, mediasize - sectorsize) !=
23518334Speter	    (ssize_t)sectorsize) {
23652284Sobrien		error = errno;
23752284Sobrien		goto out;
23852284Sobrien	}
23952284Sobrienout:
24052284Sobrien	if (sector != NULL)
24152284Sobrien		free(sector);
24252284Sobrien	close(fd);
24352284Sobrien	return (error);
24452284Sobrien}
24552284Sobrien
24652284Sobrienint
24752284Sobrieng_metadata_clear(const char *name, const char *magic)
24852284Sobrien{
24952284Sobrien	struct std_metadata md;
25052284Sobrien	char path[MAXPATHLEN];
25152284Sobrien	unsigned sectorsize;
25218334Speter	off_t mediasize;
25318334Speter	u_char *sector;
25418334Speter	int error, fd;
25518334Speter
25650397Sobrien	pathgen(name, path, sizeof(path));
25750397Sobrien	sector = NULL;
25850397Sobrien	error = 0;
25950397Sobrien
26050397Sobrien	fd = open(path, O_RDWR);
26150397Sobrien	if (fd == -1)
26252284Sobrien		return (errno);
26350397Sobrien	mediasize = g_get_mediasize(name);
26450397Sobrien	if (mediasize == 0) {
26552284Sobrien		error = errno;
26650397Sobrien		goto out;
26750397Sobrien	}
26850397Sobrien	sectorsize = g_get_sectorsize(name);
26950397Sobrien	if (sectorsize == 0) {
27050397Sobrien		error = errno;
27150397Sobrien		goto out;
27250397Sobrien	}
27350397Sobrien	sector = malloc(sectorsize);
27450397Sobrien	if (sector == NULL) {
27550397Sobrien		error = ENOMEM;
27650397Sobrien		goto out;
27750397Sobrien	}
27850397Sobrien	if (magic != NULL) {
27950397Sobrien		if (pread(fd, sector, sectorsize, mediasize - sectorsize) !=
28052284Sobrien		    (ssize_t)sectorsize) {
28150397Sobrien			error = errno;
28250397Sobrien			goto out;
28350397Sobrien		}
28450397Sobrien		std_metadata_decode(sector, &md);
28550397Sobrien		if (strcmp(md.md_magic, magic) != 0) {
28650397Sobrien			error = EINVAL;
28750397Sobrien			goto out;
28852284Sobrien		}
28918334Speter	}
29052284Sobrien	bzero(sector, sectorsize);
29152284Sobrien	if (pwrite(fd, sector, sectorsize, mediasize - sectorsize) !=
29252284Sobrien	    (ssize_t)sectorsize) {
29352284Sobrien		error = errno;
29452284Sobrien		goto out;
29552284Sobrien	}
29652284Sobrienout:
29752284Sobrien	if (sector != NULL)
29852284Sobrien		free(sector);
29952284Sobrien	close(fd);
30052284Sobrien	return (error);
30152284Sobrien}
30252284Sobrien
30352284Sobrien/*
30452284Sobrien * Set an error message, if one does not already exist.
30552284Sobrien */
30652284Sobrienvoid
30752284Sobriengctl_error(struct gctl_req *req, const char *error, ...)
30852284Sobrien{
30952284Sobrien	va_list ap;
31052284Sobrien
31152284Sobrien	if (req->error != NULL)
31252284Sobrien		return;
31352284Sobrien	va_start(ap, error);
31452284Sobrien	vasprintf(&req->error, error, ap);
31552284Sobrien	va_end(ap);
31652284Sobrien}
31752284Sobrien
31852284Sobrienstatic void *
31952284Sobriengctl_get_param(struct gctl_req *req, size_t len, const char *pfmt, va_list ap)
32052284Sobrien{
32152284Sobrien	struct gctl_req_arg *argp;
32252284Sobrien	char param[256];
32352284Sobrien	void *p;
32452284Sobrien	unsigned i;
32552284Sobrien
32652284Sobrien	vsnprintf(param, sizeof(param), pfmt, ap);
32752284Sobrien	for (i = 0; i < req->narg; i++) {
32852284Sobrien		argp = &req->arg[i];
32952284Sobrien		if (strcmp(param, argp->name))
33018334Speter			continue;
33118334Speter		if (!(argp->flag & GCTL_PARAM_RD))
33218334Speter			continue;
33318334Speter		p = argp->value;
33418334Speter		if (len == 0) {
33518334Speter			/* We are looking for a string. */
33618334Speter			if (argp->len < 1) {
33718334Speter				fprintf(stderr, "No length argument (%s).\n",
33818334Speter				    param);
33918334Speter				abort();
34018334Speter			}
34118334Speter			if (((char *)p)[argp->len - 1] != '\0') {
34218334Speter				fprintf(stderr, "Unterminated argument (%s).\n",
34318334Speter				    param);
34418334Speter				abort();
34518334Speter			}
34618334Speter		} else if ((int)len != argp->len) {
34718334Speter			fprintf(stderr, "Wrong length %s argument.\n", param);
34818334Speter			abort();
34918334Speter		}
35018334Speter		return (p);
35118334Speter	}
35218334Speter	fprintf(stderr, "No such argument (%s).\n", param);
35318334Speter	abort();
35418334Speter}
35518334Speter
35618334Speterint
35718334Spetergctl_get_int(struct gctl_req *req, const char *pfmt, ...)
35818334Speter{
35918334Speter	int *p;
36018334Speter	va_list ap;
36118334Speter
36218334Speter	va_start(ap, pfmt);
36318334Speter	p = gctl_get_param(req, sizeof(int), pfmt, ap);
36418334Speter	va_end(ap);
36518334Speter	return (*p);
36650397Sobrien}
36750397Sobrien
36850397Sobrienintmax_t
36950397Sobriengctl_get_intmax(struct gctl_req *req, const char *pfmt, ...)
37050397Sobrien{
37150397Sobrien	intmax_t *p;
37250397Sobrien	va_list ap;
37318334Speter
37418334Speter	va_start(ap, pfmt);
37518334Speter	p = gctl_get_param(req, sizeof(intmax_t), pfmt, ap);
37618334Speter	va_end(ap);
37718334Speter	return (*p);
37818334Speter}
37918334Speter
38050397Sobrienconst char *
38150397Sobriengctl_get_ascii(struct gctl_req *req, const char *pfmt, ...)
38250397Sobrien{
38350397Sobrien	const char *p;
38450397Sobrien	va_list ap;
38550397Sobrien
38650397Sobrien	va_start(ap, pfmt);
38750397Sobrien	p = gctl_get_param(req, 0, pfmt, ap);
38850397Sobrien	va_end(ap);
38950397Sobrien	return (p);
39050397Sobrien}
39150397Sobrien