FreeBSD/Linux Kernel Cross Reference
sys/geom/geom_ctl.c
1 /*-
2 * Copyright (c) 2002 Poul-Henning Kamp
3 * Copyright (c) 2002 Networks Associates Technology, Inc.
4 * All rights reserved.
5 *
6 * This software was developed for the FreeBSD Project by Poul-Henning Kamp
7 * and NAI Labs, the Security Research Division of Network Associates, Inc.
8 * under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), as part of the
9 * DARPA CHATS research program.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. The names of the authors may not be used to endorse or promote
20 * products derived from this software without specific prior written
21 * permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 *
35 * $FreeBSD: releng/5.1/sys/geom/geom_ctl.c 114670 2003-05-04 19:24:34Z phk $
36 */
37
38 #include "opt_geom.h"
39
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/kernel.h>
43 #include <sys/sysctl.h>
44 #include <sys/bio.h>
45 #include <sys/conf.h>
46 #include <sys/disk.h>
47 #include <sys/malloc.h>
48 #include <sys/sysctl.h>
49 #include <sys/sbuf.h>
50
51 #include <sys/lock.h>
52 #include <sys/mutex.h>
53
54 #include <vm/vm.h>
55 #include <vm/vm_extern.h>
56
57 #include <geom/geom.h>
58 #include <geom/geom_int.h>
59 #define GCTL_TABLE 1
60 #include <geom/geom_ctl.h>
61 #include <geom/geom_ext.h>
62
63 #include <machine/stdarg.h>
64
65 static d_ioctl_t g_ctl_ioctl;
66
67 static struct cdevsw g_ctl_cdevsw = {
68 .d_open = nullopen,
69 .d_close = nullclose,
70 .d_ioctl = g_ctl_ioctl,
71 .d_name = "g_ctl",
72 };
73
74 void
75 g_ctl_init(void)
76 {
77
78 make_dev(&g_ctl_cdevsw, 0,
79 UID_ROOT, GID_OPERATOR, 0640, PATH_GEOM_CTL);
80 KASSERT(GCTL_PARAM_RD == VM_PROT_READ,
81 ("GCTL_PARAM_RD != VM_PROT_READ"));
82 KASSERT(GCTL_PARAM_WR == VM_PROT_WRITE,
83 ("GCTL_PARAM_WR != VM_PROT_WRITE"));
84 }
85
86 /*
87 * Report an error back to the user in ascii format. Return whatever copyout
88 * returned, or EINVAL if it succeeded.
89 * XXX: should not be static.
90 * XXX: should take printf like args.
91 */
92 int
93 gctl_error(struct gctl_req *req, const char *fmt, ...)
94 {
95 int error;
96 va_list ap;
97 struct sbuf *sb;
98
99 sb = sbuf_new(NULL, NULL, 0, SBUF_AUTOEXTEND);
100 if (sb == NULL) {
101 error = copyout(fmt, req->error,
102 imin(req->lerror, strlen(fmt) + 1));
103 } else {
104 va_start(ap, fmt);
105 sbuf_vprintf(sb, fmt, ap);
106 sbuf_finish(sb);
107 if (g_debugflags & G_F_CTLDUMP)
108 printf("gctl %p error \"%s\"\n", req, sbuf_data(sb));
109 error = copyout(sbuf_data(sb), req->error,
110 imin(req->lerror, sbuf_len(sb) + 1));
111 }
112 if (!error)
113 error = EINVAL;
114 sbuf_delete(sb);
115 return (error);
116 }
117
118 /*
119 * Allocate space and copyin() something.
120 * XXX: this should really be a standard function in the kernel.
121 */
122 static void *
123 geom_alloc_copyin(struct gctl_req *req, void *uaddr, size_t len, int *errp)
124 {
125 int error;
126 void *ptr;
127
128 ptr = g_malloc(len, M_WAITOK);
129 if (ptr == NULL)
130 error = ENOMEM;
131 else
132 error = copyin(uaddr, ptr, len);
133 if (!error)
134 return (ptr);
135 gctl_error(req, "no access to argument");
136 *errp = error;
137 if (ptr != NULL)
138 g_free(ptr);
139 return (NULL);
140 }
141
142
143 /*
144 * XXX: This function is a nightmare. It walks through the request and
145 * XXX: makes sure that the various bits and pieces are there and copies
146 * XXX: some of them into kernel memory to make things easier.
147 * XXX: I really wish we had a standard marshalling layer somewhere.
148 */
149
150 static int
151 gctl_copyin(struct gctl_req *req)
152 {
153 int error, i, j;
154 struct gctl_req_arg *ap;
155 char *p;
156
157 error = 0;
158 ap = geom_alloc_copyin(req, req->arg, req->narg * sizeof(*ap), &error);
159 if (ap == NULL) {
160 gctl_error(req, "copyin() of arguments failed");
161 return (error);
162 }
163
164 for (i = 0; !error && i < req->narg; i++) {
165 if (ap[i].len > 0 &&
166 !useracc(ap[i].value, ap[i].len,
167 ap[i].flag & GCTL_PARAM_RW))
168 error = gctl_error(req, "no access to param data");
169 if (error)
170 break;
171 p = NULL;
172 if (ap[i].nlen < 1 || ap[i].nlen > SPECNAMELEN) {
173 error = gctl_error(req, "wrong param name length");
174 break;
175 }
176 p = geom_alloc_copyin(req, ap[i].name, ap[i].nlen, &error);
177 if (p == NULL)
178 break;
179 if (p[ap[i].nlen - 1] != '\0') {
180 error = gctl_error(req, "unterminated param name");
181 g_free(p);
182 break;
183 }
184 ap[i].name = p;
185 ap[i].nlen = 0;
186 }
187 if (!error) {
188 req->arg = ap;
189 return (0);
190 }
191 for (j = 0; j < i; j++)
192 if (ap[j].nlen == 0 && ap[j].name != NULL)
193 g_free(ap[j].name);
194 g_free(ap);
195 return (error);
196 }
197
198 static void
199 gctl_free(struct gctl_req *req)
200 {
201 int i;
202
203 for (i = 0; i < req->narg; i++) {
204 if (req->arg[i].nlen == 0 && req->arg[i].name != NULL)
205 g_free(req->arg[i].name);
206 }
207 g_free(req->arg);
208 }
209
210 static void
211 gctl_dump(struct gctl_req *req)
212 {
213 u_int i;
214 int j, error;
215 struct gctl_req_arg *ap;
216 void *p;
217
218
219 printf("Dump of gctl %s request at %p:\n", req->reqt->name, req);
220 if (req->lerror > 0) {
221 p = geom_alloc_copyin(req, req->error, req->lerror, &error);
222 if (p != NULL) {
223 ((char *)p)[req->lerror - 1] = '\0';
224 printf(" error:\t\"%s\"\n", (char *)p);
225 g_free(p);
226 }
227 }
228 for (i = 0; i < req->narg; i++) {
229 ap = &req->arg[i];
230 printf(" param:\t\"%s\"", ap->name);
231 printf(" [%s%s%d] = ",
232 ap->flag & GCTL_PARAM_RD ? "R" : "",
233 ap->flag & GCTL_PARAM_WR ? "W" : "",
234 ap->len);
235 if (ap->flag & GCTL_PARAM_ASCII) {
236 p = geom_alloc_copyin(req, ap->value, ap->len, &error);
237 if (p != NULL) {
238 ((char *)p)[ap->len - 1] = '\0';
239 printf("\"%s\"", (char *)p);
240 }
241 g_free(p);
242 } else if (ap->len > 0) {
243 p = geom_alloc_copyin(req, ap->value, ap->len, &error);
244 for (j = 0; j < ap->len; j++)
245 printf(" %02x", ((u_char *)p)[j]);
246 g_free(p);
247 } else {
248 printf(" = %p", ap->value);
249 }
250 printf("\n");
251 }
252 }
253
254 int
255 gctl_set_param(struct gctl_req *req, const char *param, void *ptr, int len)
256 {
257 int i, error;
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_WR)) {
265 gctl_error(req, "No write access %s argument", param);
266 return (EINVAL);
267 }
268 if (ap->len != len) {
269 gctl_error(req, "Wrong length %s argument", param);
270 return (EINVAL);
271 }
272 error = copyout(ptr, ap->value, len);
273 return (error);
274 }
275 gctl_error(req, "Missing %s argument", param);
276 return (EINVAL);
277 }
278
279 void *
280 gctl_get_param(struct gctl_req *req, const char *param, int *len)
281 {
282 int i, error, j;
283 void *p;
284 struct gctl_req_arg *ap;
285
286 for (i = 0; i < req->narg; i++) {
287 ap = &req->arg[i];
288 if (strcmp(param, ap->name))
289 continue;
290 if (!(ap->flag & GCTL_PARAM_RD))
291 continue;
292 if (ap->len > 0)
293 j = ap->len;
294 else
295 j = 0;
296 if (j != 0)
297 p = geom_alloc_copyin(req, ap->value, j, &error);
298 /* XXX: should not fail, tested prviously */
299 else
300 p = ap->value;
301 if (len != NULL)
302 *len = j;
303 return (p);
304 }
305 return (NULL);
306 }
307
308 void *
309 gctl_get_paraml(struct gctl_req *req, const char *param, int len)
310 {
311 int i;
312 void *p;
313
314 p = gctl_get_param(req, param, &i);
315 if (p == NULL)
316 gctl_error(req, "Missing %s argument", param);
317 else if (i != len) {
318 g_free(p);
319 p = NULL;
320 gctl_error(req, "Wrong length %s argument", param);
321 }
322 return (p);
323 }
324
325 static struct g_class*
326 gctl_get_class(struct gctl_req *req)
327 {
328 char *p;
329 int len;
330 struct g_class *cp;
331
332 p = gctl_get_param(req, "class", &len);
333 if (p == NULL)
334 return (NULL);
335 if (p[len - 1] != '\0') {
336 gctl_error(req, "Unterminated class name");
337 g_free(p);
338 return (NULL);
339 }
340 LIST_FOREACH(cp, &g_classes, class) {
341 if (!strcmp(p, cp->name)) {
342 g_free(p);
343 return (cp);
344 }
345 }
346 g_free(p);
347 gctl_error(req, "Class not found");
348 return (NULL);
349 }
350
351 static struct g_geom*
352 gctl_get_geom(struct gctl_req *req, struct g_class *mpr)
353 {
354 char *p;
355 int len;
356 struct g_class *mp;
357 struct g_geom *gp;
358
359 p = gctl_get_param(req, "geom", &len);
360 if (p == NULL)
361 return (NULL);
362 if (p[len - 1] != '\0') {
363 gctl_error(req, "Unterminated provider name");
364 g_free(p);
365 return (NULL);
366 }
367 LIST_FOREACH(mp, &g_classes, class) {
368 if (mpr != NULL && mpr != mp)
369 continue;
370 LIST_FOREACH(gp, &mp->geom, geom) {
371 if (!strcmp(p, gp->name)) {
372 g_free(p);
373 return (gp);
374 }
375 }
376 }
377 gctl_error(req, "Geom not found");
378 g_free(p);
379 return (NULL);
380 }
381
382 static struct g_provider*
383 gctl_get_provider(struct gctl_req *req)
384 {
385 char *p;
386 int len;
387 struct g_class *cp;
388 struct g_geom *gp;
389 struct g_provider *pp;
390
391 p = gctl_get_param(req, "provider", &len);
392 if (p == NULL)
393 return (NULL);
394 if (p[len - 1] != '\0') {
395 gctl_error(req, "Unterminated provider name");
396 g_free(p);
397 return (NULL);
398 }
399 LIST_FOREACH(cp, &g_classes, class) {
400 LIST_FOREACH(gp, &cp->geom, geom) {
401 LIST_FOREACH(pp, &gp->provider, provider) {
402 if (!strcmp(p, pp->name)) {
403 g_free(p);
404 return (pp);
405 }
406 }
407 }
408 }
409 gctl_error(req, "Provider not found");
410 g_free(p);
411 return (NULL);
412 }
413
414 static int
415 gctl_create_geom(struct gctl_req *req)
416 {
417 struct g_class *mp;
418 struct g_provider *pp;
419 int error;
420
421 g_topology_assert();
422 mp = gctl_get_class(req);
423 if (mp == NULL)
424 return (gctl_error(req, "Class not found"));
425 if (mp->create_geom == NULL)
426 return (gctl_error(req, "Class has no create_geom method"));
427 pp = gctl_get_provider(req);
428 error = mp->create_geom(req, mp, pp);
429 g_topology_assert();
430 return (error);
431 }
432
433 static int
434 gctl_destroy_geom(struct gctl_req *req)
435 {
436 struct g_class *mp;
437 struct g_geom *gp;
438 int error;
439
440 g_topology_assert();
441 mp = gctl_get_class(req);
442 if (mp == NULL)
443 return (gctl_error(req, "Class not found"));
444 if (mp->destroy_geom == NULL)
445 return (gctl_error(req, "Class has no destroy_geom method"));
446 gp = gctl_get_geom(req, mp);
447 if (gp == NULL)
448 return (gctl_error(req, "Geom not specified"));
449 if (gp->class != mp)
450 return (gctl_error(req, "Geom not of specificed class"));
451 error = mp->destroy_geom(req, mp, gp);
452 g_topology_assert();
453 return (error);
454 }
455
456 static int
457 gctl_config_geom(struct gctl_req *req)
458 {
459 struct g_class *mp;
460 struct g_geom *gp;
461 char *verb;
462 int error, vlen;
463
464 g_topology_assert();
465 mp = gctl_get_class(req);
466 if (mp == NULL)
467 return (gctl_error(req, "Class not found"));
468 if (mp->config_geom == NULL)
469 return (gctl_error(req, "Class has no config_geom method"));
470 gp = gctl_get_geom(req, mp);
471 if (gp == NULL)
472 return (gctl_error(req, "Geom not specified"));
473 if (gp->class != mp)
474 return (gctl_error(req, "Geom not of specificed class"));
475 verb = gctl_get_param(req, "verb", &vlen);
476 if (verb == NULL)
477 return (gctl_error(req, "Missing verb parameter"));
478 if (vlen < 2) {
479 g_free(verb);
480 return (gctl_error(req, "Too short verb parameter"));
481 }
482 if (verb[vlen - 1] != '\0') {
483 g_free(verb);
484 return (gctl_error(req, "Unterminated verb parameter"));
485 }
486 error = mp->config_geom(req, gp, verb);
487 g_free(verb);
488 g_topology_assert();
489 return (error);
490 }
491
492 /*
493 * Handle ioctl from libgeom::geom_ctl.c
494 */
495 static int
496 g_ctl_ioctl_ctl(dev_t dev, u_long cmd, caddr_t data, int fflag, struct thread *td)
497 {
498 int error;
499 int i;
500 struct gctl_req *req;
501
502 req = (void *)data;
503 /* It is an error if we cannot return an error text */
504 if (req->lerror < 1)
505 return (EINVAL);
506 if (!useracc(req->error, req->lerror, VM_PROT_WRITE))
507 return (EINVAL);
508
509 /* Check the version */
510 if (req->version != GCTL_VERSION)
511 return (gctl_error(req,
512 "kernel and libgeom version mismatch."));
513
514 /* Check the request type */
515 for (i = 0; gcrt[i].request != GCTL_INVALID_REQUEST; i++)
516 if (gcrt[i].request == req->request)
517 break;
518 if (gcrt[i].request == GCTL_INVALID_REQUEST)
519 return (gctl_error(req, "invalid request"));
520 req->reqt = &gcrt[i];
521
522 /* Get things on board */
523 error = gctl_copyin(req);
524 if (error)
525 return (error);
526
527 if (g_debugflags & G_F_CTLDUMP)
528 gctl_dump(req);
529 g_topology_lock();
530 switch (req->request) {
531 case GCTL_CREATE_GEOM:
532 error = gctl_create_geom(req);
533 break;
534 case GCTL_DESTROY_GEOM:
535 error = gctl_destroy_geom(req);
536 break;
537 case GCTL_CONFIG_GEOM:
538 error = gctl_config_geom(req);
539 break;
540 default:
541 error = gctl_error(req, "XXX: TBD");
542 break;
543 }
544 gctl_free(req);
545 g_topology_unlock();
546 return (error);
547 }
548
549 static int
550 g_ctl_ioctl(dev_t dev, u_long cmd, caddr_t data, int fflag, struct thread *td)
551 {
552 int error;
553
554 switch(cmd) {
555 case GEOM_CTL:
556 DROP_GIANT();
557 error = g_ctl_ioctl_ctl(dev, cmd, data, fflag, td);
558 PICKUP_GIANT();
559 break;
560 default:
561 error = ENOTTY;
562 break;
563 }
564 return (error);
565
566 }
Cache object: f938c1539da54e640bb37d409d7c8ffa
|