subr.c revision 130591
1129470Spjd/*-
2129470Spjd * Copyright (c) 2004 Pawel Jakub Dawidek <pjd@FreeBSD.org>
3129470Spjd * All rights reserved.
4129470Spjd *
5129470Spjd * Redistribution and use in source and binary forms, with or without
6129470Spjd * modification, are permitted provided that the following conditions
7129470Spjd * are met:
8129470Spjd * 1. Redistributions of source code must retain the above copyright
9129470Spjd *    notice, this list of conditions and the following disclaimer.
10129470Spjd * 2. Redistributions in binary form must reproduce the above copyright
11129470Spjd *    notice, this list of conditions and the following disclaimer in the
12129470Spjd *    documentation and/or other materials provided with the distribution.
13129470Spjd *
14129470Spjd * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
15129470Spjd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16129470Spjd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17129470Spjd * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
18129470Spjd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19129470Spjd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20129470Spjd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21129470Spjd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22129470Spjd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23129470Spjd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24129470Spjd * SUCH DAMAGE.
25129470Spjd */
26129470Spjd
27129470Spjd#include <sys/cdefs.h>
28129470Spjd__FBSDID("$FreeBSD: head/sbin/geom/misc/subr.c 130591 2004-06-16 10:44:26Z pjd $");
29129470Spjd
30129470Spjd#include <sys/param.h>
31129470Spjd#include <sys/disk.h>
32129470Spjd#include <sys/endian.h>
33129470Spjd#include <sys/uio.h>
34129470Spjd#include <errno.h>
35129470Spjd#include <fcntl.h>
36129470Spjd#include <paths.h>
37129470Spjd#include <stdio.h>
38129470Spjd#include <stdlib.h>
39129470Spjd#include <stdarg.h>
40129470Spjd#include <string.h>
41129470Spjd#include <strings.h>
42129470Spjd#include <unistd.h>
43129470Spjd#include <assert.h>
44129470Spjd#include <libgeom.h>
45129470Spjd
46129470Spjd#include "misc/subr.h"
47129470Spjd
48129470Spjd
49129470Spjdstruct std_metadata {
50129470Spjd	char		md_magic[16];
51129470Spjd	uint32_t	md_version;
52129470Spjd};
53129470Spjd
54129470Spjdstatic void
55129470Spjdstd_metadata_decode(const u_char *data, struct std_metadata *md)
56129470Spjd{
57129470Spjd
58129470Spjd        bcopy(data, md->md_magic, sizeof(md->md_magic));
59129470Spjd        md->md_version = le32dec(data + 16);
60129470Spjd}
61129470Spjd
62129470Spjdstatic void
63129470Spjdpathgen(const char *name, char *path, size_t size)
64129470Spjd{
65129470Spjd
66129470Spjd	if (strncmp(name, _PATH_DEV, strlen(_PATH_DEV)) != 0)
67129470Spjd		snprintf(path, size, "%s%s", _PATH_DEV, name);
68129470Spjd	else
69129470Spjd		strlcpy(path, name, size);
70129470Spjd}
71129470Spjd
72130591Spjd/*
73130591Spjd * Greatest Common Divisor.
74130591Spjd */
75130591Spjdstatic unsigned
76130591Spjdgcd(unsigned a, unsigned b)
77130591Spjd{
78130591Spjd	u_int c;
79130591Spjd
80130591Spjd	while (b != 0) {
81130591Spjd		c = a;
82130591Spjd		a = b;
83130591Spjd		b = (c % b);
84130591Spjd	}
85130591Spjd	return (a);
86130591Spjd}
87130591Spjd
88130591Spjd/*
89130591Spjd * Least Common Multiple.
90130591Spjd */
91130591Spjdunsigned
92130591Spjdg_lcm(unsigned a, unsigned b)
93130591Spjd{
94130591Spjd
95130591Spjd	return ((a * b) / gcd(a, b));
96130591Spjd}
97130591Spjd
98130591Spjdoff_t
99130591Spjdg_get_mediasize(const char *name)
100130591Spjd{
101130591Spjd	char path[MAXPATHLEN];
102130591Spjd	off_t mediasize;
103130591Spjd	int fd;
104130591Spjd
105130591Spjd	pathgen(name, path, sizeof(path));
106130591Spjd	fd = open(path, O_RDONLY);
107130591Spjd	if (fd == -1)
108130591Spjd		return (0);
109130591Spjd	if (ioctl(fd, DIOCGMEDIASIZE, &mediasize) < 0) {
110130591Spjd		close(fd);
111130591Spjd		return (0);
112130591Spjd	}
113130591Spjd	close(fd);
114130591Spjd	return (mediasize);
115130591Spjd}
116130591Spjd
117130591Spjdunsigned
118130591Spjdg_get_sectorsize(const char *name)
119130591Spjd{
120130591Spjd	char path[MAXPATHLEN];
121130591Spjd	unsigned sectorsize;
122130591Spjd	int fd;
123130591Spjd
124130591Spjd	pathgen(name, path, sizeof(path));
125130591Spjd	fd = open(path, O_RDONLY);
126130591Spjd	if (fd == -1)
127130591Spjd		return (0);
128130591Spjd	if (ioctl(fd, DIOCGSECTORSIZE, &sectorsize) < 0) {
129130591Spjd		close(fd);
130130591Spjd		return (0);
131130591Spjd	}
132130591Spjd	close(fd);
133130591Spjd	return (sectorsize);
134130591Spjd}
135130591Spjd
136129470Spjdint
137129470Spjdg_metadata_store(const char *name, u_char *md, size_t size)
138129470Spjd{
139129470Spjd	char path[MAXPATHLEN];
140129470Spjd	unsigned sectorsize;
141129470Spjd	off_t mediasize;
142129470Spjd	u_char *sector;
143129470Spjd	int error, fd;
144129470Spjd
145129470Spjd	pathgen(name, path, sizeof(path));
146129470Spjd	sector = NULL;
147129470Spjd	error = 0;
148129470Spjd
149129470Spjd	fd = open(path, O_WRONLY);
150129470Spjd	if (fd == -1)
151129470Spjd		return (errno);
152130591Spjd	mediasize = g_get_mediasize(name);
153130591Spjd	if (mediasize == 0) {
154129470Spjd		error = errno;
155129470Spjd		goto out;
156129470Spjd	}
157130591Spjd	sectorsize = g_get_sectorsize(name);
158130591Spjd	if (sectorsize == 0) {
159129470Spjd		error = errno;
160129470Spjd		goto out;
161129470Spjd	}
162129470Spjd	assert(sectorsize >= size);
163129470Spjd	sector = malloc(sectorsize);
164129470Spjd	if (sector == NULL) {
165129470Spjd		error = ENOMEM;
166129470Spjd		goto out;
167129470Spjd	}
168129470Spjd	bcopy(md, sector, size);
169129470Spjd	if (pwrite(fd, sector, sectorsize, mediasize - sectorsize) !=
170129470Spjd	    (ssize_t)sectorsize) {
171129470Spjd		error = errno;
172129470Spjd		goto out;
173129470Spjd	}
174129470Spjdout:
175129470Spjd	if (sector != NULL)
176129470Spjd		free(sector);
177129470Spjd	close(fd);
178129470Spjd	return (error);
179129470Spjd}
180129470Spjd
181129470Spjdint
182129470Spjdg_metadata_clear(const char *name, const char *magic)
183129470Spjd{
184129470Spjd	struct std_metadata md;
185129470Spjd	char path[MAXPATHLEN];
186129470Spjd	unsigned sectorsize;
187129470Spjd	off_t mediasize;
188129470Spjd	u_char *sector;
189129470Spjd	int error, fd;
190129470Spjd
191129470Spjd	pathgen(name, path, sizeof(path));
192129470Spjd	sector = NULL;
193129470Spjd	error = 0;
194129470Spjd
195129470Spjd	fd = open(path, O_RDWR);
196129470Spjd	if (fd == -1)
197129470Spjd		return (errno);
198130591Spjd	mediasize = g_get_mediasize(name);
199130591Spjd	if (mediasize == 0) {
200129470Spjd		error = errno;
201129470Spjd		goto out;
202129470Spjd	}
203130591Spjd	sectorsize = g_get_sectorsize(name);
204130591Spjd	if (sectorsize == 0) {
205129470Spjd		error = errno;
206129470Spjd		goto out;
207129470Spjd	}
208129470Spjd	sector = malloc(sectorsize);
209129470Spjd	if (sector == NULL) {
210129470Spjd		error = ENOMEM;
211129470Spjd		goto out;
212129470Spjd	}
213129470Spjd	if (magic != NULL) {
214129470Spjd		if (pread(fd, sector, sectorsize, mediasize - sectorsize) !=
215129470Spjd		    (ssize_t)sectorsize) {
216129470Spjd			error = errno;
217129470Spjd			goto out;
218129470Spjd		}
219129470Spjd		std_metadata_decode(sector, &md);
220129470Spjd		if (strcmp(md.md_magic, magic) != 0) {
221129470Spjd			error = EINVAL;
222129470Spjd			goto out;
223129470Spjd		}
224129470Spjd	}
225129470Spjd	bzero(sector, sectorsize);
226129470Spjd	if (pwrite(fd, sector, sectorsize, mediasize - sectorsize) !=
227129470Spjd	    (ssize_t)sectorsize) {
228129470Spjd		error = errno;
229129470Spjd		goto out;
230129470Spjd	}
231129470Spjdout:
232129470Spjd	if (sector != NULL)
233129470Spjd		free(sector);
234129470Spjd	close(fd);
235129470Spjd	return (error);
236129470Spjd}
237129470Spjd
238129470Spjd/*
239129470Spjd * Set an error message, if one does not already exist.
240129470Spjd */
241129470Spjdvoid
242129470Spjdgctl_error(struct gctl_req *req, const char *error, ...)
243129470Spjd{
244129470Spjd	va_list ap;
245129470Spjd
246129470Spjd	if (req->error != NULL)
247129470Spjd		return;
248129470Spjd	va_start(ap, error);
249129470Spjd	vasprintf(&req->error, error, ap);
250129470Spjd	va_end(ap);
251129470Spjd}
252129470Spjd
253129470Spjdvoid *
254129470Spjdgctl_get_param(struct gctl_req *req, const char *param, int *len)
255129470Spjd{
256129470Spjd	unsigned i;
257129470Spjd	void *p;
258129470Spjd	struct gctl_req_arg *ap;
259129470Spjd
260129470Spjd	for (i = 0; i < req->narg; i++) {
261129470Spjd		ap = &req->arg[i];
262129470Spjd		if (strcmp(param, ap->name))
263129470Spjd			continue;
264129470Spjd		if (!(ap->flag & GCTL_PARAM_RD))
265129470Spjd			continue;
266129470Spjd		p = ap->value;
267129470Spjd		if (len != NULL)
268129470Spjd			*len = ap->len;
269129470Spjd		return (p);
270129470Spjd	}
271129470Spjd	return (NULL);
272129470Spjd}
273129470Spjd
274129470Spjdchar const *
275129470Spjdgctl_get_asciiparam(struct gctl_req *req, const char *param)
276129470Spjd{
277129470Spjd	unsigned i;
278129470Spjd	char const *p;
279129470Spjd	struct gctl_req_arg *ap;
280129470Spjd
281129470Spjd	for (i = 0; i < req->narg; i++) {
282129470Spjd		ap = &req->arg[i];
283129470Spjd		if (strcmp(param, ap->name))
284129470Spjd			continue;
285129470Spjd		if (!(ap->flag & GCTL_PARAM_RD))
286129470Spjd			continue;
287129470Spjd		p = ap->value;
288129470Spjd		if (ap->len < 1) {
289129470Spjd			gctl_error(req, "No length argument (%s)", param);
290129470Spjd			return (NULL);
291129470Spjd		}
292129470Spjd		if (p[ap->len - 1] != '\0') {
293129470Spjd			gctl_error(req, "Unterminated argument (%s)", param);
294129470Spjd			return (NULL);
295129470Spjd		}
296129470Spjd		return (p);
297129470Spjd	}
298129470Spjd	return (NULL);
299129470Spjd}
300129470Spjd
301129470Spjdvoid *
302129470Spjdgctl_get_paraml(struct gctl_req *req, const char *param, int len)
303129470Spjd{
304129470Spjd	int i;
305129470Spjd	void *p;
306129470Spjd
307129470Spjd	p = gctl_get_param(req, param, &i);
308129470Spjd	if (p == NULL)
309129470Spjd		gctl_error(req, "Missing %s argument", param);
310129470Spjd	else if (i != len) {
311129470Spjd		p = NULL;
312129470Spjd		gctl_error(req, "Wrong length %s argument", param);
313129470Spjd	}
314129470Spjd	return (p);
315129470Spjd}
316