subr.c revision 131603
1163953Srrs/*-
2169382Srrs * Copyright (c) 2004 Pawel Jakub Dawidek <pjd@FreeBSD.org>
3235828Stuexen * All rights reserved.
4235828Stuexen *
5163953Srrs * Redistribution and use in source and binary forms, with or without
6163953Srrs * modification, are permitted provided that the following conditions
7163953Srrs * are met:
8163953Srrs * 1. Redistributions of source code must retain the above copyright
9163953Srrs *    notice, this list of conditions and the following disclaimer.
10228653Stuexen * 2. Redistributions in binary form must reproduce the above copyright
11163953Srrs *    notice, this list of conditions and the following disclaimer in the
12163953Srrs *    documentation and/or other materials provided with the distribution.
13163953Srrs *
14228653Stuexen * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
15163953Srrs * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16163953Srrs * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17163953Srrs * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
18163953Srrs * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19163953Srrs * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20163953Srrs * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21163953Srrs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22163953Srrs * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23163953Srrs * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24163953Srrs * SUCH DAMAGE.
25163953Srrs */
26163953Srrs
27163953Srrs#include <sys/cdefs.h>
28163953Srrs__FBSDID("$FreeBSD: head/sbin/geom/misc/subr.c 131603 2004-07-05 02:06:44Z pjd $");
29163953Srrs
30163953Srrs#include <sys/param.h>
31163953Srrs#include <sys/disk.h>
32174510Sobrien#include <sys/endian.h>
33235828Stuexen#include <sys/uio.h>
34235828Stuexen#include <errno.h>
35235828Stuexen#include <fcntl.h>
36163953Srrs#include <paths.h>
37163953Srrs#include <stdio.h>
38174510Sobrien#include <stdlib.h>
39163953Srrs#include <stdarg.h>
40163953Srrs#include <string.h>
41163953Srrs#include <strings.h>
42163953Srrs#include <unistd.h>
43163953Srrs#include <assert.h>
44241916Sdelphij#include <libgeom.h>
45243186Stuexen
46242327Stuexen#include "misc/subr.h"
47242327Stuexen
48241916Sdelphij
49242327Stuexenstruct std_metadata {
50242327Stuexen	char		md_magic[16];
51242327Stuexen	uint32_t	md_version;
52242327Stuexen};
53242327Stuexen
54163953Srrsstatic void
55163953Srrsstd_metadata_decode(const u_char *data, struct std_metadata *md)
56242327Stuexen{
57
58        bcopy(data, md->md_magic, sizeof(md->md_magic));
59        md->md_version = le32dec(data + 16);
60}
61
62static void
63pathgen(const char *name, char *path, size_t size)
64{
65
66	if (strncmp(name, _PATH_DEV, strlen(_PATH_DEV)) != 0)
67		snprintf(path, size, "%s%s", _PATH_DEV, name);
68	else
69		strlcpy(path, name, size);
70}
71
72/*
73 * Greatest Common Divisor.
74 */
75static unsigned
76gcd(unsigned a, unsigned b)
77{
78	u_int c;
79
80	while (b != 0) {
81		c = a;
82		a = b;
83		b = (c % b);
84	}
85	return (a);
86}
87
88/*
89 * Least Common Multiple.
90 */
91unsigned
92g_lcm(unsigned a, unsigned b)
93{
94
95	return ((a * b) / gcd(a, b));
96}
97
98off_t
99g_get_mediasize(const char *name)
100{
101	char path[MAXPATHLEN];
102	off_t mediasize;
103	int fd;
104
105	pathgen(name, path, sizeof(path));
106	fd = open(path, O_RDONLY);
107	if (fd == -1)
108		return (0);
109	if (ioctl(fd, DIOCGMEDIASIZE, &mediasize) < 0) {
110		close(fd);
111		return (0);
112	}
113	close(fd);
114	return (mediasize);
115}
116
117unsigned
118g_get_sectorsize(const char *name)
119{
120	char path[MAXPATHLEN];
121	unsigned sectorsize;
122	int fd;
123
124	pathgen(name, path, sizeof(path));
125	fd = open(path, O_RDONLY);
126	if (fd == -1)
127		return (0);
128	if (ioctl(fd, DIOCGSECTORSIZE, &sectorsize) < 0) {
129		close(fd);
130		return (0);
131	}
132	close(fd);
133	return (sectorsize);
134}
135
136int
137g_metadata_read(const char *name, u_char *md, size_t size, const char *magic)
138{
139	struct std_metadata stdmd;
140	char path[MAXPATHLEN];
141	unsigned sectorsize;
142	off_t mediasize;
143	u_char *sector;
144	int error, fd;
145
146	pathgen(name, path, sizeof(path));
147	sector = NULL;
148	error = 0;
149
150	fd = open(path, O_RDONLY);
151	if (fd == -1)
152		return (errno);
153	mediasize = g_get_mediasize(name);
154	if (mediasize == 0) {
155		error = errno;
156		goto out;
157	}
158	sectorsize = g_get_sectorsize(name);
159	if (sectorsize == 0) {
160		error = errno;
161		goto out;
162	}
163	assert(sectorsize >= size);
164	sector = malloc(sectorsize);
165	if (sector == NULL) {
166		error = ENOMEM;
167		goto out;
168	}
169	if (pread(fd, sector, sectorsize, mediasize - sectorsize) !=
170	    (ssize_t)sectorsize) {
171		error = errno;
172		goto out;
173	}
174	if (magic != NULL) {
175		std_metadata_decode(sector, &stdmd);
176		if (strcmp(stdmd.md_magic, magic) != 0) {
177			error = EINVAL;
178			goto out;
179		}
180	}
181	bcopy(sector, md, size);
182out:
183	if (sector != NULL)
184		free(sector);
185	close(fd);
186	return (error);
187}
188
189int
190g_metadata_store(const char *name, u_char *md, size_t size)
191{
192	char path[MAXPATHLEN];
193	unsigned sectorsize;
194	off_t mediasize;
195	u_char *sector;
196	int error, fd;
197
198	pathgen(name, path, sizeof(path));
199	sector = NULL;
200	error = 0;
201
202	fd = open(path, O_WRONLY);
203	if (fd == -1)
204		return (errno);
205	mediasize = g_get_mediasize(name);
206	if (mediasize == 0) {
207		error = errno;
208		goto out;
209	}
210	sectorsize = g_get_sectorsize(name);
211	if (sectorsize == 0) {
212		error = errno;
213		goto out;
214	}
215	assert(sectorsize >= size);
216	sector = malloc(sectorsize);
217	if (sector == NULL) {
218		error = ENOMEM;
219		goto out;
220	}
221	bcopy(md, sector, size);
222	if (pwrite(fd, sector, sectorsize, mediasize - sectorsize) !=
223	    (ssize_t)sectorsize) {
224		error = errno;
225		goto out;
226	}
227out:
228	if (sector != NULL)
229		free(sector);
230	close(fd);
231	return (error);
232}
233
234int
235g_metadata_clear(const char *name, const char *magic)
236{
237	struct std_metadata md;
238	char path[MAXPATHLEN];
239	unsigned sectorsize;
240	off_t mediasize;
241	u_char *sector;
242	int error, fd;
243
244	pathgen(name, path, sizeof(path));
245	sector = NULL;
246	error = 0;
247
248	fd = open(path, O_RDWR);
249	if (fd == -1)
250		return (errno);
251	mediasize = g_get_mediasize(name);
252	if (mediasize == 0) {
253		error = errno;
254		goto out;
255	}
256	sectorsize = g_get_sectorsize(name);
257	if (sectorsize == 0) {
258		error = errno;
259		goto out;
260	}
261	sector = malloc(sectorsize);
262	if (sector == NULL) {
263		error = ENOMEM;
264		goto out;
265	}
266	if (magic != NULL) {
267		if (pread(fd, sector, sectorsize, mediasize - sectorsize) !=
268		    (ssize_t)sectorsize) {
269			error = errno;
270			goto out;
271		}
272		std_metadata_decode(sector, &md);
273		if (strcmp(md.md_magic, magic) != 0) {
274			error = EINVAL;
275			goto out;
276		}
277	}
278	bzero(sector, sectorsize);
279	if (pwrite(fd, sector, sectorsize, mediasize - sectorsize) !=
280	    (ssize_t)sectorsize) {
281		error = errno;
282		goto out;
283	}
284out:
285	if (sector != NULL)
286		free(sector);
287	close(fd);
288	return (error);
289}
290
291/*
292 * Set an error message, if one does not already exist.
293 */
294void
295gctl_error(struct gctl_req *req, const char *error, ...)
296{
297	va_list ap;
298
299	if (req->error != NULL)
300		return;
301	va_start(ap, error);
302	vasprintf(&req->error, error, ap);
303	va_end(ap);
304}
305
306void *
307gctl_get_param(struct gctl_req *req, const char *param, int *len)
308{
309	unsigned i;
310	void *p;
311	struct gctl_req_arg *ap;
312
313	for (i = 0; i < req->narg; i++) {
314		ap = &req->arg[i];
315		if (strcmp(param, ap->name))
316			continue;
317		if (!(ap->flag & GCTL_PARAM_RD))
318			continue;
319		p = ap->value;
320		if (len != NULL)
321			*len = ap->len;
322		return (p);
323	}
324	return (NULL);
325}
326
327char const *
328gctl_get_asciiparam(struct gctl_req *req, const char *param)
329{
330	unsigned i;
331	char const *p;
332	struct gctl_req_arg *ap;
333
334	for (i = 0; i < req->narg; i++) {
335		ap = &req->arg[i];
336		if (strcmp(param, ap->name))
337			continue;
338		if (!(ap->flag & GCTL_PARAM_RD))
339			continue;
340		p = ap->value;
341		if (ap->len < 1) {
342			gctl_error(req, "No length argument (%s)", param);
343			return (NULL);
344		}
345		if (p[ap->len - 1] != '\0') {
346			gctl_error(req, "Unterminated argument (%s)", param);
347			return (NULL);
348		}
349		return (p);
350	}
351	return (NULL);
352}
353
354void *
355gctl_get_paraml(struct gctl_req *req, const char *param, int len)
356{
357	int i;
358	void *p;
359
360	p = gctl_get_param(req, param, &i);
361	if (p == NULL)
362		gctl_error(req, "Missing %s argument", param);
363	else if (i != len) {
364		p = NULL;
365		gctl_error(req, "Wrong length %s argument", param);
366	}
367	return (p);
368}
369