diff options
Diffstat (limited to 'snmplib/system.c')
-rw-r--r-- | snmplib/system.c | 1195 |
1 files changed, 1195 insertions, 0 deletions
diff --git a/snmplib/system.c b/snmplib/system.c new file mode 100644 index 0000000..7a26152 --- /dev/null +++ b/snmplib/system.c @@ -0,0 +1,1195 @@ +/* + * system.c + */ +/* Portions of this file are subject to the following copyright(s). See + * the Net-SNMP's COPYING file for more details and other copyrights + * that may apply: + */ +/*********************************************************** + Copyright 1992 by Carnegie Mellon University + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of CMU not be +used in advertising or publicity pertaining to distribution of the +software without specific, written prior permission. + +CMU DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. +******************************************************************/ +/* + * Portions of this file are copyrighted by: + * Copyright © 2003 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms specified in the COPYING file + * distributed with the Net-SNMP package. + */ +/* + * System dependent routines go here + */ +#include <net-snmp/net-snmp-config.h> +#include <stdio.h> +#include <ctype.h> +#include <errno.h> + +#if HAVE_IO_H +#include <io.h> +#endif +#if HAVE_DIRECT_H +#include <direct.h> +#endif +#if HAVE_UNISTD_H +#include <unistd.h> +#endif +#if HAVE_STDLIB_H +#include <stdlib.h> +#endif + +#if TIME_WITH_SYS_TIME +# ifdef WIN32 +# include <sys/timeb.h> +# else +# include <sys/time.h> +# endif +# include <time.h> +#else +# if HAVE_SYS_TIME_H +# include <sys/time.h> +# else +# include <time.h> +# endif +#endif + +#include <sys/types.h> + +#if HAVE_NETINET_IN_H +#include <netinet/in.h> +#endif + +#if HAVE_WINSOCK_H +#include <winsock.h> +#endif +#if HAVE_SYS_SOCKET_H +#include <sys/socket.h> +#endif +#if HAVE_NET_IF_H +#include <net/if.h> +#endif + +#if HAVE_SYS_SOCKIO_H +#include <sys/sockio.h> +#endif + +#if HAVE_SYS_IOCTL_H +#include <sys/ioctl.h> +#endif + +#ifdef HAVE_NLIST_H +#include <nlist.h> +#endif + +#if HAVE_SYS_FILE_H +#include <sys/file.h> +#endif + +#if HAVE_KSTAT_H +#include <kstat.h> +#endif + +#if HAVE_SYS_PARAM_H +#include <sys/param.h> +#endif +#if HAVE_SYS_SYSCTL_H +#include <sys/sysctl.h> +#endif + +#if HAVE_STRING_H +#include <string.h> +#else +#include <strings.h> +#endif + +#if HAVE_DMALLOC_H +#include <dmalloc.h> +#endif + +#ifdef HAVE_SYS_STAT_H +#include <sys/stat.h> +#endif +#if HAVE_FCNTL_H +#include <fcntl.h> +#endif + +#if defined(hpux10) || defined(hpux11) +#include <sys/pstat.h> +#endif + +#if HAVE_SYS_UTSNAME_H +#include <sys/utsname.h> +#endif + +#if HAVE_SYS_SYSTEMCFG_H +#include <sys/systemcfg.h> +#endif + +#if HAVE_SYS_SYSTEMINFO_H +#include <sys/systeminfo.h> +#endif + +#include <net-snmp/types.h> +#include <net-snmp/output_api.h> +#include <net-snmp/utilities.h> +#include <net-snmp/library/system.h> /* for "internal" definitions */ + +#include <net-snmp/library/snmp_api.h> +#include <net-snmp/library/read_config.h> /* for get_temp_file_pattern() */ + +#ifndef IFF_LOOPBACK +# define IFF_LOOPBACK 0 +#endif + +#ifdef INADDR_LOOPBACK +# define LOOPBACK INADDR_LOOPBACK +#else +# define LOOPBACK 0x7f000001 +#endif + +/** + * fork current process into the background. + * + * This function forks a process into the background, in order to + * become a daemon process. It does a few things along the way: + * + * - becoming a process/session group leader, and forking a second time so + * that process/session group leader can exit. + * + * - changing the working directory to / + * + * - closing stdin, stdout and stderr (unless stderr_log is set) and + * redirecting them to /dev/null + * + * @param quit_immediately : indicates if the parent process should + * exit after a successful fork. + * @param stderr_log : indicates if stderr is being used for + * logging and shouldn't be closed + * @returns -1 : fork error + * 0 : child process returning + * >0 : parent process returning. returned value is the child PID. + */ +int +netsnmp_daemonize(int quit_immediately, int stderr_log) +{ + int i = 0; + DEBUGMSGT(("daemonize","deamonizing...\n")); +#if HAVE_FORK + /* + * Fork to return control to the invoking process and to + * guarantee that we aren't a process group leader. + */ + i = fork(); + if (i != 0) { + /* Parent. */ + DEBUGMSGT(("daemonize","first fork returned %d.\n", i)); + if(i == -1) { + snmp_log(LOG_ERR,"first fork failed (errno %d) in " + "netsnmp_daemonize()\n", errno); + return -1; + } + if (quit_immediately) { + DEBUGMSGT(("daemonize","parent exiting\n")); + exit(0); + } + } else { + /* Child. */ +#ifdef HAVE_SETSID + /* Become a process/session group leader. */ + setsid(); +#endif + /* + * Fork to let the process/session group leader exit. + */ + if ((i = fork()) != 0) { + DEBUGMSGT(("daemonize","second fork returned %d.\n", i)); + if(i == -1) { + snmp_log(LOG_ERR,"second fork failed (errno %d) in " + "netsnmp_daemonize()\n", errno); + } + /* Parent. */ + exit(0); + } +#ifndef WIN32 + else { + /* Child. */ + + DEBUGMSGT(("daemonize","child continuing\n")); + + /* Avoid keeping any directory in use. */ + chdir("/"); + + if (!stderr_log) { + /* + * Close inherited file descriptors to avoid + * keeping unnecessary references. + */ + close(0); + close(1); + close(2); + + /* + * Redirect std{in,out,err} to /dev/null, just in + * case. + */ + open("/dev/null", O_RDWR); + dup(0); + dup(0); + } + } +#endif /* !WIN32 */ + } +#endif /* HAVE_FORK */ + return i; +} + +/* + * ********************************************* + */ +#ifdef WIN32 +# define WIN32_LEAN_AND_MEAN +# define WIN32IO_IS_STDIO +# define PATHLEN 1024 + +# include <tchar.h> +# include <windows.h> + +/* + * MinGW defines WIN32, but has working dirent stuff. + */ +#ifndef HAVE_DIRENT_H + +/* + * The idea here is to read all the directory names into a string table + * * (separated by nulls) and when one of the other dir functions is called + * * return the pointer to the current file name. + */ +DIR * +opendir(const char *filename) +{ + DIR *p; + long len; + long idx; + char scannamespc[PATHLEN]; + char *scanname = scannamespc; + struct stat sbuf; + WIN32_FIND_DATA FindData; + HANDLE fh; + + /* + * check to see if filename is a directory + */ + if ((stat(filename, &sbuf) < 0) || ((sbuf.st_mode & S_IFDIR) == 0)) { + return NULL; + } + + /* + * get the file system characteristics + */ + /* + * if(GetFullPathName(filename, SNMP_MAXPATH, root, &dummy)) { + * * if(dummy = strchr(root, '\\')) + * * *++dummy = '\0'; + * * if(GetVolumeInformation(root, volname, SNMP_MAXPATH, &serial, + * * &maxname, &flags, 0, 0)) { + * * downcase = !(flags & FS_CASE_IS_PRESERVED); + * * } + * * } + * * else { + * * downcase = TRUE; + * * } + */ + + /* + * Create the search pattern + */ + strcpy(scanname, filename); + + if (strchr("/\\", *(scanname + strlen(scanname) - 1)) == NULL) + strcat(scanname, "/*"); + else + strcat(scanname, "*"); + + /* + * do the FindFirstFile call + */ + fh = FindFirstFile(scanname, &FindData); + if (fh == INVALID_HANDLE_VALUE) { + return NULL; + } + + /* + * Get us a DIR structure + */ + p = (DIR *) malloc(sizeof(DIR)); + /* + * Newz(1303, p, 1, DIR); + */ + if (p == NULL) + return NULL; + + /* + * now allocate the first part of the string table for + * * the filenames that we find. + */ + idx = strlen(FindData.cFileName) + 1; + p->start = (char *) malloc(idx); + /* + * New(1304, p->start, idx, char); + */ + if (p->start == NULL) { + free(p); + return NULL; + } + strcpy(p->start, FindData.cFileName); + /* + * if(downcase) + * * strlwr(p->start); + */ + p->nfiles = 0; + + /* + * loop finding all the files that match the wildcard + * * (which should be all of them in this directory!). + * * the variable idx should point one past the null terminator + * * of the previous string found. + */ + while (FindNextFile(fh, &FindData)) { + len = strlen(FindData.cFileName); + /* + * bump the string table size by enough for the + * * new name and it's null terminator + */ + p->start = (char *) realloc((void *) p->start, idx + len + 1); + /* + * Renew(p->start, idx+len+1, char); + */ + if (p->start == NULL) { + free(p); + return NULL; + } + strcpy(&p->start[idx], FindData.cFileName); + /* + * if (downcase) + * * strlwr(&p->start[idx]); + */ + p->nfiles++; + idx += len + 1; + } + FindClose(fh); + p->size = idx; + p->curr = p->start; + return p; +} + + +/* + * Readdir just returns the current string pointer and bumps the + * * string pointer to the nDllExport entry. + */ +struct direct * +readdir(DIR * dirp) +{ + int len; + static int dummy = 0; + + if (dirp->curr) { + /* + * first set up the structure to return + */ + len = strlen(dirp->curr); + strcpy(dirp->dirstr.d_name, dirp->curr); + dirp->dirstr.d_namlen = len; + + /* + * Fake an inode + */ + dirp->dirstr.d_ino = dummy++; + + /* + * Now set up for the nDllExport call to readdir + */ + dirp->curr += len + 1; + if (dirp->curr >= (dirp->start + dirp->size)) { + dirp->curr = NULL; + } + + return &(dirp->dirstr); + } else + return NULL; +} + +/* + * free the memory allocated by opendir + */ +int +closedir(DIR * dirp) +{ + free(dirp->start); + free(dirp); + return 1; +} +#endif /* HAVE_DIRENT_H */ + +#ifndef HAVE_GETTIMEOFDAY + +int +gettimeofday(struct timeval *tv, struct timezone *tz) +{ + struct _timeb timebuffer; + + _ftime(&timebuffer); + tv->tv_usec = timebuffer.millitm * 1000; + tv->tv_sec = timebuffer.time; + return (0); +} +#endif /* !HAVE_GETTIMEOFDAY */ + +in_addr_t +get_myaddr(void) +{ + char local_host[130]; + int result; + LPHOSTENT lpstHostent; + SOCKADDR_IN in_addr, remote_in_addr; + SOCKET hSock; + int nAddrSize = sizeof(SOCKADDR); + + in_addr.sin_addr.s_addr = INADDR_ANY; + + result = gethostname(local_host, sizeof(local_host)); + if (result == 0) { + lpstHostent = gethostbyname((LPSTR) local_host); + if (lpstHostent) { + in_addr.sin_addr.s_addr = + *((u_long FAR *) (lpstHostent->h_addr)); + return ((in_addr_t) in_addr.sin_addr.s_addr); + } + } + + /* + * if we are here, than we don't have host addr + */ + hSock = socket(AF_INET, SOCK_DGRAM, 0); + if (hSock != INVALID_SOCKET) { + /* + * connect to any port and address + */ + remote_in_addr.sin_family = AF_INET; + remote_in_addr.sin_port = htons(IPPORT_ECHO); + remote_in_addr.sin_addr.s_addr = inet_addr("0.0.0.0"); + result = + connect(hSock, (LPSOCKADDR) & remote_in_addr, + sizeof(SOCKADDR)); + if (result != SOCKET_ERROR) { + /* + * get local ip address + */ + getsockname(hSock, (LPSOCKADDR) & in_addr, + (int FAR *) &nAddrSize); + } + closesocket(hSock); + } + return ((in_addr_t) in_addr.sin_addr.s_addr); +} + +long +get_uptime(void) +{ + long return_value = 0; + DWORD buffersize = (sizeof(PERF_DATA_BLOCK) + + sizeof(PERF_OBJECT_TYPE)), + type = REG_EXPAND_SZ; + PPERF_DATA_BLOCK perfdata = NULL; + + /* + * min requirement is one PERF_DATA_BLOCK plus one PERF_OBJECT_TYPE + */ + perfdata = (PPERF_DATA_BLOCK) malloc(buffersize); + if (!perfdata) + return 0; + + memset(perfdata, 0, buffersize); + + RegQueryValueEx(HKEY_PERFORMANCE_DATA, + "Global", NULL, &type, (LPBYTE) perfdata, &buffersize); + + /* + * we can not rely on the return value since there is always more so + * we check the signature + */ + + if (wcsncmp(perfdata->Signature, L"PERF", 4) == 0) { + /* + * signature ok, and all we need is in the in the PERF_DATA_BLOCK + */ + return_value = (long) ((perfdata->PerfTime100nSec.QuadPart / + (LONGLONG) 100000)); + } else + return_value = GetTickCount() / 10; + + RegCloseKey(HKEY_PERFORMANCE_DATA); + free(perfdata); + + return return_value; +} + +char * +winsock_startup(void) +{ + WORD VersionRequested; + WSADATA stWSAData; + int i; + static char errmsg[100]; + + /* winsock 1: use MAKEWORD(1,1) */ + /* winsock 2: use MAKEWORD(2,2) */ + + VersionRequested = MAKEWORD(2,2); + i = WSAStartup(VersionRequested, &stWSAData); + if (i != 0) { + if (i == WSAVERNOTSUPPORTED) + sprintf(errmsg, + "Unable to init. socket lib, does not support 1.1"); + else { + sprintf(errmsg, "Socket Startup error %d", i); + } + return (errmsg); + } + return (NULL); +} + +void +winsock_cleanup(void) +{ + WSACleanup(); +} + +#else /* ! WIN32 */ +/*******************************************************************/ + +/* + * XXX What if we have multiple addresses? Or no addresses for that matter? + * XXX Could it be computed once then cached? Probably not worth it (not + * used very often). + */ +in_addr_t +get_myaddr(void) +{ + int sd, i, lastlen = 0; + struct ifconf ifc; + struct ifreq *ifrp = NULL; + in_addr_t addr; + char *buf = NULL; + + if ((sd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + return 0; + } + + /* + * Cope with lots of interfaces and brokenness of ioctl SIOCGIFCONF on + * some platforms; see W. R. Stevens, ``Unix Network Programming Volume + * I'', p.435. + */ + + for (i = 8;; i += 8) { + buf = (char *) calloc(i, sizeof(struct ifreq)); + if (buf == NULL) { + close(sd); + return 0; + } + ifc.ifc_len = i * sizeof(struct ifreq); + ifc.ifc_buf = (caddr_t) buf; + + if (ioctl(sd, SIOCGIFCONF, (char *) &ifc) < 0) { + if (errno != EINVAL || lastlen != 0) { + /* + * Something has gone genuinely wrong. + */ + free(buf); + close(sd); + return 0; + } + /* + * Otherwise, it could just be that the buffer is too small. + */ + } else { + if (ifc.ifc_len == lastlen) { + /* + * The length is the same as the last time; we're done. + */ + break; + } + lastlen = ifc.ifc_len; + } + free(buf); + } + + for (ifrp = ifc.ifc_req; + (char *)ifrp < (char *)ifc.ifc_req + ifc.ifc_len; +#ifdef STRUCT_SOCKADDR_HAS_SA_LEN + ifrp = (struct ifreq *)(((char *) ifrp) + + sizeof(ifrp->ifr_name) + + ifrp->ifr_addr.sa_len) +#else + ifrp++ +#endif + ) { + if (ifrp->ifr_addr.sa_family != AF_INET) { + continue; + } + addr = ((struct sockaddr_in *) &(ifrp->ifr_addr))->sin_addr.s_addr; + + if (ioctl(sd, SIOCGIFFLAGS, (char *) ifrp) < 0) { + continue; + } + if ((ifrp->ifr_flags & IFF_UP) +#ifdef IFF_RUNNING + && (ifrp->ifr_flags & IFF_RUNNING) +#endif /* IFF_RUNNING */ + && !(ifrp->ifr_flags & IFF_LOOPBACK) + && addr != LOOPBACK) { + /* + * I *really* don't understand why this is necessary. Perhaps for + * some broken platform? Leave it for now. JBPN + */ +#ifdef SYS_IOCTL_H_HAS_SIOCGIFADDR + if (ioctl(sd, SIOCGIFADDR, (char *) ifrp) < 0) { + continue; + } + addr = + ((struct sockaddr_in *) &(ifrp->ifr_addr))->sin_addr. + s_addr; +#endif + free(buf); + close(sd); + return addr; + } + } + free(buf); + close(sd); + return 0; +} + + +#if !defined(solaris2) && !defined(linux) && !defined(cygwin) +/* + * Returns boottime in centiseconds(!). + * Caches this for future use. + */ +long +get_boottime(void) +{ + static long boottime_csecs = 0; +#if defined(hpux10) || defined(hpux11) + struct pst_static pst_buf; +#else + struct timeval boottime; +#ifdef NETSNMP_CAN_USE_SYSCTL + int mib[2]; + size_t len; +#elif defined(NETSNMP_CAN_USE_NLIST) + int kmem; + static struct nlist nl[] = { +#if !defined(hpux) + {(char *) "_boottime"}, +#else + {(char *) "boottime"}, +#endif + {(char *) ""} + }; +#endif /* NETSNMP_CAN_USE_SYSCTL */ +#endif /* hpux10 || hpux 11 */ + + + if (boottime_csecs != 0) + return (boottime_csecs); + +#if defined(hpux10) || defined(hpux11) + pstat_getstatic(&pst_buf, sizeof(struct pst_static), 1, 0); + boottime_csecs = pst_buf.boot_time * 100; +#elif NETSNMP_CAN_USE_SYSCTL + mib[0] = CTL_KERN; + mib[1] = KERN_BOOTTIME; + + len = sizeof(boottime); + + sysctl(mib, 2, &boottime, &len, NULL, 0); + boottime_csecs = (boottime.tv_sec * 100) + (boottime.tv_usec / 10000); +#elif defined(NETSNMP_CAN_USE_NLIST) + if ((kmem = open("/dev/kmem", 0)) < 0) + return 0; + nlist(KERNEL_LOC, nl); + if (nl[0].n_type == 0) { + close(kmem); + return 0; + } + + lseek(kmem, (long) nl[0].n_value, L_SET); + read(kmem, &boottime, sizeof(boottime)); + close(kmem); + boottime_csecs = (boottime.tv_sec * 100) + (boottime.tv_usec / 10000); +#else + return 0; +#endif /* hpux10 || hpux 11 */ + + return (boottime_csecs); +} +#endif + +/* + * Returns uptime in centiseconds(!). + */ +long +get_uptime(void) +{ +#if !defined(solaris2) && !defined(linux) && !defined(cygwin) && !defined(aix4) && !defined(aix5) && !defined(aix6) + struct timeval now; + long boottime_csecs, nowtime_csecs; + + boottime_csecs = get_boottime(); + if (boottime_csecs == 0) + return 0; + gettimeofday(&now, (struct timezone *) 0); + nowtime_csecs = (now.tv_sec * 100) + (now.tv_usec / 10000); + + return (nowtime_csecs - boottime_csecs); +#endif + +#if defined(aix4) || defined(aix5) || defined(aix6) + struct nlist nl; + int kmem; + time_t lbolt; + nl.n_name = "lbolt"; + if(knlist(&nl, 1, sizeof(struct nlist)) != 0) return(0); + if(nl.n_type == 0 || nl.n_value == 0) return(0); + if((kmem = open("/dev/mem", 0)) < 0) return 0; + lseek(kmem, (long) nl.n_value, L_SET); + read(kmem, &lbolt, sizeof(lbolt)); + close(kmem); + return(lbolt); +#endif + +#ifdef solaris2 + kstat_ctl_t *ksc = kstat_open(); + kstat_t *ks; + kid_t kid; + kstat_named_t *named; + u_long lbolt = 0; + + if (ksc) { + ks = kstat_lookup(ksc, "unix", -1, "system_misc"); + if (ks) { + kid = kstat_read(ksc, ks, NULL); + if (kid != -1) { + named = kstat_data_lookup(ks, "lbolt"); + if (named) { +#ifdef KSTAT_DATA_UINT32 + lbolt = named->value.ui32; +#else + lbolt = named->value.ul; +#endif + } + } + } + kstat_close(ksc); + } + return lbolt; +#endif /* solaris2 */ + +#ifdef linux + FILE *in = fopen("/proc/uptime", "r"); + long uptim = 0, a, b; + if (in) { + if (2 == fscanf(in, "%ld.%ld", &a, &b)) + uptim = a * 100 + b; + fclose(in); + } + return uptim; +#endif /* linux */ + +#ifdef cygwin + return (0); /* not implemented */ +#endif +} + +#endif /* ! WIN32 */ +/*******************************************************************/ + +#ifndef HAVE_STRNCASECMP + +/* + * test for NULL pointers before and NULL characters after + * * comparing possibly non-NULL strings. + * * WARNING: This function does NOT check for array overflow. + */ +int +strncasecmp(const char *s1, const char *s2, size_t nch) +{ + size_t ii; + int res = -1; + + if (!s1) { + if (!s2) + return 0; + return (-1); + } + if (!s2) + return (1); + + for (ii = 0; (ii < nch) && *s1 && *s2; ii++, s1++, s2++) { + res = (int) (tolower(*s1) - tolower(*s2)); + if (res != 0) + break; + } + + if (ii == nch) { + s1--; + s2--; + } + + if (!*s1) { + if (!*s2) + return 0; + return (-1); + } + if (!*s2) + return (1); + + return (res); +} + +int +strcasecmp(const char *s1, const char *s2) +{ + return strncasecmp(s1, s2, 1000000); +} + +#endif /* HAVE_STRNCASECMP */ + + +#ifndef HAVE_STRDUP +char * +strdup(const char *src) +{ + int len; + char *dst; + + len = strlen(src) + 1; + if ((dst = (char *) malloc(len)) == NULL) + return (NULL); + strcpy(dst, src); + return (dst); +} +#endif /* HAVE_STRDUP */ + +#ifndef HAVE_SETENV +int +setenv(const char *name, const char *value, int overwrite) +{ + char *cp; + int ret; + + if (overwrite == 0) { + if (getenv(name)) + return 0; + } + cp = (char *) malloc(strlen(name) + strlen(value) + 2); + if (cp == NULL) + return -1; + sprintf(cp, "%s=%s", name, value); + ret = putenv(cp); +#ifdef WIN32 + free(cp); +#endif + return ret; +} +#endif /* HAVE_SETENV */ + +/* returns centiseconds */ +int +calculate_time_diff(struct timeval *now, struct timeval *then) +{ + struct timeval tmp, diff; + memcpy(&tmp, now, sizeof(struct timeval)); + tmp.tv_sec--; + tmp.tv_usec += 1000000L; + diff.tv_sec = tmp.tv_sec - then->tv_sec; + diff.tv_usec = tmp.tv_usec - then->tv_usec; + if (diff.tv_usec > 1000000L) { + diff.tv_usec -= 1000000L; + diff.tv_sec++; + } + return ((diff.tv_sec * 100) + (diff.tv_usec / 10000)); +} + +/* returns diff in rounded seconds */ +u_int +calculate_sectime_diff(struct timeval *now, struct timeval *then) +{ + struct timeval tmp, diff; + memcpy(&tmp, now, sizeof(struct timeval)); + tmp.tv_sec--; + tmp.tv_usec += 1000000L; + diff.tv_sec = tmp.tv_sec - then->tv_sec; + diff.tv_usec = tmp.tv_usec - then->tv_usec; + if (diff.tv_usec > 1000000L) { + diff.tv_usec -= 1000000L; + diff.tv_sec++; + } + if (diff.tv_usec >= 500000L) + return diff.tv_sec + 1; + return diff.tv_sec; +} + +#ifndef HAVE_STRCASESTR +/* + * only glibc2 has this. + */ +char * +strcasestr(const char *haystack, const char *needle) +{ + const char *cp1 = haystack, *cp2 = needle; + const char *cx; + int tstch1, tstch2; + + /* + * printf("looking for '%s' in '%s'\n", needle, haystack); + */ + if (cp1 && cp2 && *cp1 && *cp2) + for (cp1 = haystack, cp2 = needle; *cp1;) { + cx = cp1; + cp2 = needle; + do { + /* + * printf("T'%c' ", *cp1); + */ + if (!*cp2) { /* found the needle */ + /* + * printf("\nfound '%s' in '%s'\n", needle, cx); + */ + return (char *) cx; + } + if (!*cp1) + break; + + tstch1 = toupper(*cp1); + tstch2 = toupper(*cp2); + if (tstch1 != tstch2) + break; + /* + * printf("M'%c' ", *cp1); + */ + cp1++; + cp2++; + } + while (1); + if (*cp1) + cp1++; + } + /* + * printf("\n"); + */ + if (cp1 && *cp1) + return (char *) cp1; + + return NULL; +} +#endif + +int +mkdirhier(const char *pathname, mode_t mode, int skiplast) +{ + struct stat sbuf; + char *ourcopy = strdup(pathname); + char *entry; + char buf[SNMP_MAXPATH]; + char *st = NULL; + +#if defined (WIN32) || defined (cygwin) + /* convert backslash to forward slash */ + for (entry = ourcopy; *entry; entry++) + if (*entry == '\\') + *entry = '/'; +#endif + + entry = strtok_r(ourcopy, "/", &st); + + buf[0] = '\0'; + +#if defined (WIN32) || defined (cygwin) + /* + * Check if first entry contains a drive-letter + * e.g "c:/path" + */ + if ((entry) && (':' == entry[1]) && + (('\0' == entry[2]) || ('/' == entry[2]))) { + strcat(buf, entry); + entry = strtok_r(NULL, "/", &st); + } +#endif + + /* + * check to see if filename is a directory + */ + while (entry) { + strcat(buf, "/"); + strcat(buf, entry); + entry = strtok_r(NULL, "/", &st); + if (entry == NULL && skiplast) + break; + if (stat(buf, &sbuf) < 0) { + /* + * DNE, make it + */ + snmp_log(LOG_INFO, "Creating directory: %s\n", buf); +#ifdef WIN32 + if (CreateDirectory(buf, NULL) == 0) +#else + if (mkdir(buf, mode) == -1) +#endif + { + free(ourcopy); + return SNMPERR_GENERR; + } + } else { + /* + * exists, is it a file? + */ + if ((sbuf.st_mode & S_IFDIR) == 0) { + /* + * ack! can't make a directory on top of a file + */ + free(ourcopy); + return SNMPERR_GENERR; + } + } + } + free(ourcopy); + return SNMPERR_SUCCESS; +} + +/** + * netsnmp_mktemp creates a temporary file based on the + * configured tempFilePattern + * + * @return file descriptor + */ +const char * +netsnmp_mktemp(void) +{ + static char name[32]; + int fd = -1; + + strcpy(name, get_temp_file_pattern()); +#ifdef HAVE_MKSTEMP + fd = mkstemp(name); +#else + if (mktemp(name)) { +# ifndef WIN32 + fd = open(name, O_CREAT | O_EXCL | O_WRONLY, S_IRUSR | S_IWUSR); +# else + /* + * Win32 needs _S_IREAD | _S_IWRITE to set permissions on file + * after closing + */ + fd = _open(name, _O_CREAT | _O_EXCL | _O_WRONLY, _S_IREAD | _S_IWRITE); +# endif + } +#endif + if (fd >= 0) { + close(fd); + DEBUGMSGTL(("netsnmp_mktemp", "temp file created: %s\n", + name)); + return name; + } + snmp_log(LOG_ERR, "netsnmp_mktemp: error creating file %s\n", + name); + return NULL; +} + +/* + * This function was created to differentiate actions + * that are appropriate for Linux 2.4 kernels, but not later kernels. + * + * This function can be used to test kernels on any platform that supports uname(). + * + * If not running a platform that supports uname(), return -1. + * + * If ospname matches, and the release matches up through the prefix, + * return 0. + * If the release is ordered higher, return 1. + * Be aware that "ordered higher" is not a guarantee of correctness. + */ +int +netsnmp_os_prematch(const char *ospmname, + const char *ospmrelprefix) +{ +#if HAVE_SYS_UTSNAME_H +static int printOSonce = 1; + struct utsname utsbuf; + if ( 0 != uname(&utsbuf)) + return -1; + + if (printOSonce) { + printOSonce = 0; + /* show the four elements that the kernel can be sure of */ + DEBUGMSGT(("daemonize","sysname '%s',\nrelease '%s',\nversion '%s',\nmachine '%s'\n", + utsbuf.sysname, utsbuf.release, utsbuf.version, utsbuf.machine)); + } + if (0 != strcasecmp(utsbuf.sysname, ospmname)) return -1; + + /* Required to match only the leading characters */ + return strncasecmp(utsbuf.release, ospmrelprefix, strlen(ospmrelprefix)); + +#else + + return -1; + +#endif /* HAVE_SYS_UTSNAME_H */ +} + +/** + * netsnmp_os_kernel_width determines kernel width at runtime + * Currently implemented for IRIX, AIX and Tru64 Unix + * + * @return kernel width (usually 32 or 64) on success, -1 on error + */ +int +netsnmp_os_kernel_width(void) +{ +#ifdef irix6 + char buf[8]; + sysinfo(_MIPS_SI_OS_NAME, buf, 7); + if (strncmp("IRIX64", buf, 6) == 0) { + return 64; + } else if (strncmp("IRIX", buf, 4) == 0) { + return 32; + } else { + return -1; + } +#elif defined(aix4) || defined(aix5) || defined(aix6) + return (__KERNEL_32() ? 32 : (__KERNEL_64() ? 64 : -1)); +#elif defined(osf4) || defined(osf5) || defined(__alpha) + return 64; /* Alpha is always 64bit */ +#else + /* kernel width detection not implemented */ + return -1; +#endif +} + |