Merge branch 'vendor/GCC47'
[dragonfly.git] / sys / libprop / prop_kern.c
1 /*      $NetBSD: prop_kern.c,v 1.17 2011/09/30 22:08:18 jym Exp $       */
2
3 /*-
4  * Copyright (c) 2006, 2009 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Jason R. Thorpe.
9  *
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.
18  *
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.
30  */
31
32 #include <sys/types.h>
33
34 #include <libprop/proplib.h>
35
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>
43
44 static int
45 _prop_object_externalize_to_pref(prop_object_t obj, struct plistref *pref,
46                                  char **bufp)
47 {
48         char *buf;
49
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);
59         }
60         if (buf == NULL) {
61                 /* Assume we ran out of memory. */
62                 return (ENOMEM);
63         }
64         pref->pref_plist = buf;
65         pref->pref_len = strlen(buf) + 1;
66
67         *bufp = buf;
68
69         return (0);
70 }
71
72 bool
73 prop_array_externalize_to_pref(prop_array_t array, struct plistref *prefp)
74 {
75         char *buf;
76         int rv;
77
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);
82 }
83
84 /*
85  * prop_array_externalize_to_pref --
86  *      Externalize an array into a plistref for sending to the kernel.
87  */
88 int
89 prop_array_send_syscall(prop_array_t array, struct plistref *prefp)
90 {
91         if (prop_array_externalize_to_pref(array, prefp))
92                 return 0;
93         else
94                 return errno;
95 }
96
97 bool
98 prop_dictionary_externalize_to_pref(prop_dictionary_t dict,
99                                     struct plistref *prefp)
100 {
101         char *buf;
102         int rv;
103
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);
108 }
109
110 /*
111  * prop_dictionary_externalize_to_pref --
112  *      Externalize an dictionary into a plistref for sending to the kernel.
113  */
114 int
115 prop_dictionary_send_syscall(prop_dictionary_t dict,
116                              struct plistref *prefp)
117 {
118         if (prop_dictionary_externalize_to_pref(dict, prefp))
119                 return 0;
120         else
121                 return errno;
122 }
123
124 static int
125 _prop_object_send_ioctl(prop_object_t obj, int fd, unsigned long cmd)
126 {
127         struct plistref pref;
128         char *buf;
129         int error;
130
131         error = _prop_object_externalize_to_pref(obj, &pref, &buf);
132         if (error)
133                 return (error);
134
135         if (ioctl(fd, cmd, &pref) == -1)
136                 error = errno;
137         else
138                 error = 0;
139         
140         free(buf);
141
142         return (error);
143 }
144
145 /*
146  * prop_array_send_ioctl --
147  *      Send an array to the kernel using the specified ioctl.
148  */
149 int
150 prop_array_send_ioctl(prop_array_t array, int fd, unsigned long cmd)
151 {
152         int rv;
153
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;
160 }
161
162 /*
163  * prop_dictionary_send_ioctl --
164  *      Send a dictionary to the kernel using the specified ioctl.
165  */
166 int
167 prop_dictionary_send_ioctl(prop_dictionary_t dict, int fd, unsigned long cmd)
168 {
169         int rv;
170
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;
177 }
178
179 static int
180 _prop_object_internalize_from_pref(const struct plistref *pref,
181                                    prop_type_t type, prop_object_t *objp)
182 {
183         prop_object_t obj = NULL;
184         char *buf;
185         int error = 0;
186
187         if (pref->pref_len == 0) {
188                 /*
189                  * This should never happen; we should always get the XML
190                  * for an empty dictionary if it's really empty.
191                  */
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;
206                 }
207                 (void) munmap(buf, pref->pref_len);
208                 if (obj == NULL && error == 0)
209                         error = EIO;
210         }
211
212  out:
213         if (error == 0)
214                 *objp = obj;
215         return (error);
216 }
217
218 /*
219  * prop_array_internalize_from_pref --
220  *      Internalize a pref into a prop_array_t object.
221  */
222 bool
223 prop_array_internalize_from_pref(const struct plistref *prefp,
224                                  prop_array_t *arrayp)
225 {
226         int rv;
227
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);
233 }
234
235 /*
236  * prop_array_recv_syscall --
237  *      Internalize an array received from the kernel as pref.
238  */
239 int
240 prop_array_recv_syscall(const struct plistref *prefp,
241                         prop_array_t *arrayp)
242 {
243         if (prop_array_internalize_from_pref(prefp, arrayp))
244                 return 0;
245         else
246                 return errno;
247 }
248
249 /*
250  * prop_dictionary_internalize_from_pref --
251  *      Internalize a pref into a prop_dictionary_t object.
252  */
253 bool
254 prop_dictionary_internalize_from_pref(const struct plistref *prefp,
255                                       prop_dictionary_t *dictp)
256 {
257         int rv;
258
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);
264 }
265
266 /*
267  * prop_dictionary_recv_syscall --
268  *      Internalize a dictionary received from the kernel as pref.
269  */
270 int
271 prop_dictionary_recv_syscall(const struct plistref *prefp,
272                              prop_dictionary_t *dictp)
273 {
274         if (prop_dictionary_internalize_from_pref(prefp, dictp))
275                 return 0;
276         else
277                 return errno;
278 }
279
280
281 /*
282  * prop_array_recv_ioctl --
283  *      Receive an array from the kernel using the specified ioctl.
284  */
285 int
286 prop_array_recv_ioctl(int fd, unsigned long cmd, prop_array_t *arrayp)
287 {
288         int rv;
289         struct plistref pref;
290
291         rv = ioctl(fd, cmd, &pref);
292         if (rv == -1)
293                 return errno;
294
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;
302 }
303
304 /*
305  * prop_dictionary_recv_ioctl --
306  *      Receive a dictionary from the kernel using the specified ioctl.
307  */
308 int
309 prop_dictionary_recv_ioctl(int fd, unsigned long cmd, prop_dictionary_t *dictp)
310 {
311         int rv;
312         struct plistref pref;
313
314         rv = ioctl(fd, cmd, &pref);
315         if (rv == -1)
316                 return errno;
317
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;
325 }
326
327 /*
328  * prop_dictionary_sendrecv_ioctl --
329  *      Combination send/receive a dictionary to/from the kernel using
330  *      the specified ioctl.
331  */
332 int
333 prop_dictionary_sendrecv_ioctl(prop_dictionary_t dict, int fd,
334                                unsigned long cmd, prop_dictionary_t *dictp)
335 {
336         struct plistref pref;
337         char *buf;
338         int error;
339
340         error = _prop_object_externalize_to_pref(dict, &pref, &buf);
341         if (error != 0) {
342                 errno = error;
343                 return error;
344         }
345
346         if (ioctl(fd, cmd, &pref) == -1)
347                 error = errno;
348         else
349                 error = 0;
350         
351         free(buf);
352
353         if (error != 0)
354                 return error;
355
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;
363 }
364 #endif /* !_KERNEL && !_STANDALONE */
365
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>
379
380 #include "prop_object_impl.h"
381
382 /* Arbitrary limit ioctl input to 64KB */
383 unsigned int prop_object_copyin_limit = 65536;
384
385 static int
386 _prop_object_copyin(const struct plistref *pref, const prop_type_t type,
387                           prop_object_t *objp)
388 {
389         prop_object_t obj = NULL;
390         char *buf;
391         int error;
392
393         /*
394          * Allocate an extra byte so we can guarantee NUL-termination.
395          *
396          * Allow malloc to fail in case pmap would be exhausted.
397          */
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);
403         }
404         buf[pref->pref_len] = '\0';
405
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;
415         }
416
417         kfree(buf, M_TEMP);
418         if (obj == NULL) {
419                 if (error == 0)
420                         error = EIO;
421         } else {
422                 *objp = obj;
423         }
424         return (error);
425 }
426
427
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)
431 {
432         if ((cmd & IOC_IN) == 0)
433                 return (EFAULT);
434
435         return _prop_object_copyin(pref, type, objp);
436 }
437
438 /*
439  * prop_array_copyin --
440  *      Copy in an array passed as a syscall arg.
441  */
442 int
443 prop_array_copyin(const struct plistref *pref, prop_array_t *arrayp)
444 {
445         return (_prop_object_copyin(pref, PROP_TYPE_ARRAY,
446                                           (prop_object_t *)arrayp));
447 }
448
449 /*
450  * prop_dictionary_copyin --
451  *      Copy in a dictionary passed as a syscall arg.
452  */
453 int
454 prop_dictionary_copyin(const struct plistref *pref, prop_dictionary_t *dictp)
455 {
456         return (_prop_object_copyin(pref, PROP_TYPE_DICTIONARY,
457                                           (prop_object_t *)dictp));
458 }
459
460
461 /*
462  * prop_array_copyin_ioctl --
463  *      Copy in an array send with an ioctl.
464  */
465 int
466 prop_array_copyin_ioctl(const struct plistref *pref, const u_long cmd,
467                         prop_array_t *arrayp)
468 {
469         return (_prop_object_copyin_ioctl(pref, PROP_TYPE_ARRAY,
470                                           cmd, (prop_object_t *)arrayp));
471 }
472
473 /*
474  * prop_dictionary_copyin_ioctl --
475  *      Copy in a dictionary sent with an ioctl.
476  */
477 int
478 prop_dictionary_copyin_ioctl(const struct plistref *pref, const u_long cmd,
479                              prop_dictionary_t *dictp)
480 {
481         return (_prop_object_copyin_ioctl(pref, PROP_TYPE_DICTIONARY,
482                                           cmd, (prop_object_t *)dictp));
483 }
484
485 static int
486 _prop_object_copyout(struct plistref *pref, prop_object_t obj)
487 {
488         struct proc *p = curproc;
489         char *buf;
490         size_t len, rlen;
491         int error = 0;
492         vm_offset_t uaddr;
493
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);
503         }
504         if (buf == NULL)
505                 return (ENOMEM);
506
507         len = strlen(buf) + 1;
508         rlen = round_page(len);
509
510         /*
511          * See sys_mmap() in sys/uvm/uvm_mmap.c.
512          * Let's act as if we were calling mmap(0, ...)
513          */
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);
519
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;
531                 }
532         }
533
534         kfree(buf, M_TEMP);
535
536         return (error);
537 }
538
539 /*
540  * prop_array_copyout --
541  *      Copy out an array to a syscall arg.
542  */
543 int
544 prop_array_copyout(struct plistref *pref, prop_array_t array)
545 {
546         return (_prop_object_copyout(pref, array));
547 }
548
549 /*
550  * prop_dictionary_copyout --
551  *      Copy out a dictionary to a syscall arg.
552  */
553 int
554 prop_dictionary_copyout(struct plistref *pref, prop_dictionary_t dict)
555 {
556         return (_prop_object_copyout(pref, dict));
557 }
558
559 static int
560 _prop_object_copyout_ioctl(struct plistref *pref, const u_long cmd,
561                            prop_object_t obj)
562 {
563         if ((cmd & IOC_OUT) == 0)
564                 return (EFAULT);
565         return _prop_object_copyout(pref, obj);
566 }
567
568
569 /*
570  * prop_array_copyout_ioctl --
571  *      Copy out an array being received with an ioctl.
572  */
573 int
574 prop_array_copyout_ioctl(struct plistref *pref, const u_long cmd,
575                          prop_array_t array)
576 {
577         return (_prop_object_copyout_ioctl(pref, cmd, array));
578 }
579
580 /*
581  * prop_dictionary_copyout_ioctl --
582  *      Copy out a dictionary being received with an ioctl.
583  */
584 int
585 prop_dictionary_copyout_ioctl(struct plistref *pref, const u_long cmd,
586                               prop_dictionary_t dict)
587 {
588         return (
589             _prop_object_copyout_ioctl(pref, cmd, dict));
590 }
591 #endif /* _KERNEL */