geom_ctl.c (112534) | geom_ctl.c (112709) |
---|---|
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 --- 18 unchanged lines hidden (view full) --- 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 * | 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 --- 18 unchanged lines hidden (view full) --- 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: head/sys/geom/geom_ctl.c 112534 2003-03-24 13:37:15Z phk $ | 35 * $FreeBSD: head/sys/geom/geom_ctl.c 112709 2003-03-27 14:35:00Z 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> --- 6 unchanged lines hidden (view full) --- 50#include <sys/lock.h> 51#include <sys/mutex.h> 52 53#include <vm/vm.h> 54#include <vm/vm_extern.h> 55 56#include <geom/geom.h> 57#include <geom/geom_int.h> | 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> --- 6 unchanged lines hidden (view full) --- 50#include <sys/lock.h> 51#include <sys/mutex.h> 52 53#include <vm/vm.h> 54#include <vm/vm_extern.h> 55 56#include <geom/geom.h> 57#include <geom/geom_int.h> |
58#define GEOM_CTL_TABLE 1 | 58#define GCTL_TABLE 1 |
59#include <geom/geom_ctl.h> 60#include <geom/geom_ext.h> 61 62static d_ioctl_t g_ctl_ioctl; 63 64static struct cdevsw g_ctl_cdevsw = { 65 .d_open = nullopen, 66 .d_close = nullclose, 67 .d_ioctl = g_ctl_ioctl, 68 .d_name = "g_ctl", 69}; 70 71void 72g_ctl_init(void) 73{ 74 75 make_dev(&g_ctl_cdevsw, 0, 76 UID_ROOT, GID_OPERATOR, 0640, PATH_GEOM_CTL); | 59#include <geom/geom_ctl.h> 60#include <geom/geom_ext.h> 61 62static d_ioctl_t g_ctl_ioctl; 63 64static struct cdevsw g_ctl_cdevsw = { 65 .d_open = nullopen, 66 .d_close = nullclose, 67 .d_ioctl = g_ctl_ioctl, 68 .d_name = "g_ctl", 69}; 70 71void 72g_ctl_init(void) 73{ 74 75 make_dev(&g_ctl_cdevsw, 0, 76 UID_ROOT, GID_OPERATOR, 0640, PATH_GEOM_CTL); |
77 KASSERT(GCTL_PARAM_RD == VM_PROT_READ, 78 ("GCTL_PARAM_RD != VM_PROT_READ")); 79 KASSERT(GCTL_PARAM_WR == VM_PROT_WRITE, 80 ("GCTL_PARAM_WR != VM_PROT_WRITE")); |
|
77} 78 79static int 80g_ctl_ioctl_configgeom(dev_t dev, u_long cmd, caddr_t data, int fflag, struct thread *td) 81{ 82 struct geomconfiggeom *gcp; 83 struct g_configargs ga; 84 int error; --- 35 unchanged lines hidden (view full) --- 120} 121 122/* 123 * Report an error back to the user in ascii format. Return whatever copyout 124 * returned, or EINVAL if it succeeded. 125 * XXX: should not be static. 126 * XXX: should take printf like args. 127 */ | 81} 82 83static int 84g_ctl_ioctl_configgeom(dev_t dev, u_long cmd, caddr_t data, int fflag, struct thread *td) 85{ 86 struct geomconfiggeom *gcp; 87 struct g_configargs ga; 88 int error; --- 35 unchanged lines hidden (view full) --- 124} 125 126/* 127 * Report an error back to the user in ascii format. Return whatever copyout 128 * returned, or EINVAL if it succeeded. 129 * XXX: should not be static. 130 * XXX: should take printf like args. 131 */ |
128static int 129g_ctl_seterror(struct geom_ctl_req *req, const char *errtxt) | 132int 133gctl_error(struct gctl_req *req, const char *errtxt) |
130{ 131 int error; 132 133 error = copyout(errtxt, req->error, 134 imin(req->lerror, strlen(errtxt) + 1)); 135 if (!error) 136 error = EINVAL; 137 return (error); 138} 139 140/* 141 * Allocate space and copyin() something. 142 * XXX: this should really be a standard function in the kernel. 143 */ 144static void * | 134{ 135 int error; 136 137 error = copyout(errtxt, req->error, 138 imin(req->lerror, strlen(errtxt) + 1)); 139 if (!error) 140 error = EINVAL; 141 return (error); 142} 143 144/* 145 * Allocate space and copyin() something. 146 * XXX: this should really be a standard function in the kernel. 147 */ 148static void * |
145geom_alloc_copyin(void *uaddr, size_t len, int *errp) | 149geom_alloc_copyin(struct gctl_req *req, void *uaddr, size_t len, int *errp) |
146{ 147 int error; 148 void *ptr; 149 150 ptr = g_malloc(len, M_WAITOK); 151 if (ptr == NULL) 152 error = ENOMEM; 153 else 154 error = copyin(uaddr, ptr, len); 155 if (!error) 156 return (ptr); | 150{ 151 int error; 152 void *ptr; 153 154 ptr = g_malloc(len, M_WAITOK); 155 if (ptr == NULL) 156 error = ENOMEM; 157 else 158 error = copyin(uaddr, ptr, len); 159 if (!error) 160 return (ptr); |
161 gctl_error(req, "no access to argument"); |
|
157 *errp = error; 158 if (ptr != NULL) 159 g_free(ptr); 160 return (NULL); 161} 162 163 164/* 165 * XXX: This function is a nightmare. It walks through the request and 166 * XXX: makes sure that the various bits and pieces are there and copies 167 * XXX: some of them into kernel memory to make things easier. 168 * XXX: I really wish we had a standard marshalling layer somewhere. 169 */ 170 171static int | 162 *errp = error; 163 if (ptr != NULL) 164 g_free(ptr); 165 return (NULL); 166} 167 168 169/* 170 * XXX: This function is a nightmare. It walks through the request and 171 * XXX: makes sure that the various bits and pieces are there and copies 172 * XXX: some of them into kernel memory to make things easier. 173 * XXX: I really wish we had a standard marshalling layer somewhere. 174 */ 175 176static int |
172geom_ctl_copyin(struct geom_ctl_req *req) | 177gctl_copyin(struct gctl_req *req) |
173{ 174 int error, i, j; | 178{ 179 int error, i, j; |
175 struct geom_ctl_req_arg *ap; | 180 struct gctl_req_arg *ap; |
176 char *p; 177 178 error = 0; | 181 char *p; 182 183 error = 0; |
179 if (!useracc(req->error, req->lerror, VM_PROT_WRITE)) 180 return (g_ctl_seterror(req, "No access to error field")); 181 ap = geom_alloc_copyin(req->arg, req->narg * sizeof(*ap), &error); 182 if (ap == NULL) | 184 ap = geom_alloc_copyin(req, req->arg, req->narg * sizeof(*ap), &error); 185 if (ap == NULL) { 186 gctl_error(req, "copyin() of arguments failed"); |
183 return (error); | 187 return (error); |
188 } 189 |
|
184 for (i = 0; !error && i < req->narg; i++) { | 190 for (i = 0; !error && i < req->narg; i++) { |
185 if (ap[i].len < 0 && 186 !useracc(ap[i].value, 1 + -ap[i].len, VM_PROT_READ)) 187 error = g_ctl_seterror(req, "No access to param data"); 188 else if (ap[i].len > 0 && 189 !useracc(ap[i].value, ap[i].len, 190 VM_PROT_READ | VM_PROT_WRITE)) 191 error = g_ctl_seterror(req, "No access to param data"); 192 if (ap[i].name == NULL) 193 continue; | 191 if (ap[i].len > 0 && 192 !useracc(ap[i].value, ap[i].len, 193 ap[i].flag & GCTL_PARAM_RW)) 194 error = gctl_error(req, "no access to param data"); 195 if (ap[i].name == NULL) { 196 if (req->reqt->meta) 197 continue; 198 error = gctl_error(req, 199 "request does not take metadata arguments"); 200 break; 201 } |
194 p = NULL; | 202 p = NULL; |
195 if (ap[i].nlen < 1 || ap[i].nlen > SPECNAMELEN) 196 error = EINVAL; 197 if (error) | 203 if (ap[i].nlen < 1 || ap[i].nlen > SPECNAMELEN) { 204 error = gctl_error(req, "wrong param name length"); |
198 break; | 205 break; |
199 p = geom_alloc_copyin(ap[i].name, ap[i].nlen + 1, &error); 200 if (error) | 206 } 207 p = geom_alloc_copyin(req, ap[i].name, ap[i].nlen, &error); 208 if (p == NULL) |
201 break; | 209 break; |
202 if (p[ap[i].nlen] != '\0') 203 error = EINVAL; 204 if (!error) { 205 ap[i].name = p; 206 ap[i].nlen = 0; 207 } else { | 210 if (p[ap[i].nlen - 1] != '\0') { 211 error = gctl_error(req, "unterminated param name"); |
208 g_free(p); 209 break; 210 } | 212 g_free(p); 213 break; 214 } |
215 ap[i].name = p; 216 ap[i].nlen = 0; |
|
211 } 212 if (!error) { 213 req->arg = ap; 214 return (0); 215 } 216 for (j = 0; j < i; j++) 217 if (ap[j].nlen == 0 && ap[j].name != NULL) 218 g_free(ap[j].name); 219 g_free(ap); 220 return (error); 221} 222 223static void | 217 } 218 if (!error) { 219 req->arg = ap; 220 return (0); 221 } 222 for (j = 0; j < i; j++) 223 if (ap[j].nlen == 0 && ap[j].name != NULL) 224 g_free(ap[j].name); 225 g_free(ap); 226 return (error); 227} 228 229static void |
224geom_ctl_dump(struct geom_ctl_req *req) | 230gctl_dump(struct gctl_req *req) |
225{ 226 u_int i; 227 int j, error; | 231{ 232 u_int i; 233 int j, error; |
228 struct geom_ctl_req_arg *ap; | 234 struct gctl_req_arg *ap; |
229 void *p; 230 231 | 235 void *p; 236 237 |
232 printf("Dump of geom_ctl %s request at %p:\n", req->reqt->name, req); | 238 printf("Dump of gctl %s request at %p:\n", req->reqt->name, req); |
233 if (req->lerror > 0) { | 239 if (req->lerror > 0) { |
234 p = geom_alloc_copyin(req->error, req->lerror, &error); | 240 p = geom_alloc_copyin(req, req->error, req->lerror, &error); |
235 if (p != NULL) { 236 ((char *)p)[req->lerror - 1] = '\0'; 237 printf(" error:\t\"%s\"\n", (char *)p); 238 g_free(p); 239 } 240 } 241 for (i = 0; i < req->narg; i++) { 242 ap = &req->arg[i]; 243 if (ap->name != NULL) 244 printf(" param:\t\"%s\"", ap->name); 245 else 246 printf(" meta:\t@%jd", (intmax_t)ap->offset); | 241 if (p != NULL) { 242 ((char *)p)[req->lerror - 1] = '\0'; 243 printf(" error:\t\"%s\"\n", (char *)p); 244 g_free(p); 245 } 246 } 247 for (i = 0; i < req->narg; i++) { 248 ap = &req->arg[i]; 249 if (ap->name != NULL) 250 printf(" param:\t\"%s\"", ap->name); 251 else 252 printf(" meta:\t@%jd", (intmax_t)ap->offset); |
247 printf(" [%d] = ", ap->len); 248 if (ap->len < 0) { 249 p = geom_alloc_copyin(ap->value, 1 + -ap->len, &error); 250 ((char *)p)[-ap->len] = '\0'; 251 if (p != NULL) | 253 printf(" [%s%s%d] = ", 254 ap->flag & GCTL_PARAM_RD ? "R" : "", 255 ap->flag & GCTL_PARAM_WR ? "W" : "", 256 ap->len); 257 if (ap->flag & GCTL_PARAM_ASCII) { 258 p = geom_alloc_copyin(req, ap->value, ap->len, &error); 259 if (p != NULL) { 260 ((char *)p)[ap->len - 1] = '\0'; |
252 printf("\"%s\"", (char *)p); | 261 printf("\"%s\"", (char *)p); |
262 } |
|
253 g_free(p); 254 } else if (ap->len > 0) { | 263 g_free(p); 264 } else if (ap->len > 0) { |
255 p = geom_alloc_copyin(ap->value, ap->len, &error); | 265 p = geom_alloc_copyin(req, ap->value, ap->len, &error); |
256 for (j = 0; j < ap->len; j++) 257 printf(" %02x", ((u_char *)p)[j]); 258 g_free(p); 259 } else { 260 printf(" = %p", ap->value); 261 } 262 printf("\n"); 263 } 264} 265 | 266 for (j = 0; j < ap->len; j++) 267 printf(" %02x", ((u_char *)p)[j]); 268 g_free(p); 269 } else { 270 printf(" = %p", ap->value); 271 } 272 printf("\n"); 273 } 274} 275 |
276void * 277gctl_get_param(struct gctl_req *req, const char *param, int *len) 278{ 279 int i, error, j; 280 void *p; 281 struct gctl_req_arg *ap; 282 283 for (i = 0; i < req->narg; i++) { 284 ap = &req->arg[i]; 285 if (strcmp(param, ap->name)) 286 continue; 287 if (!(ap->flag & GCTL_PARAM_RD)) 288 continue; 289 if (ap->len > 0) 290 j = ap->len; 291 else 292 j = 0; 293 if (j != 0) 294 p = geom_alloc_copyin(req, ap->value, j, &error); 295 /* XXX: should not fail, tested prviously */ 296 else 297 p = ap->value; 298 if (len != NULL) 299 *len = j; 300 return (p); 301 } 302 return (NULL); 303} 304 305static struct g_class* 306gctl_get_class(struct gctl_req *req) 307{ 308 char *p; 309 int len; 310 struct g_class *cp; 311 312 p = gctl_get_param(req, "class", &len); 313 if (p == NULL) 314 return (NULL); 315 if (p[len - 1] != '\0') { 316 gctl_error(req, "Unterminated class name"); 317 g_free(p); 318 return (NULL); 319 } 320 LIST_FOREACH(cp, &g_classes, class) { 321 if (!strcmp(p, cp->name)) { 322 g_free(p); 323 return (cp); 324 } 325 } 326 gctl_error(req, "Class not found"); 327 return (NULL); 328} 329 330static struct g_geom* 331gctl_get_geom(struct gctl_req *req, struct g_class *mpr) 332{ 333 char *p; 334 int len; 335 struct g_class *mp; 336 struct g_geom *gp; 337 338 p = gctl_get_param(req, "geom", &len); 339 if (p == NULL) 340 return (NULL); 341 if (p[len - 1] != '\0') { 342 gctl_error(req, "Unterminated provider name"); 343 g_free(p); 344 return (NULL); 345 } 346 LIST_FOREACH(mp, &g_classes, class) { 347 if (mpr != NULL && mpr != mp) 348 continue; 349 LIST_FOREACH(gp, &mp->geom, geom) { 350 if (!strcmp(p, gp->name)) { 351 g_free(p); 352 return (gp); 353 } 354 } 355 } 356 gctl_error(req, "Geom not found"); 357 return (NULL); 358} 359 360static struct g_provider* 361gctl_get_provider(struct gctl_req *req) 362{ 363 char *p; 364 int len; 365 struct g_class *cp; 366 struct g_geom *gp; 367 struct g_provider *pp; 368 369 p = gctl_get_param(req, "provider", &len); 370 if (p == NULL) 371 return (NULL); 372 if (p[len - 1] != '\0') { 373 gctl_error(req, "Unterminated provider name"); 374 g_free(p); 375 return (NULL); 376 } 377 LIST_FOREACH(cp, &g_classes, class) { 378 LIST_FOREACH(gp, &cp->geom, geom) { 379 LIST_FOREACH(pp, &gp->provider, provider) { 380 if (!strcmp(p, pp->name)) { 381 g_free(p); 382 return (pp); 383 } 384 } 385 } 386 } 387 gctl_error(req, "Provider not found"); 388 return (NULL); 389} 390 391static void 392gctl_create_geom(struct gctl_req *req) 393{ 394 struct g_class *mp; 395 struct g_provider *pp; 396 397 g_topology_assert(); 398 mp = gctl_get_class(req); 399 if (mp == NULL) 400 return; 401 printf("Found class: %p\n", mp); 402 if (mp->create_geom == NULL) { 403 gctl_error(req, "Class has no create_geom method"); 404 return; 405 } 406 pp = gctl_get_provider(req); 407 printf("Found provider: %p\n", pp); 408 mp->create_geom(req, mp, pp); 409 g_topology_assert(); 410} 411 412static void 413gctl_destroy_geom(struct gctl_req *req) 414{ 415 struct g_class *mp; 416 struct g_geom *gp; 417 418 g_topology_assert(); 419 mp = gctl_get_class(req); 420 if (mp == NULL) 421 return; 422 printf("Found class: %p\n", mp); 423 if (mp->destroy_geom == NULL) { 424 gctl_error(req, "Class has no destroy_geom method"); 425 return; 426 } 427 gp = gctl_get_geom(req, mp); 428 if (gp == NULL) { 429 gctl_error(req, "Geom not specified"); 430 return; 431 } 432 if (gp->class != mp) { 433 gctl_error(req, "Geom not of specificed class"); 434 return; 435 } 436 printf("Found geom: %p\n", gp); 437 mp->destroy_geom(req, mp, gp); 438 g_topology_assert(); 439} 440 |
|
266/* 267 * Handle ioctl from libgeom::geom_ctl.c 268 */ 269static int 270g_ctl_ioctl_ctl(dev_t dev, u_long cmd, caddr_t data, int fflag, struct thread *td) 271{ 272 int error; 273 int i; | 441/* 442 * Handle ioctl from libgeom::geom_ctl.c 443 */ 444static int 445g_ctl_ioctl_ctl(dev_t dev, u_long cmd, caddr_t data, int fflag, struct thread *td) 446{ 447 int error; 448 int i; |
274 struct geom_ctl_req *req; | 449 struct gctl_req *req; |
275 276 req = (void *)data; | 450 451 req = (void *)data; |
452 /* It is an error if we cannot return an error text */ |
|
277 if (req->lerror < 1) 278 return (EINVAL); | 453 if (req->lerror < 1) 454 return (EINVAL); |
279 if (req->version != GEOM_CTL_VERSION) 280 return (g_ctl_seterror(req, 281 "Kernel and libgeom version skew.")); 282 for (i = 0; gcrt[i].request != GEOM_INVALID_REQUEST; i++) 283 if (gcrt[i].request == req->request) { 284 req->reqt = &gcrt[i]; | 455 if (!useracc(req->error, req->lerror, VM_PROT_WRITE)) 456 return (EINVAL); 457 458 /* Check the version */ 459 if (req->version != GCTL_VERSION) 460 return (gctl_error(req, 461 "kernel and libgeom version mismatch.")); 462 463 /* Check the request type */ 464 for (i = 0; gcrt[i].request != GCTL_INVALID_REQUEST; i++) 465 if (gcrt[i].request == req->request) |
285 break; | 466 break; |
286 } 287 if (gcrt[i].request == GEOM_INVALID_REQUEST) 288 return (g_ctl_seterror(req, "Invalid request")); 289 error = geom_ctl_copyin(req); | 467 if (gcrt[i].request == GCTL_INVALID_REQUEST) 468 return (gctl_error(req, "invalid request")); 469 req->reqt = &gcrt[i]; 470 471 /* Get things on board */ 472 error = gctl_copyin(req); |
290 if (error) 291 return (error); | 473 if (error) 474 return (error); |
292 req->reqt = &gcrt[i]; | 475 476 gctl_dump(req); 477#if 0 |
293 g_stall_events(); | 478 g_stall_events(); |
294 geom_ctl_dump(req); | 479#endif 480 g_topology_lock(); 481 switch (req->request) { 482 case GCTL_CREATE_GEOM: 483 gctl_create_geom(req); 484 break; 485 case GCTL_DESTROY_GEOM: 486 gctl_destroy_geom(req); 487 break; 488 default: 489 gctl_error(req, "XXX: TBD"); 490 break; 491 } 492 g_topology_unlock(); 493#if 0 |
295 g_release_events(); | 494 g_release_events(); |
495#endif |
|
296 return (0); 297} 298 299static int 300g_ctl_ioctl(dev_t dev, u_long cmd, caddr_t data, int fflag, struct thread *td) 301{ 302 int error; 303 304 switch(cmd) { 305 case GEOMCONFIGGEOM: 306 DROP_GIANT(); 307 g_topology_lock(); 308 error = g_ctl_ioctl_configgeom(dev, cmd, data, fflag, td); 309 g_topology_unlock(); 310 PICKUP_GIANT(); 311 break; 312 case GEOM_CTL: | 496 return (0); 497} 498 499static int 500g_ctl_ioctl(dev_t dev, u_long cmd, caddr_t data, int fflag, struct thread *td) 501{ 502 int error; 503 504 switch(cmd) { 505 case GEOMCONFIGGEOM: 506 DROP_GIANT(); 507 g_topology_lock(); 508 error = g_ctl_ioctl_configgeom(dev, cmd, data, fflag, td); 509 g_topology_unlock(); 510 PICKUP_GIANT(); 511 break; 512 case GEOM_CTL: |
513 DROP_GIANT(); |
|
313 error = g_ctl_ioctl_ctl(dev, cmd, data, fflag, td); | 514 error = g_ctl_ioctl_ctl(dev, cmd, data, fflag, td); |
515 PICKUP_GIANT(); |
|
314 break; 315 default: 316 error = ENOTTY; 317 break; 318 } 319 return (error); 320 321} | 516 break; 517 default: 518 error = ENOTTY; 519 break; 520 } 521 return (error); 522 523} |