Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/bsnmp/gensnmptree/gensnmptree.c
39478 views
1
/*
2
* Copyright (c) 2001-2003
3
* Fraunhofer Institute for Open Communication Systems (FhG Fokus).
4
* All rights reserved.
5
*
6
* Copyright (c) 2004-2006,2018
7
* Hartmut Brandt.
8
* All rights reserved.
9
*
10
* Author: Harti Brandt <[email protected]>
11
*
12
* Redistribution and use in source and binary forms, with or without
13
* modification, are permitted provided that the following conditions
14
* are met:
15
* 1. Redistributions of source code must retain the above copyright
16
* notice, this list of conditions and the following disclaimer.
17
* 2. Redistributions in binary form must reproduce the above copyright
18
* notice, this list of conditions and the following disclaimer in the
19
* documentation and/or other materials provided with the distribution.
20
*
21
* THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
22
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24
* ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
25
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31
* SUCH DAMAGE.
32
*
33
* $Begemot: gensnmptree.c 383 2006-05-30 07:40:49Z brandt_h $
34
*
35
* Generate OID table from table description.
36
*
37
* Syntax is:
38
* ---------
39
* file := top | top file
40
*
41
* top := tree | typedef | include
42
*
43
* tree := head elements ')'
44
*
45
* entry := head ':' index STRING elements ')'
46
*
47
* leaf := head type STRING ACCESS ')'
48
*
49
* column := head type ACCESS ')'
50
*
51
* type := BASETYPE | BASETYPE '|' subtype | enum | bits
52
*
53
* subtype := STRING
54
*
55
* enum := ENUM '(' value ')'
56
*
57
* bits := BITS '(' value ')'
58
*
59
* value := optminus INT STRING | optminus INT STRING value
60
*
61
* optminus := '-' | EMPTY
62
*
63
* head := '(' INT STRING
64
*
65
* elements := EMPTY | elements element
66
*
67
* element := tree | leaf | column
68
*
69
* index := type | index type
70
*
71
* typedef := 'typedef' STRING type
72
*
73
* include := 'include' filespec
74
*
75
* filespec := '"' STRING '"' | '<' STRING '>'
76
*/
77
#include <sys/types.h>
78
#include <sys/param.h>
79
#include <stdio.h>
80
#include <stdlib.h>
81
#include <stdarg.h>
82
#include <unistd.h>
83
#include <string.h>
84
#include <ctype.h>
85
#include <inttypes.h>
86
#include <errno.h>
87
#ifdef HAVE_ERR_H
88
#include <err.h>
89
#endif
90
#include <sys/queue.h>
91
#include "support.h"
92
#include "asn1.h"
93
#include "snmp.h"
94
#include "snmpagent.h"
95
96
/*
97
* Constant prefix for all OIDs
98
*/
99
static const asn_subid_t prefix[] = { 1, 3, 6 };
100
#define PREFIX_LEN (sizeof(prefix) / sizeof(prefix[0]))
101
102
u_int tree_size;
103
static const char *file_prefix = "";
104
105
/* if true generate local include paths */
106
static int localincs = 0;
107
108
/* if true print tokens */
109
static int debug;
110
111
static const char usgtxt[] = "\
112
Generate SNMP tables.\n\
113
usage: gensnmptree [-dEeFfhlt] [-I directory] [-i infile] [-p prefix]\n\
114
[name]...\n\
115
options:\n\
116
-d debug mode\n\
117
-E extract the named or all enums and bits only\n\
118
-e extract the named oids or enums\n\
119
-F generate functions for -E into a .c file\n\
120
-f generate functions for -E into the header\n\
121
-h print this info\n\
122
-I directory add directory to include path\n\
123
-i ifile read from the named file instead of stdin\n\
124
-l generate local include directives\n\
125
-p prefix prepend prefix to file and variable names\n\
126
-t generate a .def file\n\
127
";
128
129
/**
130
* Program operation.
131
*/
132
enum op {
133
/** generate the tree */
134
OP_GEN,
135
136
/** extract OIDs */
137
OP_EXTRACT,
138
139
/** print the parsed tree */
140
OP_TREE,
141
142
/** extract enums */
143
OP_ENUMS,
144
};
145
146
/**
147
* Which functions to create.
148
*/
149
enum gen_funcs {
150
/** none */
151
GEN_FUNCS_NONE,
152
153
/** functions for header files */
154
GEN_FUNCS_H,
155
156
/** functions for C files */
157
GEN_FUNCS_C,
158
};
159
160
/*
161
* A node in the OID tree
162
*/
163
enum ntype {
164
NODE_LEAF = 1,
165
NODE_TREE,
166
NODE_ENTRY,
167
NODE_COLUMN
168
};
169
170
enum {
171
FL_GET = 0x01,
172
FL_SET = 0x02,
173
};
174
175
struct node;
176
TAILQ_HEAD(node_list, node);
177
178
struct node {
179
enum ntype type;
180
asn_subid_t id; /* last element of OID */
181
char *name; /* name of node */
182
TAILQ_ENTRY(node) link;
183
u_int lno; /* starting line number */
184
u_int flags; /* allowed operations */
185
186
union {
187
struct tree {
188
struct node_list subs;
189
} tree;
190
191
struct entry {
192
uint32_t index; /* index for table entry */
193
char *func; /* function for tables */
194
struct node_list subs;
195
char *subtypes[SNMP_INDEXES_MAX];
196
} entry;
197
198
struct leaf {
199
enum snmp_syntax syntax; /* syntax for this leaf */
200
char *func; /* function name */
201
char *subtype; /* subtype */
202
} leaf;
203
204
struct column {
205
enum snmp_syntax syntax; /* syntax for this column */
206
char *subtype; /* subtype */
207
} column;
208
} u;
209
};
210
211
struct func {
212
const char *name;
213
LIST_ENTRY(func) link;
214
};
215
216
static LIST_HEAD(, func) funcs = LIST_HEAD_INITIALIZER(funcs);
217
218
struct enums {
219
const char *name;
220
long value;
221
TAILQ_ENTRY(enums) link;
222
};
223
224
struct type {
225
const char *name;
226
const char *from_fname;
227
u_int from_lno;
228
u_int syntax;
229
int is_enum;
230
int is_bits;
231
TAILQ_HEAD(, enums) enums;
232
LIST_ENTRY(type) link;
233
};
234
235
static LIST_HEAD(, type) types = LIST_HEAD_INITIALIZER(types);
236
237
static void report(const char *, ...) __dead2 __printflike(1, 2);
238
static void report_node(const struct node *, const char *, ...)
239
__dead2 __printflike(2, 3);
240
241
/************************************************************
242
*
243
* Allocate memory and panic just in the case...
244
*/
245
static void *
246
xalloc(size_t size)
247
{
248
void *ptr;
249
250
if ((ptr = calloc(1, size)) == NULL)
251
err(1, "allocing %zu bytes", size);
252
253
return (ptr);
254
}
255
256
static char *
257
savestr(const char *s)
258
{
259
260
if (s == NULL)
261
return (NULL);
262
return (strcpy(xalloc(strlen(s) + 1), s));
263
}
264
265
/************************************************************
266
*
267
* Input stack
268
*/
269
struct input {
270
FILE *fp;
271
u_int lno;
272
char *fname;
273
char *path;
274
LIST_ENTRY(input) link;
275
};
276
static LIST_HEAD(, input) inputs = LIST_HEAD_INITIALIZER(inputs);
277
static struct input *input = NULL;
278
279
#define MAX_PATHS 100
280
static u_int npaths = 2;
281
static u_int stdpaths = 2;
282
static const char *paths[MAX_PATHS + 1] = {
283
"/usr/share/snmp/defs",
284
"/usr/local/share/snmp/defs",
285
NULL
286
};
287
288
static int pbchar = -1;
289
290
static void
291
path_new(const char *path)
292
{
293
if (npaths >= MAX_PATHS)
294
report("too many -I directives");
295
memmove(&paths[npaths - stdpaths + 1], &paths[npaths - stdpaths],
296
sizeof(path[0]) * stdpaths);
297
paths[npaths - stdpaths] = savestr(path);
298
npaths++;
299
}
300
301
static void
302
input_new(FILE *fp, const char *path, const char *fname)
303
{
304
struct input *ip;
305
306
ip = xalloc(sizeof(*ip));
307
ip->fp = fp;
308
ip->lno = 1;
309
ip->fname = savestr(fname);
310
ip->path = savestr(path);
311
LIST_INSERT_HEAD(&inputs, ip, link);
312
313
input = ip;
314
}
315
316
static void
317
input_close(void)
318
{
319
320
if (input == NULL)
321
return;
322
fclose(input->fp);
323
free(input->fname);
324
free(input->path);
325
LIST_REMOVE(input, link);
326
free(input);
327
328
input = LIST_FIRST(&inputs);
329
}
330
331
static FILE *
332
tryopen(const char *path, const char *fname)
333
{
334
char *fn;
335
FILE *fp;
336
337
if (path == NULL)
338
fn = savestr(fname);
339
else {
340
fn = xalloc(strlen(path) + strlen(fname) + 2);
341
sprintf(fn, "%s/%s", path, fname);
342
}
343
fp = fopen(fn, "r");
344
free(fn);
345
return (fp);
346
}
347
348
static void
349
input_fopen(const char *fname, int loc)
350
{
351
FILE *fp;
352
char *path;
353
u_int p;
354
355
if (fname[0] == '/') {
356
if ((fp = tryopen(NULL, fname)) != NULL) {
357
input_new(fp, NULL, fname);
358
return;
359
}
360
361
} else {
362
if (loc) {
363
if (input == NULL)
364
path = NULL;
365
else
366
path = input->path;
367
368
if ((fp = tryopen(path, fname)) != NULL) {
369
input_new(fp, NULL, fname);
370
return;
371
}
372
}
373
374
for (p = 0; paths[p] != NULL; p++)
375
if ((fp = tryopen(paths[p], fname)) != NULL) {
376
input_new(fp, paths[p], fname);
377
return;
378
}
379
}
380
report("cannot open '%s'", fname);
381
}
382
383
static int
384
tgetc(void)
385
{
386
int c;
387
388
if (pbchar != -1) {
389
c = pbchar;
390
pbchar = -1;
391
return (c);
392
}
393
394
for (;;) {
395
if (input == NULL)
396
return (EOF);
397
398
if ((c = getc(input->fp)) != EOF)
399
return (c);
400
401
input_close();
402
}
403
}
404
405
static void
406
tungetc(int c)
407
{
408
409
if (pbchar != -1)
410
abort();
411
pbchar = c;
412
}
413
414
/************************************************************
415
*
416
* Parsing input
417
*/
418
enum tok {
419
TOK_EOF = 0200, /* end-of-file seen */
420
TOK_NUM, /* number */
421
TOK_STR, /* string */
422
TOK_ACCESS, /* access operator */
423
TOK_TYPE, /* type operator */
424
TOK_ENUM, /* enum token (kind of a type) */
425
TOK_TYPEDEF, /* typedef directive */
426
TOK_DEFTYPE, /* defined type */
427
TOK_INCLUDE, /* include directive */
428
TOK_FILENAME, /* filename ("foo.bar" or <foo.bar>) */
429
TOK_BITS, /* bits token (kind of a type) */
430
};
431
432
static const struct {
433
const char *str;
434
enum tok tok;
435
u_int val;
436
} keywords[] = {
437
{ "GET", TOK_ACCESS, FL_GET },
438
{ "SET", TOK_ACCESS, FL_SET },
439
{ "NULL", TOK_TYPE, SNMP_SYNTAX_NULL },
440
{ "INTEGER", TOK_TYPE, SNMP_SYNTAX_INTEGER },
441
{ "INTEGER32", TOK_TYPE, SNMP_SYNTAX_INTEGER },
442
{ "UNSIGNED32", TOK_TYPE, SNMP_SYNTAX_GAUGE },
443
{ "OCTETSTRING", TOK_TYPE, SNMP_SYNTAX_OCTETSTRING },
444
{ "IPADDRESS", TOK_TYPE, SNMP_SYNTAX_IPADDRESS },
445
{ "OID", TOK_TYPE, SNMP_SYNTAX_OID },
446
{ "TIMETICKS", TOK_TYPE, SNMP_SYNTAX_TIMETICKS },
447
{ "COUNTER", TOK_TYPE, SNMP_SYNTAX_COUNTER },
448
{ "GAUGE", TOK_TYPE, SNMP_SYNTAX_GAUGE },
449
{ "COUNTER64", TOK_TYPE, SNMP_SYNTAX_COUNTER64 },
450
{ "ENUM", TOK_ENUM, SNMP_SYNTAX_INTEGER },
451
{ "BITS", TOK_BITS, SNMP_SYNTAX_OCTETSTRING },
452
{ "typedef", TOK_TYPEDEF, 0 },
453
{ "include", TOK_INCLUDE, 0 },
454
{ NULL, 0, 0 }
455
};
456
457
/* arbitrary upper limit on node names and function names */
458
#define MAXSTR 1000
459
static char str[MAXSTR];
460
static u_long val; /* integer values */
461
static int saved_token = -1;
462
463
/*
464
* Report an error and exit.
465
*/
466
static void
467
report(const char *fmt, ...)
468
{
469
va_list ap;
470
int c;
471
472
va_start(ap, fmt);
473
fprintf(stderr, "line %u: ", input->lno);
474
vfprintf(stderr, fmt, ap);
475
fprintf(stderr, "\n");
476
fprintf(stderr, "context: \"");
477
while ((c = tgetc()) != EOF && c != '\n')
478
fprintf(stderr, "%c", c);
479
fprintf(stderr, "\n");
480
va_end(ap);
481
exit(1);
482
}
483
static void
484
report_node(const struct node *np, const char *fmt, ...)
485
{
486
va_list ap;
487
488
va_start(ap, fmt);
489
fprintf(stderr, "line %u, node %s: ", np->lno, np->name);
490
vfprintf(stderr, fmt, ap);
491
fprintf(stderr, "\n");
492
va_end(ap);
493
exit(1);
494
}
495
496
/*
497
* Return a fresh copy of the string constituting the current token.
498
*/
499
static char *
500
savetok(void)
501
{
502
return (savestr(str));
503
}
504
505
/*
506
* Get the next token from input.
507
*/
508
static int
509
gettoken_internal(void)
510
{
511
int c;
512
struct type *t;
513
514
if (saved_token != -1) {
515
c = saved_token;
516
saved_token = -1;
517
return (c);
518
}
519
520
again:
521
/*
522
* Skip any whitespace before the next token
523
*/
524
while ((c = tgetc()) != EOF) {
525
if (c == '\n')
526
input->lno++;
527
if (!isspace(c))
528
break;
529
}
530
if (c == EOF)
531
return (TOK_EOF);
532
if (!isascii(c))
533
report("unexpected character %#2x", (u_int)c);
534
535
/*
536
* Skip comments
537
*/
538
if (c == '#') {
539
while ((c = tgetc()) != EOF) {
540
if (c == '\n') {
541
input->lno++;
542
goto again;
543
}
544
}
545
report("unexpected EOF in comment");
546
}
547
548
/*
549
* Single character tokens
550
*/
551
if (strchr("():|-", c) != NULL)
552
return (c);
553
554
if (c == '"' || c == '<') {
555
int end = c;
556
size_t n = 0;
557
558
val = 1;
559
if (c == '<') {
560
val = 0;
561
end = '>';
562
}
563
564
while ((c = tgetc()) != EOF) {
565
if (c == end)
566
break;
567
if (n == sizeof(str) - 1) {
568
str[n++] = '\0';
569
report("filename too long '%s...'", str);
570
}
571
str[n++] = c;
572
}
573
str[n++] = '\0';
574
return (TOK_FILENAME);
575
}
576
577
/*
578
* Sort out numbers
579
*/
580
if (isdigit(c)) {
581
size_t n = 0;
582
str[n++] = c;
583
while ((c = tgetc()) != EOF) {
584
if (!isdigit(c)) {
585
tungetc(c);
586
break;
587
}
588
if (n == sizeof(str) - 1) {
589
str[n++] = '\0';
590
report("number too long '%s...'", str);
591
}
592
str[n++] = c;
593
}
594
str[n++] = '\0';
595
sscanf(str, "%lu", &val);
596
return (TOK_NUM);
597
}
598
599
/*
600
* So that has to be a string.
601
*/
602
if (isalpha(c) || c == '_') {
603
size_t n = 0;
604
str[n++] = c;
605
while ((c = tgetc()) != EOF) {
606
if (!isalnum(c) && c != '_' && c != '-') {
607
tungetc(c);
608
break;
609
}
610
if (n == sizeof(str) - 1) {
611
str[n++] = '\0';
612
report("string too long '%s...'", str);
613
}
614
str[n++] = c;
615
}
616
str[n++] = '\0';
617
618
/*
619
* Keywords
620
*/
621
for (c = 0; keywords[c].str != NULL; c++)
622
if (strcmp(keywords[c].str, str) == 0) {
623
val = keywords[c].val;
624
return (keywords[c].tok);
625
}
626
627
LIST_FOREACH(t, &types, link) {
628
if (strcmp(t->name, str) == 0) {
629
val = t->syntax;
630
return (TOK_DEFTYPE);
631
}
632
}
633
return (TOK_STR);
634
}
635
if (isprint(c))
636
errx(1, "%u: unexpected character '%c'", input->lno, c);
637
else
638
errx(1, "%u: unexpected character 0x%02x", input->lno,
639
(u_int)c);
640
}
641
static int
642
gettoken(void)
643
{
644
int tok = gettoken_internal();
645
646
if (debug) {
647
switch (tok) {
648
649
case TOK_EOF:
650
fprintf(stderr, "EOF ");
651
break;
652
653
case TOK_NUM:
654
fprintf(stderr, "NUM(%lu) ", val);
655
break;
656
657
case TOK_STR:
658
fprintf(stderr, "STR(%s) ", str);
659
break;
660
661
case TOK_ACCESS:
662
fprintf(stderr, "ACCESS(%lu) ", val);
663
break;
664
665
case TOK_TYPE:
666
fprintf(stderr, "TYPE(%lu) ", val);
667
break;
668
669
case TOK_ENUM:
670
fprintf(stderr, "ENUM ");
671
break;
672
673
case TOK_BITS:
674
fprintf(stderr, "BITS ");
675
break;
676
677
case TOK_TYPEDEF:
678
fprintf(stderr, "TYPEDEF ");
679
break;
680
681
case TOK_DEFTYPE:
682
fprintf(stderr, "DEFTYPE(%s,%lu) ", str, val);
683
break;
684
685
case TOK_INCLUDE:
686
fprintf(stderr, "INCLUDE ");
687
break;
688
689
case TOK_FILENAME:
690
fprintf(stderr, "FILENAME ");
691
break;
692
693
default:
694
if (tok < TOK_EOF) {
695
if (isprint(tok))
696
fprintf(stderr, "'%c' ", tok);
697
else if (tok == '\n')
698
fprintf(stderr, "\n");
699
else
700
fprintf(stderr, "%02x ", tok);
701
} else
702
abort();
703
break;
704
}
705
}
706
return (tok);
707
}
708
709
/**
710
* Pushback a token
711
*/
712
static void
713
pushback(enum tok tok)
714
{
715
716
if (saved_token != -1)
717
abort();
718
saved_token = tok;
719
}
720
721
/*
722
* Create a new type
723
*/
724
static struct type *
725
make_type(const char *s)
726
{
727
struct type *t;
728
729
t = xalloc(sizeof(*t));
730
t->name = savestr(s);
731
t->is_enum = 0;
732
t->syntax = SNMP_SYNTAX_NULL;
733
t->from_fname = savestr(input->fname);
734
t->from_lno = input->lno;
735
TAILQ_INIT(&t->enums);
736
LIST_INSERT_HEAD(&types, t, link);
737
738
return (t);
739
}
740
741
/*
742
* Parse a type. We've seen the ENUM or type keyword already. Leave next
743
* token.
744
*/
745
static u_int
746
parse_type(enum tok *tok, struct type *t, const char *vname, char **subtype)
747
{
748
u_int syntax;
749
struct enums *e;
750
751
syntax = val;
752
if (subtype != NULL)
753
*subtype = NULL;
754
755
if (*tok == TOK_ENUM || *tok == TOK_BITS) {
756
if (t == NULL && vname != NULL) {
757
t = make_type(vname);
758
t->is_enum = (*tok == TOK_ENUM);
759
t->is_bits = (*tok == TOK_BITS);
760
t->syntax = syntax;
761
}
762
if (gettoken() != '(')
763
report("'(' expected after ENUM");
764
765
if ((*tok = gettoken()) == TOK_EOF)
766
report("unexpected EOF in ENUM");
767
do {
768
e = NULL;
769
if (t != NULL) {
770
e = xalloc(sizeof(*e));
771
}
772
if (*tok == '-') {
773
if ((*tok = gettoken()) == TOK_EOF)
774
report("unexpected EOF in ENUM");
775
e->value = -(long)val;
776
} else
777
e->value = val;
778
779
if (*tok != TOK_NUM)
780
report("need value for ENUM/BITS");
781
if (gettoken() != TOK_STR)
782
report("need string in ENUM/BITS");
783
e->name = savetok();
784
TAILQ_INSERT_TAIL(&t->enums, e, link);
785
if ((*tok = gettoken()) == TOK_EOF)
786
report("unexpected EOF in ENUM/BITS");
787
} while (*tok != ')');
788
*tok = gettoken();
789
790
} else if (*tok == TOK_DEFTYPE) {
791
*tok = gettoken();
792
793
} else {
794
if ((*tok = gettoken()) == '|') {
795
if (gettoken() != TOK_STR)
796
report("subtype expected after '|'");
797
if (subtype != NULL)
798
*subtype = savetok();
799
*tok = gettoken();
800
}
801
}
802
803
return (syntax);
804
}
805
806
/*
807
* Parse the next node (complete with all subnodes)
808
*/
809
static struct node *
810
parse(enum tok tok)
811
{
812
struct node *node;
813
struct node *sub;
814
u_int index_count;
815
816
node = xalloc(sizeof(struct node));
817
node->lno = input->lno;
818
node->flags = 0;
819
820
if (tok != '(')
821
report("'(' expected at begin of node");
822
if (gettoken() != TOK_NUM)
823
report("node id expected after opening '('");
824
if (val > ASN_MAXID)
825
report("subid too large '%lu'", val);
826
node->id = (asn_subid_t)val;
827
if (gettoken() != TOK_STR)
828
report("node name expected after '(' ID");
829
node->name = savetok();
830
831
if ((tok = gettoken()) == TOK_TYPE || tok == TOK_DEFTYPE ||
832
tok == TOK_ENUM || tok == TOK_BITS) {
833
/* LEAF or COLUM */
834
char *subtype;
835
u_int syntax = parse_type(&tok, NULL, node->name, &subtype);
836
837
if (tok == TOK_STR) {
838
/* LEAF */
839
node->type = NODE_LEAF;
840
node->u.leaf.func = savetok();
841
node->u.leaf.syntax = syntax;
842
node->u.leaf.subtype = subtype;
843
tok = gettoken();
844
} else {
845
/* COLUMN */
846
node->type = NODE_COLUMN;
847
node->u.column.syntax = syntax;
848
node->u.column.subtype = subtype;
849
}
850
851
while (tok != ')') {
852
if (tok != TOK_ACCESS)
853
report("access keyword or ')' expected");
854
node->flags |= (u_int)val;
855
tok = gettoken();
856
}
857
858
} else if (tok == ':') {
859
/* ENTRY */
860
node->type = NODE_ENTRY;
861
TAILQ_INIT(&node->u.entry.subs);
862
863
index_count = 0;
864
node->u.entry.index = 0;
865
tok = gettoken();
866
while (tok == TOK_TYPE || tok == TOK_DEFTYPE ||
867
tok == TOK_ENUM || tok == TOK_BITS) {
868
char *subtype;
869
u_int syntax = parse_type(&tok, NULL, node->name,
870
&subtype);
871
if (index_count == SNMP_INDEXES_MAX)
872
report("too many table indexes");
873
node->u.entry.subtypes[index_count++] = subtype;
874
node->u.entry.index |=
875
syntax << (SNMP_INDEX_SHIFT * index_count);
876
}
877
node->u.entry.index |= index_count;
878
if (index_count == 0)
879
report("need at least one index");
880
if (tok != TOK_STR)
881
report("function name expected");
882
883
node->u.entry.func = savetok();
884
885
tok = gettoken();
886
887
while (tok != ')') {
888
sub = parse(tok);
889
TAILQ_INSERT_TAIL(&node->u.entry.subs, sub, link);
890
tok = gettoken();
891
}
892
893
} else {
894
/* subtree */
895
node->type = NODE_TREE;
896
TAILQ_INIT(&node->u.tree.subs);
897
898
while (tok != ')') {
899
sub = parse(tok);
900
TAILQ_INSERT_TAIL(&node->u.tree.subs, sub, link);
901
tok = gettoken();
902
}
903
}
904
return (node);
905
}
906
907
/*
908
* Parse a top level element. Return the tree if it was a tree, NULL
909
* otherwise.
910
*/
911
static struct node *
912
parse_top(enum tok tok)
913
{
914
struct type *t;
915
916
if (tok == '(')
917
return (parse(tok));
918
919
if (tok == TOK_TYPEDEF) {
920
if (gettoken() != TOK_STR)
921
report("type name expected after typedef");
922
923
t = make_type(str);
924
925
tok = gettoken();
926
t->is_enum = (tok == TOK_ENUM);
927
t->is_bits = (tok == TOK_BITS);
928
929
t->syntax = parse_type(&tok, t, NULL, NULL);
930
pushback(tok);
931
932
return (NULL);
933
}
934
935
if (tok == TOK_INCLUDE) {
936
if (gettoken() != TOK_FILENAME)
937
report("filename expected in include directive");
938
939
input_fopen(str, val);
940
return (NULL);
941
}
942
943
report("'(' or 'typedef' expected");
944
}
945
946
/*
947
* Generate the C-code table part for one node.
948
*/
949
static void
950
gen_node(FILE *fp, const struct node *np, struct asn_oid *oid, u_int idx,
951
const char *func)
952
{
953
u_int n;
954
struct node *sub;
955
u_int syntax;
956
957
if (oid->len == ASN_MAXOIDLEN)
958
report_node(np, "OID too long");
959
oid->subs[oid->len++] = np->id;
960
961
if (np->type == NODE_TREE) {
962
TAILQ_FOREACH(sub, &np->u.tree.subs, link)
963
gen_node(fp, sub, oid, 0, NULL);
964
oid->len--;
965
return;
966
}
967
if (np->type == NODE_ENTRY) {
968
TAILQ_FOREACH(sub, &np->u.entry.subs, link)
969
gen_node(fp, sub, oid, np->u.entry.index,
970
np->u.entry.func);
971
oid->len--;
972
return;
973
}
974
975
/* leaf or column */
976
if ((np->flags & (FL_GET|FL_SET)) == 0) {
977
oid->len--;
978
return;
979
}
980
981
fprintf(fp, " {{ %u, {", oid->len);
982
for (n = 0; n < oid->len; n++)
983
fprintf(fp, " %u,", oid->subs[n]);
984
fprintf(fp, " }}, \"%s\", ", np->name);
985
986
if (np->type == NODE_COLUMN) {
987
syntax = np->u.column.syntax;
988
fprintf(fp, "SNMP_NODE_COLUMN, ");
989
} else {
990
syntax = np->u.leaf.syntax;
991
fprintf(fp, "SNMP_NODE_LEAF, ");
992
}
993
994
switch (syntax) {
995
996
case SNMP_SYNTAX_NULL:
997
fprintf(fp, "SNMP_SYNTAX_NULL, ");
998
break;
999
1000
case SNMP_SYNTAX_INTEGER:
1001
fprintf(fp, "SNMP_SYNTAX_INTEGER, ");
1002
break;
1003
1004
case SNMP_SYNTAX_OCTETSTRING:
1005
fprintf(fp, "SNMP_SYNTAX_OCTETSTRING, ");
1006
break;
1007
1008
case SNMP_SYNTAX_IPADDRESS:
1009
fprintf(fp, "SNMP_SYNTAX_IPADDRESS, ");
1010
break;
1011
1012
case SNMP_SYNTAX_OID:
1013
fprintf(fp, "SNMP_SYNTAX_OID, ");
1014
break;
1015
1016
case SNMP_SYNTAX_TIMETICKS:
1017
fprintf(fp, "SNMP_SYNTAX_TIMETICKS, ");
1018
break;
1019
1020
case SNMP_SYNTAX_COUNTER:
1021
fprintf(fp, "SNMP_SYNTAX_COUNTER, ");
1022
break;
1023
1024
case SNMP_SYNTAX_GAUGE:
1025
fprintf(fp, "SNMP_SYNTAX_GAUGE, ");
1026
break;
1027
1028
case SNMP_SYNTAX_COUNTER64:
1029
fprintf(fp, "SNMP_SYNTAX_COUNTER64, ");
1030
break;
1031
1032
case SNMP_SYNTAX_NOSUCHOBJECT:
1033
case SNMP_SYNTAX_NOSUCHINSTANCE:
1034
case SNMP_SYNTAX_ENDOFMIBVIEW:
1035
abort();
1036
}
1037
1038
if (np->type == NODE_COLUMN)
1039
fprintf(fp, "%s, ", func);
1040
else
1041
fprintf(fp, "%s, ", np->u.leaf.func);
1042
1043
fprintf(fp, "0");
1044
if (np->flags & FL_SET)
1045
fprintf(fp, "|SNMP_NODE_CANSET");
1046
fprintf(fp, ", %#x, NULL, NULL },\n", idx);
1047
oid->len--;
1048
return;
1049
}
1050
1051
/*
1052
* Generate the header file with the function declarations.
1053
*/
1054
static void
1055
gen_header(FILE *fp, const struct node *np, u_int oidlen, const char *func)
1056
{
1057
char f[MAXSTR + 4];
1058
struct node *sub;
1059
struct func *ptr;
1060
1061
oidlen++;
1062
if (np->type == NODE_TREE) {
1063
TAILQ_FOREACH(sub, &np->u.tree.subs, link)
1064
gen_header(fp, sub, oidlen, NULL);
1065
return;
1066
}
1067
if (np->type == NODE_ENTRY) {
1068
TAILQ_FOREACH(sub, &np->u.entry.subs, link)
1069
gen_header(fp, sub, oidlen, np->u.entry.func);
1070
return;
1071
}
1072
1073
if((np->flags & (FL_GET|FL_SET)) == 0)
1074
return;
1075
1076
if (np->type == NODE_COLUMN) {
1077
if (func == NULL)
1078
errx(1, "column without function (%s) - probably "
1079
"outside of a table", np->name);
1080
sprintf(f, "%s", func);
1081
} else
1082
sprintf(f, "%s", np->u.leaf.func);
1083
1084
LIST_FOREACH(ptr, &funcs, link)
1085
if (strcmp(ptr->name, f) == 0)
1086
break;
1087
1088
if (ptr == NULL) {
1089
ptr = xalloc(sizeof(*ptr));
1090
ptr->name = savestr(f);
1091
LIST_INSERT_HEAD(&funcs, ptr, link);
1092
1093
fprintf(fp, "int %s(struct snmp_context *, "
1094
"struct snmp_value *, u_int, u_int, "
1095
"enum snmp_op);\n", f);
1096
}
1097
1098
fprintf(fp, "# define LEAF_%s %u\n", np->name, np->id);
1099
}
1100
1101
/*
1102
* Generate the OID table.
1103
*/
1104
static void
1105
gen_table(FILE *fp, const struct node *node)
1106
{
1107
struct asn_oid oid;
1108
1109
fprintf(fp, "#include <sys/types.h>\n");
1110
fprintf(fp, "#include <stdio.h>\n");
1111
#ifdef HAVE_STDINT_H
1112
fprintf(fp, "#include <stdint.h>\n");
1113
#endif
1114
if (localincs) {
1115
fprintf(fp, "#include \"asn1.h\"\n");
1116
fprintf(fp, "#include \"snmp.h\"\n");
1117
fprintf(fp, "#include \"snmpagent.h\"\n");
1118
} else {
1119
fprintf(fp, "#include <bsnmp/asn1.h>\n");
1120
fprintf(fp, "#include <bsnmp/snmp.h>\n");
1121
fprintf(fp, "#include <bsnmp/snmpagent.h>\n");
1122
}
1123
fprintf(fp, "#include \"%stree.h\"\n", file_prefix);
1124
fprintf(fp, "\n");
1125
1126
fprintf(fp, "const struct snmp_node %sctree[] = {\n", file_prefix);
1127
1128
oid.len = PREFIX_LEN;
1129
memcpy(oid.subs, prefix, sizeof(prefix));
1130
gen_node(fp, node, &oid, 0, NULL);
1131
1132
fprintf(fp, "};\n\n");
1133
}
1134
1135
static void
1136
print_syntax(u_int syntax)
1137
{
1138
u_int i;
1139
1140
for (i = 0; keywords[i].str != NULL; i++)
1141
if (keywords[i].tok == TOK_TYPE &&
1142
keywords[i].val == syntax) {
1143
printf(" %s", keywords[i].str);
1144
return;
1145
}
1146
abort();
1147
}
1148
1149
/*
1150
* Generate a tree definition file
1151
*/
1152
static void
1153
gen_tree(const struct node *np, int level)
1154
{
1155
const struct node *sp;
1156
u_int i;
1157
1158
printf("%*s(%u %s", 2 * level, "", np->id, np->name);
1159
1160
switch (np->type) {
1161
1162
case NODE_LEAF:
1163
print_syntax(np->u.leaf.syntax);
1164
if (np->u.leaf.subtype != NULL)
1165
printf(" | %s", np->u.leaf.subtype);
1166
printf(" %s%s%s)\n", np->u.leaf.func,
1167
(np->flags & FL_GET) ? " GET" : "",
1168
(np->flags & FL_SET) ? " SET" : "");
1169
break;
1170
1171
case NODE_TREE:
1172
if (TAILQ_EMPTY(&np->u.tree.subs)) {
1173
printf(")\n");
1174
} else {
1175
printf("\n");
1176
TAILQ_FOREACH(sp, &np->u.tree.subs, link)
1177
gen_tree(sp, level + 1);
1178
printf("%*s)\n", 2 * level, "");
1179
}
1180
break;
1181
1182
case NODE_ENTRY:
1183
printf(" :");
1184
1185
for (i = 0; i < SNMP_INDEX_COUNT(np->u.entry.index); i++) {
1186
print_syntax(SNMP_INDEX(np->u.entry.index, i));
1187
if (np->u.entry.subtypes[i] != NULL)
1188
printf(" | %s", np->u.entry.subtypes[i]);
1189
}
1190
printf(" %s\n", np->u.entry.func);
1191
TAILQ_FOREACH(sp, &np->u.entry.subs, link)
1192
gen_tree(sp, level + 1);
1193
printf("%*s)\n", 2 * level, "");
1194
break;
1195
1196
case NODE_COLUMN:
1197
print_syntax(np->u.column.syntax);
1198
if (np->u.column.subtype != NULL)
1199
printf(" | %s", np->u.column.subtype);
1200
printf("%s%s)\n", (np->flags & FL_GET) ? " GET" : "",
1201
(np->flags & FL_SET) ? " SET" : "");
1202
break;
1203
}
1204
}
1205
1206
static int
1207
extract(FILE *fp, const struct node *np, struct asn_oid *oid, const char *obj,
1208
const struct asn_oid *idx, const char *iname)
1209
{
1210
struct node *sub;
1211
u_long n;
1212
1213
if (oid->len == ASN_MAXOIDLEN)
1214
report_node(np, "OID too long");
1215
oid->subs[oid->len++] = np->id;
1216
1217
if (strcmp(obj, np->name) == 0) {
1218
if (oid->len + idx->len >= ASN_MAXOIDLEN)
1219
report_node(np, "OID too long");
1220
fprintf(fp, "#define OID_%s%s\t%u\n", np->name,
1221
iname ? iname : "", np->id);
1222
fprintf(fp, "#define OIDLEN_%s%s\t%u\n", np->name,
1223
iname ? iname : "", oid->len + idx->len);
1224
fprintf(fp, "#define OIDX_%s%s\t{ %u, {", np->name,
1225
iname ? iname : "", oid->len + idx->len);
1226
for (n = 0; n < oid->len; n++)
1227
fprintf(fp, " %u,", oid->subs[n]);
1228
for (n = 0; n < idx->len; n++)
1229
fprintf(fp, " %u,", idx->subs[n]);
1230
fprintf(fp, " } }\n");
1231
return (0);
1232
}
1233
1234
if (np->type == NODE_TREE) {
1235
TAILQ_FOREACH(sub, &np->u.tree.subs, link)
1236
if (!extract(fp, sub, oid, obj, idx, iname))
1237
return (0);
1238
} else if (np->type == NODE_ENTRY) {
1239
TAILQ_FOREACH(sub, &np->u.entry.subs, link)
1240
if (!extract(fp, sub, oid, obj, idx, iname))
1241
return (0);
1242
}
1243
oid->len--;
1244
return (1);
1245
}
1246
1247
static int
1248
gen_extract(FILE *fp, const struct node *root, char *object)
1249
{
1250
struct asn_oid oid;
1251
struct asn_oid idx;
1252
char *s, *e, *end, *iname;
1253
u_long ul;
1254
int ret;
1255
1256
/* look whether the object to extract has an index part */
1257
idx.len = 0;
1258
iname = NULL;
1259
s = strchr(object, '.');
1260
if (s != NULL) {
1261
iname = malloc(strlen(s) + 1);
1262
if (iname == NULL)
1263
err(1, "cannot allocated index");
1264
1265
strcpy(iname, s);
1266
for (e = iname; *e != '\0'; e++)
1267
if (*e == '.')
1268
*e = '_';
1269
1270
*s++ = '\0';
1271
while (s != NULL) {
1272
if (*s == '\0')
1273
errx(1, "bad index syntax");
1274
if ((e = strchr(s, '.')) != NULL)
1275
*e++ = '\0';
1276
1277
errno = 0;
1278
ul = strtoul(s, &end, 0);
1279
if (*end != '\0')
1280
errx(1, "bad index syntax '%s'", end);
1281
if (errno != 0)
1282
err(1, "bad index syntax");
1283
1284
if (idx.len == ASN_MAXOIDLEN)
1285
errx(1, "index oid too large");
1286
idx.subs[idx.len++] = ul;
1287
1288
s = e;
1289
}
1290
}
1291
1292
oid.len = PREFIX_LEN;
1293
memcpy(oid.subs, prefix, sizeof(prefix));
1294
ret = extract(fp, root, &oid, object, &idx, iname);
1295
if (iname != NULL)
1296
free(iname);
1297
1298
return (ret);
1299
}
1300
1301
1302
static void
1303
check_sub_order(const struct node *np, const struct node_list *subs)
1304
{
1305
int first;
1306
const struct node *sub;
1307
asn_subid_t maxid = 0;
1308
1309
/* ensure, that subids are ordered */
1310
first = 1;
1311
TAILQ_FOREACH(sub, subs, link) {
1312
if (!first && sub->id <= maxid)
1313
report_node(np, "subids not ordered at %s", sub->name);
1314
maxid = sub->id;
1315
first = 0;
1316
}
1317
}
1318
1319
/*
1320
* Do some sanity checks on the tree definition and do some computations.
1321
*/
1322
static void
1323
check_tree(struct node *np)
1324
{
1325
struct node *sub;
1326
1327
if (np->type == NODE_LEAF || np->type == NODE_COLUMN) {
1328
if ((np->flags & (FL_GET|FL_SET)) != 0)
1329
tree_size++;
1330
return;
1331
}
1332
1333
if (np->type == NODE_ENTRY) {
1334
check_sub_order(np, &np->u.entry.subs);
1335
1336
/* ensure all subnodes are columns */
1337
TAILQ_FOREACH(sub, &np->u.entry.subs, link) {
1338
if (sub->type != NODE_COLUMN)
1339
report_node(np, "entry subnode '%s' is not "
1340
"a column", sub->name);
1341
check_tree(sub);
1342
}
1343
} else {
1344
check_sub_order(np, &np->u.tree.subs);
1345
1346
TAILQ_FOREACH(sub, &np->u.tree.subs, link)
1347
check_tree(sub);
1348
}
1349
}
1350
1351
static void
1352
merge_subs(struct node_list *s1, struct node_list *s2)
1353
{
1354
struct node *n1, *n2;
1355
1356
while (!TAILQ_EMPTY(s2)) {
1357
n2 = TAILQ_FIRST(s2);
1358
TAILQ_REMOVE(s2, n2, link);
1359
1360
TAILQ_FOREACH(n1, s1, link)
1361
if (n1->id >= n2->id)
1362
break;
1363
if (n1 == NULL)
1364
TAILQ_INSERT_TAIL(s1, n2, link);
1365
else if (n1->id > n2->id)
1366
TAILQ_INSERT_BEFORE(n1, n2, link);
1367
else {
1368
if (n1->type == NODE_TREE && n2->type == NODE_TREE) {
1369
if (strcmp(n1->name, n2->name) != 0)
1370
errx(1, "trees to merge must have "
1371
"same name '%s' '%s'", n1->name,
1372
n2->name);
1373
merge_subs(&n1->u.tree.subs, &n2->u.tree.subs);
1374
free(n2);
1375
} else if (n1->type == NODE_ENTRY &&
1376
n2->type == NODE_ENTRY) {
1377
if (strcmp(n1->name, n2->name) != 0)
1378
errx(1, "entries to merge must have "
1379
"same name '%s' '%s'", n1->name,
1380
n2->name);
1381
if (n1->u.entry.index != n2->u.entry.index)
1382
errx(1, "entries to merge must have "
1383
"same index '%s'", n1->name);
1384
if (strcmp(n1->u.entry.func,
1385
n2->u.entry.func) != 0)
1386
errx(1, "entries to merge must have "
1387
"same op '%s'", n1->name);
1388
merge_subs(&n1->u.entry.subs,
1389
&n2->u.entry.subs);
1390
free(n2);
1391
} else
1392
errx(1, "entities to merge must be both "
1393
"trees or both entries: %s, %s",
1394
n1->name, n2->name);
1395
}
1396
}
1397
}
1398
1399
static void
1400
merge(struct node **root, struct node *t)
1401
{
1402
1403
if (*root == NULL) {
1404
*root = t;
1405
return;
1406
}
1407
if (t == NULL)
1408
return;
1409
1410
/* both must be trees */
1411
if ((*root)->type != NODE_TREE)
1412
errx(1, "root is not a tree");
1413
if (t->type != NODE_TREE)
1414
errx(1, "can merge only with tree");
1415
if ((*root)->id != t->id)
1416
errx(1, "trees to merge must have same id");
1417
1418
merge_subs(&(*root)->u.tree.subs, &t->u.tree.subs);
1419
}
1420
1421
static void
1422
unminus(FILE *fp, const char *s)
1423
{
1424
1425
while (*s != '\0') {
1426
if (*s == '-')
1427
fprintf(fp, "_");
1428
else
1429
fprintf(fp, "%c", *s);
1430
s++;
1431
}
1432
}
1433
1434
/**
1435
* Generate helper functions for an enum.
1436
*
1437
* We always generate a switch statement for the isok function. The compiler
1438
* optimizes this into range checks if possible.
1439
*
1440
* \param fp file to write to
1441
* \param t type
1442
* \param ccode generate externally visible non-inline functions
1443
*/
1444
static void
1445
gen_enum_funcs(FILE *fp, const struct type *t, int ccode)
1446
{
1447
fprintf(fp, "\n");
1448
1449
if (!ccode)
1450
fprintf(fp, "static inline ");
1451
fprintf(fp, "int\n");
1452
fprintf(fp, "isok_%s(enum %s s)\n", t->name, t->name);
1453
fprintf(fp, "{\n");
1454
fprintf(fp, " switch (s) {\n");
1455
1456
const struct enums *e;
1457
TAILQ_FOREACH(e, &t->enums, link) {
1458
fprintf(fp, "\t case %s_", t->name);
1459
unminus(fp, e->name);
1460
fprintf(fp, ":\n");
1461
}
1462
1463
fprintf(fp, " return (1);\n");
1464
fprintf(fp, " }\n");
1465
fprintf(fp, " return (0);\n");
1466
fprintf(fp, "}\n\n");
1467
1468
if (!ccode)
1469
fprintf(fp, "static inline ");
1470
fprintf(fp, "const char *\n");
1471
fprintf(fp, "tostr_%s(enum %s s)\n", t->name, t->name);
1472
fprintf(fp, "{\n");
1473
fprintf(fp, " static const char *vals[] = { STRING_%s };\n", t->name);
1474
fprintf(fp, "\n");
1475
fprintf(fp, " if (isok_%s(s))\n", t->name);
1476
fprintf(fp, " return (vals[(int)s - STROFF_%s]);\n", t->name);
1477
fprintf(fp, " return (\"%s???\");\n", t->name);
1478
fprintf(fp, "}\n\n");
1479
1480
if (!ccode)
1481
fprintf(fp, "static inline ");
1482
fprintf(fp, "int\n");
1483
fprintf(fp, "fromstr_%s(const char *str, enum %s *s)\n",
1484
t->name, t->name);
1485
fprintf(fp, "{\n");
1486
fprintf(fp, " static const char *vals[] = { STRING_%s };\n", t->name);
1487
fprintf(fp, "\n");
1488
fprintf(fp, " for (size_t i = 0; i < sizeof(vals)/sizeof(vals[0]); i++) {\n");
1489
fprintf(fp, " if (vals[i] != NULL && strcmp(vals[i], str) == 0) {\n");
1490
fprintf(fp, " *s = i + STROFF_%s;\n", t->name);
1491
fprintf(fp, " return (1);\n");
1492
fprintf(fp, " }\n");
1493
fprintf(fp, " }\n");
1494
fprintf(fp, " return (0);\n");
1495
fprintf(fp, "}\n");
1496
}
1497
1498
/**
1499
* Generate a definition for the enum packed into a guard against multiple
1500
* definitions.
1501
*
1502
* \param fp file to write definition to
1503
* \param t type
1504
* \param dof generate functions too
1505
*/
1506
static void
1507
gen_enum(FILE *fp, const struct type *t, int dof)
1508
{
1509
const struct enums *e;
1510
long min = LONG_MAX;
1511
1512
fprintf(fp, "\n");
1513
fprintf(fp, "#ifndef %s_defined__\n", t->name);
1514
fprintf(fp, "#define %s_defined__\n", t->name);
1515
fprintf(fp, "/*\n");
1516
fprintf(fp, " * From %s:%u\n", t->from_fname, t->from_lno);
1517
fprintf(fp, " */\n");
1518
fprintf(fp, "enum %s {\n", t->name);
1519
TAILQ_FOREACH(e, &t->enums, link) {
1520
fprintf(fp, "\t%s_", t->name);
1521
unminus(fp, e->name);
1522
fprintf(fp, " = %ld,\n", e->value);
1523
if (e->value < min)
1524
min = e->value;
1525
}
1526
fprintf(fp, "};\n");
1527
fprintf(fp, "#define STROFF_%s %ld\n", t->name, min);
1528
fprintf(fp, "#define STRING_%s \\\n", t->name);
1529
TAILQ_FOREACH(e, &t->enums, link) {
1530
fprintf(fp, "\t[%ld] = \"%s_", e->value - min, t->name);
1531
unminus(fp, e->name);
1532
fprintf(fp, "\",\\\n");
1533
}
1534
fprintf(fp, "\n");
1535
if (dof) {
1536
fprintf(fp, "#ifdef SNMPENUM_FUNCS\n");
1537
fprintf(fp, "\n");
1538
gen_enum_funcs(fp, t, 0);
1539
fprintf(fp, "\n");
1540
fprintf(fp, "#endif\n");
1541
fprintf(fp, "\n");
1542
}
1543
fprintf(fp, "#endif /* %s_defined__ */\n", t->name);
1544
}
1545
1546
/**
1547
* Generate helper functions for an enum. This generates code for a c file.
1548
*
1549
* \param fp file to write to
1550
* \param name enum name
1551
*/
1552
static int
1553
gen_enum_funcs_str(FILE *fp, const char *name)
1554
{
1555
const struct type *t;
1556
1557
LIST_FOREACH(t, &types, link)
1558
if ((t->is_enum || t->is_bits) && strcmp(t->name, name) == 0) {
1559
gen_enum_funcs(fp, t, 1);
1560
return (0);
1561
}
1562
1563
return (-1);
1564
}
1565
1566
/**
1567
* Generate helper functions for all enums.
1568
*
1569
* \param fp file to write to
1570
* \param ccode generate externally visible non-inline functions
1571
*/
1572
static void
1573
gen_all_enum_funcs(FILE *fp, int ccode)
1574
{
1575
const struct type *t;
1576
1577
LIST_FOREACH(t, &types, link)
1578
if (t->is_enum || t->is_bits)
1579
gen_enum_funcs(fp, t, ccode);
1580
}
1581
1582
static void
1583
gen_enums(FILE *fp, int dof)
1584
{
1585
const struct type *t;
1586
1587
LIST_FOREACH(t, &types, link)
1588
if (t->is_enum || t->is_bits)
1589
gen_enum(fp, t, dof);
1590
}
1591
1592
/**
1593
* Extract a given enum to the specified file and optionally generate static
1594
* inline helper functions for them.
1595
*
1596
* \param fp file to print on
1597
* \param name name of the enum
1598
* \param gen_funcs generate the functions too
1599
*
1600
* \return 0 if found, -1 otherwise
1601
*/
1602
static int
1603
extract_enum(FILE *fp, const char *name, int gen_funcs)
1604
{
1605
const struct type *t;
1606
1607
LIST_FOREACH(t, &types, link)
1608
if ((t->is_enum || t->is_bits) && strcmp(t->name, name) == 0) {
1609
gen_enum(fp, t, gen_funcs);
1610
return (0);
1611
}
1612
return (-1);
1613
}
1614
1615
/**
1616
* Extract all enums to the given file and optionally generate static inline
1617
* helper functions for them.
1618
*
1619
* \param fp file to print on
1620
* \param gen_funcs generate the functions too
1621
*/
1622
static void
1623
extract_all_enums(FILE *fp, int gen_funcs)
1624
{
1625
const struct type *t;
1626
1627
LIST_FOREACH(t, &types, link)
1628
if (t->is_enum || t->is_bits)
1629
gen_enum(fp, t, gen_funcs);
1630
}
1631
1632
/**
1633
* Extract enums and optionally generate some helper functions for them.
1634
*
1635
* \param argc number of arguments
1636
* \param argv arguments (enum names)
1637
* \param gen_funcs which functions to generate
1638
*/
1639
static void
1640
make_enums(int argc, char *argv[], enum gen_funcs gen_funcs)
1641
{
1642
if (gen_funcs == GEN_FUNCS_C) {
1643
if (argc == 0)
1644
gen_all_enum_funcs(stdout, 1);
1645
else {
1646
for (int i = 0; i < argc; i++)
1647
if (gen_enum_funcs_str(stdout, argv[i]))
1648
errx(1, "enum not found: %s", argv[i]);
1649
}
1650
} else {
1651
if (argc == 0)
1652
extract_all_enums(stdout, gen_funcs == GEN_FUNCS_H);
1653
else {
1654
for (int i = 0; i < argc; i++)
1655
if (extract_enum(stdout, argv[i],
1656
gen_funcs == GEN_FUNCS_H))
1657
errx(1, "enum not found: %s", argv[i]);
1658
}
1659
}
1660
}
1661
1662
/**
1663
* Produce the operation tables for the daemon or a module.
1664
*
1665
* \param root tree root
1666
* \param gen_funcs generate enum funcs
1667
*/
1668
static void
1669
make_table(const struct node *root, int gen_funcs)
1670
{
1671
FILE *fp;
1672
1673
char fname[MAXPATHLEN + 1];
1674
sprintf(fname, "%stree.h", file_prefix);
1675
if ((fp = fopen(fname, "w")) == NULL)
1676
err(1, "%s: ", fname);
1677
gen_header(fp, root, PREFIX_LEN, NULL);
1678
1679
fprintf(fp, "\n#ifdef SNMPTREE_TYPES\n");
1680
gen_enums(fp, gen_funcs);
1681
fprintf(fp, "\n#endif /* SNMPTREE_TYPES */\n\n");
1682
1683
fprintf(fp, "#define %sCTREE_SIZE %u\n", file_prefix, tree_size);
1684
fprintf(fp, "extern const struct snmp_node %sctree[];\n", file_prefix);
1685
1686
fclose(fp);
1687
1688
sprintf(fname, "%stree.c", file_prefix);
1689
if ((fp = fopen(fname, "w")) == NULL)
1690
err(1, "%s: ", fname);
1691
gen_table(fp, root);
1692
fclose(fp);
1693
}
1694
1695
int
1696
main(int argc, char *argv[])
1697
{
1698
enum op op = OP_GEN;
1699
enum gen_funcs gen_funcs = GEN_FUNCS_NONE;
1700
1701
char *infile = NULL;
1702
1703
int opt;
1704
while ((opt = getopt(argc, argv, "dEeFfhI:i:lp:t")) != EOF)
1705
switch (opt) {
1706
1707
case 'd':
1708
debug = 1;
1709
break;
1710
1711
case 'E':
1712
if (op != OP_GEN && op != OP_ENUMS)
1713
errx(1, "-E conflicts with earlier options");
1714
op = OP_ENUMS;
1715
break;
1716
1717
case 'e':
1718
if (op != OP_GEN && op != OP_EXTRACT)
1719
errx(1, "-e conflicts with earlier options");
1720
op = OP_EXTRACT;
1721
break;
1722
1723
case 'F':
1724
if (gen_funcs != GEN_FUNCS_NONE &&
1725
gen_funcs != GEN_FUNCS_C)
1726
errx(1, "-F conflicts with -f");
1727
gen_funcs = GEN_FUNCS_C;
1728
break;
1729
1730
case 'f':
1731
if (gen_funcs != GEN_FUNCS_NONE &&
1732
gen_funcs != GEN_FUNCS_H)
1733
errx(1, "-f conflicts with -F");
1734
gen_funcs = GEN_FUNCS_H;
1735
break;
1736
1737
case 'h':
1738
fprintf(stderr, "%s", usgtxt);
1739
exit(0);
1740
1741
case 'I':
1742
path_new(optarg);
1743
break;
1744
1745
case 'i':
1746
infile = optarg;
1747
break;
1748
1749
case 'l':
1750
localincs = 1;
1751
break;
1752
1753
case 'p':
1754
file_prefix = optarg;
1755
if (strlen(file_prefix) + strlen("tree.c") >
1756
MAXPATHLEN)
1757
errx(1, "prefix too long");
1758
break;
1759
1760
case 't':
1761
if (op != OP_GEN && op != OP_TREE)
1762
errx(1, "-t conflicts with earlier options");
1763
op = OP_TREE;
1764
break;
1765
}
1766
1767
argc -= optind;
1768
argv += optind;
1769
1770
/* open input */
1771
if (infile == NULL) {
1772
input_new(stdin, NULL, "<stdin>");
1773
} else {
1774
FILE *fp;
1775
if ((fp = fopen(infile, "r")) == NULL)
1776
err(1, "%s", infile);
1777
input_new(fp, NULL, infile);
1778
}
1779
1780
/* parse and check input */
1781
struct node *root = parse_top(gettoken());
1782
1783
int tok;
1784
while ((tok = gettoken()) != TOK_EOF)
1785
merge(&root, parse_top(tok));
1786
1787
if (root)
1788
check_tree(root);
1789
1790
/* do what the user has requested */
1791
switch (op) {
1792
1793
case OP_EXTRACT:
1794
if (argc == 0)
1795
errx(1, "-e requires arguments");
1796
1797
for (int i = 0; i < argc; i++)
1798
if (gen_extract(stdout, root, argv[i]))
1799
errx(1, "object not found: %s", argv[i]);
1800
return (0);
1801
1802
case OP_ENUMS:
1803
make_enums(argc, argv, gen_funcs);
1804
return (0);
1805
1806
case OP_TREE:
1807
if (argc != 0)
1808
errx(1, "-t allows no arguments");
1809
gen_tree(root, 0);
1810
return (0);
1811
1812
case OP_GEN:
1813
if (argc != 0)
1814
errx(1, "tree generation allows no arguments");
1815
make_table(root, gen_funcs == GEN_FUNCS_H);
1816
return (0);
1817
}
1818
}
1819
1820