subr.c revision 130591
1/*-
2 * Copyright (c) 2004 Pawel Jakub Dawidek <pjd@FreeBSD.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27#include <sys/cdefs.h>
28__FBSDID("$FreeBSD: head/sbin/geom/misc/subr.c 130591 2004-06-16 10:44:26Z pjd $");
29
30#include <sys/param.h>
31#include <sys/disk.h>
32#include <sys/endian.h>
33#include <sys/uio.h>
34#include <errno.h>
35#include <fcntl.h>
36#include <paths.h>
37#include <stdio.h>
38#include <stdlib.h>
39#include <stdarg.h>
40#include <string.h>
41#include <strings.h>
42#include <unistd.h>
43#include <assert.h>
44#include <libgeom.h>
45
46#include "misc/subr.h"
47
48
49struct std_metadata {
50	char		md_magic[16];
51	uint32_t	md_version;
52};
53
54static void
55std_metadata_decode(const u_char *data, struct std_metadata *md)
56{
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_store(const char *name, u_char *md, size_t size)
138{
139	char path[MAXPATHLEN];
140	unsigned sectorsize;
141	off_t mediasize;
142	u_char *sector;
143	int error, fd;
144
145	pathgen(name, path, sizeof(path));
146	sector = NULL;
147	error = 0;
148
149	fd = open(path, O_WRONLY);
150	if (fd == -1)
151		return (errno);
152	mediasize = g_get_mediasize(name);
153	if (mediasize == 0) {
154		error = errno;
155		goto out;
156	}
157	sectorsize = g_get_sectorsize(name);
158	if (sectorsize == 0) {
159		error = errno;
160		goto out;
161	}
162	assert(sectorsize >= size);
163	sector = malloc(sectorsize);
164	if (sector == NULL) {
165		error = ENOMEM;
166		goto out;
167	}
168	bcopy(md, sector, size);
169	if (pwrite(fd, sector, sectorsize, mediasize - sectorsize) !=
170	    (ssize_t)sectorsize) {
171		error = errno;
172		goto out;
173	}
174out:
175	if (sector != NULL)
176		free(sector);
177	close(fd);
178	return (error);
179}
180
181int
182g_metadata_clear(const char *name, const char *magic)
183{
184	struct std_metadata md;
185	char path[MAXPATHLEN];
186	unsigned sectorsize;
187	off_t mediasize;
188	u_char *sector;
189	int error, fd;
190
191	pathgen(name, path, sizeof(path));
192	sector = NULL;
193	error = 0;
194
195	fd = open(path, O_RDWR);
196	if (fd == -1)
197		return (errno);
198	mediasize = g_get_mediasize(name);
199	if (mediasize == 0) {
200		error = errno;
201		goto out;
202	}
203	sectorsize = g_get_sectorsize(name);
204	if (sectorsize == 0) {
205		error = errno;
206		goto out;
207	}
208	sector = malloc(sectorsize);
209	if (sector == NULL) {
210		error = ENOMEM;
211		goto out;
212	}
213	if (magic != NULL) {
214		if (pread(fd, sector, sectorsize, mediasize - sectorsize) !=
215		    (ssize_t)sectorsize) {
216			error = errno;
217			goto out;
218		}
219		std_metadata_decode(sector, &md);
220		if (strcmp(md.md_magic, magic) != 0) {
221			error = EINVAL;
222			goto out;
223		}
224	}
225	bzero(sector, sectorsize);
226	if (pwrite(fd, sector, sectorsize, mediasize - sectorsize) !=
227	    (ssize_t)sectorsize) {
228		error = errno;
229		goto out;
230	}
231out:
232	if (sector != NULL)
233		free(sector);
234	close(fd);
235	return (error);
236}
237
238/*
239 * Set an error message, if one does not already exist.
240 */
241void
242gctl_error(struct gctl_req *req, const char *error, ...)
243{
244	va_list ap;
245
246	if (req->error != NULL)
247		return;
248	va_start(ap, error);
249	vasprintf(&req->error, error, ap);
250	va_end(ap);
251}
252
253void *
254gctl_get_param(struct gctl_req *req, const char *param, int *len)
255{
256	unsigned i;
257	void *p;
258	struct gctl_req_arg *ap;
259
260	for (i = 0; i < req->narg; i++) {
261		ap = &req->arg[i];
262		if (strcmp(param, ap->name))
263			continue;
264		if (!(ap->flag & GCTL_PARAM_RD))
265			continue;
266		p = ap->value;
267		if (len != NULL)
268			*len = ap->len;
269		return (p);
270	}
271	return (NULL);
272}
273
274char const *
275gctl_get_asciiparam(struct gctl_req *req, const char *param)
276{
277	unsigned i;
278	char const *p;
279	struct gctl_req_arg *ap;
280
281	for (i = 0; i < req->narg; i++) {
282		ap = &req->arg[i];
283		if (strcmp(param, ap->name))
284			continue;
285		if (!(ap->flag & GCTL_PARAM_RD))
286			continue;
287		p = ap->value;
288		if (ap->len < 1) {
289			gctl_error(req, "No length argument (%s)", param);
290			return (NULL);
291		}
292		if (p[ap->len - 1] != '\0') {
293			gctl_error(req, "Unterminated argument (%s)", param);
294			return (NULL);
295		}
296		return (p);
297	}
298	return (NULL);
299}
300
301void *
302gctl_get_paraml(struct gctl_req *req, const char *param, int len)
303{
304	int i;
305	void *p;
306
307	p = gctl_get_param(req, param, &i);
308	if (p == NULL)
309		gctl_error(req, "Missing %s argument", param);
310	else if (i != len) {
311		p = NULL;
312		gctl_error(req, "Wrong length %s argument", param);
313	}
314	return (p);
315}
316