http://downloads.netgear.com/files/GPL/GPL_Source_V361j_DM111PSP_series_consumer_rele...
[bcm963xx.git] / userapps / opensource / net-snmp / snmplib / system.c
1 /*
2  * system.c
3  */
4 /***********************************************************
5         Copyright 1992 by Carnegie Mellon University
6
7                       All Rights Reserved
8
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.
16
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
23 SOFTWARE.
24 ******************************************************************/
25 /*
26  * System dependent routines go here
27  */
28 #include <net-snmp/net-snmp-config.h>
29 #include <stdio.h>
30 #include <ctype.h>
31 #include <errno.h>
32
33 #if HAVE_UNISTD_H
34 #include <unistd.h>
35 #endif
36 #if HAVE_STDLIB_H
37 #include <stdlib.h>
38 #endif
39
40 #if TIME_WITH_SYS_TIME
41 # ifdef WIN32
42 #  include <sys/timeb.h>
43 # else
44 #  include <sys/time.h>
45 # endif
46 # include <time.h>
47 #else
48 # if HAVE_SYS_TIME_H
49 #  include <sys/time.h>
50 # else
51 #  include <time.h>
52 # endif
53 #endif
54
55 #include <sys/types.h>
56
57 #if HAVE_NETINET_IN_H
58 #include <netinet/in.h>
59 #endif
60
61 #if HAVE_WINSOCK_H
62 #include <winsock.h>
63 #endif
64 #if HAVE_SYS_SOCKET_H
65 #include <sys/socket.h>
66 #endif
67 #if HAVE_NET_IF_H
68 #include <net/if.h>
69 #endif
70
71 #if HAVE_SYS_SOCKIO_H
72 #include <sys/sockio.h>
73 #endif
74
75 #if HAVE_SYS_IOCTL_H
76 #include <sys/ioctl.h>
77 #endif
78
79 #ifdef HAVE_NLIST_H
80 #include <nlist.h>
81 #endif
82
83 #if HAVE_SYS_FILE_H
84 #include <sys/file.h>
85 #endif
86
87 #if HAVE_KSTAT_H
88 #include <kstat.h>
89 #endif
90
91 #if HAVE_SYS_PARAM_H
92 #include <sys/param.h>
93 #endif
94 #if HAVE_SYS_SYSCTL_H
95 #include <sys/sysctl.h>
96 #endif
97
98 #if HAVE_STRING_H
99 #include <string.h>
100 #else
101 #include <strings.h>
102 #endif
103
104 #if HAVE_DMALLOC_H
105 #include <dmalloc.h>
106 #endif
107
108 #ifdef HAVE_SYS_STAT_H
109 #include <sys/stat.h>
110 #endif
111
112 #if defined(hpux10) || defined(hpux11)
113 #include <sys/pstat.h>
114 #endif
115
116 #if HAVE_SYS_UTSNAME_H
117 #include <sys/utsname.h>
118 #endif
119
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 */
124
125 #include <net-snmp/library/snmp_api.h>
126
127 #ifndef IFF_LOOPBACK
128 #       define IFF_LOOPBACK 0
129 #endif
130
131 #ifdef  INADDR_LOOPBACK
132 # define LOOPBACK    INADDR_LOOPBACK
133 #else
134 # define LOOPBACK    0x7f000001
135 #endif
136
137
138
139 /*
140  * ********************************************* 
141  */
142 #ifdef                                                  WIN32
143 #       define WIN32_LEAN_AND_MEAN
144 #       define WIN32IO_IS_STDIO
145 #       define PATHLEN  1024
146
147 #       include <tchar.h>
148 #       include <windows.h>
149
150
151 /*
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.
155  */
156 DIR            *
157 opendir(const char *filename)
158 {
159     DIR            *p;
160     long            len;
161     long            idx;
162     char            scannamespc[PATHLEN];
163     char           *scanname = scannamespc;
164     struct stat     sbuf;
165     WIN32_FIND_DATA FindData;
166     HANDLE          fh;
167
168     /*
169      * check to see if filename is a directory 
170      */
171     if (stat(filename, &sbuf) < 0 || sbuf.st_mode & S_IFDIR == 0) {
172         return NULL;
173     }
174
175     /*
176      * get the file system characteristics 
177      */
178     /*
179      * if(GetFullPathName(filename, SNMP_MAXPATH, root, &dummy)) {
180      * *    if(dummy = strchr(root, '\\'))
181      * *        *++dummy = '\0';
182      * *    if(GetVolumeInformation(root, volname, SNMP_MAXPATH, &serial,
183      * *                            &maxname, &flags, 0, 0)) {
184      * *        downcase = !(flags & FS_CASE_IS_PRESERVED);
185      * *    }
186      * *  }
187      * *  else {
188      * *    downcase = TRUE;
189      * *  }
190      */
191
192     /*
193      * Create the search pattern 
194      */
195     strcpy(scanname, filename);
196
197     if (strchr("/\\", *(scanname + strlen(scanname) - 1)) == NULL)
198         strcat(scanname, "/*");
199     else
200         strcat(scanname, "*");
201
202     /*
203      * do the FindFirstFile call 
204      */
205     fh = FindFirstFile(scanname, &FindData);
206     if (fh == INVALID_HANDLE_VALUE) {
207         return NULL;
208     }
209
210     /*
211      * Get us a DIR structure 
212      */
213     p = (DIR *) malloc(sizeof(DIR));
214     /*
215      * Newz(1303, p, 1, DIR); 
216      */
217     if (p == NULL)
218         return NULL;
219
220     /*
221      * now allocate the first part of the string table for
222      * * the filenames that we find.
223      */
224     idx = strlen(FindData.cFileName) + 1;
225     p->start = (char *) malloc(idx);
226     /*
227      * New(1304, p->start, idx, char);
228      */
229     if (p->start == NULL) {
230         free(p);
231         return NULL;
232     }
233     strcpy(p->start, FindData.cFileName);
234     /*
235      * if(downcase)
236      * *    strlwr(p->start);
237      */
238     p->nfiles = 0;
239
240     /*
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.
245      */
246     while (FindNextFile(fh, &FindData)) {
247         len = strlen(FindData.cFileName);
248         /*
249          * bump the string table size by enough for the
250          * * new name and it's null terminator
251          */
252         p->start = (char *) realloc((void *) p->start, idx + len + 1);
253         /*
254          * Renew(p->start, idx+len+1, char);
255          */
256         if (p->start == NULL) {
257             free(p);
258             return NULL;
259         }
260         strcpy(&p->start[idx], FindData.cFileName);
261         /*
262          * if (downcase) 
263          * *        strlwr(&p->start[idx]);
264          */
265         p->nfiles++;
266         idx += len + 1;
267     }
268     FindClose(fh);
269     p->size = idx;
270     p->curr = p->start;
271     return p;
272 }
273
274
275 /*
276  * Readdir just returns the current string pointer and bumps the
277  * * string pointer to the nDllExport entry.
278  */
279 struct direct  *
280 readdir(DIR * dirp)
281 {
282     int             len;
283     static int      dummy = 0;
284
285     if (dirp->curr) {
286         /*
287          * first set up the structure to return 
288          */
289         len = strlen(dirp->curr);
290         strcpy(dirp->dirstr.d_name, dirp->curr);
291         dirp->dirstr.d_namlen = len;
292
293         /*
294          * Fake an inode 
295          */
296         dirp->dirstr.d_ino = dummy++;
297
298         /*
299          * Now set up for the nDllExport call to readdir 
300          */
301         dirp->curr += len + 1;
302         if (dirp->curr >= (dirp->start + dirp->size)) {
303             dirp->curr = NULL;
304         }
305
306         return &(dirp->dirstr);
307     } else
308         return NULL;
309 }
310
311 /*
312  * free the memory allocated by opendir 
313  */
314 int
315 closedir(DIR * dirp)
316 {
317     free(dirp->start);
318     free(dirp);
319     return 1;
320 }
321
322 #ifndef HAVE_GETTIMEOFDAY
323
324 int
325 gettimeofday(struct timeval *tv, struct timezone *tz)
326 {
327     struct _timeb   timebuffer;
328
329     _ftime(&timebuffer);
330     tv->tv_usec = timebuffer.millitm * 1000;
331     tv->tv_sec = timebuffer.time;
332     return (0);
333 }
334 #endif                          /* !HAVE_GETTIMEOFDAY */
335
336 in_addr_t
337 get_myaddr(void)
338 {
339     char            local_host[130];
340     int             result;
341     LPHOSTENT       lpstHostent;
342     SOCKADDR_IN     in_addr, remote_in_addr;
343     SOCKET          hSock;
344     int             nAddrSize = sizeof(SOCKADDR);
345
346     in_addr.sin_addr.s_addr = INADDR_ANY;
347
348     result = gethostname(local_host, sizeof(local_host));
349     if (result == 0) {
350         lpstHostent = gethostbyname((LPSTR) local_host);
351         if (lpstHostent) {
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);
355         }
356     }
357
358     /*
359      * if we are here, than we don't have host addr 
360      */
361     hSock = socket(AF_INET, SOCK_DGRAM, 0);
362     if (hSock != INVALID_SOCKET) {
363         /*
364          * connect to any port and address 
365          */
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");
369         result =
370             connect(hSock, (LPSOCKADDR) & remote_in_addr,
371                     sizeof(SOCKADDR));
372         if (result != SOCKET_ERROR) {
373             /*
374              * get local ip address 
375              */
376             getsockname(hSock, (LPSOCKADDR) & in_addr,
377                         (int FAR *) &nAddrSize);
378         }
379         closesocket(hSock);
380     }
381     return ((in_addr_t) in_addr.sin_addr.s_addr);
382 }
383
384 long
385 get_uptime(void)
386 {
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;
392
393     /*
394      * min requirement is one PERF_DATA_BLOCK plus one PERF_OBJECT_TYPE 
395      */
396     perfdata = (PPERF_DATA_BLOCK) malloc(buffersize);
397
398
399     memset(perfdata, 0, buffersize);
400
401     RegQueryValueEx(HKEY_PERFORMANCE_DATA,
402                     "Global", NULL, &type, (LPBYTE) perfdata, &buffersize);
403
404     /*
405      * we can not rely on the return value since there is always more so
406      * we check the signature 
407      */
408
409     if (wcsncmp(perfdata->Signature, L"PERF", 4) == 0) {
410         /*
411          * signature ok, and all we need is in the in the PERF_DATA_BLOCK 
412          */
413         return_value = (long) ((perfdata->PerfTime100nSec.QuadPart /
414                                 (LONGLONG) 100000));
415     } else
416         return_value = GetTickCount() / 10;
417
418     RegCloseKey(HKEY_PERFORMANCE_DATA);
419     free(perfdata);
420
421     return return_value;
422 }
423
424 char           *
425 winsock_startup(void)
426 {
427     WORD            VersionRequested;
428     WSADATA         stWSAData;
429     int             i;
430     static char     errmsg[100];
431
432     VersionRequested = MAKEWORD(1, 1);
433     i = WSAStartup(VersionRequested, &stWSAData);
434     if (i != 0) {
435         if (i == WSAVERNOTSUPPORTED)
436             sprintf(errmsg,
437                     "Unable to init. socket lib, does not support 1.1");
438         else {
439             sprintf(errmsg, "Socket Startup error %d", i);
440         }
441         return (errmsg);
442     }
443     return (NULL);
444 }
445
446 void
447 winsock_cleanup(void)
448 {
449     WSACleanup();
450 }
451
452 #else                           /* ! WIN32 */
453 /*******************************************************************/
454
455 /*
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
458  *                                                           used very often).
459  */
460 in_addr_t
461 get_myaddr(void)
462 {
463     int             sd, i, lastlen = 0;
464     struct ifconf   ifc;
465     struct ifreq   *ifrp = NULL;
466     in_addr_t       addr;
467     char           *buf = NULL;
468
469     if ((sd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
470         return 0;
471     }
472
473     /*
474      * Cope with lots of interfaces and brokenness of ioctl SIOCGIFCONF on
475      * some platforms; see W. R. Stevens, ``Unix Network Programming Volume
476      * I'', p.435.  
477      */
478
479     for (i = 8;; i += 8) {
480         buf = (char *) calloc(i, sizeof(struct ifreq));
481         if (buf == NULL) {
482             close(sd);
483             return 0;
484         }
485         ifc.ifc_len = i * sizeof(struct ifreq);
486         ifc.ifc_buf = (caddr_t) buf;
487
488         if (ioctl(sd, SIOCGIFCONF, (char *) &ifc) < 0) {
489             if (errno != EINVAL || lastlen != 0) {
490                 /*
491                  * Something has gone genuinely wrong.  
492                  */
493                 free(buf);
494                 close(sd);
495                 return 0;
496             }
497             /*
498              * Otherwise, it could just be that the buffer is too small.  
499              */
500         } else {
501             if (ifc.ifc_len == lastlen) {
502                 /*
503                  * The length is the same as the last time; we're done.  
504                  */
505                 break;
506             }
507             lastlen = ifc.ifc_len;
508         }
509         free(buf);
510     }
511
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)
518 #else
519         ifrp++
520 #endif
521         ) {
522         if (ifrp->ifr_addr.sa_family != AF_INET) {
523             continue;
524         }
525         addr = ((struct sockaddr_in *) &(ifrp->ifr_addr))->sin_addr.s_addr;
526
527         if (ioctl(sd, SIOCGIFFLAGS, (char *) ifrp) < 0) {
528             continue;
529         }
530         if ((ifrp->ifr_flags & IFF_UP)
531 #ifdef IFF_RUNNING
532             && (ifrp->ifr_flags & IFF_RUNNING)
533 #endif                          /* IFF_RUNNING */
534             && !(ifrp->ifr_flags & IFF_LOOPBACK)
535             && addr != LOOPBACK) {
536             /*
537              * I *really* don't understand why this is necessary.  Perhaps for
538              * some broken platform?  Leave it for now.  JBPN  
539              */
540 #ifdef SYS_IOCTL_H_HAS_SIOCGIFADDR
541             if (ioctl(sd, SIOCGIFADDR, (char *) ifrp) < 0) {
542                 continue;
543             }
544             addr =
545                 ((struct sockaddr_in *) &(ifrp->ifr_addr))->sin_addr.
546                 s_addr;
547 #endif
548             free(buf);
549             close(sd);
550             return addr;
551         }
552     }
553     free(buf);
554     close(sd);
555     return 0;
556 }
557
558
559 #if !defined(solaris2) && !defined(linux) && !defined(cygwin)
560 /*
561  * Returns boottime in centiseconds(!).
562  *      Caches this for future use.
563  */
564 long
565 get_boottime(void)
566 {
567     static long     boottime_csecs = 0;
568 #if defined(hpux10) || defined(hpux11)
569     struct pst_static pst_buf;
570 #else
571     struct timeval  boottime;
572 #ifdef  CAN_USE_SYSCTL
573     int             mib[2];
574     size_t          len;
575 #else
576     int             kmem;
577     static struct nlist nl[] = {
578 #if !defined(hpux)
579         {(char *) "_boottime"},
580 #else
581         {(char *) "boottime"},
582 #endif
583         {(char *) ""}
584     };
585 #endif                          /* CAN_USE_SYSCTL */
586 #endif                          /* hpux10 || hpux 11 */
587
588
589     if (boottime_csecs != 0)
590         return (boottime_csecs);
591
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;
595 #else
596 #ifdef CAN_USE_SYSCTL
597     mib[0] = CTL_KERN;
598     mib[1] = KERN_BOOTTIME;
599
600     len = sizeof(boottime);
601
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)
606         return 0;
607     nlist(KERNEL_LOC, nl);
608     if (nl[0].n_type == 0) {
609         close(kmem);
610         return 0;
611     }
612
613     lseek(kmem, (long) nl[0].n_value, L_SET);
614     read(kmem, &boottime, sizeof(boottime));
615     close(kmem);
616     boottime_csecs = (boottime.tv_sec * 100) + (boottime.tv_usec / 10000);
617 #endif                          /* CAN_USE_SYSCTL */
618 #endif                          /* hpux10 || hpux 11 */
619
620     return (boottime_csecs);
621 }
622 #endif
623
624 /*
625  * Returns uptime in centiseconds(!).
626  */
627 long
628 get_uptime(void)
629 {
630 #if !defined(solaris2) && !defined(linux) && !defined(cygwin)
631     struct timeval  now;
632     long            boottime_csecs, nowtime_csecs;
633
634     boottime_csecs = get_boottime();
635     if (boottime_csecs == 0)
636         return 0;
637     gettimeofday(&now, (struct timezone *) 0);
638     nowtime_csecs = (now.tv_sec * 100) + (now.tv_usec / 10000);
639
640     return (nowtime_csecs - boottime_csecs);
641 #endif
642
643 #ifdef solaris2
644     kstat_ctl_t    *ksc = kstat_open();
645     kstat_t        *ks;
646     kid_t           kid;
647     kstat_named_t  *named;
648     u_long          lbolt = 0;
649
650     if (ksc) {
651         ks = kstat_lookup(ksc, "unix", -1, "system_misc");
652         if (ks) {
653             kid = kstat_read(ksc, ks, NULL);
654             if (kid != -1) {
655                 named = kstat_data_lookup(ks, "lbolt");
656                 if (named) {
657 #ifdef KSTAT_DATA_INT32
658                     lbolt = named->value.ul;
659 #else
660                     lbolt = named->value.ul;
661 #endif
662                 }
663             }
664         }
665         kstat_close(ksc);
666     }
667     return lbolt;
668 #endif                          /* solaris2 */
669
670 #ifdef linux
671     FILE           *in = fopen("/proc/uptime", "r");
672     long            uptim = 0, a, b;
673     if (in) {
674         if (2 == fscanf(in, "%ld.%ld", &a, &b))
675             uptim = a * 100 + b;
676         fclose(in);
677     }
678     return uptim;
679 #endif                          /* linux */
680
681 #ifdef cygwin
682     return (0);                 /* not implemented */
683 #endif
684 }
685
686 #endif                          /* ! WIN32 */
687 /*******************************************************************/
688
689 #ifndef HAVE_STRNCASECMP
690
691 /*
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.
695  */
696 int
697 strncasecmp(const char *s1, const char *s2, size_t nch)
698 {
699     size_t          ii;
700     int             res = -1;
701
702     if (!s1) {
703         if (!s2)
704             return 0;
705         return (-1);
706     }
707     if (!s2)
708         return (1);
709
710     for (ii = 0; (ii < nch) && *s1 && *s2; ii++, s1++, s2++) {
711         res = (int) (tolower(*s1) - tolower(*s2));
712         if (res != 0)
713             break;
714     }
715
716     if (ii == nch) {
717         s1--;
718         s2--;
719     }
720
721     if (!*s1) {
722         if (!*s2)
723             return 0;
724         return (-1);
725     }
726     if (!*s2)
727         return (1);
728
729     return (res);
730 }
731
732 int
733 strcasecmp(const char *s1, const char *s2)
734 {
735     return strncasecmp(s1, s2, 1000000);
736 }
737
738 #endif                          /* HAVE_STRNCASECMP */
739
740
741 #ifndef HAVE_STRDUP
742 char           *
743 strdup(const char *src)
744 {
745     int             len;
746     char           *dst;
747
748     len = strlen(src) + 1;
749     if ((dst = (char *) malloc(len)) == NULL)
750         return (NULL);
751     strcpy(dst, src);
752     return (dst);
753 }
754 #endif                          /* HAVE_STRDUP */
755
756 #ifndef HAVE_SETENV
757 int
758 setenv(const char *name, const char *value, int overwrite)
759 {
760     char           *cp;
761     int             ret;
762
763     if (overwrite == 0) {
764         if (getenv(name))
765             return 0;
766     }
767     cp = (char *) malloc(strlen(name) + strlen(value) + 2);
768     if (cp == NULL)
769         return -1;
770     sprintf(cp, "%s=%s", name, value);
771     ret = putenv(cp);
772 #ifdef WIN32
773     free(cp);
774 #endif
775     return ret;
776 }
777 #endif                          /* HAVE_SETENV */
778
779 int
780 calculate_time_diff(struct timeval *now, struct timeval *then)
781 {
782     struct timeval  tmp, diff;
783     memcpy(&tmp, now, sizeof(struct timeval));
784     tmp.tv_sec--;
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;
790         diff.tv_sec++;
791     }
792     return ((diff.tv_sec * 100) + (diff.tv_usec / 10000));
793 }
794
795 #ifndef HAVE_STRCASESTR
796 /*
797  * only glibc2 has this.
798  */
799 char           *
800 strcasestr(const char *haystack, const char *needle)
801 {
802     const char     *cp1 = haystack, *cp2 = needle;
803     const char     *cx;
804     int             tstch1, tstch2;
805
806     /*
807      * printf("looking for '%s' in '%s'\n", needle, haystack); 
808      */
809     if (cp1 && cp2 && *cp1 && *cp2)
810         for (cp1 = haystack, cp2 = needle; *cp1;) {
811             cx = cp1;
812             cp2 = needle;
813             do {
814                 /*
815                  * printf("T'%c' ", *cp1); 
816                  */
817                 if (!*cp2) {    /* found the needle */
818                     /*
819                      * printf("\nfound '%s' in '%s'\n", needle, cx); 
820                      */
821                     return (char *) cx;
822                 }
823                 if (!*cp1)
824                     break;
825
826                 tstch1 = toupper(*cp1);
827                 tstch2 = toupper(*cp2);
828                 if (tstch1 != tstch2)
829                     break;
830                 /*
831                  * printf("M'%c' ", *cp1); 
832                  */
833                 cp1++;
834                 cp2++;
835             }
836             while (1);
837             if (*cp1)
838                 cp1++;
839         }
840     /*
841      * printf("\n"); 
842      */
843     if (cp1 && *cp1)
844         return (char *) cp1;
845
846     return NULL;
847 }
848 #endif
849
850 int
851 mkdirhier(const char *pathname, mode_t mode, int skiplast)
852 {
853     struct stat     sbuf;
854     char           *ourcopy = strdup(pathname);
855     char           *entry;
856     char            buf[SNMP_MAXPATH];
857
858     entry = strtok(ourcopy, "/");
859
860     buf[0] = '\0';
861     /*
862      * check to see if filename is a directory 
863      */
864     while (entry) {
865         strcat(buf, "/");
866         strcat(buf, entry);
867         entry = strtok(NULL, "/");
868         if (entry == NULL && skiplast)
869             break;
870         if (stat(buf, &sbuf) < 0) {
871             /*
872              * DNE, make it 
873              */
874             snmp_log(LOG_INFO, "Creating directory: %s\n", buf);
875 #ifdef WIN32
876             CreateDirectory(buf, NULL);
877 #else
878             if (mkdir(buf, mode) == -1) {
879                 free(ourcopy);
880                 return SNMPERR_GENERR;
881             }
882 #endif
883         } else {
884             /*
885              * exists, is it a file? 
886              */
887             if ((sbuf.st_mode & S_IFDIR) == 0) {
888                 /*
889                  * ack! can't make a directory on top of a file 
890                  */
891                 free(ourcopy);
892                 return SNMPERR_GENERR;
893             }
894         }
895     }
896     free(ourcopy);
897     return SNMPERR_SUCCESS;
898 }
899
900 /*
901  * This function was created to differentiate actions
902  * that are appropriate for Linux 2.4 kernels, but not later kernels.
903  *
904  * This function can be used to test kernels on any platform that supports uname().
905  *
906  * If not running a platform that supports uname(), return -1.
907  *
908  * If ospname matches, and the release matches up through the prefix,
909  *  return 0.
910  * If the release is ordered higher, return 1.
911  * Be aware that "ordered higher" is not a guarantee of correctness.
912  */
913 int
914 netsnmp_os_prematch(const char *ospmname,
915                     const char *ospmrelprefix)
916 {
917 #if HAVE_SYS_UTSNAME_H
918 static int printOSonce = 1;
919   struct utsname utsbuf;
920   if ( 0 != uname(&utsbuf))
921     return -1;
922
923   if (printOSonce) {
924     printOSonce = 0;
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));
928   }
929   if (0 != strcasecmp(utsbuf.sysname, ospmname)) return -1;
930
931   /* Required to match only the leading characters */
932   return strncasecmp(utsbuf.release, ospmrelprefix, strlen(ospmrelprefix));
933
934 #else
935
936   return -1;
937
938 #endif /* HAVE_SYS_UTSNAME_H */
939 }