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