Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/sbin/hastd/nv.c
39475 views
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 *
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
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
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
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
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 *
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 *
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
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
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
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
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
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
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
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
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
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
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 *
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
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
963