subr.c revision 129470
150476Speter/*-
218450Swosch * Copyright (c) 2004 Pawel Jakub Dawidek <pjd@FreeBSD.org>
358570Srwatson * All rights reserved.
418450Swosch *
518450Swosch * Redistribution and use in source and binary forms, with or without
6234823Seadler * modification, are permitted provided that the following conditions
718450Swosch * are met:
81638Srgrimes * 1. Redistributions of source code must retain the above copyright
91638Srgrimes *    notice, this list of conditions and the following disclaimer.
101638Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
11234823Seadler *    notice, this list of conditions and the following disclaimer in the
121638Srgrimes *    documentation and/or other materials provided with the distribution.
13234823Seadler *
141638Srgrimes * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
15266029Sbdrewery * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16266029Sbdrewery * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17266029Sbdrewery * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
18266029Sbdrewery * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1963199Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20266029Sbdrewery * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2158570Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
221638Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23242514Seadler * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
241638Srgrimes * SUCH DAMAGE.
251638Srgrimes */
261638Srgrimes
27243893Seadler#include <sys/cdefs.h>
28234823Seadler__FBSDID("$FreeBSD: head/sbin/geom/misc/subr.c 129470 2004-05-20 10:09:56Z pjd $");
29234823Seadler
301638Srgrimes#include <sys/param.h>
31234823Seadler#include <sys/disk.h>
32234823Seadler#include <sys/endian.h>
33234823Seadler#include <sys/uio.h>
34234823Seadler#include <errno.h>
35234823Seadler#include <fcntl.h>
36234823Seadler#include <paths.h>
371638Srgrimes#include <stdio.h>
3870892Sarchie#include <stdlib.h>
3970892Sarchie#include <stdarg.h>
4070892Sarchie#include <string.h>
4170892Sarchie#include <strings.h>
4270892Sarchie#include <unistd.h>
43234823Seadler#include <assert.h>
441638Srgrimes#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
72int
73g_metadata_store(const char *name, u_char *md, size_t size)
74{
75	char path[MAXPATHLEN];
76	unsigned sectorsize;
77	off_t mediasize;
78	u_char *sector;
79	int error, fd;
80
81	pathgen(name, path, sizeof(path));
82	sector = NULL;
83	error = 0;
84
85	fd = open(path, O_WRONLY);
86	if (fd == -1)
87		return (errno);
88	if (ioctl(fd, DIOCGMEDIASIZE, &mediasize) < 0) {
89		error = errno;
90		goto out;
91	}
92	if (ioctl(fd, DIOCGSECTORSIZE, &sectorsize) < 0) {
93		error = errno;
94		goto out;
95	}
96	assert(sectorsize >= size);
97	sector = malloc(sectorsize);
98	if (sector == NULL) {
99		error = ENOMEM;
100		goto out;
101	}
102	bcopy(md, sector, size);
103	if (pwrite(fd, sector, sectorsize, mediasize - sectorsize) !=
104	    (ssize_t)sectorsize) {
105		error = errno;
106		goto out;
107	}
108out:
109	if (sector != NULL)
110		free(sector);
111	close(fd);
112	return (error);
113}
114
115int
116g_metadata_clear(const char *name, const char *magic)
117{
118	struct std_metadata md;
119	char path[MAXPATHLEN];
120	unsigned sectorsize;
121	off_t mediasize;
122	u_char *sector;
123	int error, fd;
124
125	pathgen(name, path, sizeof(path));
126	sector = NULL;
127	error = 0;
128
129	fd = open(path, O_RDWR);
130	if (fd == -1)
131		return (errno);
132	if (ioctl(fd, DIOCGMEDIASIZE, &mediasize) < 0) {
133		error = errno;
134		goto out;
135	}
136	if (ioctl(fd, DIOCGSECTORSIZE, &sectorsize) < 0) {
137		error = errno;
138		goto out;
139	}
140	sector = malloc(sectorsize);
141	if (sector == NULL) {
142		error = ENOMEM;
143		goto out;
144	}
145	if (magic != NULL) {
146		if (pread(fd, sector, sectorsize, mediasize - sectorsize) !=
147		    (ssize_t)sectorsize) {
148			error = errno;
149			goto out;
150		}
151		std_metadata_decode(sector, &md);
152		if (strcmp(md.md_magic, magic) != 0) {
153			error = EINVAL;
154			goto out;
155		}
156	}
157	bzero(sector, sectorsize);
158	if (pwrite(fd, sector, sectorsize, mediasize - sectorsize) !=
159	    (ssize_t)sectorsize) {
160		error = errno;
161		goto out;
162	}
163out:
164	if (sector != NULL)
165		free(sector);
166	close(fd);
167	return (error);
168}
169
170/*
171 * Set an error message, if one does not already exist.
172 */
173void
174gctl_error(struct gctl_req *req, const char *error, ...)
175{
176	va_list ap;
177
178	if (req->error != NULL)
179		return;
180	va_start(ap, error);
181	vasprintf(&req->error, error, ap);
182	va_end(ap);
183}
184
185void *
186gctl_get_param(struct gctl_req *req, const char *param, int *len)
187{
188	unsigned i;
189	void *p;
190	struct gctl_req_arg *ap;
191
192	for (i = 0; i < req->narg; i++) {
193		ap = &req->arg[i];
194		if (strcmp(param, ap->name))
195			continue;
196		if (!(ap->flag & GCTL_PARAM_RD))
197			continue;
198		p = ap->value;
199		if (len != NULL)
200			*len = ap->len;
201		return (p);
202	}
203	return (NULL);
204}
205
206char const *
207gctl_get_asciiparam(struct gctl_req *req, const char *param)
208{
209	unsigned i;
210	char const *p;
211	struct gctl_req_arg *ap;
212
213	for (i = 0; i < req->narg; i++) {
214		ap = &req->arg[i];
215		if (strcmp(param, ap->name))
216			continue;
217		if (!(ap->flag & GCTL_PARAM_RD))
218			continue;
219		p = ap->value;
220		if (ap->len < 1) {
221			gctl_error(req, "No length argument (%s)", param);
222			return (NULL);
223		}
224		if (p[ap->len - 1] != '\0') {
225			gctl_error(req, "Unterminated argument (%s)", param);
226			return (NULL);
227		}
228		return (p);
229	}
230	return (NULL);
231}
232
233void *
234gctl_get_paraml(struct gctl_req *req, const char *param, int len)
235{
236	int i;
237	void *p;
238
239	p = gctl_get_param(req, param, &i);
240	if (p == NULL)
241		gctl_error(req, "Missing %s argument", param);
242	else if (i != len) {
243		p = NULL;
244		gctl_error(req, "Wrong length %s argument", param);
245	}
246	return (p);
247}
248