mdoc.local: Indent with spaces like everywhere else.
[dragonfly.git] / common / lib / libprop / prop_kern.c
1 /*      $NetBSD: prop_kern.c,v 1.13 2009/10/11 12:13:45 bad 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 #if defined(__NetBSD__)
33
34 #include <sys/types.h>
35 #include <sys/ioctl.h>
36
37 #include <prop/proplib.h>
38
39 #if !defined(_KERNEL) && !defined(_STANDALONE)
40 #include <sys/mman.h>
41 #include <errno.h>
42 #include <string.h>
43 #include <stdlib.h>
44 #include <stdio.h>
45
46 static int
47 _prop_object_externalize_to_pref(prop_object_t obj, struct plistref *pref, char **bufp)
48 {
49         char *buf;
50
51         switch (prop_object_type(obj)) {
52         case PROP_TYPE_DICTIONARY:
53                 buf = prop_dictionary_externalize(obj);
54                 break;
55         case PROP_TYPE_ARRAY:
56                 buf = prop_array_externalize(obj);
57                 break;
58         default:
59                 return (ENOTSUP);
60         }
61         if (buf == NULL) {
62                 /* Assume we ran out of memory. */
63                 return (ENOMEM);
64         }
65         pref->pref_plist = buf;
66         pref->pref_len = strlen(buf) + 1;
67
68         *bufp = buf;
69
70         return (0);
71 }
72
73 /*
74  * prop_array_externalize_to_pref --
75  *      Externalize an array into a plistref for sending to the kernel.
76  */
77 bool
78 prop_array_externalize_to_pref(prop_array_t array, struct plistref *prefp)
79 {
80         char *buf;
81         int rv;
82
83         rv = _prop_object_externalize_to_pref(array, prefp, &buf);
84         if (rv != 0)
85                 errno = rv;     /* pass up error value in errno */
86         return (rv == 0);
87 }
88
89 /*
90  * prop_dictionary_externalize_to_pref --
91  *      Externalize an dictionary into a plistref for sending to the kernel.
92  */
93 bool
94 prop_dictionary_externalize_to_pref(prop_dictionary_t dict, struct plistref *prefp)
95 {
96         char *buf;
97         int rv;
98
99         rv = _prop_object_externalize_to_pref(dict, prefp, &buf);
100         if (rv != 0)
101                 errno = rv;     /* pass up error value in errno */
102         return (rv == 0);
103 }
104
105 static int
106 _prop_object_send_ioctl(prop_object_t obj, int fd, unsigned long cmd)
107 {
108         struct plistref pref;
109         char *buf;
110         int error;
111
112         error = _prop_object_externalize_to_pref(obj, &pref, &buf);
113         if (error)
114                 return (error);
115
116         if (ioctl(fd, cmd, &pref) == -1)
117                 error = errno;
118         else
119                 error = 0;
120         
121         free(buf);
122
123         return (error);
124 }
125
126 /*
127  * prop_array_send_ioctl --
128  *      Send an array to the kernel using the specified ioctl.
129  */
130 int
131 prop_array_send_ioctl(prop_array_t array, int fd, unsigned long cmd)
132 {
133
134         return (_prop_object_send_ioctl(array, fd, cmd));
135 }
136
137 /*
138  * prop_dictionary_send_ioctl --
139  *      Send a dictionary to the kernel using the specified ioctl.
140  */
141 int
142 prop_dictionary_send_ioctl(prop_dictionary_t dict, int fd, unsigned long cmd)
143 {
144
145         return (_prop_object_send_ioctl(dict, fd, cmd));
146 }
147
148 static int
149 _prop_object_internalize_from_pref(const struct plistref *pref, prop_type_t type,
150                          prop_object_t *objp)
151 {
152         prop_object_t obj = NULL;
153         char *buf;
154         int error = 0;
155
156         if (pref->pref_len == 0) {
157                 /*
158                  * This should never happen; we should always get the XML
159                  * for an empty dictionary if it's really empty.
160                  */
161                 error = EIO;
162                 goto out;
163         } else {
164                 buf = pref->pref_plist;
165                 buf[pref->pref_len - 1] = '\0'; /* extra insurance */
166                 switch (type) {
167                 case PROP_TYPE_DICTIONARY:
168                         obj = prop_dictionary_internalize(buf);
169                         break;
170                 case PROP_TYPE_ARRAY:
171                         obj = prop_array_internalize(buf);
172                         break;
173                 default:
174                         error = ENOTSUP;
175                 }
176                 (void) munmap(buf, pref->pref_len);
177                 if (obj == NULL && error == 0)
178                         error = EIO;
179         }
180
181  out:
182         if (error == 0)
183                 *objp = obj;
184         return (error);
185 }
186
187 /*
188  * prop_array_recv_ioctl --
189  *      Receive an array from the kernel using the specified ioctl.
190  */
191 int
192 prop_array_recv_ioctl(int fd, unsigned long cmd, prop_array_t *arrayp)
193 {
194         struct plistref pref;
195
196         if (ioctl(fd, cmd, &pref) == -1)
197                 return (errno);
198         
199         return (_prop_object_internalize_from_pref(&pref, PROP_TYPE_ARRAY,
200                                          (prop_object_t *)arrayp));
201 }
202
203 /*
204  * prop_dictionary_recv_ioctl --
205  *      Receive a dictionary from the kernel using the specified ioctl.
206  */
207 int
208 prop_dictionary_recv_ioctl(int fd, unsigned long cmd, prop_dictionary_t *dictp)
209 {
210         struct plistref pref;
211
212         if (ioctl(fd, cmd, &pref) == -1)
213                 return (errno);
214
215         return (_prop_object_internalize_from_pref(&pref, PROP_TYPE_DICTIONARY,
216                                          (prop_object_t *)dictp));
217 }
218
219 /*
220  * prop_dictionary_sendrecv_ioctl --
221  *      Combination send/receive a dictionary to/from the kernel using
222  *      the specified ioctl.
223  */
224 int
225 prop_dictionary_sendrecv_ioctl(prop_dictionary_t dict, int fd,
226                                unsigned long cmd, prop_dictionary_t *dictp)
227 {
228         struct plistref pref;
229         char *buf;
230         int error;
231
232         error = _prop_object_externalize_to_pref(dict, &pref, &buf);
233         if (error)
234                 return (error);
235
236         if (ioctl(fd, cmd, &pref) == -1)
237                 error = errno;
238         else
239                 error = 0;
240         
241         free(buf);
242
243         if (error)
244                 return (error);
245
246         return (_prop_object_internalize_from_pref(&pref, PROP_TYPE_DICTIONARY,
247                             (prop_object_t *)dictp));
248 }
249 #endif /* !_KERNEL && !_STANDALONE */
250
251 #if defined(_KERNEL)
252 #include <sys/param.h>
253 #include <sys/mman.h>
254 #include <sys/errno.h>
255 #include <sys/malloc.h>
256 #include <sys/systm.h>
257 #include <sys/proc.h>
258 #include <sys/resource.h>
259 #include <sys/pool.h>
260
261 #include <uvm/uvm.h>
262
263 #include "prop_object_impl.h"
264
265 /* Arbitrary limit ioctl input to 64KB */
266 unsigned int prop_object_copyin_limit = 65536;
267
268 /* initialize proplib for use in the kernel */
269 void
270 prop_kern_init(void)
271 {
272         __link_set_decl(prop_linkpools, struct prop_pool_init);
273         struct prop_pool_init * const *pi;
274
275         __link_set_foreach(pi, prop_linkpools)
276                 pool_init((*pi)->pp, (*pi)->size, 0, 0, 0, (*pi)->wchan,
277                     &pool_allocator_nointr, IPL_NONE);
278 }
279
280 static int
281 _prop_object_copyin(const struct plistref *pref, const prop_type_t type,
282                           prop_object_t *objp)
283 {
284         prop_object_t obj = NULL;
285         char *buf;
286         int error;
287
288         /*
289          * Allocate an extra byte so we can guarantee NUL-termination.
290          *
291          * Allow malloc to fail in case pmap would be exhausted.
292          */
293         buf = malloc(pref->pref_len + 1, M_TEMP, M_WAITOK | M_CANFAIL);
294         if (buf == NULL)
295                 return (ENOMEM);
296         error = copyin(pref->pref_plist, buf, pref->pref_len);
297         if (error) {
298                 free(buf, M_TEMP);
299                 return (error);
300         }
301         buf[pref->pref_len] = '\0';
302
303         switch (type) {
304         case PROP_TYPE_ARRAY:
305                 obj = prop_array_internalize(buf);
306                 break;
307         case PROP_TYPE_DICTIONARY:
308                 obj = prop_dictionary_internalize(buf);
309                 break;
310         default:
311                 error = ENOTSUP;
312         }
313
314         free(buf, M_TEMP);
315         if (obj == NULL) {
316                 if (error == 0)
317                         error = EIO;
318         } else {
319                 *objp = obj;
320         }
321         return (error);
322 }
323
324
325 static int
326 _prop_object_copyin_ioctl(const struct plistref *pref, const prop_type_t type,
327                           const u_long cmd, prop_object_t *objp)
328 {
329         if ((cmd & IOC_IN) == 0)
330                 return (EFAULT);
331
332         return _prop_object_copyin(pref, type, objp);
333 }
334
335 /*
336  * prop_array_copyin --
337  *      Copy in an array passed as a syscall arg.
338  */
339 int
340 prop_array_copyin(const struct plistref *pref, prop_array_t *arrayp)
341 {
342         return (_prop_object_copyin(pref, PROP_TYPE_ARRAY,
343                                           (prop_object_t *)arrayp));
344 }
345
346 /*
347  * prop_dictionary_copyin --
348  *      Copy in a dictionary passed as a syscall arg.
349  */
350 int
351 prop_dictionary_copyin(const struct plistref *pref, prop_dictionary_t *dictp)
352 {
353         return (_prop_object_copyin(pref, PROP_TYPE_DICTIONARY,
354                                           (prop_object_t *)dictp));
355 }
356
357
358 /*
359  * prop_array_copyin_ioctl --
360  *      Copy in an array send with an ioctl.
361  */
362 int
363 prop_array_copyin_ioctl(const struct plistref *pref, const u_long cmd,
364                         prop_array_t *arrayp)
365 {
366         return (_prop_object_copyin_ioctl(pref, PROP_TYPE_ARRAY,
367                                           cmd, (prop_object_t *)arrayp));
368 }
369
370 /*
371  * prop_dictionary_copyin_ioctl --
372  *      Copy in a dictionary sent with an ioctl.
373  */
374 int
375 prop_dictionary_copyin_ioctl(const struct plistref *pref, const u_long cmd,
376                              prop_dictionary_t *dictp)
377 {
378         return (_prop_object_copyin_ioctl(pref, PROP_TYPE_DICTIONARY,
379                                           cmd, (prop_object_t *)dictp));
380 }
381
382 static int
383 _prop_object_copyout_ioctl(struct plistref *pref, const u_long cmd,
384                            prop_object_t obj)
385 {
386         struct lwp *l = curlwp;         /* XXX */
387         struct proc *p = l->l_proc;
388         char *buf;
389         size_t len, rlen;
390         int error = 0;
391         vaddr_t uaddr;
392
393         if ((cmd & IOC_OUT) == 0)
394                 return (EFAULT);
395
396         switch (prop_object_type(obj)) {
397         case PROP_TYPE_ARRAY:
398                 buf = prop_array_externalize(obj);
399                 break;
400         case PROP_TYPE_DICTIONARY:
401                 buf = prop_dictionary_externalize(obj);
402                 break;
403         default:
404                 return (ENOTSUP);
405         }
406         if (buf == NULL)
407                 return (ENOMEM);
408
409         len = strlen(buf) + 1;
410         rlen = round_page(len);
411
412         /*
413          * See sys_mmap() in sys/uvm/uvm_mmap.c.
414          * Let's act as if we were calling mmap(0, ...)
415          */
416         uaddr = p->p_emul->e_vm_default_addr(p,
417             (vaddr_t)p->p_vmspace->vm_daddr, rlen);
418
419         error = uvm_mmap(&p->p_vmspace->vm_map,
420                          &uaddr, rlen,
421                          VM_PROT_READ|VM_PROT_WRITE,
422                          VM_PROT_READ|VM_PROT_WRITE,
423                          MAP_PRIVATE|MAP_ANON,
424                          NULL, 0,
425                          p->p_rlimit[RLIMIT_MEMLOCK].rlim_cur);
426         
427         if (error == 0) {
428                 error = copyout(buf, (char *)uaddr, len);
429                 if (error == 0) {
430                         pref->pref_plist = (char *)uaddr;
431                         pref->pref_len   = len;
432                 }
433         }
434
435         free(buf, M_TEMP);
436
437         return (error);
438 }
439
440 /*
441  * prop_array_copyout_ioctl --
442  *      Copy out an array being received with an ioctl.
443  */
444 int
445 prop_array_copyout_ioctl(struct plistref *pref, const u_long cmd,
446                          prop_array_t array)
447 {
448         return (_prop_object_copyout_ioctl(pref, cmd, array));
449 }
450
451 /*
452  * prop_dictionary_copyout_ioctl --
453  *      Copy out a dictionary being received with an ioctl.
454  */
455 int
456 prop_dictionary_copyout_ioctl(struct plistref *pref, const u_long cmd,
457                               prop_dictionary_t dict)
458 {
459         return (_prop_object_copyout_ioctl(pref, cmd, dict));
460 }
461 #endif /* _KERNEL */
462
463 #endif /* __NetBSD__ */