hammer2 - Fix flush issues with unmounted PFSs and shutdown panic
[dragonfly.git] / sys / libprop / prop_kern.c
blob90335e9ef67c2747ebec9d67f9ca42985840f9aa
1 /* $NetBSD: prop_kern.c,v 1.17 2011/09/30 22:08:18 jym Exp $ */
3 /*-
4 * Copyright (c) 2006, 2009 The NetBSD Foundation, Inc.
5 * All rights reserved.
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Jason R. Thorpe.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
32 #include <sys/types.h>
34 #include <libprop/proplib.h>
36 #if !defined(_KERNEL) && !defined(_STANDALONE)
37 #include <sys/mman.h>
38 #include <errno.h>
39 #include <string.h>
40 #include <stdlib.h>
41 #include <stdio.h>
42 #include <sys/ioctl.h>
44 static int
45 _prop_object_externalize_to_pref(prop_object_t obj, struct plistref *pref,
46 char **bufp)
48 char *buf;
50 switch (prop_object_type(obj)) {
51 case PROP_TYPE_DICTIONARY:
52 buf = prop_dictionary_externalize(obj);
53 break;
54 case PROP_TYPE_ARRAY:
55 buf = prop_array_externalize(obj);
56 break;
57 default:
58 return (ENOTSUP);
60 if (buf == NULL) {
61 /* Assume we ran out of memory. */
62 return (ENOMEM);
64 pref->pref_plist = buf;
65 pref->pref_len = strlen(buf) + 1;
67 *bufp = buf;
69 return (0);
72 bool
73 prop_array_externalize_to_pref(prop_array_t array, struct plistref *prefp)
75 char *buf;
76 int rv;
78 rv = _prop_object_externalize_to_pref(array, prefp, &buf);
79 if (rv != 0)
80 errno = rv; /* pass up error value in errno */
81 return (rv == 0);
85 * prop_array_externalize_to_pref --
86 * Externalize an array into a plistref for sending to the kernel.
88 int
89 prop_array_send_syscall(prop_array_t array, struct plistref *prefp)
91 if (prop_array_externalize_to_pref(array, prefp))
92 return 0;
93 else
94 return errno;
97 bool
98 prop_dictionary_externalize_to_pref(prop_dictionary_t dict,
99 struct plistref *prefp)
101 char *buf;
102 int rv;
104 rv = _prop_object_externalize_to_pref(dict, prefp, &buf);
105 if (rv != 0)
106 errno = rv; /* pass up error value in errno */
107 return (rv == 0);
111 * prop_dictionary_externalize_to_pref --
112 * Externalize an dictionary into a plistref for sending to the kernel.
115 prop_dictionary_send_syscall(prop_dictionary_t dict,
116 struct plistref *prefp)
118 if (prop_dictionary_externalize_to_pref(dict, prefp))
119 return 0;
120 else
121 return errno;
124 static int
125 _prop_object_send_ioctl(prop_object_t obj, int fd, unsigned long cmd)
127 struct plistref pref;
128 char *buf;
129 int error;
131 error = _prop_object_externalize_to_pref(obj, &pref, &buf);
132 if (error)
133 return (error);
135 if (ioctl(fd, cmd, &pref) == -1)
136 error = errno;
137 else
138 error = 0;
140 free(buf);
142 return (error);
146 * prop_array_send_ioctl --
147 * Send an array to the kernel using the specified ioctl.
150 prop_array_send_ioctl(prop_array_t array, int fd, unsigned long cmd)
152 int rv;
154 rv = _prop_object_send_ioctl(array, fd, cmd);
155 if (rv != 0) {
156 errno = rv; /* pass up error value in errno */
157 return rv;
158 } else
159 return 0;
163 * prop_dictionary_send_ioctl --
164 * Send a dictionary to the kernel using the specified ioctl.
167 prop_dictionary_send_ioctl(prop_dictionary_t dict, int fd, unsigned long cmd)
169 int rv;
171 rv = _prop_object_send_ioctl(dict, fd, cmd);
172 if (rv != 0) {
173 errno = rv; /* pass up error value in errno */
174 return rv;
175 } else
176 return 0;
179 static int
180 _prop_object_internalize_from_pref(const struct plistref *pref,
181 prop_type_t type, prop_object_t *objp)
183 prop_object_t obj = NULL;
184 char *buf;
185 int error = 0;
187 if (pref->pref_len == 0) {
189 * This should never happen; we should always get the XML
190 * for an empty dictionary if it's really empty.
192 error = EIO;
193 goto out;
194 } else {
195 buf = pref->pref_plist;
196 buf[pref->pref_len - 1] = '\0'; /* extra insurance */
197 switch (type) {
198 case PROP_TYPE_DICTIONARY:
199 obj = prop_dictionary_internalize(buf);
200 break;
201 case PROP_TYPE_ARRAY:
202 obj = prop_array_internalize(buf);
203 break;
204 default:
205 error = ENOTSUP;
207 (void) munmap(buf, pref->pref_len);
208 if (obj == NULL && error == 0)
209 error = EIO;
212 out:
213 if (error == 0)
214 *objp = obj;
215 return (error);
219 * prop_array_internalize_from_pref --
220 * Internalize a pref into a prop_array_t object.
222 bool
223 prop_array_internalize_from_pref(const struct plistref *prefp,
224 prop_array_t *arrayp)
226 int rv;
228 rv = _prop_object_internalize_from_pref(prefp, PROP_TYPE_ARRAY,
229 (prop_object_t *)arrayp);
230 if (rv != 0)
231 errno = rv; /* pass up error value in errno */
232 return (rv == 0);
236 * prop_array_recv_syscall --
237 * Internalize an array received from the kernel as pref.
240 prop_array_recv_syscall(const struct plistref *prefp,
241 prop_array_t *arrayp)
243 if (prop_array_internalize_from_pref(prefp, arrayp))
244 return 0;
245 else
246 return errno;
250 * prop_dictionary_internalize_from_pref --
251 * Internalize a pref into a prop_dictionary_t object.
253 bool
254 prop_dictionary_internalize_from_pref(const struct plistref *prefp,
255 prop_dictionary_t *dictp)
257 int rv;
259 rv = _prop_object_internalize_from_pref(prefp, PROP_TYPE_DICTIONARY,
260 (prop_object_t *)dictp);
261 if (rv != 0)
262 errno = rv; /* pass up error value in errno */
263 return (rv == 0);
267 * prop_dictionary_recv_syscall --
268 * Internalize a dictionary received from the kernel as pref.
271 prop_dictionary_recv_syscall(const struct plistref *prefp,
272 prop_dictionary_t *dictp)
274 if (prop_dictionary_internalize_from_pref(prefp, dictp))
275 return 0;
276 else
277 return errno;
282 * prop_array_recv_ioctl --
283 * Receive an array from the kernel using the specified ioctl.
286 prop_array_recv_ioctl(int fd, unsigned long cmd, prop_array_t *arrayp)
288 int rv;
289 struct plistref pref;
291 rv = ioctl(fd, cmd, &pref);
292 if (rv == -1)
293 return errno;
295 rv = _prop_object_internalize_from_pref(&pref, PROP_TYPE_ARRAY,
296 (prop_object_t *)arrayp);
297 if (rv != 0) {
298 errno = rv; /* pass up error value in errno */
299 return rv;
300 } else
301 return 0;
305 * prop_dictionary_recv_ioctl --
306 * Receive a dictionary from the kernel using the specified ioctl.
309 prop_dictionary_recv_ioctl(int fd, unsigned long cmd, prop_dictionary_t *dictp)
311 int rv;
312 struct plistref pref;
314 rv = ioctl(fd, cmd, &pref);
315 if (rv == -1)
316 return errno;
318 rv = _prop_object_internalize_from_pref(&pref, PROP_TYPE_DICTIONARY,
319 (prop_object_t *)dictp);
320 if (rv != 0) {
321 errno = rv; /* pass up error value in errno */
322 return rv;
323 } else
324 return 0;
328 * prop_dictionary_sendrecv_ioctl --
329 * Combination send/receive a dictionary to/from the kernel using
330 * the specified ioctl.
333 prop_dictionary_sendrecv_ioctl(prop_dictionary_t dict, int fd,
334 unsigned long cmd, prop_dictionary_t *dictp)
336 struct plistref pref;
337 char *buf;
338 int error;
340 error = _prop_object_externalize_to_pref(dict, &pref, &buf);
341 if (error != 0) {
342 errno = error;
343 return error;
346 if (ioctl(fd, cmd, &pref) == -1)
347 error = errno;
348 else
349 error = 0;
351 free(buf);
353 if (error != 0)
354 return error;
356 error = _prop_object_internalize_from_pref(&pref, PROP_TYPE_DICTIONARY,
357 (prop_object_t *)dictp);
358 if (error != 0) {
359 errno = error; /* pass up error value in errno */
360 return error;
361 } else
362 return 0;
364 #endif /* !_KERNEL && !_STANDALONE */
366 #if defined(_KERNEL)
367 #include <sys/param.h>
368 #include <sys/mman.h>
369 #include <sys/errno.h>
370 #include <sys/malloc.h>
371 #include <sys/systm.h>
372 #include <sys/proc.h>
373 #include <sys/resource.h>
374 #include <sys/objcache.h>
375 #include <sys/ioccom.h>
376 #include <vm/vm.h>
377 #include <vm/vm_extern.h>
378 #include <vm/vm_param.h>
380 #include "prop_object_impl.h"
382 /* Arbitrary limit ioctl input to 64KB */
383 unsigned int prop_object_copyin_limit = 65536;
385 static int
386 _prop_object_copyin(const struct plistref *pref, const prop_type_t type,
387 prop_object_t *objp)
389 prop_object_t obj = NULL;
390 char *buf;
391 int error;
394 * Allocate an extra byte so we can guarantee NUL-termination.
396 * Allow malloc to fail in case pmap would be exhausted.
398 buf = kmalloc(pref->pref_len + 1, M_TEMP, M_WAITOK);
399 error = copyin(pref->pref_plist, buf, pref->pref_len);
400 if (error) {
401 kfree(buf, M_TEMP);
402 return (error);
404 buf[pref->pref_len] = '\0';
406 switch (type) {
407 case PROP_TYPE_ARRAY:
408 obj = prop_array_internalize(buf);
409 break;
410 case PROP_TYPE_DICTIONARY:
411 obj = prop_dictionary_internalize(buf);
412 break;
413 default:
414 error = ENOTSUP;
417 kfree(buf, M_TEMP);
418 if (obj == NULL) {
419 if (error == 0)
420 error = EIO;
421 } else {
422 *objp = obj;
424 return (error);
428 static int
429 _prop_object_copyin_ioctl(const struct plistref *pref, const prop_type_t type,
430 const u_long cmd, prop_object_t *objp)
432 if ((cmd & IOC_IN) == 0)
433 return (EFAULT);
435 return _prop_object_copyin(pref, type, objp);
439 * prop_array_copyin --
440 * Copy in an array passed as a syscall arg.
443 prop_array_copyin(const struct plistref *pref, prop_array_t *arrayp)
445 return (_prop_object_copyin(pref, PROP_TYPE_ARRAY,
446 (prop_object_t *)arrayp));
450 * prop_dictionary_copyin --
451 * Copy in a dictionary passed as a syscall arg.
454 prop_dictionary_copyin(const struct plistref *pref, prop_dictionary_t *dictp)
456 return (_prop_object_copyin(pref, PROP_TYPE_DICTIONARY,
457 (prop_object_t *)dictp));
462 * prop_array_copyin_ioctl --
463 * Copy in an array send with an ioctl.
466 prop_array_copyin_ioctl(const struct plistref *pref, const u_long cmd,
467 prop_array_t *arrayp)
469 return (_prop_object_copyin_ioctl(pref, PROP_TYPE_ARRAY,
470 cmd, (prop_object_t *)arrayp));
474 * prop_dictionary_copyin_ioctl --
475 * Copy in a dictionary sent with an ioctl.
478 prop_dictionary_copyin_ioctl(const struct plistref *pref, const u_long cmd,
479 prop_dictionary_t *dictp)
481 return (_prop_object_copyin_ioctl(pref, PROP_TYPE_DICTIONARY,
482 cmd, (prop_object_t *)dictp));
485 static int
486 _prop_object_copyout(struct plistref *pref, prop_object_t obj)
488 struct proc *p = curproc;
489 char *buf;
490 size_t len, rlen;
491 int error = 0;
492 vm_offset_t uaddr;
494 switch (prop_object_type(obj)) {
495 case PROP_TYPE_ARRAY:
496 buf = prop_array_externalize(obj);
497 break;
498 case PROP_TYPE_DICTIONARY:
499 buf = prop_dictionary_externalize(obj);
500 break;
501 default:
502 return (ENOTSUP);
504 if (buf == NULL)
505 return (ENOMEM);
507 len = strlen(buf) + 1;
508 rlen = round_page(len);
511 * See sys_mmap() in sys/uvm/uvm_mmap.c.
512 * Let's act as if we were calling mmap(0, ...)
514 #if 0
515 uaddr = p->p_emul->e_vm_default_addr(p,
516 (vaddr_t)p->p_vmspace->vm_daddr, rlen);
517 #endif
518 uaddr = round_page((vm_offset_t)p->p_vmspace->vm_daddr + maxdsiz);
520 error = vm_mmap(&p->p_vmspace->vm_map,
521 &uaddr, rlen,
522 VM_PROT_READ|VM_PROT_WRITE,
523 VM_PROT_READ|VM_PROT_WRITE,
524 MAP_PRIVATE|MAP_ANON,
525 NULL, 0);
526 if (error == 0) {
527 error = copyout(buf, (char *)uaddr, len);
528 if (error == 0) {
529 pref->pref_plist = (char *)uaddr;
530 pref->pref_len = len;
534 kfree(buf, M_TEMP);
536 return (error);
540 * prop_array_copyout --
541 * Copy out an array to a syscall arg.
544 prop_array_copyout(struct plistref *pref, prop_array_t array)
546 return (_prop_object_copyout(pref, array));
550 * prop_dictionary_copyout --
551 * Copy out a dictionary to a syscall arg.
554 prop_dictionary_copyout(struct plistref *pref, prop_dictionary_t dict)
556 return (_prop_object_copyout(pref, dict));
559 static int
560 _prop_object_copyout_ioctl(struct plistref *pref, const u_long cmd,
561 prop_object_t obj)
563 if ((cmd & IOC_OUT) == 0)
564 return (EFAULT);
565 return _prop_object_copyout(pref, obj);
570 * prop_array_copyout_ioctl --
571 * Copy out an array being received with an ioctl.
574 prop_array_copyout_ioctl(struct plistref *pref, const u_long cmd,
575 prop_array_t array)
577 return (_prop_object_copyout_ioctl(pref, cmd, array));
581 * prop_dictionary_copyout_ioctl --
582 * Copy out a dictionary being received with an ioctl.
585 prop_dictionary_copyout_ioctl(struct plistref *pref, const u_long cmd,
586 prop_dictionary_t dict)
588 return (
589 _prop_object_copyout_ioctl(pref, cmd, dict));
591 #endif /* _KERNEL */