/** * Iterate over all persistent pipes and close those pipes of which the * associated process has stopped. */ static void check_persist_pipes(unsigned clientreg, void *clientarg) { int i; if (!persist_pipes) return; for (i = 0; i <= numpersistpassthrus; i++) { if (process_stopped(i)) { snmp_log(LOG_INFO, "pass_persist[%d]: child process stopped - closing pipe\n", i); close_persist_pipe(i); } } }
/* * Destruct our persistent pipes * */ static void destruct_persist_pipes(void) { int i; /* * Return if there are no pipes */ if (!persist_pipes) { return; } for (i = 0; i <= numpersistpassthrus; i++) { close_persist_pipe(i); } free(persist_pipes); persist_pipes = (struct persist_pipe_type *) 0; }
void pass_persist_free_config(void) { struct extensible *etmp, *etmp2; int i; for (etmp = persistpassthrus; etmp != NULL;) { etmp2 = etmp; etmp = etmp->next; unregister_mib_priority(etmp2->miboid, etmp2->miblen, etmp2->mibpriority); free(etmp2); } if (persist_pipes) { for (i = 0; i <= numpersistpassthrus; i++) { close_persist_pipe(i); } } persistpassthrus = NULL; numpersistpassthrus = 0; }
static int write_persist_pipe(int iindex, const char *data) { #if HAVE_SIGNAL struct sigaction sa, osa; int wret = 0, werrno = 0; /* * Don't write to a non-existant process */ if (persist_pipes[iindex].pid == NETSNMP_NO_SUCH_PROCESS) { DEBUGMSGTL(("ucd-snmp/pass_persist", "write_persist_pipe: not writing %s, process is non-existent", data)); return 0; } /* * Setup our signal action to ignore SIGPIPEs */ sa.sa_handler = SIG_IGN; sigemptyset(&sa.sa_mask); sa.sa_flags = 0; if (sigaction(SIGPIPE, &sa, &osa)) { DEBUGMSGTL(("ucd-snmp/pass_persist", "write_persist_pipe: sigaction failed: %d", errno)); } /* * Do the write */ wret = write(persist_pipes[iindex].fdOut, data, strlen(data)); werrno = errno; /* * Reset the signal handler */ sigaction(SIGPIPE, &osa, (struct sigaction *) 0); if (wret < 0) { if (werrno != EPIPE) { DEBUGMSGTL(("ucd-snmp/pass_persist", "write_persist_pipe: write returned unknown error %d (%s)\n", werrno, strerror(werrno))); } close_persist_pipe(iindex); return 0; } #endif /* HAVE_SIGNAL */ #if defined(WIN32) && !defined (mingw32) && !defined (HAVE_SIGNAL) /* We have no signal here (maybe we can make a Thread?) so write may block, * but probably never will. */ int wret = 0, werrno = 0; /* * Do the write */ wret = write(persist_pipes[iindex].fdOut, data,strlen(data)); werrno = errno; if (wret < 0) { if (werrno != EINTR) { DEBUGMSGTL(("ucd-snmp/pass_persist", "write_persist_pipe: write returned unknown error %d\n",errno)); } close_persist_pipe(iindex); return 0; } #endif /* WIN32 */ return 1; }
/* * returns 0 on failure, 1 on success */ static int open_persist_pipe(int iindex, char *command) { static int recurse = 0; /* used to allow one level of recursion */ DEBUGMSGTL(("ucd-snmp/pass_persist", "open_persist_pipe(%d,'%s') recurse=%d\n", iindex, command, recurse)); /* * Open if it's not already open */ if (persist_pipes[iindex].pid == NETSNMP_NO_SUCH_PROCESS) { int fdIn, fdOut; netsnmp_pid_t pid; /* * Did we fail? */ if ((0 == get_exec_pipes(command, &fdIn, &fdOut, &pid)) || (pid == NETSNMP_NO_SUCH_PROCESS)) { DEBUGMSGTL(("ucd-snmp/pass_persist", "open_persist_pipe: pid == -1\n")); recurse = 0; return 0; } /* * If not, fill out our structure */ persist_pipes[iindex].pid = pid; persist_pipes[iindex].fdIn = fdIn; persist_pipes[iindex].fdOut = fdOut; persist_pipes[iindex].fIn = fdopen(fdIn, "r"); persist_pipes[iindex].fOut = fdopen(fdOut, "w"); /* * Setup our -non-buffered-io- */ setbuf(persist_pipes[iindex].fOut, (char *) 0); DEBUGMSGTL(("ucd-snmp/pass_persist", "open_persist_pipe: opened the pipes\n")); } /* * Send test packet always so we can self-catch */ { char buf[SNMP_MAXBUF]; /* * Should catch SIGPIPE around this call! */ if (!write_persist_pipe(iindex, "PING\n")) { DEBUGMSGTL(("ucd-snmp/pass_persist", "open_persist_pipe: Error writing PING\n")); close_persist_pipe(iindex); /* * Recurse one time if we get a SIGPIPE */ if (!recurse) { DEBUGMSGTL(("ucd-snmp/pass_persist", "open_persist_pipe: recursing to reopen\n")); recurse = 1; return open_persist_pipe(iindex, command); } recurse = 0; return 0; } if (fgets(buf, sizeof(buf), persist_pipes[iindex].fIn) == NULL) { DEBUGMSGTL(("ucd-snmp/pass_persist", "open_persist_pipe: Error reading for PONG\n")); close_persist_pipe(iindex); recurse = 0; return 0; } if (strncmp(buf, "PONG", 4)) { DEBUGMSGTL(("ucd-snmp/pass_persist", "open_persist_pipe: Got %s instead of PONG!\n", buf)); close_persist_pipe(iindex); recurse = 0; return 0; } } recurse = 0; return 1; }
int setPassPersist(int action, u_char * var_val, u_char var_val_type, size_t var_val_len, u_char * statP, oid * name, size_t name_len) { int i, rtest; struct extensible *persistpassthru; char buf[SNMP_MAXBUF], buf2[SNMP_MAXBUF]; /* * Make sure that our basic pipe structure is malloced */ init_persist_pipes(); for (i = 1; i <= numpersistpassthrus; i++) { persistpassthru = get_exten_instance(persistpassthrus, i); rtest = snmp_oidtree_compare(name, name_len, persistpassthru->miboid, persistpassthru->miblen); if (rtest <= 0) { if (action != ACTION) return SNMP_ERR_NOERROR; /* * setup args */ if (persistpassthru->miblen >= name_len || rtest < 0) sprint_mib_oid(buf, persistpassthru->miboid, persistpassthru->miblen); else sprint_mib_oid(buf, name, name_len); snprintf(persistpassthru->command, sizeof(persistpassthru->command), "set\n%s\n", buf); persistpassthru->command[ sizeof(persistpassthru->command)-1 ] = 0; netsnmp_internal_pass_set_format(buf, var_val, var_val_type, var_val_len); strlcat(persistpassthru->command, buf, sizeof(persistpassthru->command)); persistpassthru->command[ sizeof(persistpassthru->command)-2 ] = '\n'; persistpassthru->command[ sizeof(persistpassthru->command)-1 ] = 0; if (!open_persist_pipe(i, persistpassthru->name)) { return SNMP_ERR_NOTWRITABLE; } DEBUGMSGTL(("ucd-snmp/pass_persist", "persistpass-writing: %s\n", persistpassthru->command)); if (!write_persist_pipe(i, persistpassthru->command)) { close_persist_pipe(i); return SNMP_ERR_NOTWRITABLE; } if (fgets(buf, sizeof(buf), persist_pipes[i].fIn) == NULL) { close_persist_pipe(i); return SNMP_ERR_NOTWRITABLE; } return netsnmp_internal_pass_str_to_errno(buf); } } if (snmp_get_do_debugging()) { sprint_mib_oid(buf2, name, name_len); DEBUGMSGTL(("ucd-snmp/pass_persist", "persistpass-notfound: %s\n", buf2)); } return SNMP_ERR_NOSUCHNAME; }
u_char * var_extensible_pass_persist(struct variable *vp, oid * name, size_t * length, int exact, size_t * var_len, WriteMethod ** write_method) { oid newname[MAX_OID_LEN]; int i, rtest, newlen; char buf[SNMP_MAXBUF]; static char buf2[SNMP_MAXBUF]; struct extensible *persistpassthru; FILE *file; /* * Make sure that our basic pipe structure is malloced */ init_persist_pipes(); for (i = 1; i <= numpersistpassthrus; i++) { persistpassthru = get_exten_instance(persistpassthrus, i); rtest = snmp_oidtree_compare(name, *length, persistpassthru->miboid, persistpassthru->miblen); if ((exact && rtest == 0) || (!exact && rtest <= 0)) { /* * setup args */ if (persistpassthru->miblen >= *length || rtest < 0) sprint_mib_oid(buf, persistpassthru->miboid, persistpassthru->miblen); else sprint_mib_oid(buf, name, *length); /* * Open our pipe if necessary */ if (!open_persist_pipe(i, persistpassthru->name)) { return (NULL); } if (exact) snprintf(persistpassthru->command, sizeof(persistpassthru->command), "get\n%s\n", buf); else snprintf(persistpassthru->command, sizeof(persistpassthru->command), "getnext\n%s\n", buf); persistpassthru->command[ sizeof(persistpassthru->command)-1 ] = 0; DEBUGMSGTL(("ucd-snmp/pass_persist", "persistpass-sending:\n%s", persistpassthru->command)); if (!write_persist_pipe(i, persistpassthru->command)) { *var_len = 0; /* * close_persist_pipes is called in write_persist_pipe */ return (NULL); } /* * valid call. Exec and get output */ if ((file = persist_pipes[i].fIn)) { if (fgets(buf, sizeof(buf), file) == NULL) { *var_len = 0; close_persist_pipe(i); return (NULL); } /* * persistent scripts return "NONE\n" on invalid items */ if (!strncmp(buf, "NONE", 4)) { if (exact) { *var_len = 0; return (NULL); } continue; } newlen = parse_miboid(buf, newname); /* * its good, so copy onto name/length */ memcpy((char *) name, (char *) newname, (int) newlen * sizeof(oid)); *length = newlen; /* * set up return pointer for setable stuff */ *write_method = setPassPersist; if (newlen == 0 || fgets(buf, sizeof(buf), file) == NULL || fgets(buf2, sizeof(buf2), file) == NULL) { *var_len = 0; close_persist_pipe(i); return (NULL); } return netsnmp_internal_pass_parse(buf, buf2, var_len, vp); } *var_len = 0; return (NULL); } } if (var_len) *var_len = 0; *write_method = NULL; return (NULL); }