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