xref: /freebsd/sbin/geom/misc/subr.c (revision 09cc9ab63d0f50d107a03390b70dfdfbfe6aa363)
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>
3905c91076SPawel Jakub Dawidek #include <stdarg.h>
4005c91076SPawel Jakub Dawidek #include <string.h>
4105c91076SPawel Jakub Dawidek #include <strings.h>
4205c91076SPawel Jakub Dawidek #include <unistd.h>
4305c91076SPawel Jakub Dawidek #include <assert.h>
4405c91076SPawel Jakub Dawidek #include <libgeom.h>
4505c91076SPawel Jakub Dawidek 
4605c91076SPawel Jakub Dawidek #include "misc/subr.h"
4705c91076SPawel Jakub Dawidek 
4805c91076SPawel Jakub Dawidek 
4905c91076SPawel Jakub Dawidek struct std_metadata {
5005c91076SPawel Jakub Dawidek 	char		md_magic[16];
5105c91076SPawel Jakub Dawidek 	uint32_t	md_version;
5205c91076SPawel Jakub Dawidek };
5305c91076SPawel Jakub Dawidek 
5405c91076SPawel Jakub Dawidek static void
5505c91076SPawel Jakub Dawidek std_metadata_decode(const u_char *data, struct std_metadata *md)
5605c91076SPawel Jakub Dawidek {
5705c91076SPawel Jakub Dawidek 
5805c91076SPawel Jakub Dawidek         bcopy(data, md->md_magic, sizeof(md->md_magic));
5905c91076SPawel Jakub Dawidek         md->md_version = le32dec(data + 16);
6005c91076SPawel Jakub Dawidek }
6105c91076SPawel Jakub Dawidek 
6205c91076SPawel Jakub Dawidek static void
6305c91076SPawel Jakub Dawidek pathgen(const char *name, char *path, size_t size)
6405c91076SPawel Jakub Dawidek {
6505c91076SPawel Jakub Dawidek 
6605c91076SPawel Jakub Dawidek 	if (strncmp(name, _PATH_DEV, strlen(_PATH_DEV)) != 0)
6705c91076SPawel Jakub Dawidek 		snprintf(path, size, "%s%s", _PATH_DEV, name);
6805c91076SPawel Jakub Dawidek 	else
6905c91076SPawel Jakub Dawidek 		strlcpy(path, name, size);
7005c91076SPawel Jakub Dawidek }
7105c91076SPawel Jakub Dawidek 
7209cc9ab6SPawel Jakub Dawidek /*
7309cc9ab6SPawel Jakub Dawidek  * Greatest Common Divisor.
7409cc9ab6SPawel Jakub Dawidek  */
7509cc9ab6SPawel Jakub Dawidek static unsigned
7609cc9ab6SPawel Jakub Dawidek gcd(unsigned a, unsigned b)
7709cc9ab6SPawel Jakub Dawidek {
7809cc9ab6SPawel Jakub Dawidek 	u_int c;
7909cc9ab6SPawel Jakub Dawidek 
8009cc9ab6SPawel Jakub Dawidek 	while (b != 0) {
8109cc9ab6SPawel Jakub Dawidek 		c = a;
8209cc9ab6SPawel Jakub Dawidek 		a = b;
8309cc9ab6SPawel Jakub Dawidek 		b = (c % b);
8409cc9ab6SPawel Jakub Dawidek 	}
8509cc9ab6SPawel Jakub Dawidek 	return (a);
8609cc9ab6SPawel Jakub Dawidek }
8709cc9ab6SPawel Jakub Dawidek 
8809cc9ab6SPawel Jakub Dawidek /*
8909cc9ab6SPawel Jakub Dawidek  * Least Common Multiple.
9009cc9ab6SPawel Jakub Dawidek  */
9109cc9ab6SPawel Jakub Dawidek unsigned
9209cc9ab6SPawel Jakub Dawidek g_lcm(unsigned a, unsigned b)
9309cc9ab6SPawel Jakub Dawidek {
9409cc9ab6SPawel Jakub Dawidek 
9509cc9ab6SPawel Jakub Dawidek 	return ((a * b) / gcd(a, b));
9609cc9ab6SPawel Jakub Dawidek }
9709cc9ab6SPawel Jakub Dawidek 
9809cc9ab6SPawel Jakub Dawidek off_t
9909cc9ab6SPawel Jakub Dawidek g_get_mediasize(const char *name)
10009cc9ab6SPawel Jakub Dawidek {
10109cc9ab6SPawel Jakub Dawidek 	char path[MAXPATHLEN];
10209cc9ab6SPawel Jakub Dawidek 	off_t mediasize;
10309cc9ab6SPawel Jakub Dawidek 	int fd;
10409cc9ab6SPawel Jakub Dawidek 
10509cc9ab6SPawel Jakub Dawidek 	pathgen(name, path, sizeof(path));
10609cc9ab6SPawel Jakub Dawidek 	fd = open(path, O_RDONLY);
10709cc9ab6SPawel Jakub Dawidek 	if (fd == -1)
10809cc9ab6SPawel Jakub Dawidek 		return (0);
10909cc9ab6SPawel Jakub Dawidek 	if (ioctl(fd, DIOCGMEDIASIZE, &mediasize) < 0) {
11009cc9ab6SPawel Jakub Dawidek 		close(fd);
11109cc9ab6SPawel Jakub Dawidek 		return (0);
11209cc9ab6SPawel Jakub Dawidek 	}
11309cc9ab6SPawel Jakub Dawidek 	close(fd);
11409cc9ab6SPawel Jakub Dawidek 	return (mediasize);
11509cc9ab6SPawel Jakub Dawidek }
11609cc9ab6SPawel Jakub Dawidek 
11709cc9ab6SPawel Jakub Dawidek unsigned
11809cc9ab6SPawel Jakub Dawidek g_get_sectorsize(const char *name)
11909cc9ab6SPawel Jakub Dawidek {
12009cc9ab6SPawel Jakub Dawidek 	char path[MAXPATHLEN];
12109cc9ab6SPawel Jakub Dawidek 	unsigned sectorsize;
12209cc9ab6SPawel Jakub Dawidek 	int fd;
12309cc9ab6SPawel Jakub Dawidek 
12409cc9ab6SPawel Jakub Dawidek 	pathgen(name, path, sizeof(path));
12509cc9ab6SPawel Jakub Dawidek 	fd = open(path, O_RDONLY);
12609cc9ab6SPawel Jakub Dawidek 	if (fd == -1)
12709cc9ab6SPawel Jakub Dawidek 		return (0);
12809cc9ab6SPawel Jakub Dawidek 	if (ioctl(fd, DIOCGSECTORSIZE, &sectorsize) < 0) {
12909cc9ab6SPawel Jakub Dawidek 		close(fd);
13009cc9ab6SPawel Jakub Dawidek 		return (0);
13109cc9ab6SPawel Jakub Dawidek 	}
13209cc9ab6SPawel Jakub Dawidek 	close(fd);
13309cc9ab6SPawel Jakub Dawidek 	return (sectorsize);
13409cc9ab6SPawel Jakub Dawidek }
13509cc9ab6SPawel Jakub Dawidek 
13605c91076SPawel Jakub Dawidek int
13705c91076SPawel Jakub Dawidek g_metadata_store(const char *name, u_char *md, size_t size)
13805c91076SPawel Jakub Dawidek {
13905c91076SPawel Jakub Dawidek 	char path[MAXPATHLEN];
14005c91076SPawel Jakub Dawidek 	unsigned sectorsize;
14105c91076SPawel Jakub Dawidek 	off_t mediasize;
14205c91076SPawel Jakub Dawidek 	u_char *sector;
14305c91076SPawel Jakub Dawidek 	int error, fd;
14405c91076SPawel Jakub Dawidek 
14505c91076SPawel Jakub Dawidek 	pathgen(name, path, sizeof(path));
14605c91076SPawel Jakub Dawidek 	sector = NULL;
14705c91076SPawel Jakub Dawidek 	error = 0;
14805c91076SPawel Jakub Dawidek 
14905c91076SPawel Jakub Dawidek 	fd = open(path, O_WRONLY);
15005c91076SPawel Jakub Dawidek 	if (fd == -1)
15105c91076SPawel Jakub Dawidek 		return (errno);
15209cc9ab6SPawel Jakub Dawidek 	mediasize = g_get_mediasize(name);
15309cc9ab6SPawel Jakub Dawidek 	if (mediasize == 0) {
15405c91076SPawel Jakub Dawidek 		error = errno;
15505c91076SPawel Jakub Dawidek 		goto out;
15605c91076SPawel Jakub Dawidek 	}
15709cc9ab6SPawel Jakub Dawidek 	sectorsize = g_get_sectorsize(name);
15809cc9ab6SPawel Jakub Dawidek 	if (sectorsize == 0) {
15905c91076SPawel Jakub Dawidek 		error = errno;
16005c91076SPawel Jakub Dawidek 		goto out;
16105c91076SPawel Jakub Dawidek 	}
16205c91076SPawel Jakub Dawidek 	assert(sectorsize >= size);
16305c91076SPawel Jakub Dawidek 	sector = malloc(sectorsize);
16405c91076SPawel Jakub Dawidek 	if (sector == NULL) {
16505c91076SPawel Jakub Dawidek 		error = ENOMEM;
16605c91076SPawel Jakub Dawidek 		goto out;
16705c91076SPawel Jakub Dawidek 	}
16805c91076SPawel Jakub Dawidek 	bcopy(md, sector, size);
16905c91076SPawel Jakub Dawidek 	if (pwrite(fd, sector, sectorsize, mediasize - sectorsize) !=
17005c91076SPawel Jakub Dawidek 	    (ssize_t)sectorsize) {
17105c91076SPawel Jakub Dawidek 		error = errno;
17205c91076SPawel Jakub Dawidek 		goto out;
17305c91076SPawel Jakub Dawidek 	}
17405c91076SPawel Jakub Dawidek out:
17505c91076SPawel Jakub Dawidek 	if (sector != NULL)
17605c91076SPawel Jakub Dawidek 		free(sector);
17705c91076SPawel Jakub Dawidek 	close(fd);
17805c91076SPawel Jakub Dawidek 	return (error);
17905c91076SPawel Jakub Dawidek }
18005c91076SPawel Jakub Dawidek 
18105c91076SPawel Jakub Dawidek int
18205c91076SPawel Jakub Dawidek g_metadata_clear(const char *name, const char *magic)
18305c91076SPawel Jakub Dawidek {
18405c91076SPawel Jakub Dawidek 	struct std_metadata md;
18505c91076SPawel Jakub Dawidek 	char path[MAXPATHLEN];
18605c91076SPawel Jakub Dawidek 	unsigned sectorsize;
18705c91076SPawel Jakub Dawidek 	off_t mediasize;
18805c91076SPawel Jakub Dawidek 	u_char *sector;
18905c91076SPawel Jakub Dawidek 	int error, fd;
19005c91076SPawel Jakub Dawidek 
19105c91076SPawel Jakub Dawidek 	pathgen(name, path, sizeof(path));
19205c91076SPawel Jakub Dawidek 	sector = NULL;
19305c91076SPawel Jakub Dawidek 	error = 0;
19405c91076SPawel Jakub Dawidek 
19505c91076SPawel Jakub Dawidek 	fd = open(path, O_RDWR);
19605c91076SPawel Jakub Dawidek 	if (fd == -1)
19705c91076SPawel Jakub Dawidek 		return (errno);
19809cc9ab6SPawel Jakub Dawidek 	mediasize = g_get_mediasize(name);
19909cc9ab6SPawel Jakub Dawidek 	if (mediasize == 0) {
20005c91076SPawel Jakub Dawidek 		error = errno;
20105c91076SPawel Jakub Dawidek 		goto out;
20205c91076SPawel Jakub Dawidek 	}
20309cc9ab6SPawel Jakub Dawidek 	sectorsize = g_get_sectorsize(name);
20409cc9ab6SPawel Jakub Dawidek 	if (sectorsize == 0) {
20505c91076SPawel Jakub Dawidek 		error = errno;
20605c91076SPawel Jakub Dawidek 		goto out;
20705c91076SPawel Jakub Dawidek 	}
20805c91076SPawel Jakub Dawidek 	sector = malloc(sectorsize);
20905c91076SPawel Jakub Dawidek 	if (sector == NULL) {
21005c91076SPawel Jakub Dawidek 		error = ENOMEM;
21105c91076SPawel Jakub Dawidek 		goto out;
21205c91076SPawel Jakub Dawidek 	}
21305c91076SPawel Jakub Dawidek 	if (magic != NULL) {
21405c91076SPawel Jakub Dawidek 		if (pread(fd, sector, sectorsize, mediasize - sectorsize) !=
21505c91076SPawel Jakub Dawidek 		    (ssize_t)sectorsize) {
21605c91076SPawel Jakub Dawidek 			error = errno;
21705c91076SPawel Jakub Dawidek 			goto out;
21805c91076SPawel Jakub Dawidek 		}
21905c91076SPawel Jakub Dawidek 		std_metadata_decode(sector, &md);
22005c91076SPawel Jakub Dawidek 		if (strcmp(md.md_magic, magic) != 0) {
22105c91076SPawel Jakub Dawidek 			error = EINVAL;
22205c91076SPawel Jakub Dawidek 			goto out;
22305c91076SPawel Jakub Dawidek 		}
22405c91076SPawel Jakub Dawidek 	}
22505c91076SPawel Jakub Dawidek 	bzero(sector, sectorsize);
22605c91076SPawel Jakub Dawidek 	if (pwrite(fd, sector, sectorsize, mediasize - sectorsize) !=
22705c91076SPawel Jakub Dawidek 	    (ssize_t)sectorsize) {
22805c91076SPawel Jakub Dawidek 		error = errno;
22905c91076SPawel Jakub Dawidek 		goto out;
23005c91076SPawel Jakub Dawidek 	}
23105c91076SPawel Jakub Dawidek out:
23205c91076SPawel Jakub Dawidek 	if (sector != NULL)
23305c91076SPawel Jakub Dawidek 		free(sector);
23405c91076SPawel Jakub Dawidek 	close(fd);
23505c91076SPawel Jakub Dawidek 	return (error);
23605c91076SPawel Jakub Dawidek }
23705c91076SPawel Jakub Dawidek 
23805c91076SPawel Jakub Dawidek /*
23905c91076SPawel Jakub Dawidek  * Set an error message, if one does not already exist.
24005c91076SPawel Jakub Dawidek  */
24105c91076SPawel Jakub Dawidek void
24205c91076SPawel Jakub Dawidek gctl_error(struct gctl_req *req, const char *error, ...)
24305c91076SPawel Jakub Dawidek {
24405c91076SPawel Jakub Dawidek 	va_list ap;
24505c91076SPawel Jakub Dawidek 
24605c91076SPawel Jakub Dawidek 	if (req->error != NULL)
24705c91076SPawel Jakub Dawidek 		return;
24805c91076SPawel Jakub Dawidek 	va_start(ap, error);
24905c91076SPawel Jakub Dawidek 	vasprintf(&req->error, error, ap);
25005c91076SPawel Jakub Dawidek 	va_end(ap);
25105c91076SPawel Jakub Dawidek }
25205c91076SPawel Jakub Dawidek 
25305c91076SPawel Jakub Dawidek void *
25405c91076SPawel Jakub Dawidek gctl_get_param(struct gctl_req *req, const char *param, int *len)
25505c91076SPawel Jakub Dawidek {
25605c91076SPawel Jakub Dawidek 	unsigned i;
25705c91076SPawel Jakub Dawidek 	void *p;
25805c91076SPawel Jakub Dawidek 	struct gctl_req_arg *ap;
25905c91076SPawel Jakub Dawidek 
26005c91076SPawel Jakub Dawidek 	for (i = 0; i < req->narg; i++) {
26105c91076SPawel Jakub Dawidek 		ap = &req->arg[i];
26205c91076SPawel Jakub Dawidek 		if (strcmp(param, ap->name))
26305c91076SPawel Jakub Dawidek 			continue;
26405c91076SPawel Jakub Dawidek 		if (!(ap->flag & GCTL_PARAM_RD))
26505c91076SPawel Jakub Dawidek 			continue;
26605c91076SPawel Jakub Dawidek 		p = ap->value;
26705c91076SPawel Jakub Dawidek 		if (len != NULL)
26805c91076SPawel Jakub Dawidek 			*len = ap->len;
26905c91076SPawel Jakub Dawidek 		return (p);
27005c91076SPawel Jakub Dawidek 	}
27105c91076SPawel Jakub Dawidek 	return (NULL);
27205c91076SPawel Jakub Dawidek }
27305c91076SPawel Jakub Dawidek 
27405c91076SPawel Jakub Dawidek char const *
27505c91076SPawel Jakub Dawidek gctl_get_asciiparam(struct gctl_req *req, const char *param)
27605c91076SPawel Jakub Dawidek {
27705c91076SPawel Jakub Dawidek 	unsigned i;
27805c91076SPawel Jakub Dawidek 	char const *p;
27905c91076SPawel Jakub Dawidek 	struct gctl_req_arg *ap;
28005c91076SPawel Jakub Dawidek 
28105c91076SPawel Jakub Dawidek 	for (i = 0; i < req->narg; i++) {
28205c91076SPawel Jakub Dawidek 		ap = &req->arg[i];
28305c91076SPawel Jakub Dawidek 		if (strcmp(param, ap->name))
28405c91076SPawel Jakub Dawidek 			continue;
28505c91076SPawel Jakub Dawidek 		if (!(ap->flag & GCTL_PARAM_RD))
28605c91076SPawel Jakub Dawidek 			continue;
28705c91076SPawel Jakub Dawidek 		p = ap->value;
28805c91076SPawel Jakub Dawidek 		if (ap->len < 1) {
28905c91076SPawel Jakub Dawidek 			gctl_error(req, "No length argument (%s)", param);
29005c91076SPawel Jakub Dawidek 			return (NULL);
29105c91076SPawel Jakub Dawidek 		}
29205c91076SPawel Jakub Dawidek 		if (p[ap->len - 1] != '\0') {
29305c91076SPawel Jakub Dawidek 			gctl_error(req, "Unterminated argument (%s)", param);
29405c91076SPawel Jakub Dawidek 			return (NULL);
29505c91076SPawel Jakub Dawidek 		}
29605c91076SPawel Jakub Dawidek 		return (p);
29705c91076SPawel Jakub Dawidek 	}
29805c91076SPawel Jakub Dawidek 	return (NULL);
29905c91076SPawel Jakub Dawidek }
30005c91076SPawel Jakub Dawidek 
30105c91076SPawel Jakub Dawidek void *
30205c91076SPawel Jakub Dawidek gctl_get_paraml(struct gctl_req *req, const char *param, int len)
30305c91076SPawel Jakub Dawidek {
30405c91076SPawel Jakub Dawidek 	int i;
30505c91076SPawel Jakub Dawidek 	void *p;
30605c91076SPawel Jakub Dawidek 
30705c91076SPawel Jakub Dawidek 	p = gctl_get_param(req, param, &i);
30805c91076SPawel Jakub Dawidek 	if (p == NULL)
30905c91076SPawel Jakub Dawidek 		gctl_error(req, "Missing %s argument", param);
31005c91076SPawel Jakub Dawidek 	else if (i != len) {
31105c91076SPawel Jakub Dawidek 		p = NULL;
31205c91076SPawel Jakub Dawidek 		gctl_error(req, "Wrong length %s argument", param);
31305c91076SPawel Jakub Dawidek 	}
31405c91076SPawel Jakub Dawidek 	return (p);
31505c91076SPawel Jakub Dawidek }
316