net-snmp  5.4.1
system.c
00001 /*
00002  * system.c
00003  */
00004 /* Portions of this file are subject to the following copyright(s).  See
00005  * the Net-SNMP's COPYING file for more details and other copyrights
00006  * that may apply:
00007  */
00008 /***********************************************************
00009         Copyright 1992 by Carnegie Mellon University
00010 
00011                       All Rights Reserved
00012 
00013 Permission to use, copy, modify, and distribute this software and its
00014 documentation for any purpose and without fee is hereby granted,
00015 provided that the above copyright notice appear in all copies and that
00016 both that copyright notice and this permission notice appear in
00017 supporting documentation, and that the name of CMU not be
00018 used in advertising or publicity pertaining to distribution of the
00019 software without specific, written prior permission.
00020 
00021 CMU DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
00022 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
00023 CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
00024 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
00025 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
00026 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
00027 SOFTWARE.
00028 ******************************************************************/
00029 /*
00030  * Portions of this file are copyrighted by:
00031  * Copyright © 2003 Sun Microsystems, Inc. All rights reserved.
00032  * Use is subject to license terms specified in the COPYING file
00033  * distributed with the Net-SNMP package.
00034  */
00035 /*
00036  * System dependent routines go here
00037  */
00038 #include <net-snmp/net-snmp-config.h>
00039 #include <stdio.h>
00040 #include <ctype.h>
00041 #include <errno.h>
00042 
00043 #if HAVE_UNISTD_H
00044 #include <unistd.h>
00045 #endif
00046 #if HAVE_STDLIB_H
00047 #include <stdlib.h>
00048 #endif
00049 
00050 #if TIME_WITH_SYS_TIME
00051 # ifdef WIN32
00052 #  include <sys/timeb.h>
00053 # else
00054 #  include <sys/time.h>
00055 # endif
00056 # include <time.h>
00057 #else
00058 # if HAVE_SYS_TIME_H
00059 #  include <sys/time.h>
00060 # else
00061 #  include <time.h>
00062 # endif
00063 #endif
00064 
00065 #include <sys/types.h>
00066 
00067 #if HAVE_NETINET_IN_H
00068 #include <netinet/in.h>
00069 #endif
00070 
00071 #if HAVE_WINSOCK_H
00072 #include <winsock.h>
00073 #endif
00074 #if HAVE_SYS_SOCKET_H
00075 #include <sys/socket.h>
00076 #endif
00077 #if HAVE_NET_IF_H
00078 #include <net/if.h>
00079 #endif
00080 
00081 #if HAVE_SYS_SOCKIO_H
00082 #include <sys/sockio.h>
00083 #endif
00084 
00085 #if HAVE_SYS_IOCTL_H
00086 #include <sys/ioctl.h>
00087 #endif
00088 
00089 #ifdef HAVE_NLIST_H
00090 #include <nlist.h>
00091 #endif
00092 
00093 #if HAVE_SYS_FILE_H
00094 #include <sys/file.h>
00095 #endif
00096 
00097 #if HAVE_KSTAT_H
00098 #include <kstat.h>
00099 #endif
00100 
00101 #if HAVE_SYS_PARAM_H
00102 #include <sys/param.h>
00103 #endif
00104 #if HAVE_SYS_SYSCTL_H
00105 #include <sys/sysctl.h>
00106 #endif
00107 
00108 #if HAVE_STRING_H
00109 #include <string.h>
00110 #else
00111 #include <strings.h>
00112 #endif
00113 
00114 #if HAVE_DMALLOC_H
00115 #include <dmalloc.h>
00116 #endif
00117 
00118 #ifdef HAVE_SYS_STAT_H
00119 #include <sys/stat.h>
00120 #endif
00121 #if HAVE_FCNTL_H
00122 #include <fcntl.h>
00123 #endif
00124 
00125 #if defined(hpux10) || defined(hpux11)
00126 #include <sys/pstat.h>
00127 #endif
00128 
00129 #if HAVE_SYS_UTSNAME_H
00130 #include <sys/utsname.h>
00131 #endif
00132 
00133 #if HAVE_SYS_SYSTEMCFG_H
00134 #include <sys/systemcfg.h>
00135 #endif
00136 
00137 #if HAVE_SYS_SYSTEMINFO_H
00138 #include <sys/systeminfo.h>
00139 #endif
00140 
00141 #include <net-snmp/types.h>
00142 #include <net-snmp/output_api.h>
00143 #include <net-snmp/utilities.h>
00144 #include <net-snmp/library/system.h>    /* for "internal" definitions */
00145 
00146 #include <net-snmp/library/snmp_api.h>
00147 #include <net-snmp/library/read_config.h> /* for get_temp_file_pattern() */
00148 
00149 #ifndef IFF_LOOPBACK
00150 #       define IFF_LOOPBACK 0
00151 #endif
00152 
00153 #ifdef  INADDR_LOOPBACK
00154 # define LOOPBACK    INADDR_LOOPBACK
00155 #else
00156 # define LOOPBACK    0x7f000001
00157 #endif
00158 
00181 int
00182 netsnmp_daemonize(int quit_immediately, int stderr_log)
00183 {
00184     int i = 0;
00185     DEBUGMSGT(("daemonize","deamonizing...\n"));
00186 #if HAVE_FORK
00187     /*
00188      * Fork to return control to the invoking process and to
00189      * guarantee that we aren't a process group leader.
00190      */
00191     i = fork();
00192     if (i != 0) {
00193         /* Parent. */
00194         DEBUGMSGT(("daemonize","first fork returned %d.\n", i));
00195         if(i == -1) {
00196             snmp_log(LOG_ERR,"first fork failed (errno %d) in "
00197                      "netsnmp_daemonize()\n", errno);
00198             return -1;
00199         }
00200         if (quit_immediately) {
00201             DEBUGMSGT(("daemonize","parent exiting\n"));
00202             exit(0);
00203         }
00204     } else {
00205         /* Child. */
00206 #ifdef HAVE_SETSID
00207         /* Become a process/session group leader. */
00208         setsid();
00209 #endif
00210         /*
00211          * Fork to let the process/session group leader exit.
00212          */
00213         if ((i = fork()) != 0) {
00214             DEBUGMSGT(("daemonize","second fork returned %d.\n", i));
00215             if(i == -1) {
00216                 snmp_log(LOG_ERR,"second fork failed (errno %d) in "
00217                          "netsnmp_daemonize()\n", errno);
00218             }
00219             /* Parent. */
00220             exit(0);
00221         }
00222 #ifndef WIN32
00223         else {
00224             /* Child. */
00225             
00226             DEBUGMSGT(("daemonize","child continuing\n"));
00227 
00228             /* Avoid keeping any directory in use. */
00229             chdir("/");
00230             
00231             if (!stderr_log) {
00232                 /*
00233                  * Close inherited file descriptors to avoid
00234                  * keeping unnecessary references.
00235                  */
00236                 close(0);
00237                 close(1);
00238                 close(2);
00239                 
00240                 /*
00241                  * Redirect std{in,out,err} to /dev/null, just in
00242                  * case.
00243                  */
00244                 open("/dev/null", O_RDWR);
00245                 dup(0);
00246                 dup(0);
00247             }
00248         }
00249 #endif /* !WIN32 */
00250     }
00251 #endif /* HAVE_FORK */
00252     return i;
00253 }
00254 
00255 /*
00256  * ********************************************* 
00257  */
00258 #ifdef                                                  WIN32
00259 #       define WIN32_LEAN_AND_MEAN
00260 #       define WIN32IO_IS_STDIO
00261 #       define PATHLEN  1024
00262 
00263 #       include <tchar.h>
00264 #       include <windows.h>
00265 
00266 /*
00267  * MinGW defines WIN32, but has working dirent stuff.
00268  */
00269 #ifndef HAVE_DIRENT_H 
00270 
00271 /*
00272  * The idea here is to read all the directory names into a string table
00273  * * (separated by nulls) and when one of the other dir functions is called
00274  * * return the pointer to the current file name.
00275  */
00276 DIR            *
00277 opendir(const char *filename)
00278 {
00279     DIR            *p;
00280     long            len;
00281     long            idx;
00282     char            scannamespc[PATHLEN];
00283     char           *scanname = scannamespc;
00284     struct stat     sbuf;
00285     WIN32_FIND_DATA FindData;
00286     HANDLE          fh;
00287 
00288     /*
00289      * check to see if filename is a directory 
00290      */
00291     if ((stat(filename, &sbuf) < 0) || ((sbuf.st_mode & S_IFDIR) == 0)) {
00292         return NULL;
00293     }
00294 
00295     /*
00296      * get the file system characteristics 
00297      */
00298     /*
00299      * if(GetFullPathName(filename, SNMP_MAXPATH, root, &dummy)) {
00300      * *    if(dummy = strchr(root, '\\'))
00301      * *        *++dummy = '\0';
00302      * *    if(GetVolumeInformation(root, volname, SNMP_MAXPATH, &serial,
00303      * *                            &maxname, &flags, 0, 0)) {
00304      * *        downcase = !(flags & FS_CASE_IS_PRESERVED);
00305      * *    }
00306      * *  }
00307      * *  else {
00308      * *    downcase = TRUE;
00309      * *  }
00310      */
00311 
00312     /*
00313      * Create the search pattern 
00314      */
00315     strcpy(scanname, filename);
00316 
00317     if (strchr("/\\", *(scanname + strlen(scanname) - 1)) == NULL)
00318         strcat(scanname, "/*");
00319     else
00320         strcat(scanname, "*");
00321 
00322     /*
00323      * do the FindFirstFile call 
00324      */
00325     fh = FindFirstFile(scanname, &FindData);
00326     if (fh == INVALID_HANDLE_VALUE) {
00327         return NULL;
00328     }
00329 
00330     /*
00331      * Get us a DIR structure 
00332      */
00333     p = (DIR *) malloc(sizeof(DIR));
00334     /*
00335      * Newz(1303, p, 1, DIR); 
00336      */
00337     if (p == NULL)
00338         return NULL;
00339 
00340     /*
00341      * now allocate the first part of the string table for
00342      * * the filenames that we find.
00343      */
00344     idx = strlen(FindData.cFileName) + 1;
00345     p->start = (char *) malloc(idx);
00346     /*
00347      * New(1304, p->start, idx, char);
00348      */
00349     if (p->start == NULL) {
00350         free(p);
00351         return NULL;
00352     }
00353     strcpy(p->start, FindData.cFileName);
00354     /*
00355      * if(downcase)
00356      * *    strlwr(p->start);
00357      */
00358     p->nfiles = 0;
00359 
00360     /*
00361      * loop finding all the files that match the wildcard
00362      * * (which should be all of them in this directory!).
00363      * * the variable idx should point one past the null terminator
00364      * * of the previous string found.
00365      */
00366     while (FindNextFile(fh, &FindData)) {
00367         len = strlen(FindData.cFileName);
00368         /*
00369          * bump the string table size by enough for the
00370          * * new name and it's null terminator
00371          */
00372         p->start = (char *) realloc((void *) p->start, idx + len + 1);
00373         /*
00374          * Renew(p->start, idx+len+1, char);
00375          */
00376         if (p->start == NULL) {
00377             free(p);
00378             return NULL;
00379         }
00380         strcpy(&p->start[idx], FindData.cFileName);
00381         /*
00382          * if (downcase) 
00383          * *        strlwr(&p->start[idx]);
00384          */
00385         p->nfiles++;
00386         idx += len + 1;
00387     }
00388     FindClose(fh);
00389     p->size = idx;
00390     p->curr = p->start;
00391     return p;
00392 }
00393 
00394 
00395 /*
00396  * Readdir just returns the current string pointer and bumps the
00397  * * string pointer to the nDllExport entry.
00398  */
00399 struct direct  *
00400 readdir(DIR * dirp)
00401 {
00402     int             len;
00403     static int      dummy = 0;
00404 
00405     if (dirp->curr) {
00406         /*
00407          * first set up the structure to return 
00408          */
00409         len = strlen(dirp->curr);
00410         strcpy(dirp->dirstr.d_name, dirp->curr);
00411         dirp->dirstr.d_namlen = len;
00412 
00413         /*
00414          * Fake an inode 
00415          */
00416         dirp->dirstr.d_ino = dummy++;
00417 
00418         /*
00419          * Now set up for the nDllExport call to readdir 
00420          */
00421         dirp->curr += len + 1;
00422         if (dirp->curr >= (dirp->start + dirp->size)) {
00423             dirp->curr = NULL;
00424         }
00425 
00426         return &(dirp->dirstr);
00427     } else
00428         return NULL;
00429 }
00430 
00431 /*
00432  * free the memory allocated by opendir 
00433  */
00434 int
00435 closedir(DIR * dirp)
00436 {
00437     free(dirp->start);
00438     free(dirp);
00439     return 1;
00440 }
00441 #endif /* HAVE_DIRENT_H */
00442 
00443 #ifndef HAVE_GETTIMEOFDAY
00444 
00445 int
00446 gettimeofday(struct timeval *tv, struct timezone *tz)
00447 {
00448     struct _timeb   timebuffer;
00449 
00450     _ftime(&timebuffer);
00451     tv->tv_usec = timebuffer.millitm * 1000;
00452     tv->tv_sec = timebuffer.time;
00453     return (0);
00454 }
00455 #endif                          /* !HAVE_GETTIMEOFDAY */
00456 
00457 in_addr_t
00458 get_myaddr(void)
00459 {
00460     char            local_host[130];
00461     int             result;
00462     LPHOSTENT       lpstHostent;
00463     SOCKADDR_IN     in_addr, remote_in_addr;
00464     SOCKET          hSock;
00465     int             nAddrSize = sizeof(SOCKADDR);
00466 
00467     in_addr.sin_addr.s_addr = INADDR_ANY;
00468 
00469     result = gethostname(local_host, sizeof(local_host));
00470     if (result == 0) {
00471         lpstHostent = gethostbyname((LPSTR) local_host);
00472         if (lpstHostent) {
00473             in_addr.sin_addr.s_addr =
00474                 *((u_long FAR *) (lpstHostent->h_addr));
00475             return ((in_addr_t) in_addr.sin_addr.s_addr);
00476         }
00477     }
00478 
00479     /*
00480      * if we are here, than we don't have host addr 
00481      */
00482     hSock = socket(AF_INET, SOCK_DGRAM, 0);
00483     if (hSock != INVALID_SOCKET) {
00484         /*
00485          * connect to any port and address 
00486          */
00487         remote_in_addr.sin_family = AF_INET;
00488         remote_in_addr.sin_port = htons(IPPORT_ECHO);
00489         remote_in_addr.sin_addr.s_addr = inet_addr("0.0.0.0");
00490         result =
00491             connect(hSock, (LPSOCKADDR) & remote_in_addr,
00492                     sizeof(SOCKADDR));
00493         if (result != SOCKET_ERROR) {
00494             /*
00495              * get local ip address 
00496              */
00497             getsockname(hSock, (LPSOCKADDR) & in_addr,
00498                         (int FAR *) &nAddrSize);
00499         }
00500         closesocket(hSock);
00501     }
00502     return ((in_addr_t) in_addr.sin_addr.s_addr);
00503 }
00504 
00505 long
00506 get_uptime(void)
00507 {
00508     long            return_value = 0;
00509     DWORD           buffersize = (sizeof(PERF_DATA_BLOCK) +
00510                                   sizeof(PERF_OBJECT_TYPE)),
00511         type = REG_EXPAND_SZ;
00512     PPERF_DATA_BLOCK perfdata = NULL;
00513 
00514     /*
00515      * min requirement is one PERF_DATA_BLOCK plus one PERF_OBJECT_TYPE 
00516      */
00517     perfdata = (PPERF_DATA_BLOCK) malloc(buffersize);
00518     if (!perfdata)
00519         return 0;
00520 
00521     memset(perfdata, 0, buffersize);
00522 
00523     RegQueryValueEx(HKEY_PERFORMANCE_DATA,
00524                     "Global", NULL, &type, (LPBYTE) perfdata, &buffersize);
00525 
00526     /*
00527      * we can not rely on the return value since there is always more so
00528      * we check the signature 
00529      */
00530 
00531     if (wcsncmp(perfdata->Signature, L"PERF", 4) == 0) {
00532         /*
00533          * signature ok, and all we need is in the in the PERF_DATA_BLOCK 
00534          */
00535         return_value = (long) ((perfdata->PerfTime100nSec.QuadPart /
00536                                 (LONGLONG) 100000));
00537     } else
00538         return_value = GetTickCount() / 10;
00539 
00540     RegCloseKey(HKEY_PERFORMANCE_DATA);
00541     free(perfdata);
00542 
00543     return return_value;
00544 }
00545 
00546 char           *
00547 winsock_startup(void)
00548 {
00549     WORD            VersionRequested;
00550     WSADATA         stWSAData;
00551     int             i;
00552     static char     errmsg[100];
00553 
00554         /* winsock 1: use MAKEWORD(1,1) */
00555         /* winsock 2: use MAKEWORD(2,2) */
00556 
00557     VersionRequested = MAKEWORD(2,2);
00558     i = WSAStartup(VersionRequested, &stWSAData);
00559     if (i != 0) {
00560         if (i == WSAVERNOTSUPPORTED)
00561             sprintf(errmsg,
00562                     "Unable to init. socket lib, does not support 1.1");
00563         else {
00564             sprintf(errmsg, "Socket Startup error %d", i);
00565         }
00566         return (errmsg);
00567     }
00568     return (NULL);
00569 }
00570 
00571 void
00572 winsock_cleanup(void)
00573 {
00574     WSACleanup();
00575 }
00576 
00577 #else                           /* ! WIN32 */
00578 /*******************************************************************/
00579 
00580 /*
00581  * XXX  What if we have multiple addresses?  Or no addresses for that matter?
00582  * XXX  Could it be computed once then cached?  Probably not worth it (not
00583  *                                                           used very often).
00584  */
00585 in_addr_t
00586 get_myaddr(void)
00587 {
00588     int             sd, i, lastlen = 0;
00589     struct ifconf   ifc;
00590     struct ifreq   *ifrp = NULL;
00591     in_addr_t       addr;
00592     char           *buf = NULL;
00593 
00594     if ((sd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
00595         return 0;
00596     }
00597 
00598     /*
00599      * Cope with lots of interfaces and brokenness of ioctl SIOCGIFCONF on
00600      * some platforms; see W. R. Stevens, ``Unix Network Programming Volume
00601      * I'', p.435.  
00602      */
00603 
00604     for (i = 8;; i += 8) {
00605         buf = (char *) calloc(i, sizeof(struct ifreq));
00606         if (buf == NULL) {
00607             close(sd);
00608             return 0;
00609         }
00610         ifc.ifc_len = i * sizeof(struct ifreq);
00611         ifc.ifc_buf = (caddr_t) buf;
00612 
00613         if (ioctl(sd, SIOCGIFCONF, (char *) &ifc) < 0) {
00614             if (errno != EINVAL || lastlen != 0) {
00615                 /*
00616                  * Something has gone genuinely wrong.  
00617                  */
00618                 free(buf);
00619                 close(sd);
00620                 return 0;
00621             }
00622             /*
00623              * Otherwise, it could just be that the buffer is too small.  
00624              */
00625         } else {
00626             if (ifc.ifc_len == lastlen) {
00627                 /*
00628                  * The length is the same as the last time; we're done.  
00629                  */
00630                 break;
00631             }
00632             lastlen = ifc.ifc_len;
00633         }
00634         free(buf);
00635     }
00636 
00637     for (ifrp = ifc.ifc_req;
00638         (char *)ifrp < (char *)ifc.ifc_req + ifc.ifc_len;
00639 #ifdef STRUCT_SOCKADDR_HAS_SA_LEN
00640         ifrp = (struct ifreq *)(((char *) ifrp) +
00641                                 sizeof(ifrp->ifr_name) +
00642                                 ifrp->ifr_addr.sa_len)
00643 #else
00644         ifrp++
00645 #endif
00646         ) {
00647         if (ifrp->ifr_addr.sa_family != AF_INET) {
00648             continue;
00649         }
00650         addr = ((struct sockaddr_in *) &(ifrp->ifr_addr))->sin_addr.s_addr;
00651 
00652         if (ioctl(sd, SIOCGIFFLAGS, (char *) ifrp) < 0) {
00653             continue;
00654         }
00655         if ((ifrp->ifr_flags & IFF_UP)
00656 #ifdef IFF_RUNNING
00657             && (ifrp->ifr_flags & IFF_RUNNING)
00658 #endif                          /* IFF_RUNNING */
00659             && !(ifrp->ifr_flags & IFF_LOOPBACK)
00660             && addr != LOOPBACK) {
00661             /*
00662              * I *really* don't understand why this is necessary.  Perhaps for
00663              * some broken platform?  Leave it for now.  JBPN  
00664              */
00665 #ifdef SYS_IOCTL_H_HAS_SIOCGIFADDR
00666             if (ioctl(sd, SIOCGIFADDR, (char *) ifrp) < 0) {
00667                 continue;
00668             }
00669             addr =
00670                 ((struct sockaddr_in *) &(ifrp->ifr_addr))->sin_addr.
00671                 s_addr;
00672 #endif
00673             free(buf);
00674             close(sd);
00675             return addr;
00676         }
00677     }
00678     free(buf);
00679     close(sd);
00680     return 0;
00681 }
00682 
00683 
00684 #if !defined(solaris2) && !defined(linux) && !defined(cygwin)
00685 /*
00686  * Returns boottime in centiseconds(!).
00687  *      Caches this for future use.
00688  */
00689 long
00690 get_boottime(void)
00691 {
00692     static long     boottime_csecs = 0;
00693 #if defined(hpux10) || defined(hpux11)
00694     struct pst_static pst_buf;
00695 #else
00696     struct timeval  boottime;
00697 #ifdef  NETSNMP_CAN_USE_SYSCTL
00698     int             mib[2];
00699     size_t          len;
00700 #elif defined(NETSNMP_CAN_USE_NLIST)
00701     int             kmem;
00702     static struct nlist nl[] = {
00703 #if !defined(hpux)
00704         {(char *) "_boottime"},
00705 #else
00706         {(char *) "boottime"},
00707 #endif
00708         {(char *) ""}
00709     };
00710 #endif                          /* NETSNMP_CAN_USE_SYSCTL */
00711 #endif                          /* hpux10 || hpux 11 */
00712 
00713 
00714     if (boottime_csecs != 0)
00715         return (boottime_csecs);
00716 
00717 #if defined(hpux10) || defined(hpux11)
00718     pstat_getstatic(&pst_buf, sizeof(struct pst_static), 1, 0);
00719     boottime_csecs = pst_buf.boot_time * 100;
00720 #elif NETSNMP_CAN_USE_SYSCTL
00721     mib[0] = CTL_KERN;
00722     mib[1] = KERN_BOOTTIME;
00723 
00724     len = sizeof(boottime);
00725 
00726     sysctl(mib, 2, &boottime, &len, NULL, 0);
00727     boottime_csecs = (boottime.tv_sec * 100) + (boottime.tv_usec / 10000);
00728 #elif defined(NETSNMP_CAN_USE_NLIST)
00729     if ((kmem = open("/dev/kmem", 0)) < 0)
00730         return 0;
00731     nlist(KERNEL_LOC, nl);
00732     if (nl[0].n_type == 0) {
00733         close(kmem);
00734         return 0;
00735     }
00736 
00737     lseek(kmem, (long) nl[0].n_value, L_SET);
00738     read(kmem, &boottime, sizeof(boottime));
00739     close(kmem);
00740     boottime_csecs = (boottime.tv_sec * 100) + (boottime.tv_usec / 10000);
00741 #else
00742     return 0;
00743 #endif                          /* hpux10 || hpux 11 */
00744 
00745     return (boottime_csecs);
00746 }
00747 #endif
00748 
00749 /*
00750  * Returns uptime in centiseconds(!).
00751  */
00752 long
00753 get_uptime(void)
00754 {
00755 #if !defined(solaris2) && !defined(linux) && !defined(cygwin) && !defined(aix4) && !defined(aix5)
00756     struct timeval  now;
00757     long            boottime_csecs, nowtime_csecs;
00758 
00759     boottime_csecs = get_boottime();
00760     if (boottime_csecs == 0)
00761         return 0;
00762     gettimeofday(&now, (struct timezone *) 0);
00763     nowtime_csecs = (now.tv_sec * 100) + (now.tv_usec / 10000);
00764 
00765     return (nowtime_csecs - boottime_csecs);
00766 #endif
00767 
00768 #if defined(aix4) || defined(aix5)
00769     struct nlist nl;
00770     int kmem;
00771     time_t lbolt;
00772     nl.n_name = "lbolt";
00773     if(knlist(&nl, 1, sizeof(struct nlist)) != 0) return(0);
00774     if(nl.n_type == 0 || nl.n_value == 0) return(0);
00775     if((kmem = open("/dev/mem", 0)) < 0) return 0;
00776     lseek(kmem, (long) nl.n_value, L_SET);
00777     read(kmem, &lbolt, sizeof(lbolt));
00778     close(kmem);
00779     return(lbolt);
00780 #endif
00781 
00782 #ifdef solaris2
00783     kstat_ctl_t    *ksc = kstat_open();
00784     kstat_t        *ks;
00785     kid_t           kid;
00786     kstat_named_t  *named;
00787     u_long          lbolt = 0;
00788 
00789     if (ksc) {
00790         ks = kstat_lookup(ksc, "unix", -1, "system_misc");
00791         if (ks) {
00792             kid = kstat_read(ksc, ks, NULL);
00793             if (kid != -1) {
00794                 named = kstat_data_lookup(ks, "lbolt");
00795                 if (named) {
00796 #ifdef KSTAT_DATA_UINT32
00797                     lbolt = named->value.ui32;
00798 #else
00799                     lbolt = named->value.ul;
00800 #endif
00801                 }
00802             }
00803         }
00804         kstat_close(ksc);
00805     }
00806     return lbolt;
00807 #endif                          /* solaris2 */
00808 
00809 #ifdef linux
00810     FILE           *in = fopen("/proc/uptime", "r");
00811     long            uptim = 0, a, b;
00812     if (in) {
00813         if (2 == fscanf(in, "%ld.%ld", &a, &b))
00814             uptim = a * 100 + b;
00815         fclose(in);
00816     }
00817     return uptim;
00818 #endif                          /* linux */
00819 
00820 #ifdef cygwin
00821     return (0);                 /* not implemented */
00822 #endif
00823 }
00824 
00825 #endif                          /* ! WIN32 */
00826 /*******************************************************************/
00827 
00828 #ifndef HAVE_STRNCASECMP
00829 
00830 /*
00831  * test for NULL pointers before and NULL characters after
00832  * * comparing possibly non-NULL strings.
00833  * * WARNING: This function does NOT check for array overflow.
00834  */
00835 int
00836 strncasecmp(const char *s1, const char *s2, size_t nch)
00837 {
00838     size_t          ii;
00839     int             res = -1;
00840 
00841     if (!s1) {
00842         if (!s2)
00843             return 0;
00844         return (-1);
00845     }
00846     if (!s2)
00847         return (1);
00848 
00849     for (ii = 0; (ii < nch) && *s1 && *s2; ii++, s1++, s2++) {
00850         res = (int) (tolower(*s1) - tolower(*s2));
00851         if (res != 0)
00852             break;
00853     }
00854 
00855     if (ii == nch) {
00856         s1--;
00857         s2--;
00858     }
00859 
00860     if (!*s1) {
00861         if (!*s2)
00862             return 0;
00863         return (-1);
00864     }
00865     if (!*s2)
00866         return (1);
00867 
00868     return (res);
00869 }
00870 
00871 int
00872 strcasecmp(const char *s1, const char *s2)
00873 {
00874     return strncasecmp(s1, s2, 1000000);
00875 }
00876 
00877 #endif                          /* HAVE_STRNCASECMP */
00878 
00879 
00880 #ifndef HAVE_STRDUP
00881 char           *
00882 strdup(const char *src)
00883 {
00884     int             len;
00885     char           *dst;
00886 
00887     len = strlen(src) + 1;
00888     if ((dst = (char *) malloc(len)) == NULL)
00889         return (NULL);
00890     strcpy(dst, src);
00891     return (dst);
00892 }
00893 #endif                          /* HAVE_STRDUP */
00894 
00895 #ifndef HAVE_SETENV
00896 int
00897 setenv(const char *name, const char *value, int overwrite)
00898 {
00899     char           *cp;
00900     int             ret;
00901 
00902     if (overwrite == 0) {
00903         if (getenv(name))
00904             return 0;
00905     }
00906     cp = (char *) malloc(strlen(name) + strlen(value) + 2);
00907     if (cp == NULL)
00908         return -1;
00909     sprintf(cp, "%s=%s", name, value);
00910     ret = putenv(cp);
00911 #ifdef WIN32
00912     free(cp);
00913 #endif
00914     return ret;
00915 }
00916 #endif                          /* HAVE_SETENV */
00917 
00918 /* returns centiseconds */
00919 int
00920 calculate_time_diff(struct timeval *now, struct timeval *then)
00921 {
00922     struct timeval  tmp, diff;
00923     memcpy(&tmp, now, sizeof(struct timeval));
00924     tmp.tv_sec--;
00925     tmp.tv_usec += 1000000L;
00926     diff.tv_sec = tmp.tv_sec - then->tv_sec;
00927     diff.tv_usec = tmp.tv_usec - then->tv_usec;
00928     if (diff.tv_usec > 1000000L) {
00929         diff.tv_usec -= 1000000L;
00930         diff.tv_sec++;
00931     }
00932     return ((diff.tv_sec * 100) + (diff.tv_usec / 10000));
00933 }
00934 
00935 /* returns diff in rounded seconds */
00936 u_int
00937 calculate_sectime_diff(struct timeval *now, struct timeval *then)
00938 {
00939     struct timeval  tmp, diff;
00940     memcpy(&tmp, now, sizeof(struct timeval));
00941     tmp.tv_sec--;
00942     tmp.tv_usec += 1000000L;
00943     diff.tv_sec = tmp.tv_sec - then->tv_sec;
00944     diff.tv_usec = tmp.tv_usec - then->tv_usec;
00945     if (diff.tv_usec > 1000000L) {
00946         diff.tv_usec -= 1000000L;
00947         diff.tv_sec++;
00948     }
00949     if (diff.tv_usec >= 500000L)
00950         return diff.tv_sec + 1;
00951     return  diff.tv_sec;
00952 }
00953 
00954 #ifndef HAVE_STRCASESTR
00955 /*
00956  * only glibc2 has this.
00957  */
00958 char           *
00959 strcasestr(const char *haystack, const char *needle)
00960 {
00961     const char     *cp1 = haystack, *cp2 = needle;
00962     const char     *cx;
00963     int             tstch1, tstch2;
00964 
00965     /*
00966      * printf("looking for '%s' in '%s'\n", needle, haystack); 
00967      */
00968     if (cp1 && cp2 && *cp1 && *cp2)
00969         for (cp1 = haystack, cp2 = needle; *cp1;) {
00970             cx = cp1;
00971             cp2 = needle;
00972             do {
00973                 /*
00974                  * printf("T'%c' ", *cp1); 
00975                  */
00976                 if (!*cp2) {    /* found the needle */
00977                     /*
00978                      * printf("\nfound '%s' in '%s'\n", needle, cx); 
00979                      */
00980                     return (char *) cx;
00981                 }
00982                 if (!*cp1)
00983                     break;
00984 
00985                 tstch1 = toupper(*cp1);
00986                 tstch2 = toupper(*cp2);
00987                 if (tstch1 != tstch2)
00988                     break;
00989                 /*
00990                  * printf("M'%c' ", *cp1); 
00991                  */
00992                 cp1++;
00993                 cp2++;
00994             }
00995             while (1);
00996             if (*cp1)
00997                 cp1++;
00998         }
00999     /*
01000      * printf("\n"); 
01001      */
01002     if (cp1 && *cp1)
01003         return (char *) cp1;
01004 
01005     return NULL;
01006 }
01007 #endif
01008 
01009 int
01010 mkdirhier(const char *pathname, mode_t mode, int skiplast)
01011 {
01012     struct stat     sbuf;
01013     char           *ourcopy = strdup(pathname);
01014     char           *entry;
01015     char            buf[SNMP_MAXPATH];
01016     char           *st = NULL;
01017 
01018 #if defined (WIN32) || defined (cygwin)
01019     /* convert backslash to forward slash */
01020     for (entry = ourcopy; *entry; entry++)
01021         if (*entry == '\\')
01022             *entry = '/';
01023 #endif
01024 
01025     entry = strtok_r(ourcopy, "/", &st);
01026 
01027     buf[0] = '\0';
01028 
01029 #if defined (WIN32) || defined (cygwin)
01030     /*
01031      * Check if first entry contains a drive-letter
01032      *   e.g  "c:/path"
01033      */
01034     if ((entry) && (':' == entry[1]) &&
01035         (('\0' == entry[2]) || ('/' == entry[2]))) {
01036         strcat(buf, entry);
01037         entry = strtok_r(NULL, "/", &st);
01038     }
01039 #endif
01040 
01041     /*
01042      * check to see if filename is a directory 
01043      */
01044     while (entry) {
01045         strcat(buf, "/");
01046         strcat(buf, entry);
01047         entry = strtok_r(NULL, "/", &st);
01048         if (entry == NULL && skiplast)
01049             break;
01050         if (stat(buf, &sbuf) < 0) {
01051             /*
01052              * DNE, make it 
01053              */
01054             snmp_log(LOG_INFO, "Creating directory: %s\n", buf);
01055 #ifdef WIN32
01056             if (CreateDirectory(buf, NULL) == 0)
01057 #else
01058             if (mkdir(buf, mode) == -1)
01059 #endif
01060             {
01061                 free(ourcopy);
01062                 return SNMPERR_GENERR;
01063             }
01064         } else {
01065             /*
01066              * exists, is it a file? 
01067              */
01068             if ((sbuf.st_mode & S_IFDIR) == 0) {
01069                 /*
01070                  * ack! can't make a directory on top of a file 
01071                  */
01072                 free(ourcopy);
01073                 return SNMPERR_GENERR;
01074             }
01075         }
01076     }
01077     free(ourcopy);
01078     return SNMPERR_SUCCESS;
01079 }
01080 
01087 const char     *
01088 netsnmp_mktemp(void)
01089 {
01090     static char     name[32];
01091     int             fd = -1;
01092 
01093     strcpy(name, get_temp_file_pattern());
01094 #ifdef HAVE_MKSTEMP
01095     fd = mkstemp(name);
01096 #else
01097     if (mktemp(name)) {
01098 # ifndef WIN32
01099         fd = open(name, O_CREAT | O_EXCL | O_WRONLY);
01100 # else
01101         /*
01102          * Win32 needs _S_IREAD | _S_IWRITE to set permissions on file
01103          * after closing
01104          */
01105         fd = _open(name, _O_CREAT,
01106                    _S_IREAD | _S_IWRITE | _O_EXCL | _O_WRONLY);
01107 # endif
01108     }
01109 #endif
01110     if (fd >= 0) {
01111         close(fd);
01112         DEBUGMSGTL(("netsnmp_mktemp", "temp file created: %s\n",
01113                     name));
01114         return name;
01115     }
01116     snmp_log(LOG_ERR, "netsnmp_mktemp: error creating file %s\n",
01117              name);
01118     return NULL;
01119 }
01120 
01121 /*
01122  * This function was created to differentiate actions
01123  * that are appropriate for Linux 2.4 kernels, but not later kernels.
01124  *
01125  * This function can be used to test kernels on any platform that supports uname().
01126  *
01127  * If not running a platform that supports uname(), return -1.
01128  *
01129  * If ospname matches, and the release matches up through the prefix,
01130  *  return 0.
01131  * If the release is ordered higher, return 1.
01132  * Be aware that "ordered higher" is not a guarantee of correctness.
01133  */
01134 int
01135 netsnmp_os_prematch(const char *ospmname,
01136                     const char *ospmrelprefix)
01137 {
01138 #if HAVE_SYS_UTSNAME_H
01139 static int printOSonce = 1;
01140   struct utsname utsbuf;
01141   if ( 0 != uname(&utsbuf))
01142     return -1;
01143 
01144   if (printOSonce) {
01145     printOSonce = 0;
01146     /* show the four elements that the kernel can be sure of */
01147   DEBUGMSGT(("daemonize","sysname '%s',\nrelease '%s',\nversion '%s',\nmachine '%s'\n",
01148       utsbuf.sysname, utsbuf.release, utsbuf.version, utsbuf.machine));
01149   }
01150   if (0 != strcasecmp(utsbuf.sysname, ospmname)) return -1;
01151 
01152   /* Required to match only the leading characters */
01153   return strncasecmp(utsbuf.release, ospmrelprefix, strlen(ospmrelprefix));
01154 
01155 #else
01156 
01157   return -1;
01158 
01159 #endif /* HAVE_SYS_UTSNAME_H */
01160 }
01161 
01168 int
01169 netsnmp_os_kernel_width(void)
01170 {
01171 #ifdef irix6
01172   char buf[8];
01173   sysinfo(_MIPS_SI_OS_NAME, buf, 7);
01174   if (strncmp("IRIX64", buf, 6) == 0) {
01175     return 64;
01176   } else if (strncmp("IRIX", buf, 4) == 0) {
01177     return 32;
01178   } else {
01179     return -1;
01180   }
01181 #elif defined(aix4) || defined(aix5)
01182   return (__KERNEL_32() ? 32 : (__KERNEL_64() ? 64 : -1));
01183 #elif defined(osf4) || defined(osf5) || defined(__alpha)
01184   return 64; /* Alpha is always 64bit */
01185 #else
01186   /* kernel width detection not implemented */
01187   return -1;
01188 #endif
01189 }
01190