xref: /freebsd/lib/libgeom/geom_ctl.c (revision ec3a1a66aad80b656971dcff4277d8ea4967fbb5)
1 /*-
2  * Copyright (c) 2003 Poul-Henning Kamp
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  * 3. The names of the authors may not be used to endorse or promote
14  *    products derived from this software without specific prior written
15  *    permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  * $FreeBSD$
30  */
31 
32 #include <stdio.h>
33 #include <fcntl.h>
34 #include <errno.h>
35 #include <stdint.h>
36 #include <sys/types.h>
37 #include <stdarg.h>
38 #include <string.h>
39 #include <stdlib.h>
40 #include <paths.h>
41 
42 #include <sys/queue.h>
43 
44 #define GEOM_CTL_TABLE 1
45 #include <libgeom.h>
46 
47 #include <geom/geom_ext.h>
48 
49 void
50 geom_ctl_dump(struct geom_ctl_req *req, FILE *f)
51 {
52 	u_int i;
53 	int j;
54 	struct geom_ctl_req_arg *ap;
55 
56 	if (req == NULL) {
57 		fprintf(f, "Dump of geom_ctl request at NULL\n");
58 		return;
59 	}
60 	fprintf(f, "Dump of geom_ctl %s request at %p:\n", req->reqt->name, req);
61 	if (req->error != NULL)
62 		fprintf(f, "  error:\t\"%s\"\n", req->error);
63 	else
64 		fprintf(f, "  error:\tNULL\n");
65 	for (i = 0; i < req->narg; i++) {
66 		ap = &req->arg[i];
67 		if (ap->name != NULL)
68 			fprintf(f, "  param:\t\"%s\"", ap->name);
69 		else
70 			fprintf(f, "  meta:\t@%jd", (intmax_t)ap->offset);
71 		fflush(f);
72 		if (ap->len < 0)
73 			fprintf(f, " = [%d] \"%s\"", -ap->len, (char *)ap->value);
74 		else if (ap->len > 0) {
75 			fprintf(f, " = [%d]", ap->len);
76 			fflush(f);
77 			for (j = 0; j < ap->len; j++) {
78 				fprintf(f, " %02x", ((u_char *)ap->value)[j]);
79 			}
80 		} else {
81 			fprintf(f, " = [0] %p", ap->value);
82 		}
83 		fprintf(f, "\n");
84 	}
85 }
86 
87 static void
88 geom_ctl_set_error(struct geom_ctl_req *req, const char *error, ...)
89 {
90 	va_list ap;
91 
92 	if (req->error != NULL)
93 		return;
94 	va_start(ap, error);
95 	vasprintf(&req->error, error, ap);
96 }
97 
98 static void
99 geom_ctl_check_alloc(struct geom_ctl_req *req, void *ptr)
100 {
101 	if (ptr != NULL)
102 		return;
103 	geom_ctl_set_error(req, "Could not allocate memory");
104 }
105 
106 struct geom_ctl_req *
107 geom_ctl_get_handle(enum geom_ctl_request req)
108 {
109 	struct geom_ctl_req_table *gtp;
110 	struct geom_ctl_req *rp;
111 
112 	rp = calloc(1, sizeof *rp);
113 	if (rp == NULL)
114 		return (NULL);
115 	for (gtp = gcrt; gtp->request != req; gtp++)
116 		if (gtp->request == GEOM_INVALID_REQUEST)
117 			break;
118 
119 	rp->request = req;
120 	rp->reqt = gtp;
121 	if (rp->reqt->request == GEOM_INVALID_REQUEST)
122 		geom_ctl_set_error(rp, "Invalid request");
123 	return (rp);
124 }
125 
126 void
127 geom_ctl_set_param(struct geom_ctl_req *req, const char *name, int len, void* value)
128 {
129 	struct geom_ctl_req_arg *ap;
130 
131 	if (req == NULL || req->error != NULL)
132 		return;
133 	if (req->reqt->params == 0)
134 		geom_ctl_set_error(req, "Request takes no parameters");
135 	req->narg++;
136 	req->arg = realloc(req->arg, sizeof *ap * req->narg);
137 	geom_ctl_check_alloc(req, req->arg);
138 	if (req->arg != NULL) {
139 		ap = req->arg + (req->narg - 1);
140 		memset(ap, 0, sizeof *ap);
141 		ap->name = strdup(name);
142 		geom_ctl_check_alloc(req, ap->name);
143 		ap->nlen = strlen(ap->name);
144 		ap->len = len;
145 		if (len > 0) {
146 			ap->value = value;
147 		} else if (len < 0) {
148 			ap->len = -strlen(value);
149 			ap->value = strdup(value);
150 		} else {
151 			ap->value = value;
152 		}
153 		if (len != 0)
154 			geom_ctl_check_alloc(req, ap->value);
155 	} else {
156 		req->narg = 0;
157 	}
158 }
159 
160 void
161 geom_ctl_set_meta(struct geom_ctl_req *req, off_t offset, u_int len, void* value)
162 {
163 	struct geom_ctl_req_arg *ap;
164 	u_int i;
165 
166 	if (req == NULL || req->error != NULL)
167 		return;
168 	if (req->reqt->meta == 0)
169 		geom_ctl_set_error(req, "Request takes no meta data");
170 	for (i = 0; i < req->narg; i++) {
171 		ap = &req->arg[i];
172 		if (ap->name != NULL)
173 			continue;
174 		if (ap->offset >= offset + len)
175 			continue;
176 		if (ap->offset + ap->len <= offset)
177 			continue;
178 		geom_ctl_set_error(req, "Overlapping meta data");
179 		return;
180 	}
181 	req->narg++;
182 	req->arg = realloc(req->arg, sizeof *ap * req->narg);
183 	geom_ctl_check_alloc(req, req->arg);
184 	if (req->arg != NULL) {
185 		ap = req->arg + (req->narg - 1);
186 		memset(ap, 0, sizeof *ap);
187 		ap->value = value;
188 		ap->offset = offset;
189 		ap->len = len;
190 	} else {
191 		req->narg = 0;
192 	}
193 }
194 
195 const char *
196 geom_ctl_issue(struct geom_ctl_req *req)
197 {
198 	int fd, error;
199 
200 	if (req == NULL)
201 		return ("NULL request pointer");
202 	if (req->error != NULL)
203 		return (req->error);
204 
205 	req->version = GEOM_CTL_VERSION;
206 	req->lerror = BUFSIZ;		/* XXX: arbitrary number */
207 	req->error = malloc(req->lerror);
208 	memset(req->error, 0, req->lerror);
209 	req->lerror--;
210 	fd = open(_PATH_DEV PATH_GEOM_CTL, O_RDONLY);
211 	if (fd < 0)
212 		return(strerror(errno));
213 	error = ioctl(fd, GEOM_CTL, req);
214 	if (error && errno == EINVAL && req->error[0] != '\0')
215 		return (req->error);
216 	if (error != 0)
217 		return(strerror(errno));
218 	return (NULL);
219 }
220 
221 void
222 geom_ctl_free(struct geom_ctl_req *req)
223 {
224 	u_int i;
225 
226 	for (i = 0; i < req->narg; i++) {
227 		if (req->arg[i].name != NULL)
228 			free(req->arg[i].name);
229 		if (req->arg[i].len < 0)
230 			free(req->arg[i].value);
231 	}
232 	if (req->error != NULL)
233 		free(req->error);
234 	free(req->arg);
235 	free(req);
236 }
237 
238