1#!/bin/sh
2#
3# Copyright (c) 1994-2008 Carnegie Mellon University.  All rights reserved.
4#
5# Redistribution and use in source and binary forms, with or without
6# modification, are permitted provided that the following conditions
7# are met:
8#
9# 1. Redistributions of source code must retain the above copyright
10#    notice, this list of conditions and the following disclaimer.
11#
12# 2. Redistributions in binary form must reproduce the above copyright
13#    notice, this list of conditions and the following disclaimer in
14#    the documentation and/or other materials provided with the
15#    distribution.
16#
17# 3. The name "Carnegie Mellon University" must not be used to
18#    endorse or promote products derived from this software without
19#    prior written permission. For permission or any legal
20#    details, please contact
21#      Carnegie Mellon University
22#      Center for Technology Transfer and Enterprise Creation
23#      4615 Forbes Avenue
24#      Suite 302
25#      Pittsburgh, PA  15213
26#      (412) 268-7393, fax: (412) 268-7395
27#      innovation@andrew.cmu.edu
28#
29# 4. Redistributions of any form whatsoever must retain the following
30#    acknowledgment:
31#    "This product includes software developed by Computing Services
32#     at Carnegie Mellon University (http://www.cmu.edu/computing/)."
33#
34# CARNEGIE MELLON UNIVERSITY DISCLAIMS ALL WARRANTIES WITH REGARD TO
35# THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
36# AND FITNESS, IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY BE LIABLE
37# FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
38# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
39# AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
40# OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
41
42exec perl -x -S $0 ${1+"$@"} # -*-perl-*-
43#!perl -w
44
45if ($] !~ /^5\..*/) {
46  # uh-oh. this isn't perl 5.
47  foreach (split(/:/, $ENV{PATH})) { # try to find "perl5".
48    exec("$_/perl5", "-w", "-x", "-S", $0, @ARGV) if (-x "$_/perl5");
49  }
50  # we failed. bail.
51  die "Your perl is too old; I need perl 5.\n";
52}
53
54# load the real script. this is isolated in an 'eval' so perl4 won't
55# choke on the perl5-isms.
56eval join("\n", <DATA>);
57if ($@) { die "$@"; }
58
59__END__
60require 5;
61
62#Tim Martin
63# 2/10/2000
64
65use Getopt::Long;
66my $opt_extra = undef;
67
68$ret = GetOptions("extra:s");
69if (!$ret || $#ARGV != 0) {
70    print STDERR "snmpgen [--extra=trailer.in] app.snmp\n";
71    exit;
72}
73
74$infile = $ARGV[0];
75
76if ($infile =~ m|.*/(.*)\.snmp|) {
77    $basename = $1;
78} elsif ($infile =~ m|(.*)\.snmp|) {
79    $basename = $1;
80} else {
81    $basename = $infile;
82}
83print "basename $basename\n";
84$outheader = "$basename.h";
85$outprog = "$basename.c";
86
87open (INPUT,"<$infile");
88
89my $linenum = 0;
90my $found = 0;
91my $base = "NOT";
92my $num_cmds = 0;
93
94my %T; # maps names to types
95my %D; # maps names to descs
96my %O; # maps names to oids
97
98push @Varlist, "LISTEND";
99
100#first find the BASE
101while (defined ($line = <INPUT>)) {
102    $linenum++;
103
104    if ($line =~ /^#/) {
105        # comment
106        next;
107    }
108    if ($line =~ /^\s*$/) {
109        # just whitespace. ignore
110        next;
111    }
112
113    if ($line =~ /^define\s+(\w+)\s+((\d|\.|\[\w+\])+)/)
114    {
115      $defname = $1;
116      $defoid = $2;
117
118      #resolve definitions
119      while ($defoid =~ /(\[(\w+)\])/)
120      {
121        my $f = 0;
122        foreach my $a (keys %Definelist)
123        {
124          if ($a eq $2)
125          {
126            $defoid =~ s/\[\w+\]/$Definelist{$a}/;
127            $f = 1;
128          }
129        }
130        if ($f == 0) {
131          die "Unable to resolve definition $2";
132        }
133      }
134
135      $Definelist{$defname} = $defoid;
136      next;
137    }
138
139    if ($line =~ /^var\s+(\w+)/) {
140      push @Varlist, $1;
141      next;
142    }
143
144    if ($line =~ /^BASE\s+((\d+|\.|\{\w+\}|\[\w+\])+)/) {
145        $base = $1;
146
147        #resolve definitions
148        while ($base =~ /(\[(\w+)\])/)
149        {
150          my $f = 0;
151          foreach my $a (keys %Definelist)
152          {
153            if ($a eq $2)
154            {
155              $base =~ s/\[\w+\]/$Definelist{$a}/;
156              $f = 1;
157            }
158          }
159          if ($f == 0) {
160            die "Unable to resolve definition $2";
161          }
162        }
163
164        #add lowest base to register list
165        if ($base =~ /((\d+\.)+\d+)/) {
166          push @Registerlist, $1;
167        }
168
169        undef @baseVlist;
170        #xxx check all vars in varlist
171        while ($base =~ /(\{(\w+)\})/)
172        {
173          push @baseVlist, $2;
174          $base =~ s/\{\w+\}/%d/;
175        }
176
177        $basecount = 0;
178        next;
179    }
180
181    chomp $line;
182    ($type, $name, $desc, $oid, $dummy) = split(/\s*,\s*/, $line, 5);
183
184    if (!(defined $oid) || (defined $dummy)) {
185        die "syntax error on line $linenum\n";
186    }
187
188    if ($oid eq "auto") {
189        $oid = $base . ".$basecount";
190        $basecount++;
191    } else {
192        $oid = $base . "." . $oid;
193    }
194
195    $T{$name} = $type;
196    $D{$name} = $desc;
197    $O{$name} = $oid;
198    $Ovlist{$name} = [ @baseVlist ];
199}
200
201open (OUTPUT_H, ">$outheader");
202
203print OUTPUT_H <<EOF
204/* $outheader -- statistics push interface
205 * generated automatically from $infile by snmpgen
206 *
207 * Copyright 2000 Carnegie Mellon University
208 *
209 * No warranty, yadda yadda
210 */
211
212#ifndef ${basename}_H
213#define ${basename}_H
214
215EOF
216;
217
218foreach my $a (keys %Definelist)
219{
220  print OUTPUT_H "#define SNMPDEFINE_$a \"$Definelist{$a}\"\n";
221}
222
223print OUTPUT_H <<EOF
224
225#ifndef USING_SNMPGEN
226
227#define snmp_connect()
228#define snmp_close()
229#define snmp_increment(a, b)
230#define snmp_increment_args(a, b, c, d, e)
231#define snmp_set(a, b)
232#define snmp_set_str(a, b)
233#define snmp_set_oid(a, b)
234#define snmp_set_time(a, b)
235#define snmp_getdescription(a)
236#define snmp_getoid(a, b, c, d)
237#define snmp_setvariable(a, b)
238
239typedef void ${basename}_t;
240
241#else
242
243typedef enum {
244EOF
245;
246
247# Avoid putting a comma after the last item as not every C compiler
248# accepts it
249my $initialized = 0;
250foreach my $name (keys %T) {
251    print OUTPUT_H ",\n" if $initialized;
252    print OUTPUT_H "    $name";
253    $initialized = 1;
254}
255
256print OUTPUT_H <<EOF
257} ${basename}_t;
258
259typedef enum {
260EOF
261;
262
263$initialized = 0;
264foreach my $name (@Varlist) {
265    print OUTPUT_H ",\n" if $initialized;
266    print OUTPUT_H "    VARIABLE_$name";
267    $initialized = 1;
268}
269
270
271print OUTPUT_H <<EOF
272
273} ${basename}_variable_t;
274
275int snmp_connect(void);
276
277int snmp_close(void);
278
279/* only valid on counters */
280int snmp_increment(${basename}_t cmd, int);
281int snmp_increment_args(${basename}_t cmd, int incr, ...);
282
283/* only valid on values */
284int snmp_set(${basename}_t cmd, int);
285
286int snmp_set_str(${basename}_t cmd, char *value);
287
288int snmp_set_oid(${basename}_t cmd, char *str);
289
290int snmp_set_time(${basename}_t cmd, time_t t);
291
292const char *snmp_getdescription(${basename}_t cmd);
293
294const char *snmp_getoid(const char *name, ${basename}_t cmd, char* buf, int buflen);
295
296void snmp_setvariable(${basename}_variable_t, int);
297
298#endif /* USING_SNMPGEN */
299
300#endif /* ${basename}_H */
301
302EOF
303;
304
305close OUTPUT_H;
306
307open (OUTPUT_C,">$outprog");
308
309print OUTPUT_C <<EOF
310/* $outprog -- automatically generated from $infile by snmpgen */
311
312#ifdef USING_SNMPGEN
313
314/* We disable this code for now since it doesn't actually work and wastes
315 * resources.  At some point in time, we'll make it work again as it would
316 * be useful to gather aggregate statistics on what commands are being used
317 * so we can better tune the server.  This change closes bug #1191.
318 * New bug 1267 opened to re-enable the feature.
319 */
320
321#ifdef HAVE_UNISTD_H
322#include <unistd.h>
323#endif
324#include <stdio.h>
325#include <stdlib.h>
326#include <errno.h>
327#include <string.h>
328#include <sys/types.h>
329#include <sys/socket.h>
330#include <sys/un.h>
331#include <fcntl.h>
332#include <stdarg.h>
333
334#include "index.h"
335#include "$outheader"
336
337extern int close(int);
338
339int variable_value[$#Varlist+1];
340int variable_tmpvalue[$#Varlist+1];
341
342int varvalue(${basename}_variable_t var)
343{
344    if (variable_tmpvalue[var]!=-1)
345        return variable_tmpvalue[var];
346
347    return variable_value[var];
348}
349
350const char *snmp_getdescription(${basename}_t evt)
351{
352    switch (evt) {
353EOF
354;
355
356foreach my $a (keys %T)
357{
358    print OUTPUT_C "        case $a: return $D{$a};\n";
359}
360
361print OUTPUT_C <<EOF
362    }
363    return NULL;
364}
365
366const char *snmp_getoid(const char *name __attribute__((unused)),
367                        ${basename}_t evt, char *buf, int buflen)
368{
369    switch (evt) {
370EOF
371;
372
373foreach my $a (keys %T)
374{
375  print OUTPUT_C "        case $a: snprintf(buf,buflen,\"$O{$a}\"";
376  foreach my $b (@{ $Ovlist{$a} })
377    {
378      print OUTPUT_C ",varvalue(VARIABLE_$b)";
379    }
380  print OUTPUT_C "); return buf;\n";
381
382}
383
384
385$snmp.= "    default: return \"0.0.0\";\n";
386$snmp.= "  }\n";
387$snmp.= "}\n";
388
389print OUTPUT_C <<EOF
390    }
391    return NULL;
392}
393
394#define SOCK_PATH "/tmp/.snmp_door"
395
396static int mysock = -1;
397static struct sockaddr_un remote;
398static int sockaddr_len = 0;
399
400static void snmp_send(char *str)
401{
402    if (mysock == -1) return;
403
404    if (sendto(mysock, str, strlen(str), 0, (struct sockaddr *) &remote, sockaddr_len) == -1) {
405        return;
406    }
407
408    return;
409}
410
411int snmp_connect(void)
412{
413    int s;
414    int fdflags;
415    int lup;
416
417    if ((s = socket(AF_UNIX, SOCK_DGRAM, 0)) == -1) {
418        return 1;
419    }
420
421    for (lup=0;lup < $#Varlist+1; lup++)
422        variable_tmpvalue[lup] = -1;
423
424    remote.sun_family = AF_UNIX;
425    strlcpy(remote.sun_path, SOCK_PATH, sizeof(remote.sun_path));
426    sockaddr_len = strlen(remote.sun_path) + sizeof(remote.sun_family);
427
428    /* put us in non-blocking mode */
429    fdflags = fcntl(s, F_GETFD, 0);
430    if (fdflags != -1) fdflags = fcntl(s, F_SETFL, O_NONBLOCK | fdflags);
431    if (fdflags == -1) { close(s); return -1; }
432
433    mysock = s;
434EOF
435;
436
437foreach my $oid (@Registerlist) {
438    print OUTPUT_C "    snmp_send(\"R $oid\\n\");\n";
439}
440
441
442print OUTPUT_C <<EOF
443    return 0;
444}
445
446int snmp_close(void)
447{
448    if (mysock > -1)
449        close(mysock);
450
451    return 0;
452}
453
454int snmp_increment_args(${basename}_t cmd, int incr, ...)
455{
456    char tosend[256]; /* xxx UDP max size??? */
457    char buf[256];
458
459      va_list ap; /* varargs thing */
460      ${basename}_variable_t vval;
461      int ival;
462
463      if (mysock == -1) return 1;
464
465      va_start(ap, incr);
466
467      do {
468          vval = va_arg(ap, ${basename}_variable_t); /* get the next arg */
469
470          if (vval!=VARIABLE_LISTEND)
471          {
472              ival = va_arg(ap, int); /* get the next arg */
473              variable_tmpvalue[vval] = ival;
474          }
475
476      } while ( vval != VARIABLE_LISTEND);
477
478      va_end(ap);
479
480    snprintf(tosend, sizeof(tosend),"C %s %d\\n",snmp_getoid(NULL,cmd,buf,sizeof(buf)), incr);
481
482    if (sendto(mysock, tosend, strlen(tosend), 0, (struct sockaddr *) &remote, sockaddr_len) == -1) {
483        return 1;
484    }
485
486    /* set tmp variables back */
487    va_start(ap, incr);
488
489      do {
490          vval = va_arg(ap, ${basename}_variable_t); /* get the next arg */
491
492          if (vval!=VARIABLE_LISTEND)
493          {
494              ival = va_arg(ap, int); /* get the next arg */
495              variable_tmpvalue[vval] = -1;
496          }
497
498      } while ( vval != VARIABLE_LISTEND);
499
500      va_end(ap);
501
502    return 0;
503}
504
505int snmp_increment(${basename}_t cmd, int incr)
506{
507    char tosend[256]; /* xxx UDP max size??? */
508    char buf[256];
509
510    if (mysock == -1) return 1;
511
512    snprintf(tosend, sizeof(tosend),"C %s %d\\n",snmp_getoid(NULL,cmd,buf,sizeof(buf)), incr);
513
514    if (sendto(mysock, tosend, strlen(tosend), 0, (struct sockaddr *) &remote, sockaddr_len) == -1) {
515        return 1;
516    }
517
518    return 0;
519}
520
521int snmp_set(${basename}_t cmd, int value)
522{
523    char tosend[256];
524    char buf[256];
525
526    if (mysock == -1) return 1;
527
528    snprintf(tosend, sizeof(tosend),"I %s %d\\n",snmp_getoid(NULL,cmd,buf,sizeof(buf)), value);
529
530    if (sendto(mysock, tosend, strlen(tosend), 0, (struct sockaddr *) &remote, sockaddr_len) == -1) {
531        return 1;
532    }
533
534    return 1;
535}
536
537int snmp_set_str(${basename}_t cmd, char *value)
538{
539    char tosend[256];
540    char buf[256];
541
542    if (mysock == -1) return 1;
543
544    snprintf(tosend, sizeof(tosend),"S %s %s\\n",snmp_getoid(NULL,cmd,buf,sizeof(buf)), value);
545
546    if (sendto(mysock, tosend, strlen(tosend), 0, (struct sockaddr *) &remote, sockaddr_len) == -1) {
547        return 1;
548    }
549
550    return 1;
551}
552
553int snmp_set_time(${basename}_t cmd, time_t t)
554{
555    char tosend[256];
556    char buf[256];
557
558    if (mysock == -1) return 1;
559
560    snprintf(tosend, sizeof(tosend),"T %s %lu\\n",snmp_getoid(NULL,cmd,buf,sizeof(buf)), t);
561
562    if (sendto(mysock, tosend, strlen(tosend), 0, (struct sockaddr *) &remote, sockaddr_len) == -1) {
563        return 1;
564    }
565
566    return 1;
567}
568
569/* should use SNMPDEFINE's as parameter */
570int snmp_set_oid(${basename}_t cmd, char *str)
571{
572   return snmp_set_str(cmd,str);
573}
574
575void snmp_setvariable(${basename}_variable_t name, int value)
576{
577    variable_value[name] = value;
578}
579
580#endif
581
582
583EOF
584;
585
586if (defined $opt_extra) {
587   open (INPUT_IN,"<$opt_extra");
588   while( <INPUT_IN> )
589   {
590       print OUTPUT_C;
591   }
592   close INPUT_IN;
593}
594
595close OUTPUT_C;
596
597