Add ELFOSABI_ARM_AEABI ELF OSABI constant
[freebsd-src.git] / sbin / hastd / nv.c
blobfefc2dfbdf841e0562a32709e0e06cef2786bf73
1 /*-
2 * Copyright (c) 2009-2010 The FreeBSD Foundation
3 * All rights reserved.
5 * This software was developed by Pawel Jakub Dawidek under sponsorship from
6 * the FreeBSD Foundation.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
33 #include <sys/param.h>
34 #include <sys/endian.h>
36 #include <bitstring.h>
37 #include <errno.h>
38 #include <stdarg.h>
39 #include <stdbool.h>
40 #include <stdint.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include <unistd.h>
45 #include <ebuf.h>
46 #include <pjdlog.h>
48 #include "nv.h"
50 #ifndef PJDLOG_ASSERT
51 #include <assert.h>
52 #define PJDLOG_ASSERT(...) assert(__VA_ARGS__)
53 #endif
54 #ifndef PJDLOG_ABORT
55 #define PJDLOG_ABORT(...) abort()
56 #endif
58 #define NV_TYPE_NONE 0
60 #define NV_TYPE_INT8 1
61 #define NV_TYPE_UINT8 2
62 #define NV_TYPE_INT16 3
63 #define NV_TYPE_UINT16 4
64 #define NV_TYPE_INT32 5
65 #define NV_TYPE_UINT32 6
66 #define NV_TYPE_INT64 7
67 #define NV_TYPE_UINT64 8
68 #define NV_TYPE_INT8_ARRAY 9
69 #define NV_TYPE_UINT8_ARRAY 10
70 #define NV_TYPE_INT16_ARRAY 11
71 #define NV_TYPE_UINT16_ARRAY 12
72 #define NV_TYPE_INT32_ARRAY 13
73 #define NV_TYPE_UINT32_ARRAY 14
74 #define NV_TYPE_INT64_ARRAY 15
75 #define NV_TYPE_UINT64_ARRAY 16
76 #define NV_TYPE_STRING 17
78 #define NV_TYPE_MASK 0x7f
79 #define NV_TYPE_FIRST NV_TYPE_INT8
80 #define NV_TYPE_LAST NV_TYPE_STRING
82 #define NV_ORDER_NETWORK 0x00
83 #define NV_ORDER_HOST 0x80
85 #define NV_ORDER_MASK 0x80
87 #define NV_MAGIC 0xaea1e
88 struct nv {
89 int nv_magic;
90 int nv_error;
91 struct ebuf *nv_ebuf;
94 struct nvhdr {
95 uint8_t nvh_type;
96 uint8_t nvh_namesize;
97 uint32_t nvh_dsize;
98 char nvh_name[0];
99 } __packed;
100 #define NVH_DATA(nvh) ((unsigned char *)nvh + NVH_HSIZE(nvh))
101 #define NVH_HSIZE(nvh) \
102 (sizeof(struct nvhdr) + roundup2((nvh)->nvh_namesize, 8))
103 #define NVH_DSIZE(nvh) \
104 (((nvh)->nvh_type & NV_ORDER_MASK) == NV_ORDER_HOST ? \
105 (nvh)->nvh_dsize : \
106 le32toh((nvh)->nvh_dsize))
107 #define NVH_SIZE(nvh) (NVH_HSIZE(nvh) + roundup2(NVH_DSIZE(nvh), 8))
109 #define NV_CHECK(nv) do { \
110 PJDLOG_ASSERT((nv) != NULL); \
111 PJDLOG_ASSERT((nv)->nv_magic == NV_MAGIC); \
112 } while (0)
114 static void nv_add(struct nv *nv, const unsigned char *value, size_t vsize,
115 int type, const char *name);
116 static void nv_addv(struct nv *nv, const unsigned char *value, size_t vsize,
117 int type, const char *namefmt, va_list nameap);
118 static struct nvhdr *nv_find(struct nv *nv, int type, const char *namefmt,
119 va_list nameap);
120 static void nv_swap(struct nvhdr *nvh, bool tohost);
123 * Allocate and initialize new nv structure.
124 * Return NULL in case of malloc(3) failure.
126 struct nv *
127 nv_alloc(void)
129 struct nv *nv;
131 nv = malloc(sizeof(*nv));
132 if (nv == NULL)
133 return (NULL);
134 nv->nv_ebuf = ebuf_alloc(0);
135 if (nv->nv_ebuf == NULL) {
136 free(nv);
137 return (NULL);
139 nv->nv_error = 0;
140 nv->nv_magic = NV_MAGIC;
141 return (nv);
145 * Free the given nv structure.
147 void
148 nv_free(struct nv *nv)
151 if (nv == NULL)
152 return;
154 NV_CHECK(nv);
156 nv->nv_magic = 0;
157 ebuf_free(nv->nv_ebuf);
158 free(nv);
162 * Return error for the given nv structure.
165 nv_error(const struct nv *nv)
168 if (nv == NULL)
169 return (ENOMEM);
171 NV_CHECK(nv);
173 return (nv->nv_error);
177 * Set error for the given nv structure and return previous error.
180 nv_set_error(struct nv *nv, int error)
182 int preverr;
184 if (nv == NULL)
185 return (ENOMEM);
187 NV_CHECK(nv);
189 preverr = nv->nv_error;
190 nv->nv_error = error;
191 return (preverr);
195 * Validate correctness of the entire nv structure and all its elements.
196 * If extrap is not NULL, store number of extra bytes at the end of the buffer.
199 nv_validate(struct nv *nv, size_t *extrap)
201 struct nvhdr *nvh;
202 unsigned char *data, *ptr;
203 size_t dsize, size, vsize;
204 int error;
206 if (nv == NULL) {
207 errno = ENOMEM;
208 return (-1);
211 NV_CHECK(nv);
212 PJDLOG_ASSERT(nv->nv_error == 0);
214 /* TODO: Check that names are unique? */
216 error = 0;
217 ptr = ebuf_data(nv->nv_ebuf, &size);
218 while (size > 0) {
220 * Zeros at the end of the buffer are acceptable.
222 if (ptr[0] == '\0')
223 break;
225 * Minimum size at this point is size of nvhdr structure, one
226 * character long name plus terminating '\0'.
228 if (size < sizeof(*nvh) + 2) {
229 error = EINVAL;
230 break;
232 nvh = (struct nvhdr *)ptr;
233 if (size < NVH_HSIZE(nvh)) {
234 error = EINVAL;
235 break;
237 if (nvh->nvh_name[nvh->nvh_namesize - 1] != '\0') {
238 error = EINVAL;
239 break;
241 if (strlen(nvh->nvh_name) !=
242 (size_t)(nvh->nvh_namesize - 1)) {
243 error = EINVAL;
244 break;
246 if ((nvh->nvh_type & NV_TYPE_MASK) < NV_TYPE_FIRST ||
247 (nvh->nvh_type & NV_TYPE_MASK) > NV_TYPE_LAST) {
248 error = EINVAL;
249 break;
251 dsize = NVH_DSIZE(nvh);
252 if (dsize == 0) {
253 error = EINVAL;
254 break;
256 if (size < NVH_SIZE(nvh)) {
257 error = EINVAL;
258 break;
260 vsize = 0;
261 switch (nvh->nvh_type & NV_TYPE_MASK) {
262 case NV_TYPE_INT8:
263 case NV_TYPE_UINT8:
264 if (vsize == 0)
265 vsize = 1;
266 /* FALLTHROUGH */
267 case NV_TYPE_INT16:
268 case NV_TYPE_UINT16:
269 if (vsize == 0)
270 vsize = 2;
271 /* FALLTHROUGH */
272 case NV_TYPE_INT32:
273 case NV_TYPE_UINT32:
274 if (vsize == 0)
275 vsize = 4;
276 /* FALLTHROUGH */
277 case NV_TYPE_INT64:
278 case NV_TYPE_UINT64:
279 if (vsize == 0)
280 vsize = 8;
281 if (dsize != vsize) {
282 error = EINVAL;
283 break;
285 break;
286 case NV_TYPE_INT8_ARRAY:
287 case NV_TYPE_UINT8_ARRAY:
288 break;
289 case NV_TYPE_INT16_ARRAY:
290 case NV_TYPE_UINT16_ARRAY:
291 if (vsize == 0)
292 vsize = 2;
293 /* FALLTHROUGH */
294 case NV_TYPE_INT32_ARRAY:
295 case NV_TYPE_UINT32_ARRAY:
296 if (vsize == 0)
297 vsize = 4;
298 /* FALLTHROUGH */
299 case NV_TYPE_INT64_ARRAY:
300 case NV_TYPE_UINT64_ARRAY:
301 if (vsize == 0)
302 vsize = 8;
303 if ((dsize % vsize) != 0) {
304 error = EINVAL;
305 break;
307 break;
308 case NV_TYPE_STRING:
309 data = NVH_DATA(nvh);
310 if (data[dsize - 1] != '\0') {
311 error = EINVAL;
312 break;
314 if (strlen((char *)data) != dsize - 1) {
315 error = EINVAL;
316 break;
318 break;
319 default:
320 PJDLOG_ABORT("invalid condition");
322 if (error != 0)
323 break;
324 ptr += NVH_SIZE(nvh);
325 size -= NVH_SIZE(nvh);
327 if (error != 0) {
328 errno = error;
329 if (nv->nv_error == 0)
330 nv->nv_error = error;
331 return (-1);
333 if (extrap != NULL)
334 *extrap = size;
335 return (0);
339 * Convert the given nv structure to network byte order and return ebuf
340 * structure.
342 struct ebuf *
343 nv_hton(struct nv *nv)
345 struct nvhdr *nvh;
346 unsigned char *ptr;
347 size_t size;
349 NV_CHECK(nv);
350 PJDLOG_ASSERT(nv->nv_error == 0);
352 ptr = ebuf_data(nv->nv_ebuf, &size);
353 while (size > 0) {
355 * Minimum size at this point is size of nvhdr structure,
356 * one character long name plus terminating '\0'.
358 PJDLOG_ASSERT(size >= sizeof(*nvh) + 2);
359 nvh = (struct nvhdr *)ptr;
360 PJDLOG_ASSERT(NVH_SIZE(nvh) <= size);
361 nv_swap(nvh, false);
362 ptr += NVH_SIZE(nvh);
363 size -= NVH_SIZE(nvh);
366 return (nv->nv_ebuf);
370 * Create nv structure based on ebuf received from the network.
372 struct nv *
373 nv_ntoh(struct ebuf *eb)
375 struct nv *nv;
376 size_t extra;
377 int rerrno;
379 PJDLOG_ASSERT(eb != NULL);
381 nv = malloc(sizeof(*nv));
382 if (nv == NULL)
383 return (NULL);
384 nv->nv_error = 0;
385 nv->nv_ebuf = eb;
386 nv->nv_magic = NV_MAGIC;
388 if (nv_validate(nv, &extra) == -1) {
389 rerrno = errno;
390 nv->nv_magic = 0;
391 free(nv);
392 errno = rerrno;
393 return (NULL);
396 * Remove extra zeros at the end of the buffer.
398 ebuf_del_tail(eb, extra);
400 return (nv);
403 #define NV_DEFINE_ADD(type, TYPE) \
404 void \
405 nv_add_##type(struct nv *nv, type##_t value, const char *namefmt, ...) \
407 va_list nameap; \
409 va_start(nameap, namefmt); \
410 nv_addv(nv, (unsigned char *)&value, sizeof(value), \
411 NV_TYPE_##TYPE, namefmt, nameap); \
412 va_end(nameap); \
415 NV_DEFINE_ADD(int8, INT8)
416 NV_DEFINE_ADD(uint8, UINT8)
417 NV_DEFINE_ADD(int16, INT16)
418 NV_DEFINE_ADD(uint16, UINT16)
419 NV_DEFINE_ADD(int32, INT32)
420 NV_DEFINE_ADD(uint32, UINT32)
421 NV_DEFINE_ADD(int64, INT64)
422 NV_DEFINE_ADD(uint64, UINT64)
424 #undef NV_DEFINE_ADD
426 #define NV_DEFINE_ADD_ARRAY(type, TYPE) \
427 void \
428 nv_add_##type##_array(struct nv *nv, const type##_t *value, \
429 size_t nsize, const char *namefmt, ...) \
431 va_list nameap; \
433 va_start(nameap, namefmt); \
434 nv_addv(nv, (const unsigned char *)value, \
435 sizeof(value[0]) * nsize, NV_TYPE_##TYPE##_ARRAY, namefmt, \
436 nameap); \
437 va_end(nameap); \
440 NV_DEFINE_ADD_ARRAY(int8, INT8)
441 NV_DEFINE_ADD_ARRAY(uint8, UINT8)
442 NV_DEFINE_ADD_ARRAY(int16, INT16)
443 NV_DEFINE_ADD_ARRAY(uint16, UINT16)
444 NV_DEFINE_ADD_ARRAY(int32, INT32)
445 NV_DEFINE_ADD_ARRAY(uint32, UINT32)
446 NV_DEFINE_ADD_ARRAY(int64, INT64)
447 NV_DEFINE_ADD_ARRAY(uint64, UINT64)
449 #undef NV_DEFINE_ADD_ARRAY
451 void
452 nv_add_string(struct nv *nv, const char *value, const char *namefmt, ...)
454 va_list nameap;
455 size_t size;
457 size = strlen(value) + 1;
459 va_start(nameap, namefmt);
460 nv_addv(nv, (const unsigned char *)value, size, NV_TYPE_STRING,
461 namefmt, nameap);
462 va_end(nameap);
465 void
466 nv_add_stringf(struct nv *nv, const char *name, const char *valuefmt, ...)
468 va_list valueap;
470 va_start(valueap, valuefmt);
471 nv_add_stringv(nv, name, valuefmt, valueap);
472 va_end(valueap);
475 void
476 nv_add_stringv(struct nv *nv, const char *name, const char *valuefmt,
477 va_list valueap)
479 char *value;
480 ssize_t size;
482 size = vasprintf(&value, valuefmt, valueap);
483 if (size == -1) {
484 if (nv->nv_error == 0)
485 nv->nv_error = ENOMEM;
486 return;
488 size++;
489 nv_add(nv, (const unsigned char *)value, size, NV_TYPE_STRING, name);
490 free(value);
493 #define NV_DEFINE_GET(type, TYPE) \
494 type##_t \
495 nv_get_##type(struct nv *nv, const char *namefmt, ...) \
497 struct nvhdr *nvh; \
498 va_list nameap; \
499 type##_t value; \
501 va_start(nameap, namefmt); \
502 nvh = nv_find(nv, NV_TYPE_##TYPE, namefmt, nameap); \
503 va_end(nameap); \
504 if (nvh == NULL) \
505 return (0); \
506 PJDLOG_ASSERT((nvh->nvh_type & NV_ORDER_MASK) == NV_ORDER_HOST);\
507 PJDLOG_ASSERT(sizeof(value) == nvh->nvh_dsize); \
508 bcopy(NVH_DATA(nvh), &value, sizeof(value)); \
510 return (value); \
513 NV_DEFINE_GET(int8, INT8)
514 NV_DEFINE_GET(uint8, UINT8)
515 NV_DEFINE_GET(int16, INT16)
516 NV_DEFINE_GET(uint16, UINT16)
517 NV_DEFINE_GET(int32, INT32)
518 NV_DEFINE_GET(uint32, UINT32)
519 NV_DEFINE_GET(int64, INT64)
520 NV_DEFINE_GET(uint64, UINT64)
522 #undef NV_DEFINE_GET
524 #define NV_DEFINE_GET_ARRAY(type, TYPE) \
525 const type##_t * \
526 nv_get_##type##_array(struct nv *nv, size_t *sizep, \
527 const char *namefmt, ...) \
529 struct nvhdr *nvh; \
530 va_list nameap; \
532 va_start(nameap, namefmt); \
533 nvh = nv_find(nv, NV_TYPE_##TYPE##_ARRAY, namefmt, nameap); \
534 va_end(nameap); \
535 if (nvh == NULL) \
536 return (NULL); \
537 PJDLOG_ASSERT((nvh->nvh_type & NV_ORDER_MASK) == NV_ORDER_HOST);\
538 PJDLOG_ASSERT((nvh->nvh_dsize % sizeof(type##_t)) == 0); \
539 if (sizep != NULL) \
540 *sizep = nvh->nvh_dsize / sizeof(type##_t); \
541 return ((type##_t *)(void *)NVH_DATA(nvh)); \
544 NV_DEFINE_GET_ARRAY(int8, INT8)
545 NV_DEFINE_GET_ARRAY(uint8, UINT8)
546 NV_DEFINE_GET_ARRAY(int16, INT16)
547 NV_DEFINE_GET_ARRAY(uint16, UINT16)
548 NV_DEFINE_GET_ARRAY(int32, INT32)
549 NV_DEFINE_GET_ARRAY(uint32, UINT32)
550 NV_DEFINE_GET_ARRAY(int64, INT64)
551 NV_DEFINE_GET_ARRAY(uint64, UINT64)
553 #undef NV_DEFINE_GET_ARRAY
555 const char *
556 nv_get_string(struct nv *nv, const char *namefmt, ...)
558 struct nvhdr *nvh;
559 va_list nameap;
560 char *str;
562 va_start(nameap, namefmt);
563 nvh = nv_find(nv, NV_TYPE_STRING, namefmt, nameap);
564 va_end(nameap);
565 if (nvh == NULL)
566 return (NULL);
567 PJDLOG_ASSERT((nvh->nvh_type & NV_ORDER_MASK) == NV_ORDER_HOST);
568 PJDLOG_ASSERT(nvh->nvh_dsize >= 1);
569 str = (char *)NVH_DATA(nvh);
570 PJDLOG_ASSERT(str[nvh->nvh_dsize - 1] == '\0');
571 PJDLOG_ASSERT(strlen(str) == nvh->nvh_dsize - 1);
572 return (str);
575 static bool
576 nv_vexists(struct nv *nv, const char *namefmt, va_list nameap)
578 struct nvhdr *nvh;
579 int snverror, serrno;
581 if (nv == NULL)
582 return (false);
584 serrno = errno;
585 snverror = nv->nv_error;
587 nvh = nv_find(nv, NV_TYPE_NONE, namefmt, nameap);
589 errno = serrno;
590 nv->nv_error = snverror;
592 return (nvh != NULL);
595 bool
596 nv_exists(struct nv *nv, const char *namefmt, ...)
598 va_list nameap;
599 bool ret;
601 va_start(nameap, namefmt);
602 ret = nv_vexists(nv, namefmt, nameap);
603 va_end(nameap);
605 return (ret);
608 void
609 nv_assert(struct nv *nv, const char *namefmt, ...)
611 va_list nameap;
613 va_start(nameap, namefmt);
614 PJDLOG_ASSERT(nv_vexists(nv, namefmt, nameap));
615 va_end(nameap);
619 * Dump content of the nv structure.
621 void
622 nv_dump(struct nv *nv)
624 struct nvhdr *nvh;
625 unsigned char *data, *ptr;
626 size_t dsize, size;
627 unsigned int ii;
628 bool swap;
630 if (nv_validate(nv, NULL) == -1) {
631 printf("error: %d\n", errno);
632 return;
635 NV_CHECK(nv);
636 PJDLOG_ASSERT(nv->nv_error == 0);
638 ptr = ebuf_data(nv->nv_ebuf, &size);
639 while (size > 0) {
640 PJDLOG_ASSERT(size >= sizeof(*nvh) + 2);
641 nvh = (struct nvhdr *)ptr;
642 PJDLOG_ASSERT(size >= NVH_SIZE(nvh));
643 swap = ((nvh->nvh_type & NV_ORDER_MASK) == NV_ORDER_NETWORK);
644 dsize = NVH_DSIZE(nvh);
645 data = NVH_DATA(nvh);
646 printf(" %s", nvh->nvh_name);
647 switch (nvh->nvh_type & NV_TYPE_MASK) {
648 case NV_TYPE_INT8:
649 printf("(int8): %jd", (intmax_t)(*(int8_t *)data));
650 break;
651 case NV_TYPE_UINT8:
652 printf("(uint8): %ju", (uintmax_t)(*(uint8_t *)data));
653 break;
654 case NV_TYPE_INT16:
655 printf("(int16): %jd", swap ?
656 (intmax_t)le16toh(*(int16_t *)(void *)data) :
657 (intmax_t)*(int16_t *)(void *)data);
658 break;
659 case NV_TYPE_UINT16:
660 printf("(uint16): %ju", swap ?
661 (uintmax_t)le16toh(*(uint16_t *)(void *)data) :
662 (uintmax_t)*(uint16_t *)(void *)data);
663 break;
664 case NV_TYPE_INT32:
665 printf("(int32): %jd", swap ?
666 (intmax_t)le32toh(*(int32_t *)(void *)data) :
667 (intmax_t)*(int32_t *)(void *)data);
668 break;
669 case NV_TYPE_UINT32:
670 printf("(uint32): %ju", swap ?
671 (uintmax_t)le32toh(*(uint32_t *)(void *)data) :
672 (uintmax_t)*(uint32_t *)(void *)data);
673 break;
674 case NV_TYPE_INT64:
675 printf("(int64): %jd", swap ?
676 (intmax_t)le64toh(*(int64_t *)(void *)data) :
677 (intmax_t)*(int64_t *)(void *)data);
678 break;
679 case NV_TYPE_UINT64:
680 printf("(uint64): %ju", swap ?
681 (uintmax_t)le64toh(*(uint64_t *)(void *)data) :
682 (uintmax_t)*(uint64_t *)(void *)data);
683 break;
684 case NV_TYPE_INT8_ARRAY:
685 printf("(int8 array):");
686 for (ii = 0; ii < dsize; ii++)
687 printf(" %jd", (intmax_t)((int8_t *)data)[ii]);
688 break;
689 case NV_TYPE_UINT8_ARRAY:
690 printf("(uint8 array):");
691 for (ii = 0; ii < dsize; ii++)
692 printf(" %ju", (uintmax_t)((uint8_t *)data)[ii]);
693 break;
694 case NV_TYPE_INT16_ARRAY:
695 printf("(int16 array):");
696 for (ii = 0; ii < dsize / 2; ii++) {
697 printf(" %jd", swap ?
698 (intmax_t)le16toh(((int16_t *)(void *)data)[ii]) :
699 (intmax_t)((int16_t *)(void *)data)[ii]);
701 break;
702 case NV_TYPE_UINT16_ARRAY:
703 printf("(uint16 array):");
704 for (ii = 0; ii < dsize / 2; ii++) {
705 printf(" %ju", swap ?
706 (uintmax_t)le16toh(((uint16_t *)(void *)data)[ii]) :
707 (uintmax_t)((uint16_t *)(void *)data)[ii]);
709 break;
710 case NV_TYPE_INT32_ARRAY:
711 printf("(int32 array):");
712 for (ii = 0; ii < dsize / 4; ii++) {
713 printf(" %jd", swap ?
714 (intmax_t)le32toh(((int32_t *)(void *)data)[ii]) :
715 (intmax_t)((int32_t *)(void *)data)[ii]);
717 break;
718 case NV_TYPE_UINT32_ARRAY:
719 printf("(uint32 array):");
720 for (ii = 0; ii < dsize / 4; ii++) {
721 printf(" %ju", swap ?
722 (uintmax_t)le32toh(((uint32_t *)(void *)data)[ii]) :
723 (uintmax_t)((uint32_t *)(void *)data)[ii]);
725 break;
726 case NV_TYPE_INT64_ARRAY:
727 printf("(int64 array):");
728 for (ii = 0; ii < dsize / 8; ii++) {
729 printf(" %ju", swap ?
730 (uintmax_t)le64toh(((uint64_t *)(void *)data)[ii]) :
731 (uintmax_t)((uint64_t *)(void *)data)[ii]);
733 break;
734 case NV_TYPE_UINT64_ARRAY:
735 printf("(uint64 array):");
736 for (ii = 0; ii < dsize / 8; ii++) {
737 printf(" %ju", swap ?
738 (uintmax_t)le64toh(((uint64_t *)(void *)data)[ii]) :
739 (uintmax_t)((uint64_t *)(void *)data)[ii]);
741 break;
742 case NV_TYPE_STRING:
743 printf("(string): %s", (char *)data);
744 break;
745 default:
746 PJDLOG_ABORT("invalid condition");
748 printf("\n");
749 ptr += NVH_SIZE(nvh);
750 size -= NVH_SIZE(nvh);
755 * Local routines below.
758 static void
759 nv_add(struct nv *nv, const unsigned char *value, size_t vsize, int type,
760 const char *name)
762 static unsigned char align[7];
763 struct nvhdr *nvh;
764 size_t namesize;
766 if (nv == NULL) {
767 errno = ENOMEM;
768 return;
771 NV_CHECK(nv);
773 namesize = strlen(name) + 1;
775 nvh = malloc(sizeof(*nvh) + roundup2(namesize, 8));
776 if (nvh == NULL) {
777 if (nv->nv_error == 0)
778 nv->nv_error = ENOMEM;
779 return;
781 nvh->nvh_type = NV_ORDER_HOST | type;
782 nvh->nvh_namesize = (uint8_t)namesize;
783 nvh->nvh_dsize = (uint32_t)vsize;
784 bcopy(name, nvh->nvh_name, namesize);
786 /* Add header first. */
787 if (ebuf_add_tail(nv->nv_ebuf, nvh, NVH_HSIZE(nvh)) == -1) {
788 PJDLOG_ASSERT(errno != 0);
789 if (nv->nv_error == 0)
790 nv->nv_error = errno;
791 free(nvh);
792 return;
794 free(nvh);
795 /* Add the actual data. */
796 if (ebuf_add_tail(nv->nv_ebuf, value, vsize) == -1) {
797 PJDLOG_ASSERT(errno != 0);
798 if (nv->nv_error == 0)
799 nv->nv_error = errno;
800 return;
802 /* Align the data (if needed). */
803 vsize = roundup2(vsize, 8) - vsize;
804 if (vsize == 0)
805 return;
806 PJDLOG_ASSERT(vsize > 0 && vsize <= sizeof(align));
807 if (ebuf_add_tail(nv->nv_ebuf, align, vsize) == -1) {
808 PJDLOG_ASSERT(errno != 0);
809 if (nv->nv_error == 0)
810 nv->nv_error = errno;
811 return;
815 static void
816 nv_addv(struct nv *nv, const unsigned char *value, size_t vsize, int type,
817 const char *namefmt, va_list nameap)
819 char name[255];
820 size_t namesize;
822 namesize = vsnprintf(name, sizeof(name), namefmt, nameap);
823 PJDLOG_ASSERT(namesize > 0 && namesize < sizeof(name));
825 nv_add(nv, value, vsize, type, name);
828 static struct nvhdr *
829 nv_find(struct nv *nv, int type, const char *namefmt, va_list nameap)
831 char name[255];
832 struct nvhdr *nvh;
833 unsigned char *ptr;
834 size_t size, namesize;
836 if (nv == NULL) {
837 errno = ENOMEM;
838 return (NULL);
841 NV_CHECK(nv);
843 namesize = vsnprintf(name, sizeof(name), namefmt, nameap);
844 PJDLOG_ASSERT(namesize > 0 && namesize < sizeof(name));
845 namesize++;
847 ptr = ebuf_data(nv->nv_ebuf, &size);
848 while (size > 0) {
849 PJDLOG_ASSERT(size >= sizeof(*nvh) + 2);
850 nvh = (struct nvhdr *)ptr;
851 PJDLOG_ASSERT(size >= NVH_SIZE(nvh));
852 nv_swap(nvh, true);
853 if (strcmp(nvh->nvh_name, name) == 0) {
854 if (type != NV_TYPE_NONE &&
855 (nvh->nvh_type & NV_TYPE_MASK) != type) {
856 errno = EINVAL;
857 if (nv->nv_error == 0)
858 nv->nv_error = EINVAL;
859 return (NULL);
861 return (nvh);
863 ptr += NVH_SIZE(nvh);
864 size -= NVH_SIZE(nvh);
866 errno = ENOENT;
867 if (nv->nv_error == 0)
868 nv->nv_error = ENOENT;
869 return (NULL);
872 static void
873 nv_swap(struct nvhdr *nvh, bool tohost)
875 unsigned char *data, *end, *p;
876 size_t vsize;
878 data = NVH_DATA(nvh);
879 if (tohost) {
880 if ((nvh->nvh_type & NV_ORDER_MASK) == NV_ORDER_HOST)
881 return;
882 nvh->nvh_dsize = le32toh(nvh->nvh_dsize);
883 end = data + nvh->nvh_dsize;
884 nvh->nvh_type &= ~NV_ORDER_MASK;
885 nvh->nvh_type |= NV_ORDER_HOST;
886 } else {
887 if ((nvh->nvh_type & NV_ORDER_MASK) == NV_ORDER_NETWORK)
888 return;
889 end = data + nvh->nvh_dsize;
890 nvh->nvh_dsize = htole32(nvh->nvh_dsize);
891 nvh->nvh_type &= ~NV_ORDER_MASK;
892 nvh->nvh_type |= NV_ORDER_NETWORK;
895 vsize = 0;
897 switch (nvh->nvh_type & NV_TYPE_MASK) {
898 case NV_TYPE_INT8:
899 case NV_TYPE_UINT8:
900 case NV_TYPE_INT8_ARRAY:
901 case NV_TYPE_UINT8_ARRAY:
902 break;
903 case NV_TYPE_INT16:
904 case NV_TYPE_UINT16:
905 case NV_TYPE_INT16_ARRAY:
906 case NV_TYPE_UINT16_ARRAY:
907 if (vsize == 0)
908 vsize = 2;
909 /* FALLTHROUGH */
910 case NV_TYPE_INT32:
911 case NV_TYPE_UINT32:
912 case NV_TYPE_INT32_ARRAY:
913 case NV_TYPE_UINT32_ARRAY:
914 if (vsize == 0)
915 vsize = 4;
916 /* FALLTHROUGH */
917 case NV_TYPE_INT64:
918 case NV_TYPE_UINT64:
919 case NV_TYPE_INT64_ARRAY:
920 case NV_TYPE_UINT64_ARRAY:
921 if (vsize == 0)
922 vsize = 8;
923 for (p = data; p < end; p += vsize) {
924 if (tohost) {
925 switch (vsize) {
926 case 2:
927 *(uint16_t *)(void *)p =
928 le16toh(*(uint16_t *)(void *)p);
929 break;
930 case 4:
931 *(uint32_t *)(void *)p =
932 le32toh(*(uint32_t *)(void *)p);
933 break;
934 case 8:
935 *(uint64_t *)(void *)p =
936 le64toh(*(uint64_t *)(void *)p);
937 break;
938 default:
939 PJDLOG_ABORT("invalid condition");
941 } else {
942 switch (vsize) {
943 case 2:
944 *(uint16_t *)(void *)p =
945 htole16(*(uint16_t *)(void *)p);
946 break;
947 case 4:
948 *(uint32_t *)(void *)p =
949 htole32(*(uint32_t *)(void *)p);
950 break;
951 case 8:
952 *(uint64_t *)(void *)p =
953 htole64(*(uint64_t *)(void *)p);
954 break;
955 default:
956 PJDLOG_ABORT("invalid condition");
960 break;
961 case NV_TYPE_STRING:
962 break;
963 default:
964 PJDLOG_ABORT("unrecognized type");