5 #include <net-snmp/net-snmp-config.h>
17 #include <sys/types.h>
25 # include <sys/wait.h>
34 # define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8)
37 # define WIFEXITED(stat_val) (((stat_val) & 255) == 0)
39 #if TIME_WITH_SYS_TIME
41 # include <sys/timeb.h>
43 # include <sys/time.h>
48 # include <sys/time.h>
71 #include <netinet/in.h>
75 #define ssize_t SSIZE_T
81 #include <net-snmp/net-snmp-includes.h>
82 #include <net-snmp/agent/net-snmp-agent-includes.h>
85 #include "util_funcs.h"
90 #ifdef USING_UCD_SNMP_ERRORMIB_MODULE
91 #include "ucd-snmp/errormib.h"
93 #define setPerrorstatus(x) snmp_log_perror(x)
98 static long cachetime;
101 extern int numprocs, numextens;
106 snmp_log(LOG_ERR, "Server Exiting with code %d\n", var);
110 #ifdef BRCM_SNMP_NOT_USE
114 static char name[32];
117 strcpy(name, "/tmp/snmpdXXXXXX");
122 fd = open(name, O_CREAT | O_EXCL | O_WRONLY);
132 shell_command(struct extensible *ex)
136 char shellline[STRMAX];
139 ofname = make_tempfile();
140 if (ofname == NULL) {
146 snprintf(shellline, sizeof(shellline), "%s > %s", ex->command, ofname);
147 shellline[ sizeof(shellline)-1 ] = 0;
148 ex->result = system(shellline);
149 ex->result = WEXITSTATUS(ex->result);
150 shellout = fopen(ofname, "r");
151 if (shellout != NULL) {
152 if (fgets(ex->output, sizeof(ex->output), shellout) == NULL) {
165 #define MAXOUTPUT 300
168 exec_command(struct extensible *ex)
174 if ((fd = get_exec_output(ex)) != -1) {
175 file = fdopen(fd, "r");
176 if (fgets(ex->output, sizeof(ex->output), file) == NULL) {
191 wait_on_exec(struct extensible *ex)
194 if (ex->pid && waitpid(ex->pid, &ex->result, 0) < 0) {
195 setPerrorstatus("waitpid");
204 get_exec_output(struct extensible *ex)
208 char ctmp[STRMAX], *cptr1, *cptr2, argvs[STRMAX], **argv,
211 char cachefile[STRMAX];
212 char cache[MAXCACHESIZE];
215 static char lastcmd[STRMAX];
217 static int lastresult;
222 sprintf(cachefile, "%s/%s", get_persistent_directory(), CACHEFILE);
223 curtime = time(NULL);
224 if (curtime > (cachetime + EXCACHETIME) ||
225 strcmp(ex->command, lastcmd) != 0) {
226 strcpy(lastcmd, ex->command);
230 setPerrorstatus("pipe");
236 if ((ex->pid = fork()) == 0) {
238 if (dup(fd[1]) != 1) {
239 setPerrorstatus("dup");
244 * write standard output and standard error to pipe.
247 * close all other file descriptors.
249 for (cnt = getdtablesize() - 1; cnt >= 2; --cnt)
251 (void) dup(1); /* stderr */
254 * set standard input to /dev/null
257 (void) open("/dev/null", O_RDWR);
259 for (cnt = 1, cptr1 = ex->command, cptr2 = argvs;
260 cptr1 && *cptr1 != 0; cptr2++, cptr1++) {
264 if ((cptr1 = skip_white(cptr1)) == NULL)
275 argv = (char **) malloc((cnt + 2) * sizeof(char *));
277 return 0; /* memory alloc error */
280 for (cptr2 = argvs, i = 1; i != cnt; cptr2++)
282 *(aptr++) = cptr2 + 1;
288 copy_nword(ex->command, ctmp, sizeof(ctmp));
296 setPerrorstatus("fork");
305 * XXX Use SNMP_FILEMODE_CLOSED instead of 644?
308 open(cachefile, O_WRONLY | O_TRUNC | O_CREAT,
310 setPerrorstatus(cachefile);
314 fcntl(fd[0], F_SETFL, O_NONBLOCK); /* don't block on reads */
316 for (readcount = 0; readcount <= MAXREADCOUNT * 100 &&
317 (cachebytes = read(fd[0], (void *) cache, MAXCACHESIZE));
320 for (readcount = 0; readcount <= MAXREADCOUNT &&
321 (cachebytes = read(fd[0], (void *) cache, MAXCACHESIZE));
325 write(cfd, (void *) cache, cachebytes);
326 else if (cachebytes == -1 && errno != EAGAIN) {
327 setPerrorstatus("read");
331 usleep(10000); /* sleeps for 0.01 sec */
339 * wait for the child to finish
341 if (ex->pid > 0 && waitpid(ex->pid, &ex->result, 0) < 0) {
342 setPerrorstatus("waitpid()");
347 ex->result = WEXITSTATUS(ex->result);
348 lastresult = ex->result;
349 #else /* !EXCACHETIME */
355 ex->result = lastresult;
357 if ((cfd = open(cachefile, O_RDONLY)) < 0) {
358 setPerrorstatus(cachefile);
364 #else /* !HAVE_EXECV */
370 get_exec_pipes(char *cmd, int *fdIn, int *fdOut, int *pid)
373 int fd[2][2], i, cnt;
374 char ctmp[STRMAX], *cptr1, *cptr2, argvs[STRMAX], **argv,
379 if (pipe(fd[0]) || pipe(fd[1])) {
380 setPerrorstatus("pipe");
383 if ((*pid = fork()) == 0) { /* First handle for the child */
385 if (dup(fd[0][0]) != 0) {
386 setPerrorstatus("dup 0");
390 if (dup(fd[1][1]) != 1) {
391 setPerrorstatus("dup 1");
396 * write standard output and standard error to pipe.
399 * close all non-standard open file descriptors
401 for (cnt = getdtablesize() - 1; cnt >= 2; --cnt)
403 (void) dup(1); /* stderr */
405 for (cnt = 1, cptr1 = cmd, cptr2 = argvs; *cptr1 != 0;
410 if ((cptr1 = skip_white(cptr1)) == NULL)
419 argv = (char **) malloc((cnt + 2) * sizeof(char *));
421 return 0; /* memory alloc error */
424 for (cptr2 = argvs, i = 1; i != cnt; cptr2++)
426 *(aptr++) = cptr2 + 1;
432 copy_nword(cmd, ctmp, sizeof(ctmp));
442 setPerrorstatus("fork");
447 return (1); /* We are returning 0 for error... */
449 #endif /* !HAVE_EXECV */
454 clear_cache(int action,
458 u_char * statP, oid * name, size_t name_len)
463 if (var_val_type != ASN_INTEGER) {
464 snmp_log(LOG_NOTICE, "Wrong type != int\n");
465 return SNMP_ERR_WRONGTYPE;
467 tmp = *((long *) var_val);
468 if (tmp == 1 && action == COMMIT) {
470 cachetime = 0; /* reset the cache next read */
473 return SNMP_ERR_NOERROR;
475 #endif /* BRCM_SNMP_NOT_USE */
476 char **argvrestartp, *argvrestartname, *argvrestart;
478 #ifdef BRCM_SNMP_NOT_USE
482 snmp_shutdown("snmpd");
488 execv(argvrestartname, argvrestartp);
489 setPerrorstatus(argvrestartname);
494 restart_hook(int action,
498 u_char * statP, oid * name, size_t name_len)
503 if (var_val_type != ASN_INTEGER) {
504 snmp_log(LOG_NOTICE, "Wrong type != int\n");
505 return SNMP_ERR_WRONGTYPE;
507 tmp = *((long *) var_val);
508 if (tmp == 1 && action == COMMIT) {
510 signal(SIGALRM, restart_doit);
514 return SNMP_ERR_NOERROR;
518 print_mib_oid(oid name[], size_t len)
521 buffer = (char *) malloc(11 * len); /* maximum digit lengths for int32 + a '.' */
523 snmp_log(LOG_ERR, "Malloc failed - out of memory?");
526 sprint_mib_oid(buffer, name, len);
527 snmp_log(LOG_NOTICE, "Mib: %s\n", buffer);
532 sprint_mib_oid(char *buf, oid name[], size_t len)
535 for (i = 0; i < (int) len; i++) {
536 sprintf(buf, ".%d", (int) name[i]);
541 #endif /* BRCM_SNMP_NOT_USED */
542 /*******************************************************************-o-******
543 * header_simple_table
547 * *name Fully instantiated OID name.
548 * *length Length of name.
549 * exact TRUE if an exact match is desired.
550 * *var_len Hook for size of returned data type.
551 * (**write_method) Hook for write method (UNUSED).
555 * 0 If name matches vp->name (accounting for 'exact') and is
556 * not greater in length than 'max'.
560 * Compare 'name' to vp->name for the best match or an exact match (if
561 * requested). Also check that 'name' is not longer than 'max' if
562 * max is greater-than/equal 0.
563 * Store a successful match in 'name', and increment the OID instance if
564 * the match was not exact.
566 * 'name' and 'length' are undefined upon failure.
570 header_simple_table(struct variable *vp, oid * name, size_t * length,
571 int exact, size_t * var_len,
572 WriteMethod ** write_method, int max)
574 int i, rtest; /* Set to: -1 If name < vp->name,
575 * 1 If name > vp->name,
578 oid newname[MAX_OID_LEN];
580 for (i = 0, rtest = 0;
581 i < (int) vp->namelen && i < (int) (*length) && !rtest; i++) {
582 if (name[i] != vp->name[i]) {
583 if (name[i] < vp->name[i])
591 && (rtest || (int) *length != (int) (vp->namelen + 1)))) {
597 memset(newname, 0, sizeof(newname));
599 if (((int) *length) <= (int) vp->namelen || rtest == -1) {
600 memmove(newname, vp->name, (int) vp->namelen * sizeof(oid));
601 newname[vp->namelen] = 1;
602 *length = vp->namelen + 1;
603 } else if (((int) *length) > (int) vp->namelen + 1) { /* exact case checked earlier */
604 *length = vp->namelen + 1;
605 memmove(newname, name, (*length) * sizeof(oid));
606 if (name[*length - 1] < ULONG_MAX) {
607 newname[*length - 1] = name[*length - 1] + 1;
610 * Careful not to overflow...
612 newname[*length - 1] = name[*length - 1];
615 *length = vp->namelen + 1;
616 memmove(newname, name, (*length) * sizeof(oid));
618 if (name[*length - 1] < ULONG_MAX) {
619 newname[*length - 1] = name[*length - 1] + 1;
622 * Careful not to overflow...
624 newname[*length - 1] = name[*length - 1];
627 newname[*length - 1] = name[*length - 1];
630 if ((max >= 0 && (newname[*length - 1] > max)) ||
631 ( 0 == newname[*length - 1] )) {
637 memmove(name, newname, (*length) * sizeof(oid));
641 *var_len = sizeof(long); /* default */
642 return (MATCH_SUCCEEDED);
648 * vp IN - pointer to variable entry that points here
649 * name IN/OUT - IN/name requested, OUT/name found
650 * length IN/OUT - length of IN/OUT oid's
651 * exact IN - TRUE if an exact match was requested
652 * var_len OUT - length of variable or 0 if function returned
657 /*******************************************************************-o-******
661 * *vp (I) Pointer to variable entry that points here.
662 * *name (I/O) Input name requested, output name found.
663 * *length (I/O) Length of input and output oid's.
664 * exact (I) TRUE if an exact match was requested.
665 * *var_len (O) Length of variable or 0 if function returned.
666 * (**write_method) Hook to name a write method (UNUSED).
669 * MATCH_SUCCEEDED If vp->name matches name (accounting for exact bit).
670 * MATCH_FAILED Otherwise,
673 * Check whether variable (vp) matches name.
676 header_generic(struct variable *vp,
679 int exact, size_t * var_len, WriteMethod ** write_method)
681 oid newname[MAX_OID_LEN];
684 DEBUGMSGTL(("util_funcs", "header_generic: "));
685 DEBUGMSGOID(("util_funcs", name, *length));
686 DEBUGMSG(("util_funcs", " exact=%d\n", exact));
688 memcpy((char *) newname, (char *) vp->name,
689 (int) vp->namelen * sizeof(oid));
690 newname[vp->namelen] = 0;
691 result = snmp_oid_compare(name, *length, newname, vp->namelen + 1);
692 DEBUGMSGTL(("util_funcs", " result: %d\n", result));
693 if ((exact && (result != 0)) || (!exact && (result >= 0)))
694 return (MATCH_FAILED);
695 memcpy((char *) name, (char *) newname,
696 ((int) vp->namelen + 1) * sizeof(oid));
697 *length = vp->namelen + 1;
700 *var_len = sizeof(long); /* default to 'long' results */
701 return (MATCH_SUCCEEDED);
704 #ifdef BRCM_SNMP_NOT_USE
706 * checkmib(): provided for backwards compatibility, do not use:
709 checkmib(struct variable *vp, oid * name, size_t * length,
710 int exact, size_t * var_len, WriteMethod ** write_method, int max)
713 * checkmib used to be header_simple_table, with reveresed boolean
714 * return output. header_simple_table() was created to match
717 return (!header_simple_table(vp, name, length, exact, var_len,
722 find_field(char *ptr, int field)
727 if (field == LASTFIELD) {
734 * rewind a field length
736 while (*ptr != 0 && isspace(*ptr) && init <= ptr)
738 while (*ptr != 0 && !isspace(*ptr) && init <= ptr)
741 ptr++; /* past space */
744 if (!isspace(*ptr) && *ptr != 0)
747 if ((ptr = skip_white(ptr)) == NULL)
749 for (i = 1; *ptr != 0 && i != field; i++) {
750 if ((ptr = skip_not_white(ptr)) == NULL)
752 if ((ptr = skip_white(ptr)) == NULL)
755 if (*ptr != 0 && i == field)
763 parse_miboid(const char *buf, oid * oidout)
771 for (i = 0; isdigit(*buf); i++) {
772 oidout[i] = atoi(buf);
773 while (isdigit(*buf++));
778 * oidout[i] = -1; hmmm
784 string_append_int(char *s, int val)
793 sprintf(textVal, "%d", val);
798 struct internal_mib_table {
799 int max_size; /* Size of the current data table */
800 int next_index; /* Index of the next free entry */
801 int current_index; /* Index of the 'current' entry */
803 marker_t cache_marker;
804 RELOAD *reload; /* Routine to read in the data */
805 COMPARE *compare; /* Routine to compare two entries */
806 int data_size; /* Size of an individual entry */
807 void *data; /* The table itself */
811 Initialise_Table(int size, int timeout, RELOAD reload, COMPARE compare)
813 struct internal_mib_table *t;
815 t = (struct internal_mib_table *)
816 malloc(sizeof(struct internal_mib_table));
821 t->next_index = 1; /* Don't use index 0 */
822 t->current_index = 1;
823 t->cache_timeout = timeout;
824 t->cache_marker = NULL;
826 t->compare = compare;
830 return (mib_table_t) t;
833 #define TABLE_ADD( x, y ) ((void*)((char*)(x) + y))
834 #define TABLE_INDEX(t, i) (TABLE_ADD(t->data, i * t->data_size))
835 #define TABLE_START(t) (TABLE_INDEX(t, 1))
836 #define TABLE_NEXT(t) (TABLE_INDEX(t, t->next_index))
837 #define TABLE_CURRENT(t) (TABLE_INDEX(t, t->current_index))
840 check_and_reload_table(struct internal_mib_table *table)
843 * If the saved data is fairly recent,
844 * we don't need to reload it
846 if (table->cache_marker &&
847 !(atime_ready(table->cache_marker, table->cache_timeout * 1000)))
852 * Call the routine provided to read in the data
854 * N.B: Update the cache marker *before* calling
855 * this routine, to avoid problems with recursion
857 if (!table->cache_marker)
858 table->cache_marker = atime_newMarker();
860 atime_setMarker(table->cache_marker);
862 table->next_index = 1;
863 if (table->reload((mib_table_t) table) < 0) {
864 free(table->cache_marker);
865 table->cache_marker = NULL;
868 table->current_index = 1;
869 if (table->compare != NULL) /* Sort the table */
870 qsort(TABLE_START(table), table->next_index,
871 table->data_size, table->compare);
876 Search_Table(mib_table_t t, void *entry, int exact)
878 struct internal_mib_table *table = (struct internal_mib_table *) t;
882 if (!check_and_reload_table(table))
885 if (table->compare == NULL) {
887 * XXX - not sure this is right ?
889 memcpy(entry, table->data, table->data_size);
893 if (table->next_index == table->current_index)
894 table->current_index = 1;
896 entry2 = TABLE_CURRENT(table);
897 res = table->compare(entry, entry2);
898 if ((res < 0) && (table->current_index != 1)) {
899 table->current_index = 1;
900 entry2 = TABLE_CURRENT(table);
901 res = table->compare(entry, entry2);
905 table->current_index++;
906 if (table->next_index == table->current_index)
908 entry2 = TABLE_CURRENT(table);
909 res = table->compare(entry, entry2);
912 if (exact && res != 0)
915 if (!exact && res == 0) {
916 table->current_index++;
917 if (table->next_index == table->current_index)
919 entry2 = TABLE_CURRENT(table);
921 memcpy(entry, entry2, table->data_size);
926 Add_Entry(mib_table_t t, void *entry)
928 struct internal_mib_table *table = (struct internal_mib_table *) t;
930 void *new_data; /* Used for
931 * a) extending the data table
932 * b) the next entry to use
935 if (table->max_size <= table->next_index) {
937 * Table is full, so extend it to double the size
939 new_max = 2 * table->max_size;
941 new_max = 10; /* Start with 10 entries */
943 new_data = (void *) malloc(new_max * table->data_size);
944 if (new_data == NULL)
948 memcpy(new_data, table->data,
949 table->max_size * table->data_size);
952 table->data = new_data;
953 table->max_size = new_max;
957 * Insert the new entry into the data array
959 new_data = TABLE_NEXT(table);
960 memcpy(new_data, entry, table->data_size);
966 Retrieve_Table_Data(mib_table_t t, int *max_idx)
968 struct internal_mib_table *table = (struct internal_mib_table *) t;
970 if (!check_and_reload_table(table))
972 *max_idx = table->next_index - 1;
975 #endif /* BRCM_SNMP_NOT_USE */