kernel: Remove some unneeded NULL checks after kmalloc() with M_WAITOK.
[dragonfly.git] / sys / libprop / prop_kern.c
CommitLineData
d623d4f9 1/* $NetBSD: prop_kern.c,v 1.17 2011/09/30 22:08:18 jym Exp $ */
349fb218
AH
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
349fb218 32#include <sys/types.h>
349fb218 33
9f95f3e0 34#include <libprop/proplib.h>
349fb218
AH
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>
9f95f3e0 42#include <sys/ioctl.h>
349fb218
AH
43
44static int
d623d4f9
FT
45_prop_object_externalize_to_pref(prop_object_t obj, struct plistref *pref,
46 char **bufp)
349fb218
AH
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
349fb218
AH
72bool
73prop_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/*
d623d4f9
FT
85 * prop_array_externalize_to_pref --
86 * Externalize an array into a plistref for sending to the kernel.
349fb218 87 */
d623d4f9
FT
88int
89prop_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
349fb218 97bool
d623d4f9
FT
98prop_dictionary_externalize_to_pref(prop_dictionary_t dict,
99 struct plistref *prefp)
349fb218
AH
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}
d623d4f9
FT
109
110/*
111 * prop_dictionary_externalize_to_pref --
112 * Externalize an dictionary into a plistref for sending to the kernel.
113 */
114int
115prop_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}
349fb218
AH
123
124static 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;
4b4863a7 139
349fb218
AH
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 */
149int
150prop_array_send_ioctl(prop_array_t array, int fd, unsigned long cmd)
151{
d623d4f9 152 int rv;
349fb218 153
d623d4f9
FT
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;
349fb218
AH
160}
161
162/*
163 * prop_dictionary_send_ioctl --
164 * Send a dictionary to the kernel using the specified ioctl.
165 */
166int
167prop_dictionary_send_ioctl(prop_dictionary_t dict, int fd, unsigned long cmd)
168{
d623d4f9 169 int rv;
349fb218 170
d623d4f9
FT
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;
349fb218
AH
177}
178
179static int
d623d4f9
FT
180_prop_object_internalize_from_pref(const struct plistref *pref,
181 prop_type_t type, prop_object_t *objp)
349fb218
AH
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/*
d623d4f9
FT
219 * prop_array_internalize_from_pref --
220 * Internalize a pref into a prop_array_t object.
349fb218 221 */
d623d4f9
FT
222bool
223prop_array_internalize_from_pref(const struct plistref *prefp,
224 prop_array_t *arrayp)
349fb218 225{
d623d4f9 226 int rv;
349fb218 227
d623d4f9
FT
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);
349fb218
AH
233}
234
235/*
d623d4f9
FT
236 * prop_array_recv_syscall --
237 * Internalize an array received from the kernel as pref.
349fb218
AH
238 */
239int
d623d4f9
FT
240prop_array_recv_syscall(const struct plistref *prefp,
241 prop_array_t *arrayp)
349fb218 242{
d623d4f9
FT
243 if (prop_array_internalize_from_pref(prefp, arrayp))
244 return 0;
245 else
246 return errno;
349fb218
AH
247}
248
249/*
d623d4f9
FT
250 * prop_dictionary_internalize_from_pref --
251 * Internalize a pref into a prop_dictionary_t object.
4b4863a7
AH
252 */
253bool
d623d4f9
FT
254prop_dictionary_internalize_from_pref(const struct plistref *prefp,
255 prop_dictionary_t *dictp)
4b4863a7 256{
d623d4f9
FT
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);
4b4863a7
AH
264}
265
266/*
267 * prop_dictionary_recv_syscall --
d623d4f9 268 * Internalize a dictionary received from the kernel as pref.
4b4863a7 269 */
d623d4f9
FT
270int
271prop_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 */
285int
286prop_array_recv_ioctl(int fd, unsigned long cmd, prop_array_t *arrayp)
4b4863a7 287{
d623d4f9
FT
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 */
308int
309prop_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;
4b4863a7
AH
325}
326
327/*
349fb218
AH
328 * prop_dictionary_sendrecv_ioctl --
329 * Combination send/receive a dictionary to/from the kernel using
330 * the specified ioctl.
331 */
332int
333prop_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);
d623d4f9
FT
341 if (error != 0) {
342 errno = error;
343 return error;
344 }
349fb218
AH
345
346 if (ioctl(fd, cmd, &pref) == -1)
347 error = errno;
348 else
349 error = 0;
4b4863a7 350
349fb218
AH
351 free(buf);
352
d623d4f9
FT
353 if (error != 0)
354 return error;
349fb218 355
d623d4f9
FT
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;
349fb218
AH
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>
9f95f3e0
AH
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>
349fb218
AH
379
380#include "prop_object_impl.h"
381
382/* Arbitrary limit ioctl input to 64KB */
383unsigned int prop_object_copyin_limit = 65536;
384
349fb218
AH
385static 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 */
9f95f3e0 398 buf = kmalloc(pref->pref_len + 1, M_TEMP, M_WAITOK);
349fb218
AH
399 error = copyin(pref->pref_plist, buf, pref->pref_len);
400 if (error) {
9f95f3e0 401 kfree(buf, M_TEMP);
349fb218
AH
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
9f95f3e0 417 kfree(buf, M_TEMP);
349fb218
AH
418 if (obj == NULL) {
419 if (error == 0)
420 error = EIO;
421 } else {
422 *objp = obj;
423 }
424 return (error);
425}
426
427
428static 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 */
442int
443prop_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 */
453int
454prop_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 */
465int
466prop_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 */
477int
478prop_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
485static int
4b4863a7 486_prop_object_copyout(struct plistref *pref, prop_object_t obj)
349fb218 487{
9f95f3e0 488 struct proc *p = curproc;
349fb218
AH
489 char *buf;
490 size_t len, rlen;
491 int error = 0;
9f95f3e0 492 vm_offset_t uaddr;
349fb218 493
349fb218
AH
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 */
9f95f3e0 514#if 0
349fb218
AH
515 uaddr = p->p_emul->e_vm_default_addr(p,
516 (vaddr_t)p->p_vmspace->vm_daddr, rlen);
9f95f3e0
AH
517#endif
518 uaddr = round_page((vm_offset_t)p->p_vmspace->vm_daddr + maxdsiz);
349fb218 519
9f95f3e0 520 error = vm_mmap(&p->p_vmspace->vm_map,
349fb218
AH
521 &uaddr, rlen,
522 VM_PROT_READ|VM_PROT_WRITE,
523 VM_PROT_READ|VM_PROT_WRITE,
524 MAP_PRIVATE|MAP_ANON,
9f95f3e0 525 NULL, 0);
349fb218
AH
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
9f95f3e0 534 kfree(buf, M_TEMP);
349fb218
AH
535
536 return (error);
537}
538
539/*
4b4863a7
AH
540 * prop_array_copyout --
541 * Copy out an array to a syscall arg.
542 */
543int
544prop_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 */
553int
554prop_dictionary_copyout(struct plistref *pref, prop_dictionary_t dict)
555{
556 return (_prop_object_copyout(pref, dict));
557}
558
559static 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/*
349fb218
AH
570 * prop_array_copyout_ioctl --
571 * Copy out an array being received with an ioctl.
572 */
573int
574prop_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 */
584int
585prop_dictionary_copyout_ioctl(struct plistref *pref, const u_long cmd,
586 prop_dictionary_t dict)
587{
4b4863a7
AH
588 return (
589 _prop_object_copyout_ioctl(pref, cmd, dict));
349fb218
AH
590}
591#endif /* _KERNEL */