📄 parse.c
字号:
/*********************************************************** Copyright 1989 by Carnegie Mellon University All Rights ReservedPermission to use, copy, modify, and distribute this software and its documentation for any purpose and without fee is hereby granted, provided that the above copyright notice appear in all copies and thatboth that copyright notice and this permission notice appear in supporting documentation, and that the name of CMU not beused in advertising or publicity pertaining to distribution of thesoftware without specific, written prior permission. CMU DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDINGALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALLCMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES ORANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THISSOFTWARE.******************************************************************//* * parse.c */#include "config.h"#include <stdio.h>#if HAVE_UNISTD_H#include <unistd.h>#endif#if HAVE_STDLIB_H#include <stdlib.h>#endif#if HAVE_SYS_TYPES_H#include <sys/types.h>#endif#if HAVE_CTYPE_H#include <ctype.h>#endif#if HAVE_GNUMALLOC_H#include <gnumalloc.h>#elif HAVE_MALLOC_H && !defined(_SQUID_FREEBSD_) && !defined(_SQUID_NEXT_)#include <malloc.h>#endif#if HAVE_MEMORY_H#include <memory.h>#endif#ifdef HAVE_STRING_H#include <string.h>#endif#ifdef HAVE_STRINGS_H#include <strings.h>#endif#if HAVE_BSTRING_H#include <bstring.h>#endif#if HAVE_SYS_SOCKET_H#include <sys/socket.h>#endif#if HAVE_NETINET_IN_H#include <netinet/in.h>#endif#if HAVE_ARPA_INET_H#include <arpa/inet.h>#endif#if HAVE_SYS_TIME_H#include <sys/time.h>#endif#if HAVE_NETDB_H#include <netdb.h>#endif#if HAVE_ASSERT_H#include <assert.h>#endif#include "asn1.h"#include "snmp_vars.h"#include "parse.h"#include "snmp_debug.h"#include "util.h"#include "cache_snmp.h"/* * This is one element of an object identifier with either an integer subidentifier, * or a textual string label, or both. * The subid is -1 if not present, and label is NULL if not present. */struct subid { int subid; char *label;};/* * A linked list of nodes. */struct node { struct node *next; char label[64]; /* This node's (unique) textual name */ u_int subid; /* This node's integer subidentifier */ char parent[64]; /* The parent's textual name */ int type; /* The type of object this represents */ struct enum_list *enums; /* (optional) list of enumerated integers (otherwise NULL) */};int Line = 1;/* types of tokens */#define CONTINUE -1#define ENDOFFILE 0#define LABEL 1#define SUBTREE 2#define SYNTAX 3#undef OBJID#define OBJID 4#define OCTETSTR 5#undef INTEGER#define INTEGER 6#define NETADDR 7#define IPADDR 8#define COUNTER 9#define GAUGE 10#define TIMETICKS 11#define OPAQUE 12#define NUL 13#define SEQUENCE 14#define OF 15 /* SEQUENCE OF */#define OBJTYPE 16#define ACCESS 17#define READONLY 18#define READWRITE 19#define WRITEONLY 20#undef NOACCESS#define NOACCESS 21#define STATUS 22#define MANDATORY 23#define OPTIONAL 24#define OBSOLETE 25#define RECOMMENDED 26#define PUNCT 27#define EQUALS 28#define NUMBER 29#define LEFTBRACKET 30#define RIGHTBRACKET 31#define LEFTPAREN 32#define RIGHTPAREN 33#define COMMA 34/* For SNMPv2 SMI pseudo-compliance */#define DESCRIPTION 35#define INDEX 36#define QUOTE 37struct tok { char *name; /* token name */ int len; /* length not counting nul */ int token; /* value */ int hash; /* hash of name */ struct tok *next; /* pointer to next in hash table */};struct tok tokens[] ={ {"obsolete", sizeof("obsolete") - 1, OBSOLETE}, {"Opaque", sizeof("Opaque") - 1, OPAQUE}, {"recommended", sizeof("recommended") - 1, RECOMMENDED}, {"optional", sizeof("optional") - 1, OPTIONAL}, {"mandatory", sizeof("mandatory") - 1, MANDATORY}, {"current", sizeof("current") - 1, MANDATORY}, {"not-accessible", sizeof("not-accessible") - 1, NOACCESS}, {"write-only", sizeof("write-only") - 1, WRITEONLY}, {"read-write", sizeof("read-write") - 1, READWRITE}, {"TimeTicks", sizeof("TimeTicks") - 1, TIMETICKS}, {"OBJECTIDENTIFIER", sizeof("OBJECTIDENTIFIER") - 1, OBJID}, /* * This CONTINUE appends the next word onto OBJECT, * hopefully matching OBJECTIDENTIFIER above. */ {"OBJECT", sizeof("OBJECT") - 1, CONTINUE}, {"NetworkAddress", sizeof("NetworkAddress") - 1, NETADDR}, {"Gauge", sizeof("Gauge") - 1, GAUGE}, {"OCTETSTRING", sizeof("OCTETSTRING") - 1, OCTETSTR}, {"OCTET", sizeof("OCTET") - 1, -1}, {"OF", sizeof("OF") - 1, OF}, {"SEQUENCE", sizeof("SEQUENCE") - 1, SEQUENCE}, {"NULL", sizeof("NULL") - 1, NUL}, {"IpAddress", sizeof("IpAddress") - 1, IPADDR}, {"INTEGER", sizeof("INTEGER") - 1, INTEGER}, {"Counter", sizeof("Counter") - 1, COUNTER}, {"read-only", sizeof("read-only") - 1, READONLY}, {"ACCESS", sizeof("ACCESS") - 1, ACCESS}, {"MAX-ACCESS", sizeof("MAX-ACCESS") - 1, ACCESS}, {"STATUS", sizeof("STATUS") - 1, STATUS}, {"SYNTAX", sizeof("SYNTAX") - 1, SYNTAX}, {"OBJECT-TYPE", sizeof("OBJECT-TYPE") - 1, OBJTYPE}, {"{", sizeof("{") - 1, LEFTBRACKET}, {"}", sizeof("}") - 1, RIGHTBRACKET}, {"::=", sizeof("::=") - 1, EQUALS}, {"(", sizeof("(") - 1, LEFTPAREN}, {")", sizeof(")") - 1, RIGHTPAREN}, {",", sizeof(",") - 1, COMMA}, {"DESCRIPTION", sizeof("DESCRIPTION") - 1, DESCRIPTION}, {"INDEX", sizeof("INDEX") - 1, INDEX}, {"\"", sizeof("\"") - 1, QUOTE}, {"END", sizeof("END") - 1, ENDOFFILE},/* Hacks for easier MIBFILE coercing */ {"read-create", sizeof("read-create") - 1, READWRITE}, {NULL}};#define HASHSIZE 32#define BUCKET(x) (x & 0x01F)static struct tok *buckets[HASHSIZE];static voidhash_init(){ register struct tok *tp; register char *cp; register int h; register int b; memset((char *) buckets, '\0', sizeof(buckets)); for (tp = tokens; tp->name; tp++) { for (h = 0, cp = tp->name; *cp; cp++) h += *cp; tp->hash = h; b = BUCKET(h); if (buckets[b]) tp->next = buckets[b]; /* BUG ??? */ buckets[b] = tp; }}#define NHASHSIZE 128#define NBUCKET(x) (x & 0x7F)struct node *nbuckets[NHASHSIZE];static voidinit_node_hash(nodes) struct node *nodes;{ register struct node *np, *nextp; register char *cp; register int hash; memset((char *) nbuckets, '\0', sizeof(nbuckets)); for (np = nodes; np;) { nextp = np->next; hash = 0; for (cp = np->parent; *cp; cp++) hash += *cp; np->next = nbuckets[NBUCKET(hash)]; nbuckets[NBUCKET(hash)] = np; np = nextp; }}static voidprint_error(string, token, type) char *string; char *token; int type;{ assert(string != NULL); if (type == ENDOFFILE) snmplib_debug(0, "%s(EOF): On or around line %d\n", string, Line); else if (token) snmplib_debug(0, "%s(%s): On or around line %d\n", string, token, Line); else snmplib_debug(0, "%s: On or around line %d\n", string, Line);}#ifdef TESTprint_subtree(tree, count) struct snmp_mib_tree *tree; int count;{ struct snmp_mib_tree *tp; int i; for (i = 0; i < count; i++) printf(" "); printf("Children of %s:\n", tree->label); count++; for (tp = tree->child_list; tp; tp = tp->next_peer) { for (i = 0; i < count; i++) printf(" "); printf("%s\n", tp->label); } for (tp = tree->child_list; tp; tp = tp->next_peer) { print_subtree(tp, count); }}#endif /* TEST */int translation_table[40];static voidbuild_translation_table(){ int count; for (count = 0; count < 40; count++) { switch (count) { case OBJID: translation_table[count] = TYPE_OBJID; break; case OCTETSTR: translation_table[count] = TYPE_OCTETSTR; break; case INTEGER: translation_table[count] = TYPE_INTEGER; break; case NETADDR: translation_table[count] = TYPE_IPADDR; break; case IPADDR: translation_table[count] = TYPE_IPADDR; break; case COUNTER: translation_table[count] = TYPE_COUNTER; break; case GAUGE: translation_table[count] = TYPE_GAUGE; break; case TIMETICKS: translation_table[count] = TYPE_TIMETICKS; break; case OPAQUE: translation_table[count] = TYPE_OPAQUE; break; case NUL: translation_table[count] = TYPE_NULL; break; default: translation_table[count] = TYPE_OTHER; break; } }}/* * Find all the children of root in the list of nodes. Link them into the * tree and out of the nodes list. */static voiddo_subtree(root, nodes) struct snmp_mib_tree *root; struct node **nodes;{ register struct snmp_mib_tree *tp; struct snmp_mib_tree *peer = NULL; register struct node *np = NULL, **headp = NULL; struct node *oldnp = NULL, *child_list = NULL, *childp = NULL; char *cp; int hash; tp = root; hash = 0; for (cp = tp->label; *cp; cp++) hash += *cp; headp = &nbuckets[NBUCKET(hash)]; /* * Search each of the nodes for one whose parent is root, and * move each into a separate list. */ for (np = *headp; np; np = np->next) { if ((*tp->label != *np->parent) || strcmp(tp->label, np->parent)) { if ((*tp->label == *np->label) && !strcmp(tp->label, np->label)) { /* if there is another node with the same label, assume that * any children after this point in the list belong to the other node. * This adds some scoping to the table and allows vendors to * reuse names such as "ip". */ break; } oldnp = np; } else { if (child_list == NULL) { child_list = childp = np; /* first entry in child list */ } else { childp->next = np; childp = np; } /* take this node out of the node list */ if (oldnp == NULL) { *headp = np->next; /* fix root of node list */ } else { oldnp->next = np->next; /* link around this node */ } } } if (childp) childp->next = 0; /* re-terminate list */ /* * Take each element in the child list and place it into the tree. */ for (np = child_list; np; np = np->next) { tp = (struct snmp_mib_tree *) xmalloc(sizeof(struct snmp_mib_tree)); tp->parent = root; tp->next_peer = NULL; tp->child_list = NULL; strcpy(tp->label, np->label); tp->subid = np->subid; tp->type = translation_table[np->type]; tp->enums = np->enums; np->enums = NULL; /* so we don't free them later */ if (root->child_list == NULL) { root->child_list = tp; } else { peer->next_peer = tp; } peer = tp;/* if (tp->type == TYPE_OTHER) */ do_subtree(tp, nodes); /* recurse on this child if it isn't an end node */ } /* free all nodes that were copied into tree */ oldnp = NULL; for (np = child_list; np; np = np->next) { if (oldnp) xfree(oldnp); oldnp = np; } if (oldnp) xfree(oldnp);}#ifndef TESTstatic#endifstruct snmp_mib_tree *build_tree(nodes) struct node *nodes;{ struct node *np; struct snmp_mib_tree *tp; int bucket, nodes_left = 0; /* build root node */ tp = (struct snmp_mib_tree *) xmalloc(sizeof(struct snmp_mib_tree)); tp->parent = NULL; tp->next_peer = NULL; tp->child_list = NULL; tp->enums = NULL; strcpy(tp->label, "iso"); tp->subid = 1; tp->type = 0; build_translation_table(); /* grow tree from this root node */ init_node_hash(nodes); /* XXX nodes isn't needed in do_subtree() ??? */ do_subtree(tp, &nodes);#ifdef TEST print_subtree(tp, 0);#endif /* TEST */ /* If any nodes are left, the tree is probably inconsistent */ for (bucket = 0; bucket < NHASHSIZE; bucket++) { if (nbuckets[bucket]) { nodes_left = 1; break; } } if (nodes_left) { snmplib_debug(0, "The mib description doesn't seem to be consistent.\n"); snmplib_debug(0, "Some nodes couldn't be linked under the \"iso\" tree.\n"); snmplib_debug(0, "these nodes are left:\n"); for (bucket = 0; bucket < NHASHSIZE; bucket++) { for (np = nbuckets[bucket]; np; np = np->next) snmplib_debug(5, "%s ::= { %s %d } (%d)\n", np->label, np->parent, np->subid, np->type); } } return tp;}/* * Parses a token from the file. The type of the token parsed is returned, * and the text is placed in the string pointed to by token. */static char last = ' ';static intget_token(fp, token) register FILE *fp; register char *token;{ register int ch; register char *cp = token; register int hash = 0; register struct tok *tp; *cp = 0; ch = last; /* skip all white space */ while (isspace(ch) && ch != -1) { ch = getc(fp); if (ch == '\n') Line++; } if (ch == -1) return ENDOFFILE; /* * Accumulate characters until end of token is found. Then attempt to match this * token as a reserved word. If a match is found, return the type. Else it is * a label. */ do { if (ch == '\n') Line++; if (isspace(ch) || ch == '(' || ch == ')' || ch == '{' || ch == '}' || ch == ',' || ch == '"') { if (!isspace(ch) && *token == 0) { hash += ch; *cp++ = ch; last = ' '; } else { last = ch; } *cp = '\0'; for (tp = buckets[BUCKET(hash)]; tp; tp = tp->next) { if ((tp->hash == hash) && (strcmp(tp->name, token) == 0)) break; } if (tp) { if (tp->token == CONTINUE) continue; return (tp->token); } if (token[0] == '-' && token[1] == '-') { /* strip comment */ while ((ch = getc(fp)) != -1) if (ch == '\n') { Line++; break; } if (ch == -1) return ENDOFFILE; last = ch; return get_token(fp, token); } for (cp = token; *cp; cp++) if (!isdigit(*cp)) return LABEL; return NUMBER; } else { hash += ch; *cp++ = ch; if (ch == '\n') Line++; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -