xref: /freebsd/sbin/geom/misc/subr.c (revision dba6dd177bdee890cf445fbe21a5dccefd5de18e)
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$");
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 
49 struct std_metadata {
50 	char		md_magic[16];
51 	uint32_t	md_version;
52 };
53 
54 static void
55 std_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 
62 static void
63 pathgen(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 int
73 g_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 	}
108 out:
109 	if (sector != NULL)
110 		free(sector);
111 	close(fd);
112 	return (error);
113 }
114 
115 int
116 g_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 	}
163 out:
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  */
173 void
174 gctl_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 
185 void *
186 gctl_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 
206 char const *
207 gctl_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 
233 void *
234 gctl_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