1:
2: /*
3: * Copyright (c) 2001-2002 Packet Design, LLC.
4: * All rights reserved.
5: *
6: * Subject to the following obligations and disclaimer of warranty,
7: * use and redistribution of this software, in source or object code
8: * forms, with or without modifications are expressly permitted by
9: * Packet Design; provided, however, that:
10: *
11: * (i) Any and all reproductions of the source or object code
12: * must include the copyright notice above and the following
13: * disclaimer of warranties; and
14: * (ii) No rights are granted, in any manner or form, to use
15: * Packet Design trademarks, including the mark "PACKET DESIGN"
16: * on advertising, endorsements, or otherwise except as such
17: * appears in the above copyright notice or in the software.
18: *
19: * THIS SOFTWARE IS BEING PROVIDED BY PACKET DESIGN "AS IS", AND
20: * TO THE MAXIMUM EXTENT PERMITTED BY LAW, PACKET DESIGN MAKES NO
21: * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING
22: * THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED
23: * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
24: * OR NON-INFRINGEMENT. PACKET DESIGN DOES NOT WARRANT, GUARANTEE,
25: * OR MAKE ANY REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS
26: * OF THE USE OF THIS SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY,
27: * RELIABILITY OR OTHERWISE. IN NO EVENT SHALL PACKET DESIGN BE
28: * LIABLE FOR ANY DAMAGES RESULTING FROM OR ARISING OUT OF ANY USE
29: * OF THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY DIRECT,
30: * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, PUNITIVE, OR CONSEQUENTIAL
31: * DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, LOSS OF
32: * USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY THEORY OF
33: * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
35: * THE USE OF THIS SOFTWARE, EVEN IF PACKET DESIGN IS ADVISED OF
36: * THE POSSIBILITY OF SUCH DAMAGE.
37: *
38: * Author: Archie Cobbs <archie@freebsd.org>
39: */
40:
41: #include <sys/types.h>
42:
43: #include <stdlib.h>
44: #include <stdio.h>
45: #include <stdarg.h>
46: #include <assert.h>
47: #include <string.h>
48: #include <ctype.h>
49: #include <errno.h>
50:
51: #include "structs/structs.h"
52: #include "structs/type/int.h"
53: #include "structs/type/array.h"
54: #include "structs/type/string.h"
55: #include "structs/type/struct.h"
56: #include "structs/type/union.h"
57: #include "util/typed_mem.h"
58:
59: /* Special handling for array length as a read-only field */
60: static const struct structs_type structs_type_array_length = {
61: sizeof(u_int),
62: "uint",
63: STRUCTS_TYPE_PRIMITIVE,
64: structs_region_init,
65: structs_region_copy,
66: structs_region_equal,
67: structs_int_ascify,
68: structs_notsupp_binify,
69: structs_region_encode_netorder,
70: structs_notsupp_decode,
71: structs_nothing_free,
72: { { (void *)2 }, { (void *)0 } } /* args for structs_int_ascify */
73: };
74:
75: /* Special handling for union field name as a read-only field */
76: static const struct structs_type structs_type_union_field_name = {
77: sizeof(char *),
78: "string",
79: STRUCTS_TYPE_PRIMITIVE,
80: structs_notsupp_init,
81: structs_notsupp_copy,
82: structs_string_equal,
83: structs_string_ascify,
84: structs_notsupp_binify,
85: structs_notsupp_encode,
86: structs_notsupp_decode,
87: structs_nothing_free,
88: { { (void *)"union field_name" }, /* args for structs_type_string */
89: { (void *)0 } }
90: };
91:
92: /*
93: * Initialize an item.
94: */
95: int
96: structs_init(const struct structs_type *type, const char *name, void *data)
97: {
98: /* Find item */
99: if ((type = structs_find(type, name, &data, 0)) == NULL)
100: return (-1);
101:
102: /* Initialize it */
103: return ((*type->init)(type, data));
104: }
105:
106: /*
107: * Reset an item.
108: */
109: int
110: structs_reset(const struct structs_type *type, const char *name, void *data)
111: {
112: void *temp;
113:
114: /* Find item */
115: if ((type = structs_find(type, name, &data, 0)) == NULL)
116: return (-1);
117:
118: /* Make a temporary new copy */
119: if ((temp = MALLOC(TYPED_MEM_TEMP, type->size)) == NULL)
120: return (-1);
121: memset(temp, 0, type->size);
122: if ((*type->init)(type, temp) == -1) {
123: FREE(TYPED_MEM_TEMP, temp);
124: return (-1);
125: }
126:
127: /* Replace existing item, freeing it first */
128: (*type->uninit)(type, data);
129: memcpy(data, temp, type->size);
130: FREE(TYPED_MEM_TEMP, temp);
131: return (0);
132: }
133:
134: /*
135: * Free an item, returning it to its initialized state.
136: *
137: * If "name" is NULL or empty string, the entire structure is free'd.
138: */
139: int
140: structs_free(const struct structs_type *type, const char *name, void *data)
141: {
142: const int errno_save = errno;
143:
144: /* Find item */
145: if ((type = structs_find(type, name, &data, 0)) == NULL)
146: return (-1);
147:
148: /* Free it */
149: (*type->uninit)(type, data);
150: errno = errno_save;
151: return (0);
152: }
153:
154: /*
155: * Get a copy of an item.
156: *
157: * If "name" is NULL or empty string, the entire structure is copied.
158: *
159: * It is assumed that "to" points to a region big enough to hold
160: * the copy of the item. "to" will not be free'd first, so it should
161: * not already be initialized.
162: *
163: * Note: "name" is only applied to "from". The structs types of
164: * "from.<name>" and "to" must be the same.
165: */
166: int
167: structs_get(const struct structs_type *type,
168: const char *name, const void *from, void *to)
169: {
170: /* Find item */
171: if ((type = structs_find(type, name, (void **)&from, 0)) == NULL)
172: return (-1);
173:
174: /* Copy item */
175: return ((*type->copy)(type, from, to));
176: }
177:
178: /*
179: * Set an item in a structure.
180: *
181: * If "name" is NULL or empty string, the entire structure is copied.
182: *
183: * It is assumed that "to" is already initialized.
184: *
185: * Note: "name" is only applied to "to". The structs types of
186: * "from" and "to.<name>" must be the same.
187: */
188: int
189: structs_set(const struct structs_type *type,
190: const void *from, const char *name, void *to)
191: {
192: void *copy;
193:
194: /* Find item */
195: if ((type = structs_find(type, name, &to, 0)) == NULL)
196: return (-1);
197:
198: /* Make a new copy of 'from' */
199: if ((copy = MALLOC(TYPED_MEM_TEMP, type->size)) == NULL)
200: return (-1);
201: if ((*type->copy)(type, from, copy) == -1) {
202: FREE(TYPED_MEM_TEMP, copy);
203: return (-1);
204: }
205:
206: /* Free overwritten item in 'to' */
207: (*type->uninit)(type, to);
208:
209: /* Move new item in its place */
210: memcpy(to, copy, type->size);
211:
212: /* Done */
213: FREE(TYPED_MEM_TEMP, copy);
214: return (0);
215: }
216:
217: /*
218: * Get the ASCII form of an item.
219: */
220: char *
221: structs_get_string(const struct structs_type *type,
222: const char *name, const void *data, const char *mtype)
223: {
224: /* Find item */
225: if ((type = structs_find(type, name, (void **)&data, 0)) == NULL)
226: return (NULL);
227:
228: /* Ascify it */
229: return ((*type->ascify)(type, mtype, data));
230: }
231:
232: /*
233: * Set an item's value from a string.
234: *
235: * The referred to item must be of a type that supports ASCII encoding,
236: * and is assumed to be already initialized.
237: */
238: int
239: structs_set_string(const struct structs_type *type, const char *name,
240: const char *ascii, void *data, char *ebuf, size_t emax)
241: {
242: void *temp;
243: char dummy[1];
244:
245: /* Sanity check */
246: if (ascii == NULL)
247: ascii = "";
248: if (ebuf == NULL) {
249: ebuf = dummy;
250: emax = sizeof(dummy);
251: }
252:
253: /* Initialize error buffer */
254: if (emax > 0)
255: *ebuf = '\0';
256:
257: /* Find item */
258: if ((type = structs_find(type, name, &data, 1)) == NULL) {
259: strlcpy(ebuf, strerror(errno), emax);
260: return (-1);
261: }
262:
263: /* Binify item into temporary storage */
264: if ((temp = MALLOC(TYPED_MEM_TEMP, type->size)) == NULL)
265: return (-1);
266: memset(temp, 0, type->size);
267: if ((*type->binify)(type, ascii, temp, ebuf, emax) == -1) {
268: FREE(TYPED_MEM_TEMP, temp);
269: if (emax > 0 && *ebuf == '\0')
270: strlcpy(ebuf, strerror(errno), emax);
271: return (-1);
272: }
273:
274: /* Replace existing item, freeing it first */
275: (*type->uninit)(type, data);
276: memcpy(data, temp, type->size);
277: FREE(TYPED_MEM_TEMP, temp);
278: return (0);
279: }
280:
281: /*
282: * Get the binary encoded form of an item, allocated with type 'mtype'.
283: */
284: int
285: structs_get_binary(const struct structs_type *type, const char *name,
286: const void *data, const char *mtype, struct structs_data *code)
287: {
288: /* Find item */
289: if ((type = structs_find(type, name, (void **)&data, 0)) == NULL) {
290: memset(code, 0, sizeof(*code));
291: return (-1);
292: }
293:
294: /* Encode it */
295: if ((*type->encode)(type, mtype, code, data) == -1) {
296: memset(code, 0, sizeof(*code));
297: return (-1);
298: }
299:
300: /* Done */
301: return (0);
302: }
303:
304: /*
305: * Set an item's value from its binary encoded value.
306: */
307: int
308: structs_set_binary(const struct structs_type *type, const char *name,
309: const struct structs_data *code, void *data, char *ebuf, size_t emax)
310: {
311: void *temp;
312: int clen;
313:
314: /* Initialize error buffer */
315: if (emax > 0)
316: *ebuf = '\0';
317:
318: /* Find item */
319: if ((type = structs_find(type, name, (void **)&data, 0)) == NULL) {
320: strlcpy(ebuf, strerror(errno), emax);
321: return (-1);
322: }
323:
324: /* Decode item into temporary storage */
325: if ((temp = MALLOC(TYPED_MEM_TEMP, type->size)) == NULL)
326: return (-1);
327: memset(temp, 0, type->size);
328: if ((clen = (*type->decode)(type, code->data,
329: code->length, temp, ebuf, emax)) == -1) {
330: FREE(TYPED_MEM_TEMP, temp);
331: if (emax > 0 && *ebuf == '\0')
332: strlcpy(ebuf, strerror(errno), emax);
333: return (-1);
334: }
335: assert(clen <= code->length);
336:
337: /* Replace existing item, freeing it first */
338: (*type->uninit)(type, data);
339: memcpy(data, temp, type->size);
340: FREE(TYPED_MEM_TEMP, temp);
341:
342: /* Done */
343: return (clen);
344: }
345:
346: /*
347: * Test for equality.
348: */
349: int
350: structs_equal(const struct structs_type *type,
351: const char *name, const void *data1, const void *data2)
352: {
353: /* Find items */
354: if (structs_find(type, name, (void **)&data1, 0) == NULL)
355: return (-1);
356: if ((type = structs_find(type, name, (void **)&data2, 0)) == NULL)
357: return (-1);
358:
359: /* Compare them */
360: return ((*type->equal)(type, data1, data2));
361: }
362:
363: /*
364: * Find an item in a structure.
365: */
366: const struct structs_type *
367: structs_find(const struct structs_type *type, const char *name,
368: void **datap, int set_union)
369: {
370: void *data = *datap;
371: const char *next;
372:
373: /* Empty string means stop recursing */
374: if (name == NULL || *name == '\0')
375: return (type);
376:
377: /* Primitive types don't have sub-elements */
378: if (type->tclass == STRUCTS_TYPE_PRIMITIVE) {
379: errno = ENOENT;
380: return (NULL);
381: }
382:
383: /* Dereference through pointer(s) */
384: while (type->tclass == STRUCTS_TYPE_POINTER) {
385: type = type->args[0].v;
386: data = *((void **)data);
387: }
388:
389: /* Get next name component */
390: if ((next = strchr(name, STRUCTS_SEPARATOR)) != NULL)
391: next++;
392:
393: /* Find element of aggregate structure update type and data */
394: switch (type->tclass) {
395: case STRUCTS_TYPE_ARRAY:
396: {
397: const struct structs_type *const etype = type->args[0].v;
398: const struct structs_array *const ary = data;
399: u_long index;
400: char *eptr;
401:
402: /* Special handling for "length" */
403: if (strcmp(name, "length") == 0) {
404: type = &structs_type_array_length;
405: data = (void *)&ary->length;
406: break;
407: }
408:
409: /* Decode an index */
410: index = strtoul(name, &eptr, 10);
411: if (!isdigit(*name)
412: || eptr == name
413: || (*eptr != '\0' && *eptr != STRUCTS_SEPARATOR)) {
414: errno = ENOENT;
415: return (NULL);
416: }
417: if (index >= ary->length) {
418: errno = EDOM;
419: return (NULL);
420: }
421: type = etype;
422: data = (char *)ary->elems + (index * etype->size);
423: break;
424: }
425: case STRUCTS_TYPE_FIXEDARRAY:
426: {
427: const struct structs_type *const etype = type->args[0].v;
428: const u_int length = type->args[2].i;
429: u_long index;
430: char *eptr;
431:
432: /* Special handling for "length" */
433: if (strcmp(name, "length") == 0) {
434: type = &structs_type_array_length;
435: data = (void *)&type->args[2].i;
436: break;
437: }
438:
439: /* Decode an index */
440: index = strtoul(name, &eptr, 10);
441: if (!isdigit(*name)
442: || eptr == name
443: || (*eptr != '\0' && *eptr != STRUCTS_SEPARATOR)) {
444: errno = ENOENT;
445: return (NULL);
446: }
447: if (index >= length) {
448: errno = EDOM;
449: return (NULL);
450: }
451: type = etype;
452: data = (char *)data + (index * etype->size);
453: break;
454: }
455: case STRUCTS_TYPE_STRUCTURE:
456: {
457: const struct structs_field *field;
458:
459: /* Find the field */
460: for (field = type->args[0].v; field->name != NULL; field++) {
461: const size_t fnlen = strlen(field->name);
462:
463: /* Handle field names with separator in them */
464: if (strncmp(name, field->name, fnlen) == 0
465: && (name[fnlen] == '\0'
466: || name[fnlen] == STRUCTS_SEPARATOR)) {
467: next = (name[fnlen] != '\0') ?
468: name + fnlen + 1 : NULL;
469: break;
470: }
471: }
472: if (field->name == NULL) {
473: errno = ENOENT;
474: return (NULL);
475: }
476: type = field->type;
477: data = (char *)data + field->offset;
478: break;
479: }
480: case STRUCTS_TYPE_UNION:
481: {
482: const struct structs_ufield *const fields = type->args[0].v;
483: const char *const mtype = type->args[1].s;
484: struct structs_union *const un = data;
485: const size_t oflen = strlen(un->field_name);
486: const struct structs_ufield *ofield;
487: const struct structs_ufield *field;
488: void *new_un;
489: void *data2;
490:
491: /* Special handling for "field_name" */
492: if (strcmp(name, "field_name") == 0) {
493: type = &structs_type_union_field_name;
494: data = (void *)&un->field_name;
495: break;
496: }
497:
498: /* Find the old field */
499: for (ofield = fields; ofield->name != NULL; ofield++) {
500: if (strcmp(ofield->name, un->field_name) == 0)
501: break;
502: }
503: if (ofield->name == NULL) {
504: assert(0);
505: errno = EINVAL;
506: return (NULL);
507: }
508:
509: /*
510: * Check if the union is already set to the desired field,
511: * handling field names with the separator char in them.
512: */
513: if (strncmp(name, un->field_name, oflen) == 0
514: && (name[oflen] == '\0'
515: || name[oflen] == STRUCTS_SEPARATOR)) {
516: next = (name[oflen] != '\0') ? name + oflen + 1 : NULL;
517: field = ofield;
518: goto union_done;
519: }
520:
521: /* Is modifying the union to get the right name acceptable? */
522: if (!set_union) {
523: errno = ENOENT;
524: return (NULL);
525: }
526:
527: /* Find the new field */
528: for (field = fields; field->name != NULL; field++) {
529: const size_t fnlen = strlen(field->name);
530:
531: /* Handle field names with separator in them */
532: if (strncmp(name, field->name, fnlen) == 0
533: && (name[fnlen] == '\0'
534: || name[fnlen] == STRUCTS_SEPARATOR)) {
535: next = (name[fnlen] != '\0') ?
536: name + fnlen + 1 : NULL;
537: break;
538: }
539: }
540: if (field->name == NULL) {
541: errno = ENOENT;
542: return (NULL);
543: }
544:
545: /* Create a new union with the new field type */
546: if ((new_un = MALLOC(mtype, field->type->size)) == NULL)
547: return (NULL);
548: if ((*field->type->init)(field->type, new_un) == -1) {
549: FREE(mtype, new_un);
550: return (NULL);
551: }
552:
553: /* See if name would be found with new union instead of old */
554: data2 = new_un;
555: if (next != NULL
556: && structs_find(field->type, next, &data2, 1) == NULL) {
557: (*field->type->uninit)(field->type, new_un);
558: FREE(mtype, new_un);
559: return (NULL);
560: }
561:
562: /* Replace existing union with new one having desired type */
563: (*ofield->type->uninit)(ofield->type, un->un);
564: FREE(mtype, un->un);
565: un->un = new_un;
566: *((const char **)&un->field_name) = field->name;
567:
568: union_done:
569: /* Continue recursing */
570: type = field->type;
571: data = un->un;
572: break;
573: }
574: default:
575: assert(0);
576: return (NULL);
577: }
578:
579: /* Recurse on sub-element */
580: if ((type = structs_find(type, next, &data, set_union)) == NULL)
581: return (NULL);
582:
583: /* Done */
584: *datap = data;
585: return (type);
586: }
587:
588: /*
589: * Traverse a structure.
590: */
591:
592: struct structs_trav {
593: char **list;
594: u_int len;
595: u_int alloc;
596: const char *mtype;
597: };
598:
599: static int structs_trav(struct structs_trav *t, const char *name,
600: const struct structs_type *type, const void *data);
601:
602: int
603: structs_traverse(const struct structs_type *type,
604: const void *data, char ***listp, const char *mtype)
605: {
606: struct structs_trav t;
607:
608: /* Initialize traversal structure */
609: memset(&t, 0, sizeof(t));
610: t.mtype = mtype;
611:
612: /* Recurse */
613: if (structs_trav(&t, "", type, data) == -1) {
614: while (t.len > 0)
615: FREE(t.mtype, t.list[--t.len]);
616: FREE(t.mtype, t.list);
617: return (-1);
618: }
619:
620: /* Return the result */
621: *listp = t.list;
622: return (t.len);
623: }
624:
625: static int
626: structs_trav(struct structs_trav *t, const char *name,
627: const struct structs_type *type, const void *data)
628: {
629: const char *const dot = (*name == '\0' ? "" : ".");
630: char *ename;
631: int i;
632:
633: /* Dereference through pointer(s) */
634: while (type->tclass == STRUCTS_TYPE_POINTER) {
635: type = type->args[0].v;
636: data = *((void **)data);
637: }
638:
639: switch (type->tclass) {
640: case STRUCTS_TYPE_PRIMITIVE:
641: {
642: /* Grow list as necessary */
643: if (t->len == t->alloc) {
644: u_int new_alloc;
645: char **new_list;
646:
647: new_alloc = (t->alloc + 32) * 2;
648: if ((new_list = REALLOC(t->mtype,
649: t->list, new_alloc * sizeof(*t->list))) == NULL)
650: return (-1);
651: t->list = new_list;
652: t->alloc = new_alloc;
653: }
654:
655: /* Add new name to list */
656: if ((t->list[t->len] = STRDUP(t->mtype, name)) == NULL)
657: return (-1);
658: t->len++;
659:
660: /* Done */
661: return (0);
662: }
663:
664: case STRUCTS_TYPE_ARRAY:
665: {
666: const struct structs_type *const etype = type->args[0].v;
667: const struct structs_array *const ary = data;
668:
669: /* Iterate over array elements */
670: for (i = 0; i < ary->length; i++) {
671: const void *const edata
672: = (char *)ary->elems + (i * etype->size);
673:
674: if (ASPRINTF(t->mtype,
675: &ename, "%s%s%d", name, dot, i) == -1)
676: return (-1);
677: if (structs_trav(t, ename, etype, edata) == -1) {
678: FREE(t->mtype, ename);
679: return (-1);
680: }
681: FREE(t->mtype, ename);
682: }
683:
684: /* Done */
685: return (0);
686: }
687:
688: case STRUCTS_TYPE_FIXEDARRAY:
689: {
690: const struct structs_type *const etype = type->args[0].v;
691: const u_int length = type->args[2].i;
692:
693: /* Iterate over array elements */
694: for (i = 0; i < length; i++) {
695: const void *const edata
696: = (char *)data + (i * etype->size);
697:
698: if (ASPRINTF(t->mtype,
699: &ename, "%s%s%d", name, dot, i) == -1)
700: return (-1);
701: if (structs_trav(t, ename, etype, edata) == -1) {
702: FREE(t->mtype, ename);
703: return (-1);
704: }
705: FREE(t->mtype, ename);
706: }
707:
708: /* Done */
709: return (0);
710: }
711:
712: case STRUCTS_TYPE_STRUCTURE:
713: {
714: const struct structs_field *field;
715:
716: /* Iterate over structure fields */
717: for (field = type->args[0].v; field->name != NULL; field++) {
718: const void *const edata
719: = (char *)data + field->offset;
720:
721: if (ASPRINTF(t->mtype,
722: &ename, "%s%s%s", name, dot, field->name) == -1)
723: return (-1);
724: if (structs_trav(t, ename, field->type, edata) == -1) {
725: FREE(t->mtype, ename);
726: return (-1);
727: }
728: FREE(t->mtype, ename);
729: }
730:
731: /* Done */
732: return (0);
733: }
734:
735: case STRUCTS_TYPE_UNION:
736: {
737: const struct structs_ufield *const fields = type->args[0].v;
738: const struct structs_union *const un = data;
739: const struct structs_ufield *field;
740:
741: /* Find field */
742: for (field = fields; field->name != NULL
743: && strcmp(un->field_name, field->name) != 0; field++);
744: if (field->name == NULL) {
745: assert(0);
746: errno = EINVAL;
747: return (-1);
748: }
749:
750: /* Do selected union field */
751: if (ASPRINTF(t->mtype,
752: &ename, "%s%s%s", name, dot, field->name) == -1)
753: return (-1);
754: if (structs_trav(t, ename, field->type, un->un) == -1) {
755: FREE(t->mtype, ename);
756: return (-1);
757: }
758: FREE(t->mtype, ename);
759:
760: /* Done */
761: return (0);
762: }
763:
764: default:
765: assert(0);
766: errno = ECONNABORTED;
767: return (-1);
768: }
769: }
770:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>