added files
[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 #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 */
120
121 #include <net-snmp/library/snmp_api.h>
122
123 #ifndef IFF_LOOPBACK
124 #       define IFF_LOOPBACK 0
125 #endif
126
127 #ifdef  INADDR_LOOPBACK
128 # define LOOPBACK    INADDR_LOOPBACK
129 #else
130 # define LOOPBACK    0x7f000001
131 #endif
132
133
134
135 /*
136  * ********************************************* 
137  */
138 #ifdef                                                  WIN32
139 #       define WIN32_LEAN_AND_MEAN
140 #       define WIN32IO_IS_STDIO
141 #       define PATHLEN  1024
142
143 #       include <tchar.h>
144 #       include <windows.h>
145
146
147 /*
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.
151  */
152 DIR            *
153 opendir(const char *filename)
154 {
155     DIR            *p;
156     long            len;
157     long            idx;
158     char            scannamespc[PATHLEN];
159     char           *scanname = scannamespc;
160     struct stat     sbuf;
161     WIN32_FIND_DATA FindData;
162     HANDLE          fh;
163
164     /*
165      * check to see if filename is a directory 
166      */
167     if (stat(filename, &sbuf) < 0 || sbuf.st_mode & S_IFDIR == 0) {
168         return NULL;
169     }
170
171     /*
172      * get the file system characteristics 
173      */
174     /*
175      * if(GetFullPathName(filename, SNMP_MAXPATH, root, &dummy)) {
176      * *    if(dummy = strchr(root, '\\'))
177      * *        *++dummy = '\0';
178      * *    if(GetVolumeInformation(root, volname, SNMP_MAXPATH, &serial,
179      * *                            &maxname, &flags, 0, 0)) {
180      * *        downcase = !(flags & FS_CASE_IS_PRESERVED);
181      * *    }
182      * *  }
183      * *  else {
184      * *    downcase = TRUE;
185      * *  }
186      */
187
188     /*
189      * Create the search pattern 
190      */
191     strcpy(scanname, filename);
192
193     if (strchr("/\\", *(scanname + strlen(scanname) - 1)) == NULL)
194         strcat(scanname, "/*");
195     else
196         strcat(scanname, "*");
197
198     /*
199      * do the FindFirstFile call 
200      */
201     fh = FindFirstFile(scanname, &FindData);
202     if (fh == INVALID_HANDLE_VALUE) {
203         return NULL;
204     }
205
206     /*
207      * Get us a DIR structure 
208      */
209     p = (DIR *) malloc(sizeof(DIR));
210     /*
211      * Newz(1303, p, 1, DIR); 
212      */
213     if (p == NULL)
214         return NULL;
215
216     /*
217      * now allocate the first part of the string table for
218      * * the filenames that we find.
219      */
220     idx = strlen(FindData.cFileName) + 1;
221     p->start = (char *) malloc(idx);
222     /*
223      * New(1304, p->start, idx, char);
224      */
225     if (p->start == NULL) {
226         free(p);
227         return NULL;
228     }
229     strcpy(p->start, FindData.cFileName);
230     /*
231      * if(downcase)
232      * *    strlwr(p->start);
233      */
234     p->nfiles = 0;
235
236     /*
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.
241      */
242     while (FindNextFile(fh, &FindData)) {
243         len = strlen(FindData.cFileName);
244         /*
245          * bump the string table size by enough for the
246          * * new name and it's null terminator
247          */
248         p->start = (char *) realloc((void *) p->start, idx + len + 1);
249         /*
250          * Renew(p->start, idx+len+1, char);
251          */
252         if (p->start == NULL) {
253             free(p);
254             return NULL;
255         }
256         strcpy(&p->start[idx], FindData.cFileName);
257         /*
258          * if (downcase) 
259          * *        strlwr(&p->start[idx]);
260          */
261         p->nfiles++;
262         idx += len + 1;
263     }
264     FindClose(fh);
265     p->size = idx;
266     p->curr = p->start;
267     return p;
268 }
269
270
271 /*
272  * Readdir just returns the current string pointer and bumps the
273  * * string pointer to the nDllExport entry.
274  */
275 struct direct  *
276 readdir(DIR * dirp)
277 {
278     int             len;
279     static int      dummy = 0;
280
281     if (dirp->curr) {
282         /*
283          * first set up the structure to return 
284          */
285         len = strlen(dirp->curr);
286         strcpy(dirp->dirstr.d_name, dirp->curr);
287         dirp->dirstr.d_namlen = len;
288
289         /*
290          * Fake an inode 
291          */
292         dirp->dirstr.d_ino = dummy++;
293
294         /*
295          * Now set up for the nDllExport call to readdir 
296          */
297         dirp->curr += len + 1;
298         if (dirp->curr >= (dirp->start + dirp->size)) {
299             dirp->curr = NULL;
300         }
301
302         return &(dirp->dirstr);
303     } else
304         return NULL;
305 }
306
307 /*
308  * free the memory allocated by opendir 
309  */
310 int
311 closedir(DIR * dirp)
312 {
313     free(dirp->start);
314     free(dirp);
315     return 1;
316 }
317
318 #ifndef HAVE_GETTIMEOFDAY
319
320 int
321 gettimeofday(struct timeval *tv, struct timezone *tz)
322 {
323     struct _timeb   timebuffer;
324
325     _ftime(&timebuffer);
326     tv->tv_usec = timebuffer.millitm * 1000;
327     tv->tv_sec = timebuffer.time;
328     return (0);
329 }
330 #endif                          /* !HAVE_GETTIMEOFDAY */
331
332 in_addr_t
333 get_myaddr(void)
334 {
335     char            local_host[130];
336     int             result;
337     LPHOSTENT       lpstHostent;
338     SOCKADDR_IN     in_addr, remote_in_addr;
339     SOCKET          hSock;
340     int             nAddrSize = sizeof(SOCKADDR);
341
342     in_addr.sin_addr.s_addr = INADDR_ANY;
343
344     result = gethostname(local_host, sizeof(local_host));
345     if (result == 0) {
346         lpstHostent = gethostbyname((LPSTR) local_host);
347         if (lpstHostent) {
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);
351         }
352     }
353
354     /*
355      * if we are here, than we don't have host addr 
356      */
357     hSock = socket(AF_INET, SOCK_DGRAM, 0);
358     if (hSock != INVALID_SOCKET) {
359         /*
360          * connect to any port and address 
361          */
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");
365         result =
366             connect(hSock, (LPSOCKADDR) & remote_in_addr,
367                     sizeof(SOCKADDR));
368         if (result != SOCKET_ERROR) {
369             /*
370              * get local ip address 
371              */
372             getsockname(hSock, (LPSOCKADDR) & in_addr,
373                         (int FAR *) &nAddrSize);
374         }
375         closesocket(hSock);
376     }
377     return ((in_addr_t) in_addr.sin_addr.s_addr);
378 }
379
380 long
381 get_uptime(void)
382 {
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;
388
389     /*
390      * min requirement is one PERF_DATA_BLOCK plus one PERF_OBJECT_TYPE 
391      */
392     perfdata = (PPERF_DATA_BLOCK) malloc(buffersize);
393
394
395     memset(perfdata, 0, buffersize);
396
397     RegQueryValueEx(HKEY_PERFORMANCE_DATA,
398                     "Global", NULL, &type, (LPBYTE) perfdata, &buffersize);
399
400     /*
401      * we can not rely on the return value since there is always more so
402      * we check the signature 
403      */
404
405     if (wcsncmp(perfdata->Signature, L"PERF", 4) == 0) {
406         /*
407          * signature ok, and all we need is in the in the PERF_DATA_BLOCK 
408          */
409         return_value = (long) ((perfdata->PerfTime100nSec.QuadPart /
410                                 (LONGLONG) 100000));
411     } else
412         return_value = GetTickCount() / 10;
413
414     RegCloseKey(HKEY_PERFORMANCE_DATA);
415     free(perfdata);
416
417     return return_value;
418 }
419
420 char           *
421 winsock_startup(void)
422 {
423     WORD            VersionRequested;
424     WSADATA         stWSAData;
425     int             i;
426     static char     errmsg[100];
427
428     VersionRequested = MAKEWORD(1, 1);
429     i = WSAStartup(VersionRequested, &stWSAData);
430     if (i != 0) {
431         if (i == WSAVERNOTSUPPORTED)
432             sprintf(errmsg,
433                     "Unable to init. socket lib, does not support 1.1");
434         else {
435             sprintf(errmsg, "Socket Startup error %d", i);
436         }
437         return (errmsg);
438     }
439     return (NULL);
440 }
441
442 void
443 winsock_cleanup(void)
444 {
445     WSACleanup();
446 }
447
448 #else                           /* ! WIN32 */
449 /*******************************************************************/
450
451 /*
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
454  *                                                           used very often).
455  */
456 in_addr_t
457 get_myaddr(void)
458 {
459     int             sd, i, lastlen = 0;
460     struct ifconf   ifc;
461     struct ifreq   *ifrp = NULL;
462     in_addr_t       addr;
463     char           *buf = NULL;
464
465     if ((sd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
466         return 0;
467     }
468
469     /*
470      * Cope with lots of interfaces and brokenness of ioctl SIOCGIFCONF on
471      * some platforms; see W. R. Stevens, ``Unix Network Programming Volume
472      * I'', p.435.  
473      */
474
475     for (i = 8;; i += 8) {
476         buf = (char *) calloc(i, sizeof(struct ifreq));
477         if (buf == NULL) {
478             close(sd);
479             return 0;
480         }
481         ifc.ifc_len = i * sizeof(struct ifreq);
482         ifc.ifc_buf = (caddr_t) buf;
483
484         if (ioctl(sd, SIOCGIFCONF, (char *) &ifc) < 0) {
485             if (errno != EINVAL || lastlen != 0) {
486                 /*
487                  * Something has gone genuinely wrong.  
488                  */
489                 free(buf);
490                 close(sd);
491                 return 0;
492             }
493             /*
494              * Otherwise, it could just be that the buffer is too small.  
495              */
496         } else {
497             if (ifc.ifc_len == lastlen) {
498                 /*
499                  * The length is the same as the last time; we're done.  
500                  */
501                 break;
502             }
503             lastlen = ifc.ifc_len;
504         }
505         free(buf);
506     }
507
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)
514 #else
515         ifrp++
516 #endif
517         ) {
518         if (ifrp->ifr_addr.sa_family != AF_INET) {
519             continue;
520         }
521         addr = ((struct sockaddr_in *) &(ifrp->ifr_addr))->sin_addr.s_addr;
522
523         if (ioctl(sd, SIOCGIFFLAGS, (char *) ifrp) < 0) {
524             continue;
525         }
526         if ((ifrp->ifr_flags & IFF_UP)
527 #ifdef IFF_RUNNING
528             && (ifrp->ifr_flags & IFF_RUNNING)
529 #endif                          /* IFF_RUNNING */
530             && !(ifrp->ifr_flags & IFF_LOOPBACK)
531             && addr != LOOPBACK) {
532             /*
533              * I *really* don't understand why this is necessary.  Perhaps for
534              * some broken platform?  Leave it for now.  JBPN  
535              */
536 #ifdef SYS_IOCTL_H_HAS_SIOCGIFADDR
537             if (ioctl(sd, SIOCGIFADDR, (char *) ifrp) < 0) {
538                 continue;
539             }
540             addr =
541                 ((struct sockaddr_in *) &(ifrp->ifr_addr))->sin_addr.
542                 s_addr;
543 #endif
544             free(buf);
545             close(sd);
546             return addr;
547         }
548     }
549     free(buf);
550     close(sd);
551     return 0;
552 }
553
554
555 #if !defined(solaris2) && !defined(linux) && !defined(cygwin)
556 /*
557  * Returns boottime in centiseconds(!).
558  *      Caches this for future use.
559  */
560 long
561 get_boottime(void)
562 {
563     static long     boottime_csecs = 0;
564 #if defined(hpux10) || defined(hpux11)
565     struct pst_static pst_buf;
566 #else
567     struct timeval  boottime;
568 #ifdef  CAN_USE_SYSCTL
569     int             mib[2];
570     size_t          len;
571 #else
572     int             kmem;
573     static struct nlist nl[] = {
574 #if !defined(hpux)
575         {(char *) "_boottime"},
576 #else
577         {(char *) "boottime"},
578 #endif
579         {(char *) ""}
580     };
581 #endif                          /* CAN_USE_SYSCTL */
582 #endif                          /* hpux10 || hpux 11 */
583
584
585     if (boottime_csecs != 0)
586         return (boottime_csecs);
587
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;
591 #else
592 #ifdef CAN_USE_SYSCTL
593     mib[0] = CTL_KERN;
594     mib[1] = KERN_BOOTTIME;
595
596     len = sizeof(boottime);
597
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)
602         return 0;
603     nlist(KERNEL_LOC, nl);
604     if (nl[0].n_type == 0) {
605         close(kmem);
606         return 0;
607     }
608
609     lseek(kmem, (long) nl[0].n_value, L_SET);
610     read(kmem, &boottime, sizeof(boottime));
611     close(kmem);
612     boottime_csecs = (boottime.tv_sec * 100) + (boottime.tv_usec / 10000);
613 #endif                          /* CAN_USE_SYSCTL */
614 #endif                          /* hpux10 || hpux 11 */
615
616     return (boottime_csecs);
617 }
618 #endif
619
620 /*
621  * Returns uptime in centiseconds(!).
622  */
623 long
624 get_uptime(void)
625 {
626 #if !defined(solaris2) && !defined(linux) && !defined(cygwin)
627     struct timeval  now;
628     long            boottime_csecs, nowtime_csecs;
629
630     boottime_csecs = get_boottime();
631     if (boottime_csecs == 0)
632         return 0;
633     gettimeofday(&now, (struct timezone *) 0);
634     nowtime_csecs = (now.tv_sec * 100) + (now.tv_usec / 10000);
635
636     return (nowtime_csecs - boottime_csecs);
637 #endif
638
639 #ifdef solaris2
640     kstat_ctl_t    *ksc = kstat_open();
641     kstat_t        *ks;
642     kid_t           kid;
643     kstat_named_t  *named;
644     u_long          lbolt = 0;
645
646     if (ksc) {
647         ks = kstat_lookup(ksc, "unix", -1, "system_misc");
648         if (ks) {
649             kid = kstat_read(ksc, ks, NULL);
650             if (kid != -1) {
651                 named = kstat_data_lookup(ks, "lbolt");
652                 if (named) {
653 #ifdef KSTAT_DATA_INT32
654                     lbolt = named->value.ul;
655 #else
656                     lbolt = named->value.ul;
657 #endif
658                 }
659             }
660         }
661         kstat_close(ksc);
662     }
663     return lbolt;
664 #endif                          /* solaris2 */
665
666 #ifdef linux
667     FILE           *in = fopen("/proc/uptime", "r");
668     long            uptim = 0, a, b;
669     if (in) {
670         if (2 == fscanf(in, "%ld.%ld", &a, &b))
671             uptim = a * 100 + b;
672         fclose(in);
673     }
674     return uptim;
675 #endif                          /* linux */
676
677 #ifdef cygwin
678     return (0);                 /* not implemented */
679 #endif
680 }
681
682 #endif                          /* ! WIN32 */
683 /*******************************************************************/
684
685 #ifndef HAVE_STRNCASECMP
686
687 /*
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.
691  */
692 int
693 strncasecmp(const char *s1, const char *s2, size_t nch)
694 {
695     size_t          ii;
696     int             res = -1;
697
698     if (!s1) {
699         if (!s2)
700             return 0;
701         return (-1);
702     }
703     if (!s2)
704         return (1);
705
706     for (ii = 0; (ii < nch) && *s1 && *s2; ii++, s1++, s2++) {
707         res = (int) (tolower(*s1) - tolower(*s2));
708         if (res != 0)
709             break;
710     }
711
712     if (ii == nch) {
713         s1--;
714         s2--;
715     }
716
717     if (!*s1) {
718         if (!*s2)
719             return 0;
720         return (-1);
721     }
722     if (!*s2)
723         return (1);
724
725     return (res);
726 }
727
728 int
729 strcasecmp(const char *s1, const char *s2)
730 {
731     return strncasecmp(s1, s2, 1000000);
732 }
733
734 #endif                          /* HAVE_STRNCASECMP */
735
736
737 #ifndef HAVE_STRDUP
738 char           *
739 strdup(const char *src)
740 {
741     int             len;
742     char           *dst;
743
744     len = strlen(src) + 1;
745     if ((dst = (char *) malloc(len)) == NULL)
746         return (NULL);
747     strcpy(dst, src);
748     return (dst);
749 }
750 #endif                          /* HAVE_STRDUP */
751
752 #ifndef HAVE_SETENV
753 int
754 setenv(const char *name, const char *value, int overwrite)
755 {
756     char           *cp;
757     int             ret;
758
759     if (overwrite == 0) {
760         if (getenv(name))
761             return 0;
762     }
763     cp = (char *) malloc(strlen(name) + strlen(value) + 2);
764     if (cp == NULL)
765         return -1;
766     sprintf(cp, "%s=%s", name, value);
767     ret = putenv(cp);
768 #ifdef WIN32
769     free(cp);
770 #endif
771     return ret;
772 }
773 #endif                          /* HAVE_SETENV */
774
775 int
776 calculate_time_diff(struct timeval *now, struct timeval *then)
777 {
778     struct timeval  tmp, diff;
779     memcpy(&tmp, now, sizeof(struct timeval));
780     tmp.tv_sec--;
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;
786         diff.tv_sec++;
787     }
788     return ((diff.tv_sec * 100) + (diff.tv_usec / 10000));
789 }
790
791 #ifndef HAVE_STRCASESTR
792 /*
793  * only glibc2 has this.
794  */
795 char           *
796 strcasestr(const char *haystack, const char *needle)
797 {
798     const char     *cp1 = haystack, *cp2 = needle;
799     const char     *cx;
800     int             tstch1, tstch2;
801
802     /*
803      * printf("looking for '%s' in '%s'\n", needle, haystack); 
804      */
805     if (cp1 && cp2 && *cp1 && *cp2)
806         for (cp1 = haystack, cp2 = needle; *cp1;) {
807             cx = cp1;
808             cp2 = needle;
809             do {
810                 /*
811                  * printf("T'%c' ", *cp1); 
812                  */
813                 if (!*cp2) {    /* found the needle */
814                     /*
815                      * printf("\nfound '%s' in '%s'\n", needle, cx); 
816                      */
817                     return (char *) cx;
818                 }
819                 if (!*cp1)
820                     break;
821
822                 tstch1 = toupper(*cp1);
823                 tstch2 = toupper(*cp2);
824                 if (tstch1 != tstch2)
825                     break;
826                 /*
827                  * printf("M'%c' ", *cp1); 
828                  */
829                 cp1++;
830                 cp2++;
831             }
832             while (1);
833             if (*cp1)
834                 cp1++;
835         }
836     /*
837      * printf("\n"); 
838      */
839     if (cp1 && *cp1)
840         return (char *) cp1;
841
842     return NULL;
843 }
844 #endif
845
846 int
847 mkdirhier(const char *pathname, mode_t mode, int skiplast)
848 {
849     struct stat     sbuf;
850     char           *ourcopy = strdup(pathname);
851     char           *entry;
852     char            buf[SNMP_MAXPATH];
853
854     entry = strtok(ourcopy, "/");
855
856     buf[0] = '\0';
857     /*
858      * check to see if filename is a directory 
859      */
860     while (entry) {
861         strcat(buf, "/");
862         strcat(buf, entry);
863         entry = strtok(NULL, "/");
864         if (entry == NULL && skiplast)
865             break;
866         if (stat(buf, &sbuf) < 0) {
867             /*
868              * DNE, make it 
869              */
870             snmp_log(LOG_INFO, "Creating directory: %s\n", buf);
871 #ifdef WIN32
872             CreateDirectory(buf, NULL);
873 #else
874             if (mkdir(buf, mode) == -1) {
875                 free(ourcopy);
876                 return SNMPERR_GENERR;
877             }
878 #endif
879         } else {
880             /*
881              * exists, is it a file? 
882              */
883             if ((sbuf.st_mode & S_IFDIR) == 0) {
884                 /*
885                  * ack! can't make a directory on top of a file 
886                  */
887                 free(ourcopy);
888                 return SNMPERR_GENERR;
889             }
890         }
891     }
892     free(ourcopy);
893     return SNMPERR_SUCCESS;
894 }