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 #include <net-snmp/types.h>
117 #include <net-snmp/output_api.h>
118 #include <net-snmp/utilities.h>
119 #include <net-snmp/library/system.h> /* for "internal" definitions */
121 #include <net-snmp/library/snmp_api.h>
124 # define IFF_LOOPBACK 0
127 #ifdef INADDR_LOOPBACK
128 # define LOOPBACK INADDR_LOOPBACK
130 # define LOOPBACK 0x7f000001
136 * *********************************************
139 # define WIN32_LEAN_AND_MEAN
140 # define WIN32IO_IS_STDIO
141 # define PATHLEN 1024
144 # include <windows.h>
148 * The idea here is to read all the directory names into a string table
149 * * (separated by nulls) and when one of the other dir functions is called
150 * * return the pointer to the current file name.
153 opendir(const char *filename)
158 char scannamespc[PATHLEN];
159 char *scanname = scannamespc;
161 WIN32_FIND_DATA FindData;
165 * check to see if filename is a directory
167 if (stat(filename, &sbuf) < 0 || sbuf.st_mode & S_IFDIR == 0) {
172 * get the file system characteristics
175 * if(GetFullPathName(filename, SNMP_MAXPATH, root, &dummy)) {
176 * * if(dummy = strchr(root, '\\'))
178 * * if(GetVolumeInformation(root, volname, SNMP_MAXPATH, &serial,
179 * * &maxname, &flags, 0, 0)) {
180 * * downcase = !(flags & FS_CASE_IS_PRESERVED);
189 * Create the search pattern
191 strcpy(scanname, filename);
193 if (strchr("/\\", *(scanname + strlen(scanname) - 1)) == NULL)
194 strcat(scanname, "/*");
196 strcat(scanname, "*");
199 * do the FindFirstFile call
201 fh = FindFirstFile(scanname, &FindData);
202 if (fh == INVALID_HANDLE_VALUE) {
207 * Get us a DIR structure
209 p = (DIR *) malloc(sizeof(DIR));
211 * Newz(1303, p, 1, DIR);
217 * now allocate the first part of the string table for
218 * * the filenames that we find.
220 idx = strlen(FindData.cFileName) + 1;
221 p->start = (char *) malloc(idx);
223 * New(1304, p->start, idx, char);
225 if (p->start == NULL) {
229 strcpy(p->start, FindData.cFileName);
232 * * strlwr(p->start);
237 * loop finding all the files that match the wildcard
238 * * (which should be all of them in this directory!).
239 * * the variable idx should point one past the null terminator
240 * * of the previous string found.
242 while (FindNextFile(fh, &FindData)) {
243 len = strlen(FindData.cFileName);
245 * bump the string table size by enough for the
246 * * new name and it's null terminator
248 p->start = (char *) realloc((void *) p->start, idx + len + 1);
250 * Renew(p->start, idx+len+1, char);
252 if (p->start == NULL) {
256 strcpy(&p->start[idx], FindData.cFileName);
259 * * strlwr(&p->start[idx]);
272 * Readdir just returns the current string pointer and bumps the
273 * * string pointer to the nDllExport entry.
279 static int dummy = 0;
283 * first set up the structure to return
285 len = strlen(dirp->curr);
286 strcpy(dirp->dirstr.d_name, dirp->curr);
287 dirp->dirstr.d_namlen = len;
292 dirp->dirstr.d_ino = dummy++;
295 * Now set up for the nDllExport call to readdir
297 dirp->curr += len + 1;
298 if (dirp->curr >= (dirp->start + dirp->size)) {
302 return &(dirp->dirstr);
308 * free the memory allocated by opendir
318 #ifndef HAVE_GETTIMEOFDAY
321 gettimeofday(struct timeval *tv, struct timezone *tz)
323 struct _timeb timebuffer;
326 tv->tv_usec = timebuffer.millitm * 1000;
327 tv->tv_sec = timebuffer.time;
330 #endif /* !HAVE_GETTIMEOFDAY */
335 char local_host[130];
337 LPHOSTENT lpstHostent;
338 SOCKADDR_IN in_addr, remote_in_addr;
340 int nAddrSize = sizeof(SOCKADDR);
342 in_addr.sin_addr.s_addr = INADDR_ANY;
344 result = gethostname(local_host, sizeof(local_host));
346 lpstHostent = gethostbyname((LPSTR) local_host);
348 in_addr.sin_addr.s_addr =
349 *((u_long FAR *) (lpstHostent->h_addr));
350 return ((in_addr_t) in_addr.sin_addr.s_addr);
355 * if we are here, than we don't have host addr
357 hSock = socket(AF_INET, SOCK_DGRAM, 0);
358 if (hSock != INVALID_SOCKET) {
360 * connect to any port and address
362 remote_in_addr.sin_family = AF_INET;
363 remote_in_addr.sin_port = htons(IPPORT_ECHO);
364 remote_in_addr.sin_addr.s_addr = inet_addr("128.22.33.11");
366 connect(hSock, (LPSOCKADDR) & remote_in_addr,
368 if (result != SOCKET_ERROR) {
370 * get local ip address
372 getsockname(hSock, (LPSOCKADDR) & in_addr,
373 (int FAR *) &nAddrSize);
377 return ((in_addr_t) in_addr.sin_addr.s_addr);
383 long return_value = 0;
384 DWORD buffersize = (sizeof(PERF_DATA_BLOCK) +
385 sizeof(PERF_OBJECT_TYPE)),
386 type = REG_EXPAND_SZ;
387 PPERF_DATA_BLOCK perfdata = NULL;
390 * min requirement is one PERF_DATA_BLOCK plus one PERF_OBJECT_TYPE
392 perfdata = (PPERF_DATA_BLOCK) malloc(buffersize);
395 memset(perfdata, 0, buffersize);
397 RegQueryValueEx(HKEY_PERFORMANCE_DATA,
398 "Global", NULL, &type, (LPBYTE) perfdata, &buffersize);
401 * we can not rely on the return value since there is always more so
402 * we check the signature
405 if (wcsncmp(perfdata->Signature, L"PERF", 4) == 0) {
407 * signature ok, and all we need is in the in the PERF_DATA_BLOCK
409 return_value = (long) ((perfdata->PerfTime100nSec.QuadPart /
412 return_value = GetTickCount() / 10;
414 RegCloseKey(HKEY_PERFORMANCE_DATA);
421 winsock_startup(void)
423 WORD VersionRequested;
426 static char errmsg[100];
428 VersionRequested = MAKEWORD(1, 1);
429 i = WSAStartup(VersionRequested, &stWSAData);
431 if (i == WSAVERNOTSUPPORTED)
433 "Unable to init. socket lib, does not support 1.1");
435 sprintf(errmsg, "Socket Startup error %d", i);
443 winsock_cleanup(void)
449 /*******************************************************************/
452 * XXX What if we have multiple addresses? Or no addresses for that matter?
453 * XXX Could it be computed once then cached? Probably not worth it (not
459 int sd, i, lastlen = 0;
461 struct ifreq *ifrp = NULL;
465 if ((sd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
470 * Cope with lots of interfaces and brokenness of ioctl SIOCGIFCONF on
471 * some platforms; see W. R. Stevens, ``Unix Network Programming Volume
475 for (i = 8;; i += 8) {
476 buf = (char *) calloc(i, sizeof(struct ifreq));
481 ifc.ifc_len = i * sizeof(struct ifreq);
482 ifc.ifc_buf = (caddr_t) buf;
484 if (ioctl(sd, SIOCGIFCONF, (char *) &ifc) < 0) {
485 if (errno != EINVAL || lastlen != 0) {
487 * Something has gone genuinely wrong.
494 * Otherwise, it could just be that the buffer is too small.
497 if (ifc.ifc_len == lastlen) {
499 * The length is the same as the last time; we're done.
503 lastlen = ifc.ifc_len;
508 for (ifrp = ifc.ifc_req;
509 (char *)ifrp < (char *)ifc.ifc_req + ifc.ifc_len;
510 #ifdef STRUCT_SOCKADDR_HAS_SA_LEN
511 ifrp = (struct ifreq *)(((char *) ifrp) +
512 sizeof(ifrp->ifr_name) +
513 ifrp->ifr_addr.sa_len)
518 if (ifrp->ifr_addr.sa_family != AF_INET) {
521 addr = ((struct sockaddr_in *) &(ifrp->ifr_addr))->sin_addr.s_addr;
523 if (ioctl(sd, SIOCGIFFLAGS, (char *) ifrp) < 0) {
526 if ((ifrp->ifr_flags & IFF_UP)
528 && (ifrp->ifr_flags & IFF_RUNNING)
529 #endif /* IFF_RUNNING */
530 && !(ifrp->ifr_flags & IFF_LOOPBACK)
531 && addr != LOOPBACK) {
533 * I *really* don't understand why this is necessary. Perhaps for
534 * some broken platform? Leave it for now. JBPN
536 #ifdef SYS_IOCTL_H_HAS_SIOCGIFADDR
537 if (ioctl(sd, SIOCGIFADDR, (char *) ifrp) < 0) {
541 ((struct sockaddr_in *) &(ifrp->ifr_addr))->sin_addr.
555 #if !defined(solaris2) && !defined(linux) && !defined(cygwin)
557 * Returns boottime in centiseconds(!).
558 * Caches this for future use.
563 static long boottime_csecs = 0;
564 #if defined(hpux10) || defined(hpux11)
565 struct pst_static pst_buf;
567 struct timeval boottime;
568 #ifdef CAN_USE_SYSCTL
573 static struct nlist nl[] = {
575 {(char *) "_boottime"},
577 {(char *) "boottime"},
581 #endif /* CAN_USE_SYSCTL */
582 #endif /* hpux10 || hpux 11 */
585 if (boottime_csecs != 0)
586 return (boottime_csecs);
588 #if defined(hpux10) || defined(hpux11)
589 pstat_getstatic(&pst_buf, sizeof(struct pst_static), 1, 0);
590 boottime_csecs = pst_buf.boot_time * 100;
592 #ifdef CAN_USE_SYSCTL
594 mib[1] = KERN_BOOTTIME;
596 len = sizeof(boottime);
598 sysctl(mib, 2, &boottime, &len, NULL, NULL);
599 boottime_csecs = (boottime.tv_sec * 100) + (boottime.tv_usec / 10000);
600 #else /* CAN_USE_SYSCTL */
601 if ((kmem = open("/dev/kmem", 0)) < 0)
603 nlist(KERNEL_LOC, nl);
604 if (nl[0].n_type == 0) {
609 lseek(kmem, (long) nl[0].n_value, L_SET);
610 read(kmem, &boottime, sizeof(boottime));
612 boottime_csecs = (boottime.tv_sec * 100) + (boottime.tv_usec / 10000);
613 #endif /* CAN_USE_SYSCTL */
614 #endif /* hpux10 || hpux 11 */
616 return (boottime_csecs);
621 * Returns uptime in centiseconds(!).
626 #if !defined(solaris2) && !defined(linux) && !defined(cygwin)
628 long boottime_csecs, nowtime_csecs;
630 boottime_csecs = get_boottime();
631 if (boottime_csecs == 0)
633 gettimeofday(&now, (struct timezone *) 0);
634 nowtime_csecs = (now.tv_sec * 100) + (now.tv_usec / 10000);
636 return (nowtime_csecs - boottime_csecs);
640 kstat_ctl_t *ksc = kstat_open();
643 kstat_named_t *named;
647 ks = kstat_lookup(ksc, "unix", -1, "system_misc");
649 kid = kstat_read(ksc, ks, NULL);
651 named = kstat_data_lookup(ks, "lbolt");
653 #ifdef KSTAT_DATA_INT32
654 lbolt = named->value.ul;
656 lbolt = named->value.ul;
664 #endif /* solaris2 */
667 FILE *in = fopen("/proc/uptime", "r");
668 long uptim = 0, a, b;
670 if (2 == fscanf(in, "%ld.%ld", &a, &b))
678 return (0); /* not implemented */
683 /*******************************************************************/
685 #ifndef HAVE_STRNCASECMP
688 * test for NULL pointers before and NULL characters after
689 * * comparing possibly non-NULL strings.
690 * * WARNING: This function does NOT check for array overflow.
693 strncasecmp(const char *s1, const char *s2, size_t nch)
706 for (ii = 0; (ii < nch) && *s1 && *s2; ii++, s1++, s2++) {
707 res = (int) (tolower(*s1) - tolower(*s2));
729 strcasecmp(const char *s1, const char *s2)
731 return strncasecmp(s1, s2, 1000000);
734 #endif /* HAVE_STRNCASECMP */
739 strdup(const char *src)
744 len = strlen(src) + 1;
745 if ((dst = (char *) malloc(len)) == NULL)
750 #endif /* HAVE_STRDUP */
754 setenv(const char *name, const char *value, int overwrite)
759 if (overwrite == 0) {
763 cp = (char *) malloc(strlen(name) + strlen(value) + 2);
766 sprintf(cp, "%s=%s", name, value);
773 #endif /* HAVE_SETENV */
776 calculate_time_diff(struct timeval *now, struct timeval *then)
778 struct timeval tmp, diff;
779 memcpy(&tmp, now, sizeof(struct timeval));
781 tmp.tv_usec += 1000000L;
782 diff.tv_sec = tmp.tv_sec - then->tv_sec;
783 diff.tv_usec = tmp.tv_usec - then->tv_usec;
784 if (diff.tv_usec > 1000000L) {
785 diff.tv_usec -= 1000000L;
788 return ((diff.tv_sec * 100) + (diff.tv_usec / 10000));
791 #ifndef HAVE_STRCASESTR
793 * only glibc2 has this.
796 strcasestr(const char *haystack, const char *needle)
798 const char *cp1 = haystack, *cp2 = needle;
803 * printf("looking for '%s' in '%s'\n", needle, haystack);
805 if (cp1 && cp2 && *cp1 && *cp2)
806 for (cp1 = haystack, cp2 = needle; *cp1;) {
811 * printf("T'%c' ", *cp1);
813 if (!*cp2) { /* found the needle */
815 * printf("\nfound '%s' in '%s'\n", needle, cx);
822 tstch1 = toupper(*cp1);
823 tstch2 = toupper(*cp2);
824 if (tstch1 != tstch2)
827 * printf("M'%c' ", *cp1);
847 mkdirhier(const char *pathname, mode_t mode, int skiplast)
850 char *ourcopy = strdup(pathname);
852 char buf[SNMP_MAXPATH];
854 entry = strtok(ourcopy, "/");
858 * check to see if filename is a directory
863 entry = strtok(NULL, "/");
864 if (entry == NULL && skiplast)
866 if (stat(buf, &sbuf) < 0) {
870 snmp_log(LOG_INFO, "Creating directory: %s\n", buf);
872 CreateDirectory(buf, NULL);
874 if (mkdir(buf, mode) == -1) {
876 return SNMPERR_GENERR;
881 * exists, is it a file?
883 if ((sbuf.st_mode & S_IFDIR) == 0) {
885 * ack! can't make a directory on top of a file
888 return SNMPERR_GENERR;
893 return SNMPERR_SUCCESS;