RETSIGTYPE restart_doit(int a) { char * name = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_APPTYPE); snmp_shutdown(name); /* This signal handler may run with SIGALARM blocked. * Since the signal mask is preserved accross execv(), we must * make sure that SIGALARM is unblocked prior of execv'ing. * Otherwise SIGALARM will be ignored in the next incarnation * of snmpd, because the signal is blocked. And thus, the * restart doesn't work anymore. */ #if HAVE_SIGBLOCK sigsetmask(0); #endif /* * do the exec */ #if HAVE_EXECV execv(argvrestartname, argvrestartp); setPerrorstatus(argvrestartname); #endif }
void wait_on_exec(struct extensible *ex) { #if defined(WIN32) && !defined (mingw32) int rc; if (ex->tid != 0 && ex->pid != 0) { HANDLE hThread = (HANDLE) ex->tid; HANDLE hProcess = (HANDLE) ex->pid; rc = WaitForSingleObject(hProcess, NETSNMP_TIMEOUT_WAITFORSINGLEOBJECT); DEBUGMSGT(("exec:wait_on_exec","WaitForSingleObject rc=(%d)\n",rc )); rc = CloseHandle( hThread ); DEBUGMSGT(("exec:wait_on_exec","CloseHandle hThread=(%d)\n",rc )); rc = CloseHandle( hProcess ); DEBUGMSGT(("exec:wait_on_exec","CloseHandle hProcess=(%d)\n",rc )); ex->pid = 0; ex->tid = 0; } #else #ifndef NETSNMP_EXCACHETIME if (ex->pid && waitpid(ex->pid, &ex->result, 0) < 0) { setPerrorstatus("waitpid"); } ex->pid = 0; #endif /* NETSNMP_EXCACHETIME */ #endif /* WIN32 */ }
int sh_count_regexp_procs(char *procname, pcre *regexp) { char line[STRMAX], *cptr, *cp; int ret = 0, fd; FILE *file; #ifndef NETSNMP_EXCACHETIME #endif struct extensible ex; int slow = strstr(PSCMD, "ax") != NULL; strcpy(ex.command, PSCMD); if ((fd = get_exec_output(&ex)) >= 0) { if ((file = fdopen(fd, "r")) == NULL) { setPerrorstatus("fdopen"); close(fd); return (-1); } while (fgets(line, sizeof(line), file) != NULL) { if (slow) { cptr = find_field(line, 5); cp = strrchr(cptr, '/'); if (cp) cptr = cp + 1; else if (*cptr == '-') cptr++; else if (*cptr == '[') { cptr++; cp = strchr(cptr, ']'); if (cp) *cp = 0; } copy_nword(cptr, line, sizeof(line)); cp = line + strlen(line) - 1; if (*cp == ':') *cp = 0; } else { if ((cptr = find_field(line, NETSNMP_LASTFIELD)) == NULL) continue; copy_nword(cptr, line, sizeof(line)); } if (!strcmp(line, procname)) ret++; } if (ftell(file) < 2) { #ifdef USING_UCD_SNMP_ERRORMIB_MODULE seterrorstatus("process list unreasonable short (mem?)", 2); #endif ret = -1; } fclose(file); wait_on_exec(&ex); } else { ret = -1; } return (ret); }
void wait_on_exec(struct extensible *ex) { #ifndef EXCACHETIME if (ex->pid && waitpid(ex->pid, &ex->result, 0) < 0) { setPerrorstatus("waitpid"); } ex->pid = 0; #endif }
RETSIGTYPE restart_doit(int a) { char * name = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_APPTYPE); snmp_shutdown(name); /* This signal handler may run with SIGALARM blocked. * Since the signal mask is preserved accross execv(), we must * make sure that SIGALARM is unblocked prior of execv'ing. * Otherwise SIGALARM will be ignored in the next incarnation * of snmpd, because the signal is blocked. And thus, the * restart doesn't work anymore. * * A quote from the sigprocmask() man page: * The use of sigprocmask() is unspecified in a multithreaded process; see * pthread_sigmask(3). */ #if HAVE_SIGPROCMASK { sigset_t empty_set; sigemptyset(&empty_set); sigprocmask(SIG_SETMASK, &empty_set, NULL); } #elif HAVE_SIGBLOCK sigsetmask(0); #endif /* * do the exec */ #if HAVE_EXECV execv(argvrestartname, argvrestartp); setPerrorstatus(argvrestartname); #endif }
int get_exec_output(struct extensible *ex) { #if HAVE_EXECV int fd[2], i, cnt; char ctmp[STRMAX], *cptr1, *cptr2, argvs[STRMAX], **argv, **aptr; #ifdef EXCACHETIME char cachefile[STRMAX]; char cache[MAXCACHESIZE]; ssize_t cachebytes; long curtime; static char lastcmd[STRMAX]; int cfd; static int lastresult; int readcount; #endif #ifdef EXCACHETIME sprintf(cachefile, "%s/%s", get_persistent_directory(), CACHEFILE); curtime = time(NULL); if (curtime > (cachetime + EXCACHETIME) || strcmp(ex->command, lastcmd) != 0) { strcpy(lastcmd, ex->command); cachetime = curtime; #endif if (pipe(fd)) { setPerrorstatus("pipe"); #ifdef EXCACHETIME cachetime = 0; #endif return -1; } if ((ex->pid = fork()) == 0) { close(1); if (dup(fd[1]) != 1) { setPerrorstatus("dup"); return -1; } /* * write standard output and standard error to pipe. */ /* * close all other file descriptors. */ for (cnt = getdtablesize() - 1; cnt >= 2; --cnt) (void) close(cnt); (void) dup(1); /* stderr */ /* * set standard input to /dev/null */ close(0); (void) open("/dev/null", O_RDWR); for (cnt = 1, cptr1 = ex->command, cptr2 = argvs; cptr1 && *cptr1 != 0; cptr2++, cptr1++) { *cptr2 = *cptr1; if (*cptr1 == ' ') { *(cptr2++) = 0; if ((cptr1 = skip_white(cptr1)) == NULL) break; if (cptr1) { *cptr2 = *cptr1; if (*cptr1 != 0) cnt++; } } } *cptr2 = 0; *(cptr2 + 1) = 0; argv = (char **) malloc((cnt + 2) * sizeof(char *)); if (argv == NULL) return 0; /* memory alloc error */ aptr = argv; *(aptr++) = argvs; for (cptr2 = argvs, i = 1; i != cnt; cptr2++) if (*cptr2 == 0) { *(aptr++) = cptr2 + 1; i++; } while (*cptr2 != 0) cptr2++; *(aptr++) = NULL; copy_nword(ex->command, ctmp, sizeof(ctmp)); execv(ctmp, argv); perror(ctmp); exit(1); } else { close(fd[1]); if (ex->pid < 0) { close(fd[0]); setPerrorstatus("fork"); #ifdef EXCACHETIME cachetime = 0; #endif return -1; } #ifdef EXCACHETIME unlink(cachefile); /* * XXX Use SNMP_FILEMODE_CLOSED instead of 644? */ if ((cfd = open(cachefile, O_WRONLY | O_TRUNC | O_CREAT, 0644)) < 0) { setPerrorstatus(cachefile); cachetime = 0; return -1; } fcntl(fd[0], F_SETFL, O_NONBLOCK); /* don't block on reads */ #ifdef HAVE_USLEEP for (readcount = 0; readcount <= MAXREADCOUNT * 100 && (cachebytes = read(fd[0], (void *) cache, MAXCACHESIZE)); readcount++) { #else for (readcount = 0; readcount <= MAXREADCOUNT && (cachebytes = read(fd[0], (void *) cache, MAXCACHESIZE)); readcount++) { #endif if (cachebytes > 0) write(cfd, (void *) cache, cachebytes); else if (cachebytes == -1 && errno != EAGAIN) { setPerrorstatus("read"); break; } else #ifdef HAVE_USLEEP usleep(10000); /* sleeps for 0.01 sec */ #else sleep(1); #endif } close(cfd); close(fd[0]); /* * wait for the child to finish */ if (ex->pid > 0 && waitpid(ex->pid, &ex->result, 0) < 0) { setPerrorstatus("waitpid()"); cachetime = 0; return -1; } ex->pid = 0; ex->result = WEXITSTATUS(ex->result); lastresult = ex->result; #else /* !EXCACHETIME */ return (fd[0]); #endif } #ifdef EXCACHETIME } else {
int run_exec_command( char *command, char *input, char *output, int *out_len) /* Or realloc style ? */ { #if HAVE_EXECV int ipipe[2]; int opipe[2]; int i; int pid; int result; char **argv; int argc; DEBUGMSGTL(("run:exec", "running '%s'\n", command)); pipe(ipipe); pipe(opipe); if ((pid = fork()) == 0) { /* * Child process */ /* * Set stdin/out/err to use the pipe * and close everything else */ close(0); dup( ipipe[0]); close(ipipe[1]); close(1); dup( opipe[1]); close(opipe[0]); close(2); dup(1); for (i = getdtablesize()-1; i>2; i--) close(i); /* * Set up the argv array and execute it * This is being run in the child process, * so will release resources when it terminates. */ argv = tokenize_exec_command( command, &argc ); execv( argv[0], argv ); perror( argv[0] ); exit(1); /* End of child */ } else if (pid > 0) { char cache[NETSNMP_MAXCACHESIZE]; char *cache_ptr; ssize_t count, cache_size, offset = 0; int waited = 0, numfds; fd_set readfds; struct timeval timeout; /* * Parent process */ /* * Pass the input message (if any) to the child, * wait for the child to finish executing, and read * any output into the output buffer (if provided) */ close(ipipe[0]); close(opipe[1]); if (input) { write(ipipe[1], input, strlen(input)); close(ipipe[1]); /* or flush? */ } else close(ipipe[1]); /* * child will block if it writes a lot of data and * fills up the pipe before exiting, so we read data * to keep the pipe empty. */ if (output && ((NULL == out_len) || (0 == *out_len))) { DEBUGMSGTL(("run:exec", "invalid params; no output will be returned\n")); output = NULL; } if (output) { cache_ptr = output; cache_size = *out_len - 1; } else { cache_ptr = cache; cache_size = sizeof(cache); } /* * xxx: some of this code was lifted from get_exec_output * in util_funcs.c. Probably should be moved to a common * routine for both to use. */ DEBUGMSGTL(("verbose:run:exec"," waiting for child %d...\n", pid)); numfds = opipe[0] + 1; i = NETSNMP_MAXREADCOUNT; for (; i; --i) { /* * set up data for select */ FD_ZERO(&readfds); FD_SET(opipe[0],&readfds); timeout.tv_sec = 1; timeout.tv_usec = 0; DEBUGMSGTL(("verbose:run:exec", " calling select\n")); count = select(numfds, &readfds, NULL, NULL, &timeout); if (count == -1) { if (EAGAIN == errno) continue; else { DEBUGMSGTL(("verbose:run:exec", " errno %d\n", errno)); setPerrorstatus("read"); break; } } else if (0 == count) { DEBUGMSGTL(("verbose:run:exec", " timeout\n")); continue; } if (! FD_ISSET(opipe[0], &readfds)) { DEBUGMSGTL(("verbose:run:exec", " fd not ready!\n")); continue; } /* * read data from the pipe, optionally saving to output buffer */ count = read(opipe[0], &cache_ptr[offset], cache_size); DEBUGMSGTL(("verbose:run:exec", " read %d bytes\n", (int)count)); if (0 == count) { int rc; /* * we shouldn't get no data, because select should * wait til the fd is ready. before we go back around, * check to see if the child exited. */ DEBUGMSGTL(("verbose:run:exec", " no data!\n")); if ((rc = waitpid(pid, &result, WNOHANG)) <= 0) { if (rc < 0) { snmp_log_perror("waitpid"); break; } else DEBUGMSGTL(("verbose:run:exec", " child not done!?!\n"));; } else { DEBUGMSGTL(("verbose:run:exec", " child done\n")); waited = 1; /* don't wait again */ break; } } else if (count > 0) { /* * got some data. fix up offset, if needed. */ if(output) { offset += count; cache_size -= count; if (cache_size <= 0) { DEBUGMSGTL(("verbose:run:exec", " output full\n")); break; } DEBUGMSGTL(("verbose:run:exec", " %d left in buffer\n", (int)cache_size)); } } else if ((count == -1) && (EAGAIN != errno)) { /* * if error, break */ DEBUGMSGTL(("verbose:run:exec", " errno %d\n", errno)); setPerrorstatus("read"); break; } } DEBUGMSGTL(("verbose:run:exec", " done reading\n")); if (output) DEBUGMSGTL(("run:exec", " got %d bytes\n", *out_len)); /* * close pipe to signal that we aren't listenting any more. */ close(opipe[0]); /* * if we didn't wait successfully above, wait now. * xxx-rks: seems like this is a waste of the agent's * time. maybe start a time to wait(WNOHANG) once a second, * and late the agent continue? */ if ((!waited) && (waitpid(pid, &result, 0) < 0 )) { snmp_log_perror("waitpid"); return -1; } /* * null terminate any output */ if (output) { output[offset] = 0; *out_len = offset; } DEBUGMSGTL(("run:exec"," child %d finished. result=%d\n", pid,result)); return WEXITSTATUS(result); } else { /* * Parent process - fork failed */ snmp_log_perror("fork"); close(ipipe[0]); close(ipipe[1]); close(opipe[0]); close(opipe[1]); return -1; } #else /* * If necessary, fall back to using 'system' */ DEBUGMSGTL(("run:exec", "running shell command '%s'\n", command)); return run_shell_command( command, input, output, out_len ); #endif }
int get_exec_pipes(char *cmd, int *fdIn, int *fdOut, int *pid) { /* Alexander Prömel, [email protected] 08/24/2006 The following code, is tested on picotux rev. 1.01. I think, it will be better to put the named pipes, into /var/run or make it selectable via CONFIG file. If the pipe file already exist, the creation will fail. I put the pipes into /flash, the pipepath has to change in ucd-snmp/pass_persist.c too, if you change it here. */ #if HAVE_EXECV #ifdef __uClinux__ /* HAVE uClinux */ int in,out; char fifo_in_path[256]; char fifo_out_path[256]; pid_t tpid; if ((tpid = vfork()) == 0) { /*temp child*/ execve(cmd, NULL,NULL); perror(cmd); exit(1); } else { if(tpid > 0) { /*initialize workspace*/ snprintf(fifo_in_path, 256, "/flash/cp_%d", tpid); snprintf(fifo_out_path, 256, "/flash/pc_%d", tpid); in = mkfifo(fifo_in_path, S_IRWXU); /*Create Input Pipe, 700*/ if ( in ) { perror("parent: inpipe"); exit(0); } out = mkfifo(fifo_out_path, S_IRWXU); /*Create Output Pipe, 700*/ if ( out ) { perror("parent: outpipe"); exit(0); } in = open(fifo_in_path,O_RDONLY); /*open the Input Pipe read Only*/ if(in < 0) { perror("parent: input"); exit(0); } out = open(fifo_out_path,O_WRONLY); /*open the Output Pipe write Only*/ if(out < 0) { perror("parent: output"); exit(0); } *fdIn = in; /*read*/ *fdOut = out; /*write*/ *pid = tpid; return (1); /* We are returning 0 for error... */ } else { /*pid < 0*/ setPerrorstatus("vfork"); return 0; } } #else /*HAVE x86*/ int fd[2][2], i, cnt; char ctmp[STRMAX], *cptr1, *cptr2, argvs[STRMAX], **argv, **aptr; /* * Setup our pipes */ if (pipe(fd[0]) || pipe(fd[1])) { setPerrorstatus("pipe"); return 0; } if ((*pid = fork()) == 0) { /* First handle for the child */ close(0); if (dup(fd[0][0]) != 0) { setPerrorstatus("dup 0"); return 0; } close(1); if (dup(fd[1][1]) != 1) { setPerrorstatus("dup 1"); return 0; } /* * write standard output and standard error to pipe. */ /* * close all non-standard open file descriptors */ for (cnt = getdtablesize() - 1; cnt >= 2; --cnt) (void) close(cnt); (void) dup(1); /* stderr */ for (cnt = 1, cptr1 = cmd, cptr2 = argvs; *cptr1 != 0; cptr2++, cptr1++) { *cptr2 = *cptr1; if (*cptr1 == ' ') { *(cptr2++) = 0; if ((cptr1 = skip_white(cptr1)) == NULL) break; *cptr2 = *cptr1; if (*cptr1 != 0) cnt++; } } *cptr2 = 0; *(cptr2 + 1) = 0; argv = (char **) malloc((cnt + 2) * sizeof(char *)); if (argv == NULL) return 0; /* memory alloc error */ aptr = argv; *(aptr++) = argvs; for (cptr2 = argvs, i = 1; i != cnt; cptr2++) if (*cptr2 == 0) { *(aptr++) = cptr2 + 1; i++; } while (*cptr2 != 0) cptr2++; *(aptr++) = NULL; copy_nword(cmd, ctmp, sizeof(ctmp)); execv(ctmp, argv); perror(ctmp); exit(1); } else { close(fd[0][0]); close(fd[1][1]); if (*pid < 0) { close(fd[0][1]); close(fd[1][0]); setPerrorstatus("fork"); return 0; } *fdIn = fd[1][0]; *fdOut = fd[0][1]; return (1); /* We are returning 0 for error... */ } #endif /* uClinux or x86 */ #endif /* !HAVE_EXECV */ #if defined(WIN32) && !defined (mingw32) && !defined(HAVE_EXECV) /* MSVC (MinGW not working but should use this code). Cygwin already works as it has execv and fork */ /* Reference: MS tech note: 190351 */ HANDLE hInputWriteTmp, hInputRead, hInputWrite = NULL; HANDLE hOutputReadTmp, hOutputRead, hOutputWrite = NULL; HANDLE hErrorWrite; SECURITY_ATTRIBUTES sa; PROCESS_INFORMATION pi; STARTUPINFO si; sa.nLength= sizeof(SECURITY_ATTRIBUTES); sa.lpSecurityDescriptor = NULL; sa.bInheritHandle = TRUE; /* Child temporary output pipe with Inheritance on (sa.bInheritHandle is true) */ if (!CreatePipe(&hOutputReadTmp,&hOutputWrite,&sa,0)) { DEBUGMSGTL(("util_funcs", "get_exec_pipes CreatePipe ChildOut: %d\n", GetLastError())); return 0; } /* Child temporary input pipe with Inheritance on (sa.bInheritHandle is true) */ if (!CreatePipe(&hInputRead,&hInputWriteTmp,&sa,0)) { DEBUGMSGTL(("util_funcs", "get_exec_pipes CreatePipe ChildIn: %d\n", GetLastError())); return 0; } /* Copy the stdout handle to the stderr handle in case the child closes one of * its stdout handles. */ if (!DuplicateHandle(GetCurrentProcess(),hOutputWrite, GetCurrentProcess(), &hErrorWrite,0, TRUE,DUPLICATE_SAME_ACCESS)) { DEBUGMSGTL(("util_funcs", "get_exec_pipes DuplicateHandle: %d\n", GetLastError())); return 0; } /* Create new copies of the input and output handles but set bInheritHandle to * FALSE so the new handle can not be inherited. Otherwise the handles can not * be closed. */ if (!DuplicateHandle(GetCurrentProcess(), hOutputReadTmp, GetCurrentProcess(), &hOutputRead, 0, FALSE, DUPLICATE_SAME_ACCESS)) { DEBUGMSGTL(("util_funcs", "get_exec_pipes DupliateHandle ChildOut: %d\n", GetLastError())); CloseHandle(hErrorWrite); return 0; } if (!DuplicateHandle(GetCurrentProcess(),hInputWriteTmp, GetCurrentProcess(), &hInputWrite, 0, FALSE, DUPLICATE_SAME_ACCESS)) { DEBUGMSGTL(("util_funcs","get_exec_pipes DupliateHandle ChildIn: %d\n", GetLastError())); CloseHandle(hErrorWrite); CloseHandle(hOutputRead); return 0; } /* Close the temporary output and input handles */ if (!CloseHandle(hOutputReadTmp)) { DEBUGMSGTL(("util_funcs", "get_exec_pipes CloseHandle (hOutputReadTmp): %d\n", GetLastError())); CloseHandle(hErrorWrite); CloseHandle(hOutputRead); CloseHandle(hInputWrite); return 0; } if (!CloseHandle(hInputWriteTmp)) { DEBUGMSGTL(("util_funcs", "get_exec_pipes CloseHandle (hInputWriteTmp): %d\n", GetLastError())); CloseHandle(hErrorWrite); CloseHandle(hOutputRead); CloseHandle(hInputWrite); return 0; } /* Associates a C run-time file descriptor with an existing operating-system file handle. */ *fdIn = _open_osfhandle((long) hOutputRead, 0); *fdOut = _open_osfhandle((long) hInputWrite, 0); /* Set up STARTUPINFO for CreateProcess with the handles and have it hide the window * for the new process. */ ZeroMemory(&si,sizeof(STARTUPINFO)); si.cb = sizeof(STARTUPINFO); si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW; si.hStdOutput = hOutputWrite; si.hStdInput = hInputRead; si.hStdError = hErrorWrite; si.wShowWindow = SW_HIDE; /* Launch the process that you want to redirect. Example snmpd.conf pass_persist: * pass_persist .1.3.6.1.4.1.2021.255 c:/perl/bin/perl c:/temp/pass_persisttest */ if (!CreateProcess(NULL, cmd, NULL, NULL, TRUE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi)) { DEBUGMSGTL(("util_funcs","get_exec_pipes CreateProcess:'%s' %d\n",cmd, GetLastError())); CloseHandle(hErrorWrite); CloseHandle(hOutputRead); CloseHandle(hInputWrite); return 0; } DEBUGMSGTL(("util_funcs","child hProcess (stored in pid): %d\n",(int)pi.hProcess)); DEBUGMSGTL(("util_funcs","child dwProcessId (task manager): %d\n",(int)pi.dwProcessId)); /* Set global child process handle */ *pid = (int)pi.hProcess; /* Cleanup */ if (!CloseHandle(pi.hThread)) DEBUGMSGTL(("util_funcs","get_exec_pipes CloseHandle pi.hThread: %d\n",cmd)); /* Close pipe handles to make sure that no handles to the write end of the * output pipe are maintained in this process or else the pipe will * not close when the child process exits and any calls to ReadFile * will hang. */ if (!CloseHandle(hOutputWrite)){ DEBUGMSGTL(("util_funcs","get_exec_pipes CloseHandle hOutputWrite: %d\n",cmd, GetLastError())); return 0; } if (!CloseHandle(hInputRead)) { DEBUGMSGTL(("util_funcs","get_exec_pipes CloseHandle hInputRead: %d\n",cmd, GetLastError())); return 0; } if (!CloseHandle(hErrorWrite)) { DEBUGMSGTL(("util_funcs","get_exec_pipes CloseHandle hErrorWrite: %d\n",cmd, GetLastError())); return 0; } return 1; #endif /* WIN32 */ return 0; }
int get_exec_output(struct extensible *ex) { #if HAVE_EXECV && HAVE_FORK char cachefile[STRMAX]; char cache[NETSNMP_MAXCACHESIZE]; ssize_t cachebytes; int cfd; #ifdef NETSNMP_EXCACHETIME long curtime; static char lastcmd[STRMAX]; static int lastresult; #endif DEBUGMSGTL(("exec:get_exec_output","calling %s\n", ex->command)); sprintf(cachefile, "%s/%s", get_persistent_directory(), NETSNMP_CACHEFILE); #ifdef NETSNMP_EXCACHETIME curtime = time(NULL); if (curtime > (cachetime + NETSNMP_EXCACHETIME) || strcmp(ex->command, lastcmd) != 0) { strcpy(lastcmd, ex->command); cachetime = curtime; #endif cachebytes = NETSNMP_MAXCACHESIZE; ex->result = run_exec_command( ex->command, NULL, cache, &cachebytes ); unlink(cachefile); /* * XXX Use SNMP_FILEMODE_CLOSED instead of 644? */ if ((cfd = open(cachefile, O_WRONLY | O_TRUNC | O_CREAT, 0600)) < 0) { snmp_log(LOG_ERR,"can not create cache file\n"); setPerrorstatus(cachefile); cachetime = 0; return -1; } if (cachebytes > 0) write(cfd, (void *) cache, cachebytes); close(cfd); #ifdef NETSNMP_EXCACHETIME lastresult = ex->result; } else { ex->result = lastresult; } #endif DEBUGMSGTL(("exec:get_exec_output","using cached value\n")); if ((cfd = open(cachefile, O_RDONLY)) < 0) { snmp_log(LOG_ERR,"can not open cache file\n"); setPerrorstatus(cachefile); return -1; } return (cfd); #else /* !HAVE_EXECV || !HAVE_FORK */ #if defined(WIN32) && !defined(HAVE_EXECV) /* MSVC and MinGW. Cygwin already works as it has execv and fork */ int fd; /* Reference: MS tech note: 190351 */ HANDLE hOutputReadTmp, hOutputRead, hOutputWrite = NULL; HANDLE hErrorWrite; SECURITY_ATTRIBUTES sa; PROCESS_INFORMATION pi; STARTUPINFO si; sa.nLength= sizeof(SECURITY_ATTRIBUTES); sa.lpSecurityDescriptor = NULL; sa.bInheritHandle = TRUE; DEBUGMSGTL(("exec:get_exec_output","calling %s\n", ex->command)); /* Child temporary output pipe with Inheritance on (sa.bInheritHandle is true) */ if (!CreatePipe(&hOutputReadTmp,&hOutputWrite,&sa,0)) { DEBUGMSGTL(("util_funcs", "get_exec_pipes CreatePipe ChildOut: %d\n", GetLastError())); return -1; } /* Copy the stdout handle to the stderr handle in case the child closes one of * its stdout handles. */ if (!DuplicateHandle(GetCurrentProcess(),hOutputWrite, GetCurrentProcess(), &hErrorWrite,0, TRUE,DUPLICATE_SAME_ACCESS)) { DEBUGMSGTL(("util_funcs", "get_exec_output DuplicateHandle: %d\n", GetLastError())); return -1; } /* Create new copies of the input and output handles but set bInheritHandle to * FALSE so the new handle can not be inherited. Otherwise the handles can not * be closed. */ if (!DuplicateHandle(GetCurrentProcess(), hOutputReadTmp, GetCurrentProcess(), &hOutputRead, 0, FALSE, DUPLICATE_SAME_ACCESS)) { DEBUGMSGTL(("util_funcs", "get_exec_output DupliateHandle ChildOut: %d\n", GetLastError())); CloseHandle(hErrorWrite); return -1; } /* Close the temporary output and input handles */ if (!CloseHandle(hOutputReadTmp)) { DEBUGMSGTL(("util_funcs", "get_exec_output CloseHandle (hOutputReadTmp): %d\n", GetLastError())); CloseHandle(hErrorWrite); CloseHandle(hOutputRead); return -1; } /* Associates a C run-time file descriptor with an existing operating-system file handle. */ fd = _open_osfhandle((long) hOutputRead, 0); /* Set up STARTUPINFO for CreateProcess with the handles and have it hide the window * for the new process. */ ZeroMemory(&si,sizeof(STARTUPINFO)); si.cb = sizeof(STARTUPINFO); si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW; si.hStdOutput = hOutputWrite; si.hStdError = hErrorWrite; si.wShowWindow = SW_HIDE; /* Launch the process that you want to redirect. Example snmpd.conf pass_persist: * pass_persist .1.3.6.1.4.1.2021.255 c:/perl/bin/perl c:/temp/pass_persisttest */ if (!CreateProcess(NULL, ex->command, NULL, NULL, TRUE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi)) { DEBUGMSGTL(("util_funcs","get_exec_output CreateProcess:'%s' %d\n",ex->command, GetLastError())); CloseHandle(hErrorWrite); CloseHandle(hOutputRead); return -1; } /* Set global child process handle */ ex->pid = (int)pi.hProcess; ex->tid = (int)pi.hThread; /* Close pipe handles to make sure that no handles to the write end of the * output pipe are maintained in this process or else the pipe will * not close when the child process exits and any calls to ReadFile * will hang. */ if (!CloseHandle(hOutputWrite)){ DEBUGMSGTL(("util_funcs","get_exec_output CloseHandle hOutputWrite: %d\n",ex->command, GetLastError())); return -1; } if (!CloseHandle(hErrorWrite)) { DEBUGMSGTL(("util_funcs","get_exec_output CloseHandle hErrorWrite: %d\n",ex->command, GetLastError())); return -1; } return fd; #endif /* WIN32 */ return -1; #endif }
unsigned char *var_extensible_disk(struct variable *vp, oid *name, int *length, int exact, int *var_len, WriteMethod **write_method) { int percent, iserror, disknum=0; #if !defined(HAVE_SYS_STATVFS_H) && !defined(HAVE_STATFS) double totalblks, free, used, avail, availblks; #else static long avail; #endif static long long_ret; static char errmsg[300]; #if defined(HAVE_STATVFS) || defined(HAVE_STATFS) #ifdef STAT_STATFS_FS_DATA struct fs_data fsd; struct { u_int f_blocks, f_bfree, f_bavail; } vfs; #else struct statvfs vfs; #endif #else #if HAVE_FSTAB_H int file; union { struct fs iu_fs; char dummy[SBSIZE]; } sb; #define filesys sb.iu_fs #endif #endif if (header_simple_table(vp,name,length,exact,var_len,write_method,numdisks)) return(NULL); disknum = name[*length - 1] - 1; switch (vp->magic) { case MIBINDEX: long_ret = disknum+1; return((u_char *) (&long_ret)); case ERRORNAME: /* DISKPATH */ *var_len = strlen(disks[disknum].path); return((u_char *) disks[disknum].path); case DISKDEVICE: *var_len = strlen(disks[disknum].device); return((u_char *) disks[disknum].device); case DISKMINIMUM: long_ret = disks[disknum].minimumspace; return((u_char *) (&long_ret)); case DISKMINPERCENT: long_ret = disks[disknum].minpercent; return((u_char *) (&long_ret)); } #if defined(HAVE_SYS_STATVFS_H) || defined(HAVE_STATFS) #ifdef STAT_STATFS_FS_DATA if (statvfs (disks[disknum].path, &fsd) == -1) { #else if (statvfs (disks[disknum].path, &vfs) == -1) { #endif fprintf(stderr,"Couldn't open device %s\n",disks[disknum].device); setPerrorstatus("statvfs dev/disk"); return NULL; } #ifdef STAT_STATFS_FS_DATA vfs.f_blocks = fsd.fd_btot; vfs.f_bfree = fsd.fd_bfree; vfs.f_bavail = fsd.fd_bfreen; #endif #if defined(HAVE_ODS) vfs.f_blocks = vfs.f_spare[0]; vfs.f_bfree = vfs.f_spare[1]; vfs.f_bavail = vfs.f_spare[2]; #endif percent = vfs.f_bavail <= 0 ? 100 : (int) ((double) (vfs.f_blocks - vfs.f_bfree) / (double) (vfs.f_blocks - (vfs.f_bfree - vfs.f_bavail)) * 100.0 + 0.5); avail = vfs.f_bavail; #ifdef STRUCT_STATVFS_HAS_F_FRSIZE if (vfs.f_frsize > 255) avail = avail * (vfs.f_frsize / 1024); #endif iserror = (disks[disknum].minimumspace >= 0 ? avail < disks[disknum].minimumspace : 100-percent <= disks[disknum].minpercent) ? 1 : 0; switch (vp->magic) { case DISKTOTAL: long_ret = vfs.f_blocks; #ifdef STRUCT_STATVFS_HAS_F_FRSIZE if (vfs.f_frsize > 255) long_ret = long_ret * (vfs.f_frsize / 1024); #endif return((u_char *) (&long_ret)); case DISKAVAIL: return((u_char *) (&avail)); case DISKUSED: long_ret = (vfs.f_blocks - vfs.f_bfree); #ifdef STRUCT_STATVFS_HAS_F_FRSIZE if (vfs.f_frsize > 255) long_ret = long_ret * (vfs.f_frsize / 1024); #endif return((u_char *) (&long_ret)); case DISKPERCENT: long_ret = percent; return ((u_char *) (&long_ret)); case ERRORFLAG: long_ret = iserror; return((u_char *) (&long_ret)); case ERRORMSG: if (iserror) { if (disks[disknum].minimumspace >= 0) sprintf(errmsg,"%s: less than %d free (= %d)",disks[disknum].path, disks[disknum].minimumspace, (int) avail); else sprintf(errmsg,"%s: less than %d%% free (= %d%%)",disks[disknum].path, disks[disknum].minpercent, percent); } else errmsg[0] = 0; *var_len = strlen(errmsg); return((u_char *) (errmsg)); } #else #if HAVE_FSTAB_H /* read the disk information */ if ((file = open(disks[disknum].device,0)) < 0) { fprintf(stderr,"Couldn't open device %s\n",disks[disknum].device); setPerrorstatus("open dev/disk"); return(NULL); } lseek(file, (long) (SBLOCK * DEV_BSIZE), 0); if (read(file,(char *) &filesys, SBSIZE) != SBSIZE) { setPerrorstatus("open dev/disk"); fprintf(stderr,"Error reading device %s\n",disks[disknum].device); close(file); return(NULL); } close(file); totalblks = filesys.fs_dsize; free = filesys.fs_cstotal.cs_nbfree * filesys.fs_frag + filesys.fs_cstotal.cs_nffree; used = totalblks - free; availblks = totalblks * (100 - filesys.fs_minfree) / 100; avail = availblks > used ? availblks - used : 0; percent = availblks == 0 ? 100 : (int) ((double) used / (double) totalblks * 100.0 + 0.5); iserror = (disks[disknum].minimumspace >= 0 ? avail * filesys.fs_fsize / 1024 < disks[disknum].minimumspace : 100-percent <= disks[disknum].minpercent) ? 1 : 0; switch (vp->magic) { case DISKTOTAL: long_ret = (totalblks * filesys.fs_fsize / 1024); return((u_char *) (&long_ret)); case DISKAVAIL: long_ret = avail * filesys.fs_fsize/1024; return((u_char *) (&long_ret)); case DISKUSED: long_ret = used * filesys.fs_fsize/1024; return((u_char *) (&long_ret)); case DISKPERCENT: long_ret = percent; return ((u_char *) (&long_ret)); case ERRORFLAG: long_ret = iserror; return((u_char *) (&long_ret)); case ERRORMSG: if (iserror) if (disks[disknum].minimumspace >= 0) sprintf(errmsg,"%s: less than %d free (= %d)",disks[disknum].path, disks[disknum].minimumspace, avail * filesys.fs_fsize/1024); else sprintf(errmsg,"%s: less than %d%% free (= %d%%)",disks[disknum].path, disks[disknum].minpercent, percent); else errmsg[0] = 0; *var_len = strlen(errmsg); return((u_char *) (errmsg)); } #endif #endif return NULL; }