BSD 4_3_Net_2 development
[unix-history] / usr / src / contrib / isode / snmp / objects.c
/* objects.c - SMI object handling */
#ifndef lint
static char *rcsid = "$Header: /f/osi/snmp/RCS/objects.c,v 7.14 91/02/22 09:43:44 mrose Interim $";
#endif
/*
* $Header: /f/osi/snmp/RCS/objects.c,v 7.14 91/02/22 09:43:44 mrose Interim $
*
* Contributed by NYSERNet Inc. This work was partially supported by the
* U.S. Defense Advanced Research Projects Agency and the Rome Air Development
* Center of the U.S. Air Force Systems Command under contract number
* F30602-88-C-0016.
*
*
* $Log: objects.c,v $
* Revision 7.14 91/02/22 09:43:44 mrose
* Interim 6.8
*
* Revision 7.13 90/12/11 21:56:34 mrose
* again
*
* Revision 7.12 90/09/26 18:47:15 mrose
* more-compile
*
* Revision 7.11 90/08/30 15:11:09 mrose
* ho-hum
*
* Revision 7.10 90/07/09 14:48:54 mrose
* sync
*
* Revision 7.9 90/06/21 21:26:23 mrose
* 0.0
*
* Revision 7.8 90/06/20 21:38:21 mrose
* update
*
* Revision 7.7 90/06/12 09:22:06 mrose
* write-only
*
* Revision 7.6 90/05/28 21:49:51 mrose
* not-accessible
*
* Revision 7.5 90/05/13 16:18:14 mrose
* views
*
* Revision 7.4 90/05/12 17:37:04 mrose
* typo
*
* Revision 7.3 90/02/19 15:54:04 mrose
* touch-up
*
* Revision 7.2 90/02/17 10:38:22 mrose
* smux
*
* Revision 7.1 90/01/11 18:34:23 mrose
* real-sync
*
* Revision 7.0 89/11/23 22:23:18 mrose
* Release 6.0
*
*/
/*
* NOTICE
*
* Acquisition, use, and distribution of this module and related
* materials are subject to the restrictions of a license agreement.
* Consult the Preface in the User's Manual for the full terms of
* this agreement.
*
*/
#include <ctype.h>
#include <stdio.h>
#include "objects.h"
#include "tailor.h"
/* \f DATA */
#define TBUCKETS 0x80
static int once_only = 0;
static int compile_flag;
static OT compile_heap1;
static char *compile_heap2;
static unsigned int *compile_heap3;
static OID compile_heap4;
static OT Tbuckets[TBUCKETS];
static OT anchor;
static OT chain;
OID resolve ();
extern int errno;
/* \f OBJECTS */
static int THASH (name)
char *name;
{
char c;
register char *cp,
*dp;
for (c = *(dp = cp = name); *cp; cp++)
if (isupper (*cp))
c = tolower (*(dp = cp));
if (*++dp)
return (((c - *dp) & 0x1f) + (*(dp + 1) & 0x5f));
else
return (c & 0x7f);
}
#define OT_XXX 0x04
static int ot_compar (a, b)
OT *a,
*b;
{
int i = oid_cmp ((*a) -> ot_name, (*b) -> ot_name);
if (i == 0
&& (!((*a) -> ot_access & OT_XXX)
|| !((*b) -> ot_access & OT_XXX))) {
OID oid = (*a) -> ot_name;
register unsigned int *ip = oid -> oid_elements;
/* XXX: 0.0 is a special case */
if (oid -> oid_nelem == 2 && ip[0] == 0 && ip[1] == 0)
return 0;
if (PY_pepy[0])
(void) sprintf (PY_pepy + strlen (PY_pepy), ", ");
else
(void) sprintf (PY_pepy, "duplicate objects: ");
(void) sprintf (PY_pepy + strlen (PY_pepy), "\"%s\" and \"%s\"",
(*a) -> ot_text, (*b) -> ot_text);
(*a) -> ot_access |= OT_XXX, (*b) -> ot_access |= OT_XXX;
}
return i;
}
static char *roots[] = { "ccitt", "iso", "joint-iso-ccitt" };
int readobjects (file)
char *file;
{
register char *cp,
**ap;
char buffer[BUFSIZ],
line[BUFSIZ],
*vec[NVEC + NSLACK + 1];
register OT ot;
FILE *fp;
if (file == NULL)
file = "objects.defs";
if ((fp = fopen (file, "r")) == NULL
&& (fp = fopen (cp = isodefile (file, 0), "r")) == NULL) {
(void) sprintf (PY_pepy, "unable to read %s: %s",
cp, sys_errname (errno));
return NOTOK;
}
if (once_only == 0) {
bzero ((char *) Tbuckets, sizeof Tbuckets);
readsyntax ();
compile_flag = -1;
if (fgets (buffer, sizeof buffer, fp)
&& strncmp (buffer, "--* compiled",
sizeof "--* compiled" - 1) == 0) {
int i,
j,
k;
compile_flag = 1;
anchor = chain = NULL;
if (sscanf (buffer, "--* compiled %d %d %d", &i, &j, &k) == 3) {
if ((compile_heap1 = (OT) calloc ((unsigned) i,
sizeof *compile_heap1))
== NULL) {
(void) sprintf (PY_pepy,
"out of memory allocating %d objects", i);
goto you_lose;
}
if ((compile_heap2 = malloc ((unsigned) j)) == NULL) {
(void) sprintf (PY_pepy,
"out of memory allocating %d octets", j);
goto you_lose;
}
if ((compile_heap3 = (unsigned int *)
calloc ((unsigned) k, sizeof *compile_heap3))
== NULL) {
(void) sprintf (PY_pepy,
"out of memory allocating %d sub-identitifers",
k);
goto you_lose;
}
if ((compile_heap4 = (OID) calloc ((unsigned) i,
sizeof *compile_heap4))
== NULL) {
(void) sprintf (PY_pepy,
"out of memory allocating %d identitifers",
i);
goto you_lose;
}
}
else
compile_heap1 = NULLOT,
compile_heap2 = NULL,
compile_heap3 = NULL,
compile_heap4 = NULL;
}
else {
compile_flag = 0;
(void) rewind (fp);
for (ap = roots + (sizeof roots / sizeof roots[0]) - 1;
ap >= roots;
ap--) {
(void) sprintf (buffer, "%d", ap - roots);
if (read_name (*ap, buffer) == NOTOK) {
you_lose: ;
(void) fclose (fp);
return NOTOK;
}
}
}
once_only = 1;
}
else
if (compile_flag > 0) {
(void) sprintf (PY_pepy, "only one compiled file is allowed");
goto you_lose;
}
while (fgets (buffer, sizeof buffer, fp)) {
if (*buffer == '#' || strncmp (buffer, "--", 2) == 0)
continue;
if (cp = index (buffer, '\n'))
*cp = NULL;
(void) strcpy (line, buffer);
bzero ((char *) vec, sizeof vec);
switch (str2vec (buffer, vec)) {
case 0:
break;
case 2:
if (read_name (vec[0], vec[1]) == NOTOK)
goto you_lose;
break;
case 5:
if (read_type (vec) == NOTOK)
goto you_lose;
break;
default:
(void) sprintf (PY_pepy, "malformed line: \"%s\"", line);
goto you_lose;
}
}
(void) fclose (fp);
PY_pepy[0] = NULL;
if (compile_flag < 1) {
int again,
hit,
i;
register int j = 0;
register OT *op,
*ep;
OT *base,
oz;
hit = 1, oz = NULLOT;
do {
if (!hit) {
(void) sprintf (PY_pepy, "unable to resolve object \"%s\"",
oz -> ot_text);
return NOTOK;
}
again = hit = 0;
for (i = 0; i < TBUCKETS; i++)
for (ot = Tbuckets[i];
ot && ot -> ot_text;
ot = ot -> ot_chain)
if (ot -> ot_name == NULLOID)
if (ot -> ot_name = resolve (ot -> ot_id, ot))
hit = 1;
else
oz = ot, again = 1;
} while (again);
for (i = 0; i < TBUCKETS; i++)
for (ot = Tbuckets[i]; ot && ot -> ot_text; ot = ot -> ot_chain)
j++;
/* j > 1 ALWAYS */
if ((base = (OT *) malloc ((unsigned) (j * sizeof *base))) == NULL) {
(void) sprintf (PY_pepy, "out of memory");
return NOTOK;
}
op = base;
for (i = 0; i < TBUCKETS; i++)
for (ot = Tbuckets[i]; ot && ot -> ot_text; ot = ot -> ot_chain)
*op++ = ot;
ep = op;
qsort ((char *) base, j, sizeof *base, ot_compar);
op = base;
anchor = ot = *op++;
while (op < ep) {
ot -> ot_next = *op;
ot = *op++;
}
(chain = ot) -> ot_next = NULL;
free ((char *) base);
}
else {
for (ot = anchor; ot; ot = ot -> ot_next) {
OID oid;
if ((oid = str2oid (ot -> ot_id)) == NULLOID) {
(void) sprintf (PY_pepy,
"invalid OID (%s) for \"%s\" in compiled file",
ot -> ot_id, ot -> ot_text);
return NOTOK;
}
if (compile_heap3) {
ot -> ot_name = compile_heap4++;
bcopy ((char *) oid -> oid_elements,
(char *) (ot -> ot_name -> oid_elements
= compile_heap3),
(ot -> ot_name -> oid_nelem = oid -> oid_nelem)
* sizeof *oid -> oid_elements);
compile_heap3 += oid -> oid_nelem + 1;
}
else
if ((ot -> ot_name = oid_cpy (oid)) == NULLOID) {
(void) sprintf (PY_pepy, "out of memory");
return NOTOK;
}
}
if (add_objects_aux () == NOTOK)
return NOTOK;
}
#ifdef notdef
#ifdef DEBUG
dump_objects_by_tree ();
#endif
#endif
return (PY_pepy[0] ? NOTOK : OK);
}
/* \f */
static int read_name (name, value)
char *name,
*value;
{
int i;
register OT ot;
if (text2obj (name)) {
(void) sprintf (PY_pepy, "duplicate object \"%s\"", name);
return NOTOK;
}
if (compile_flag > 0 && compile_heap1)
ot = compile_heap1++;
else
if ((ot = (OT) calloc (1, sizeof *ot)) == NULL) {
(void) sprintf (PY_pepy, "out of memory");
return NOTOK;
}
if (compile_flag > 0 && compile_heap2) {
(void) strcpy (ot -> ot_text = compile_heap2, name);
compile_heap2 += strlen (compile_heap2) + 1;
(void) strcpy (ot -> ot_id = compile_heap2, value);
compile_heap2 += strlen (compile_heap2) + 1;
}
else
if ((ot -> ot_text = strdup (name)) == NULL
|| (ot -> ot_id = strdup (value)) == NULL) {
(void) sprintf (PY_pepy, "out of memory");
return NOTOK;
}
ot -> ot_chain = Tbuckets[i = THASH (name)];
Tbuckets[i] = ot;
if (compile_flag) {
if (chain)
chain -> ot_next = ot;
else
anchor = ot;
chain = ot;
}
return OK;
}
/* \f */
static int read_type (vec)
char **vec;
{
int i;
register OT ot;
if (text2obj (*vec)) {
(void) sprintf (PY_pepy, "duplicate object \"%s\"", *vec);
return NOTOK;
}
if (compile_flag > 0 && compile_heap1)
ot = compile_heap1++;
else
if ((ot = (OT) calloc (1, sizeof *ot)) == NULL) {
(void) sprintf (PY_pepy, "out of memory");
return NOTOK;
}
if (compile_flag > 0 && compile_heap2) {
(void) strcpy (ot -> ot_text = compile_heap2, *vec++);
compile_heap2 += strlen (compile_heap2) + 1;
(void) strcpy (ot -> ot_id = compile_heap2, *vec++);
compile_heap2 += strlen (compile_heap2) + 1;
}
else
if ((ot -> ot_text = strdup (*vec++)) == NULL
|| (ot -> ot_id = strdup (*vec++)) == NULL) {
(void) sprintf (PY_pepy, "out of memory");
return NOTOK;
}
if ((ot -> ot_syntax = text2syn (*vec)) == NULL
&& lexequ (*vec, "Aggregate")
&& debug)
fprintf (stderr,
"warning: object \"%s\" has unknown SYNTAX \"%s\"\n",
ot -> ot_text, *vec);
vec++;
if (lexequ (*vec, "read-only") == 0)
ot -> ot_access = OT_RDONLY;
else
if (lexequ (*vec, "read-write") == 0)
ot -> ot_access = OT_RDWRITE;
else
if (lexequ (*vec, "write-only") == 0)
ot -> ot_access = OT_WRONLY;
else
if (lexequ (*vec, "not-accessible") && debug)
fprintf (stderr,
"warning: object \"%s\" has unknown ACCESS \"%s\"\n",
ot -> ot_text, *vec);
vec++;
if (lexequ (*vec, "mandatory") == 0)
ot -> ot_status = OT_MANDATORY;
else
if (lexequ (*vec, "optional") == 0)
ot -> ot_status = OT_OPTIONAL;
else
if (lexequ (*vec, "deprecated") == 0)
ot -> ot_status = OT_DEPRECATED;
else
if (lexequ (*vec, "obsolete") && debug)
fprintf (stderr,
"warning: object \"%s\" has unknown STATUS \"%s\"\n",
ot -> ot_text, *vec);
vec++;
ot -> ot_chain = Tbuckets[i = THASH (ot -> ot_text)];
Tbuckets[i] = ot;
if (compile_flag > 0) {
chain -> ot_next = ot;
chain = ot;
}
return OK;
}
/* \f */
/* does not insert into THASH table... */
int add_objects (ot)
register OT ot;
{
register OID oid = ot -> ot_name;
register OT ot2,
*otp;
if (oid_cmp (chain -> ot_name, oid) < 0) {
chain -> ot_next = ot;
(chain = ot) -> ot_next = NULLOT;
}
else {
for (otp = &anchor; ot2 = *otp; otp = &ot2 -> ot_next)
if (oid_cmp (ot2 -> ot_name, oid) > 0)
break;
ot -> ot_next = ot2;
*otp = ot;
}
for (ot = anchor; ot; ot = ot -> ot_next)
ot -> ot_sibling = ot -> ot_children = NULLOT;
return add_objects_aux ();
}
static int add_objects_aux ()
{
register OT ot,
ot2;
for (ot = anchor; ot; ot = ot -> ot_next) {
OIDentifier oids;
if (ot -> ot_name -> oid_nelem <= 1)
continue;
ot2 = NULLOT;
for (oids.oid_elements = ot -> ot_name -> oid_elements,
oids.oid_nelem = ot -> ot_name -> oid_nelem - 1;
oids.oid_nelem > 0;
oids.oid_nelem--)
if (ot2 = name2obj (&oids))
break;
if (ot2) {
ot -> ot_sibling = ot2 -> ot_children;
ot2 -> ot_children = ot;
}
else
if (debug)
fprintf (stderr, "no distant parent for %s",
sprintoid (ot -> ot_name));
}
return OK;
}
/* \f */
OID text2oid (name)
char *name;
{
int i,
j;
register unsigned int *ip,
*jp;
unsigned int elements[NELEM + 1];
register char *cp;
OID oid,
new;
for (cp = name + strlen (name) - 1; cp >= name; cp--)
if (!isdigit (*cp) && *cp != '.')
break;
cp++;
if (isdigit (*cp) && cp != name)
for (cp++; *cp; cp++)
if (*cp == '.')
break;
if (*cp == NULL) /* name */
i = 0;
else
if (cp == name) { /* 1.3.6.1.2.1.1.1.0 */
if ((i = str2elem (cp, elements)) < 2)
return NULL;
}
else /* name.numbers */
if ((i = str2elem (cp + 1, elements)) < 1)
return NULL;
if (cp != name) {
*cp = NULL;
if ((oid = resolve (name, NULLOT)) == NULLOID)
return NULL;
if (i == 0)
return oid;
j = oid -> oid_nelem;
}
else
oid = NULL, j = 0;
if ((new = (OID) malloc (sizeof *new)) == NULLOID) {
oid_free (oid);
return NULL;
}
if ((ip = (unsigned int *) malloc ((unsigned) (i + j + 1) * sizeof *ip))
== NULL) {
oid_free (oid);
free ((char *) new);
}
new -> oid_elements = ip, new -> oid_nelem = i + j;
if (oid) {
for (j = 0, jp = oid -> oid_elements; j < oid -> oid_nelem; j++, jp++)
*ip++ = *jp;
oid_free (oid);
}
if (i > 0)
for (j = 0, jp = elements; j < i; j++, jp++)
*ip++ = *jp;
new -> oid_nelem = ip - new -> oid_elements;
return new;
}
static OID resolve (id, ot)
char *id;
register OT ot;
{
int i;
unsigned int elements[NELEM + 1];
register char *cp;
register OT ot2;
struct OIDentifier oids;
register OID oid = &oids;
oid -> oid_elements = elements;
if (cp = index (id, '.'))
*cp = NULL;
if (isdigit (*id)) {
ot2 = NULLOT;
oid -> oid_nelem = 1;
oid -> oid_elements[0] = atoi (id);
if (cp)
*cp = '.';
}
else {
ot2 = text2obj (id);
if (cp)
*cp = '.';
if (ot2 == NULLOT || ot2 -> ot_name == NULLOID)
return NULLOID;
oid -> oid_nelem = ot2 -> ot_name -> oid_nelem;
bcopy ((char *) ot2 -> ot_name -> oid_elements,
(char *) oid -> oid_elements,
oid -> oid_nelem * sizeof *elements);
}
if (cp) {
if ((i = str2elem (++cp, oid -> oid_elements + oid -> oid_nelem)) < 1)
return NULLOID;
oid -> oid_nelem += i;
if (ot && ot2) { /* XXX: not normalized... */
ot -> ot_sibling = ot2 -> ot_children;
ot2 -> ot_children = ot;
}
}
return oid_cpy (oid);
}
/* \f */
/* partial matches are made only on leaf nodes... */
OT name2obj (oid)
OID oid;
{
register int i,
j;
register unsigned *ip;
register OID nm;
register OT ot;
if (oid == NULLOID
|| oid -> oid_nelem < 1
|| (i = (ip = oid -> oid_elements)[0])
>= (sizeof roots / sizeof roots[0])
|| (ot = text2obj (roots[i])) == NULL)
return NULLOT;
i = 0;
while (ot) {
if ((j = (nm = ot -> ot_name) -> oid_nelem) > oid -> oid_nelem)
return NULLOT;
if (bcmp ((char *) ip, (char *) (nm -> oid_elements + i),
(j - i) * sizeof *ip))
ot = ot -> ot_sibling;
else
if (oid -> oid_nelem == j
|| ot -> ot_children == NULLOT
|| ot -> ot_smux)
break;
else {
ot = ot -> ot_children;
ip = oid -> oid_elements + j, i = j;
}
}
return ot;
}
/* \f */
OT text2obj (text)
char *text;
{
register OT ot;
if (text == NULL || once_only == 0)
return NULLOT;
for (ot = Tbuckets[THASH (text)];
ot && strcmp (ot -> ot_text, text);
ot = ot -> ot_chain)
continue;
return ot;
}
/* \f */
/* ARGSUSED */
char *oid2ode_aux (oid, quoted)
OID oid;
int quoted;
{
register int i;
register char *bp;
register unsigned int *ip;
register OID oid2;
register OT ot;
static char buffer[BUFSIZ];
if ((oid -> oid_nelem == 2 /* XXX: 0.0 is a special case */
&& oid -> oid_elements[0] == 0
&& oid -> oid_elements[1] == 0)
|| (ot = name2obj (oid)) == NULLOT)
return sprintoid (oid);
(void) strcpy (bp = buffer, ot -> ot_text);
bp += strlen (bp);
for (ip = oid -> oid_elements + (oid2 = ot -> ot_name) -> oid_nelem,
i = oid -> oid_nelem - oid2 -> oid_nelem;
i-- > 0;
ip++) {
(void) sprintf (bp, ".%u", *ip);
bp += strlen (bp);
}
return buffer;
}
/* \f */
OI name2inst (oid)
OID oid;
{
static object_instance ois;
register OI oi = &ois;
if ((oi -> oi_type = name2obj (oi -> oi_name = oid)) == NULLOT)
return NULLOI;
return oi;
}
OI next2inst (oid)
OID oid;
{
static object_instance ois;
register OI oi = &ois;
register OT ot;
for (ot = anchor; ot; ot = ot -> ot_next) {
if (ot -> ot_smux) {
if (oid -> oid_nelem < ot -> ot_name -> oid_nelem
|| bcmp ((char *) oid -> oid_elements,
(char *) ot -> ot_name -> oid_elements,
ot -> ot_name -> oid_nelem
* sizeof oid -> oid_elements[0]))
continue;
}
else
if (oid_cmp (oid, ot -> ot_name) > 0)
continue;
oi -> oi_name = (oi -> oi_type = ot) -> ot_name;
return oi;
}
return NULLOI;
}
/* \f */
OI text2inst (text)
char *text;
{
static object_instance ois;
register OI oi = &ois;
static OID oid = NULLOID;
if (oid)
oid_free (oid), oid = NULLOID;
if ((oid = text2oid (text)) == NULLOID)
return NULLOI;
if ((oi -> oi_type = name2obj (oi -> oi_name = oid)) == NULLOT) {
if (debug)
fprintf (stderr, "got name \"%s\", but not object\n", text);
return NULLOI;
}
return oi;
}
/* \f DUMP */
#ifdef DEBUG
dump_objects_by_text ()
{
int hit;
register int i;
register OT ot;
for (i = 0; i < TBUCKETS; i++) {
hit = 0;
for (ot = Tbuckets[i]; ot && ot -> ot_text; ot = ot -> ot_chain) {
if (!hit)
printf ("Bucket %d:\n", i), hit = 1;
dump_object (ot, 2);
}
}
printf ("///////\n");
}
dump_objects_by_tree ()
{
register char **ap;
char **bp;
register OT ot;
for (bp = (ap = roots) + (sizeof roots / sizeof roots[0]); ap < bp; ap++) {
if (ot = text2obj (*ap))
dump_object_by_tree (ot, 0);
else
printf ("no object for root \"%s\"\n", *ap);
}
printf ("///////\n");
}
dump_object_by_tree (ot, i)
register OT ot;
int i;
{
if (ot == NULL)
return;
dump_object (ot, i);
dump_object_by_tree (ot -> ot_children, i + 1);
dump_object_by_tree (ot -> ot_sibling, i);
}
dump_objects_by_xxx ()
{
register OT ot;
for (ot = anchor; ot; ot = ot -> ot_next)
dump_object (ot, 0);
printf ("///////\n");
}
static dump_object (ot, i)
register OT ot;
int i;
{
printf ("%*.*s%s %s %s %s %d %d 0x%x\n", i, i, "",
ot -> ot_text, ot -> ot_id, sprintoid (ot -> ot_name),
ot -> ot_syntax ? ot -> ot_syntax -> os_name : "NULL",
ot -> ot_access, ot -> ot_status, ot -> ot_smux);
}
#endif
/* \f MISCELLANY */
char *strdup (s)
char *s;
{
char *p;
if (p = malloc ((unsigned) (strlen (s) + 1)))
(void) strcpy (p, s);
return p;
}