4 /***********************************************************
5 Copyright 1992 by Carnegie Mellon University
9 Permission to use, copy, modify, and distribute this software and its
10 documentation for any purpose and without fee is hereby granted,
11 provided that the above copyright notice appear in all copies and that
12 both that copyright notice and this permission notice appear in
13 supporting documentation, and that the name of CMU not be
14 used in advertising or publicity pertaining to distribution of the
15 software without specific, written prior permission.
17 CMU DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
18 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
19 CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
20 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
21 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
22 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
24 ******************************************************************/
26 * System dependent routines go here
28 #include <net-snmp/net-snmp-config.h>
40 #if TIME_WITH_SYS_TIME
42 # include <sys/timeb.h>
44 # include <sys/time.h>
49 # include <sys/time.h>
55 #include <sys/types.h>
58 #include <netinet/in.h>
65 #include <sys/socket.h>
72 #include <sys/sockio.h>
76 #include <sys/ioctl.h>
92 #include <sys/param.h>
95 #include <sys/sysctl.h>
108 #ifdef HAVE_SYS_STAT_H
109 #include <sys/stat.h>
112 #if defined(hpux10) || defined(hpux11)
113 #include <sys/pstat.h>
116 #if HAVE_SYS_UTSNAME_H
117 #include <sys/utsname.h>
120 #include <net-snmp/types.h>
121 #include <net-snmp/output_api.h>
122 #include <net-snmp/utilities.h>
123 #include <net-snmp/library/system.h> /* for "internal" definitions */
125 #include <net-snmp/library/snmp_api.h>
128 # define IFF_LOOPBACK 0
131 #ifdef INADDR_LOOPBACK
132 # define LOOPBACK INADDR_LOOPBACK
134 # define LOOPBACK 0x7f000001
140 * *********************************************
143 # define WIN32_LEAN_AND_MEAN
144 # define WIN32IO_IS_STDIO
145 # define PATHLEN 1024
148 # include <windows.h>
152 * The idea here is to read all the directory names into a string table
153 * * (separated by nulls) and when one of the other dir functions is called
154 * * return the pointer to the current file name.
157 opendir(const char *filename)
162 char scannamespc[PATHLEN];
163 char *scanname = scannamespc;
165 WIN32_FIND_DATA FindData;
169 * check to see if filename is a directory
171 if (stat(filename, &sbuf) < 0 || sbuf.st_mode & S_IFDIR == 0) {
176 * get the file system characteristics
179 * if(GetFullPathName(filename, SNMP_MAXPATH, root, &dummy)) {
180 * * if(dummy = strchr(root, '\\'))
182 * * if(GetVolumeInformation(root, volname, SNMP_MAXPATH, &serial,
183 * * &maxname, &flags, 0, 0)) {
184 * * downcase = !(flags & FS_CASE_IS_PRESERVED);
193 * Create the search pattern
195 strcpy(scanname, filename);
197 if (strchr("/\\", *(scanname + strlen(scanname) - 1)) == NULL)
198 strcat(scanname, "/*");
200 strcat(scanname, "*");
203 * do the FindFirstFile call
205 fh = FindFirstFile(scanname, &FindData);
206 if (fh == INVALID_HANDLE_VALUE) {
211 * Get us a DIR structure
213 p = (DIR *) malloc(sizeof(DIR));
215 * Newz(1303, p, 1, DIR);
221 * now allocate the first part of the string table for
222 * * the filenames that we find.
224 idx = strlen(FindData.cFileName) + 1;
225 p->start = (char *) malloc(idx);
227 * New(1304, p->start, idx, char);
229 if (p->start == NULL) {
233 strcpy(p->start, FindData.cFileName);
236 * * strlwr(p->start);
241 * loop finding all the files that match the wildcard
242 * * (which should be all of them in this directory!).
243 * * the variable idx should point one past the null terminator
244 * * of the previous string found.
246 while (FindNextFile(fh, &FindData)) {
247 len = strlen(FindData.cFileName);
249 * bump the string table size by enough for the
250 * * new name and it's null terminator
252 p->start = (char *) realloc((void *) p->start, idx + len + 1);
254 * Renew(p->start, idx+len+1, char);
256 if (p->start == NULL) {
260 strcpy(&p->start[idx], FindData.cFileName);
263 * * strlwr(&p->start[idx]);
276 * Readdir just returns the current string pointer and bumps the
277 * * string pointer to the nDllExport entry.
283 static int dummy = 0;
287 * first set up the structure to return
289 len = strlen(dirp->curr);
290 strcpy(dirp->dirstr.d_name, dirp->curr);
291 dirp->dirstr.d_namlen = len;
296 dirp->dirstr.d_ino = dummy++;
299 * Now set up for the nDllExport call to readdir
301 dirp->curr += len + 1;
302 if (dirp->curr >= (dirp->start + dirp->size)) {
306 return &(dirp->dirstr);
312 * free the memory allocated by opendir
322 #ifndef HAVE_GETTIMEOFDAY
325 gettimeofday(struct timeval *tv, struct timezone *tz)
327 struct _timeb timebuffer;
330 tv->tv_usec = timebuffer.millitm * 1000;
331 tv->tv_sec = timebuffer.time;
334 #endif /* !HAVE_GETTIMEOFDAY */
339 char local_host[130];
341 LPHOSTENT lpstHostent;
342 SOCKADDR_IN in_addr, remote_in_addr;
344 int nAddrSize = sizeof(SOCKADDR);
346 in_addr.sin_addr.s_addr = INADDR_ANY;
348 result = gethostname(local_host, sizeof(local_host));
350 lpstHostent = gethostbyname((LPSTR) local_host);
352 in_addr.sin_addr.s_addr =
353 *((u_long FAR *) (lpstHostent->h_addr));
354 return ((in_addr_t) in_addr.sin_addr.s_addr);
359 * if we are here, than we don't have host addr
361 hSock = socket(AF_INET, SOCK_DGRAM, 0);
362 if (hSock != INVALID_SOCKET) {
364 * connect to any port and address
366 remote_in_addr.sin_family = AF_INET;
367 remote_in_addr.sin_port = htons(IPPORT_ECHO);
368 remote_in_addr.sin_addr.s_addr = inet_addr("128.22.33.11");
370 connect(hSock, (LPSOCKADDR) & remote_in_addr,
372 if (result != SOCKET_ERROR) {
374 * get local ip address
376 getsockname(hSock, (LPSOCKADDR) & in_addr,
377 (int FAR *) &nAddrSize);
381 return ((in_addr_t) in_addr.sin_addr.s_addr);
387 long return_value = 0;
388 DWORD buffersize = (sizeof(PERF_DATA_BLOCK) +
389 sizeof(PERF_OBJECT_TYPE)),
390 type = REG_EXPAND_SZ;
391 PPERF_DATA_BLOCK perfdata = NULL;
394 * min requirement is one PERF_DATA_BLOCK plus one PERF_OBJECT_TYPE
396 perfdata = (PPERF_DATA_BLOCK) malloc(buffersize);
399 memset(perfdata, 0, buffersize);
401 RegQueryValueEx(HKEY_PERFORMANCE_DATA,
402 "Global", NULL, &type, (LPBYTE) perfdata, &buffersize);
405 * we can not rely on the return value since there is always more so
406 * we check the signature
409 if (wcsncmp(perfdata->Signature, L"PERF", 4) == 0) {
411 * signature ok, and all we need is in the in the PERF_DATA_BLOCK
413 return_value = (long) ((perfdata->PerfTime100nSec.QuadPart /
416 return_value = GetTickCount() / 10;
418 RegCloseKey(HKEY_PERFORMANCE_DATA);
425 winsock_startup(void)
427 WORD VersionRequested;
430 static char errmsg[100];
432 VersionRequested = MAKEWORD(1, 1);
433 i = WSAStartup(VersionRequested, &stWSAData);
435 if (i == WSAVERNOTSUPPORTED)
437 "Unable to init. socket lib, does not support 1.1");
439 sprintf(errmsg, "Socket Startup error %d", i);
447 winsock_cleanup(void)
453 /*******************************************************************/
456 * XXX What if we have multiple addresses? Or no addresses for that matter?
457 * XXX Could it be computed once then cached? Probably not worth it (not
463 int sd, i, lastlen = 0;
465 struct ifreq *ifrp = NULL;
469 if ((sd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
474 * Cope with lots of interfaces and brokenness of ioctl SIOCGIFCONF on
475 * some platforms; see W. R. Stevens, ``Unix Network Programming Volume
479 for (i = 8;; i += 8) {
480 buf = (char *) calloc(i, sizeof(struct ifreq));
485 ifc.ifc_len = i * sizeof(struct ifreq);
486 ifc.ifc_buf = (caddr_t) buf;
488 if (ioctl(sd, SIOCGIFCONF, (char *) &ifc) < 0) {
489 if (errno != EINVAL || lastlen != 0) {
491 * Something has gone genuinely wrong.
498 * Otherwise, it could just be that the buffer is too small.
501 if (ifc.ifc_len == lastlen) {
503 * The length is the same as the last time; we're done.
507 lastlen = ifc.ifc_len;
512 for (ifrp = ifc.ifc_req;
513 (char *)ifrp < (char *)ifc.ifc_req + ifc.ifc_len;
514 #ifdef STRUCT_SOCKADDR_HAS_SA_LEN
515 ifrp = (struct ifreq *)(((char *) ifrp) +
516 sizeof(ifrp->ifr_name) +
517 ifrp->ifr_addr.sa_len)
522 if (ifrp->ifr_addr.sa_family != AF_INET) {
525 addr = ((struct sockaddr_in *) &(ifrp->ifr_addr))->sin_addr.s_addr;
527 if (ioctl(sd, SIOCGIFFLAGS, (char *) ifrp) < 0) {
530 if ((ifrp->ifr_flags & IFF_UP)
532 && (ifrp->ifr_flags & IFF_RUNNING)
533 #endif /* IFF_RUNNING */
534 && !(ifrp->ifr_flags & IFF_LOOPBACK)
535 && addr != LOOPBACK) {
537 * I *really* don't understand why this is necessary. Perhaps for
538 * some broken platform? Leave it for now. JBPN
540 #ifdef SYS_IOCTL_H_HAS_SIOCGIFADDR
541 if (ioctl(sd, SIOCGIFADDR, (char *) ifrp) < 0) {
545 ((struct sockaddr_in *) &(ifrp->ifr_addr))->sin_addr.
559 #if !defined(solaris2) && !defined(linux) && !defined(cygwin)
561 * Returns boottime in centiseconds(!).
562 * Caches this for future use.
567 static long boottime_csecs = 0;
568 #if defined(hpux10) || defined(hpux11)
569 struct pst_static pst_buf;
571 struct timeval boottime;
572 #ifdef CAN_USE_SYSCTL
577 static struct nlist nl[] = {
579 {(char *) "_boottime"},
581 {(char *) "boottime"},
585 #endif /* CAN_USE_SYSCTL */
586 #endif /* hpux10 || hpux 11 */
589 if (boottime_csecs != 0)
590 return (boottime_csecs);
592 #if defined(hpux10) || defined(hpux11)
593 pstat_getstatic(&pst_buf, sizeof(struct pst_static), 1, 0);
594 boottime_csecs = pst_buf.boot_time * 100;
596 #ifdef CAN_USE_SYSCTL
598 mib[1] = KERN_BOOTTIME;
600 len = sizeof(boottime);
602 sysctl(mib, 2, &boottime, &len, NULL, NULL);
603 boottime_csecs = (boottime.tv_sec * 100) + (boottime.tv_usec / 10000);
604 #else /* CAN_USE_SYSCTL */
605 if ((kmem = open("/dev/kmem", 0)) < 0)
607 nlist(KERNEL_LOC, nl);
608 if (nl[0].n_type == 0) {
613 lseek(kmem, (long) nl[0].n_value, L_SET);
614 read(kmem, &boottime, sizeof(boottime));
616 boottime_csecs = (boottime.tv_sec * 100) + (boottime.tv_usec / 10000);
617 #endif /* CAN_USE_SYSCTL */
618 #endif /* hpux10 || hpux 11 */
620 return (boottime_csecs);
625 * Returns uptime in centiseconds(!).
630 #if !defined(solaris2) && !defined(linux) && !defined(cygwin)
632 long boottime_csecs, nowtime_csecs;
634 boottime_csecs = get_boottime();
635 if (boottime_csecs == 0)
637 gettimeofday(&now, (struct timezone *) 0);
638 nowtime_csecs = (now.tv_sec * 100) + (now.tv_usec / 10000);
640 return (nowtime_csecs - boottime_csecs);
644 kstat_ctl_t *ksc = kstat_open();
647 kstat_named_t *named;
651 ks = kstat_lookup(ksc, "unix", -1, "system_misc");
653 kid = kstat_read(ksc, ks, NULL);
655 named = kstat_data_lookup(ks, "lbolt");
657 #ifdef KSTAT_DATA_INT32
658 lbolt = named->value.ul;
660 lbolt = named->value.ul;
668 #endif /* solaris2 */
671 FILE *in = fopen("/proc/uptime", "r");
672 long uptim = 0, a, b;
674 if (2 == fscanf(in, "%ld.%ld", &a, &b))
682 return (0); /* not implemented */
687 /*******************************************************************/
689 #ifndef HAVE_STRNCASECMP
692 * test for NULL pointers before and NULL characters after
693 * * comparing possibly non-NULL strings.
694 * * WARNING: This function does NOT check for array overflow.
697 strncasecmp(const char *s1, const char *s2, size_t nch)
710 for (ii = 0; (ii < nch) && *s1 && *s2; ii++, s1++, s2++) {
711 res = (int) (tolower(*s1) - tolower(*s2));
733 strcasecmp(const char *s1, const char *s2)
735 return strncasecmp(s1, s2, 1000000);
738 #endif /* HAVE_STRNCASECMP */
743 strdup(const char *src)
748 len = strlen(src) + 1;
749 if ((dst = (char *) malloc(len)) == NULL)
754 #endif /* HAVE_STRDUP */
758 setenv(const char *name, const char *value, int overwrite)
763 if (overwrite == 0) {
767 cp = (char *) malloc(strlen(name) + strlen(value) + 2);
770 sprintf(cp, "%s=%s", name, value);
777 #endif /* HAVE_SETENV */
780 calculate_time_diff(struct timeval *now, struct timeval *then)
782 struct timeval tmp, diff;
783 memcpy(&tmp, now, sizeof(struct timeval));
785 tmp.tv_usec += 1000000L;
786 diff.tv_sec = tmp.tv_sec - then->tv_sec;
787 diff.tv_usec = tmp.tv_usec - then->tv_usec;
788 if (diff.tv_usec > 1000000L) {
789 diff.tv_usec -= 1000000L;
792 return ((diff.tv_sec * 100) + (diff.tv_usec / 10000));
795 #ifndef HAVE_STRCASESTR
797 * only glibc2 has this.
800 strcasestr(const char *haystack, const char *needle)
802 const char *cp1 = haystack, *cp2 = needle;
807 * printf("looking for '%s' in '%s'\n", needle, haystack);
809 if (cp1 && cp2 && *cp1 && *cp2)
810 for (cp1 = haystack, cp2 = needle; *cp1;) {
815 * printf("T'%c' ", *cp1);
817 if (!*cp2) { /* found the needle */
819 * printf("\nfound '%s' in '%s'\n", needle, cx);
826 tstch1 = toupper(*cp1);
827 tstch2 = toupper(*cp2);
828 if (tstch1 != tstch2)
831 * printf("M'%c' ", *cp1);
851 mkdirhier(const char *pathname, mode_t mode, int skiplast)
854 char *ourcopy = strdup(pathname);
856 char buf[SNMP_MAXPATH];
858 entry = strtok(ourcopy, "/");
862 * check to see if filename is a directory
867 entry = strtok(NULL, "/");
868 if (entry == NULL && skiplast)
870 if (stat(buf, &sbuf) < 0) {
874 snmp_log(LOG_INFO, "Creating directory: %s\n", buf);
876 CreateDirectory(buf, NULL);
878 if (mkdir(buf, mode) == -1) {
880 return SNMPERR_GENERR;
885 * exists, is it a file?
887 if ((sbuf.st_mode & S_IFDIR) == 0) {
889 * ack! can't make a directory on top of a file
892 return SNMPERR_GENERR;
897 return SNMPERR_SUCCESS;
901 * This function was created to differentiate actions
902 * that are appropriate for Linux 2.4 kernels, but not later kernels.
904 * This function can be used to test kernels on any platform that supports uname().
906 * If not running a platform that supports uname(), return -1.
908 * If ospname matches, and the release matches up through the prefix,
910 * If the release is ordered higher, return 1.
911 * Be aware that "ordered higher" is not a guarantee of correctness.
914 netsnmp_os_prematch(const char *ospmname,
915 const char *ospmrelprefix)
917 #if HAVE_SYS_UTSNAME_H
918 static int printOSonce = 1;
919 struct utsname utsbuf;
920 if ( 0 != uname(&utsbuf))
925 /* show the four elements that the kernel can be sure of */
926 DEBUGMSGT(("daemonize","sysname '%s',\nrelease '%s',\nversion '%s',\nmachine '%s'\n",
927 utsbuf.sysname, utsbuf.release, utsbuf.version, utsbuf.machine));
929 if (0 != strcasecmp(utsbuf.sysname, ospmname)) return -1;
931 /* Required to match only the leading characters */
932 return strncasecmp(utsbuf.release, ospmrelprefix, strlen(ospmrelprefix));
938 #endif /* HAVE_SYS_UTSNAME_H */