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 * Portions of this file are copyrighted by: 00037 * Copyright (C) 2007 Apple, Inc. All rights reserved. 00038 * Use is subject to license terms specified in the COPYING file 00039 * distributed with the Net-SNMP package. 00040 */ 00041 /* 00042 * System dependent routines go here 00043 */ 00044 #include <net-snmp/net-snmp-config.h> 00045 #include <stdio.h> 00046 #include <ctype.h> 00047 #include <errno.h> 00048 00049 #if HAVE_IO_H 00050 #include <io.h> 00051 #endif 00052 #if HAVE_DIRECT_H 00053 #include <direct.h> 00054 #endif 00055 #if HAVE_UNISTD_H 00056 #include <unistd.h> 00057 #endif 00058 #if HAVE_STDLIB_H 00059 #include <stdlib.h> 00060 #endif 00061 00062 #if TIME_WITH_SYS_TIME 00063 # ifdef WIN32 00064 # include <sys/timeb.h> 00065 # else 00066 # include <sys/time.h> 00067 # endif 00068 # include <time.h> 00069 #else 00070 # if HAVE_SYS_TIME_H 00071 # include <sys/time.h> 00072 # else 00073 # include <time.h> 00074 # endif 00075 #endif 00076 00077 #include <sys/types.h> 00078 00079 #if HAVE_NETINET_IN_H 00080 #include <netinet/in.h> 00081 #endif 00082 00083 #if HAVE_WINSOCK_H 00084 #include <winsock.h> 00085 #endif 00086 #if HAVE_SYS_SOCKET_H 00087 #include <sys/socket.h> 00088 #endif 00089 #if HAVE_NET_IF_H 00090 #include <net/if.h> 00091 #endif 00092 #if HAVE_NETDB_H 00093 #include <netdb.h> 00094 #endif 00095 00096 00097 #if HAVE_SYS_SOCKIO_H 00098 #include <sys/sockio.h> 00099 #endif 00100 00101 #if HAVE_SYS_IOCTL_H 00102 #include <sys/ioctl.h> 00103 #endif 00104 00105 #ifdef HAVE_NLIST_H 00106 #include <nlist.h> 00107 #endif 00108 00109 #if HAVE_SYS_FILE_H 00110 #include <sys/file.h> 00111 #endif 00112 00113 #if HAVE_KSTAT_H 00114 #include <kstat.h> 00115 #endif 00116 00117 #if HAVE_SYS_PARAM_H 00118 #include <sys/param.h> 00119 #endif 00120 #if HAVE_SYS_SYSCTL_H 00121 #include <sys/sysctl.h> 00122 #endif 00123 00124 #if HAVE_STRING_H 00125 #include <string.h> 00126 #else 00127 #include <strings.h> 00128 #endif 00129 00130 #if HAVE_DMALLOC_H 00131 #include <dmalloc.h> 00132 #endif 00133 00134 #ifdef HAVE_SYS_STAT_H 00135 #include <sys/stat.h> 00136 #endif 00137 #if HAVE_FCNTL_H 00138 #include <fcntl.h> 00139 #endif 00140 00141 #if defined(hpux10) || defined(hpux11) 00142 #include <sys/pstat.h> 00143 #endif 00144 00145 #if HAVE_SYS_UTSNAME_H 00146 #include <sys/utsname.h> 00147 #endif 00148 00149 #if HAVE_SYS_SYSTEMCFG_H 00150 #include <sys/systemcfg.h> 00151 #endif 00152 00153 #if HAVE_SYS_SYSTEMINFO_H 00154 #include <sys/systeminfo.h> 00155 #endif 00156 00157 #if defined(darwin9) 00158 #include <crt_externs.h> /* for _NSGetArgv() */ 00159 #endif 00160 00161 #if HAVE_PWD_H 00162 #include <pwd.h> 00163 #endif 00164 #if HAVE_GRP_H 00165 #include <grp.h> 00166 #endif 00167 00168 #include <net-snmp/types.h> 00169 #include <net-snmp/output_api.h> 00170 #include <net-snmp/utilities.h> 00171 #include <net-snmp/library/system.h> /* for "internal" definitions */ 00172 00173 #include <net-snmp/library/snmp_api.h> 00174 #include <net-snmp/library/read_config.h> /* for get_temp_file_pattern() */ 00175 00176 #ifndef IFF_LOOPBACK 00177 # define IFF_LOOPBACK 0 00178 #endif 00179 00180 #ifdef INADDR_LOOPBACK 00181 # define LOOPBACK INADDR_LOOPBACK 00182 #else 00183 # define LOOPBACK 0x7f000001 00184 #endif 00185 00186 static void 00187 _daemon_prep(int stderr_log) 00188 { 00189 /* Avoid keeping any directory in use. */ 00190 chdir("/"); 00191 00192 if (stderr_log) 00193 return; 00194 00195 /* 00196 * Close inherited file descriptors to avoid 00197 * keeping unnecessary references. 00198 */ 00199 close(0); 00200 close(1); 00201 close(2); 00202 00203 /* 00204 * Redirect std{in,out,err} to /dev/null, just in case. 00205 */ 00206 open("/dev/null", O_RDWR); 00207 dup(0); 00208 dup(0); 00209 } 00210 00233 int 00234 netsnmp_daemonize(int quit_immediately, int stderr_log) 00235 { 00236 int i = 0; 00237 DEBUGMSGT(("daemonize","deamonizing...\n")); 00238 #if HAVE_FORK 00239 #if defined(darwin9) 00240 char path [PATH_MAX] = ""; 00241 uint32_t size = sizeof (path); 00242 00243 /* 00244 * if we are already launched in a "daemonized state", just 00245 * close & redirect the file descriptors 00246 */ 00247 if(getppid() <= 2) { 00248 _daemon_prep(stderr_log); 00249 return 0; 00250 } 00251 00252 if (_NSGetExecutablePath (path, &size)) 00253 return -1; 00254 #endif 00255 /* 00256 * Fork to return control to the invoking process and to 00257 * guarantee that we aren't a process group leader. 00258 */ 00259 i = fork(); 00260 if (i != 0) { 00261 /* Parent. */ 00262 DEBUGMSGT(("daemonize","first fork returned %d.\n", i)); 00263 if(i == -1) { 00264 snmp_log(LOG_ERR,"first fork failed (errno %d) in " 00265 "netsnmp_daemonize()\n", errno); 00266 return -1; 00267 } 00268 if (quit_immediately) { 00269 DEBUGMSGT(("daemonize","parent exiting\n")); 00270 exit(0); 00271 } 00272 } else { 00273 /* Child. */ 00274 #ifdef HAVE_SETSID 00275 /* Become a process/session group leader. */ 00276 setsid(); 00277 #endif 00278 /* 00279 * Fork to let the process/session group leader exit. 00280 */ 00281 if ((i = fork()) != 0) { 00282 DEBUGMSGT(("daemonize","second fork returned %d.\n", i)); 00283 if(i == -1) { 00284 snmp_log(LOG_ERR,"second fork failed (errno %d) in " 00285 "netsnmp_daemonize()\n", errno); 00286 } 00287 /* Parent. */ 00288 exit(0); 00289 } 00290 #ifndef WIN32 00291 else { 00292 /* Child. */ 00293 00294 DEBUGMSGT(("daemonize","child continuing\n")); 00295 00296 #if ! defined(darwin9) 00297 _daemon_prep(stderr_log); 00298 #else 00299 /* 00300 * Some darwin calls (using mach ports) don't work after 00301 * a fork. So, now that we've forked, we re-exec ourself 00302 * to ensure that the child's mach ports are all set up correctly, 00303 * the getppid call above will prevent the exec child from 00304 * forking... 00305 */ 00306 char * const *argv = *_NSGetArgv (); 00307 DEBUGMSGT(("daemonize","re-execing forked child\n")); 00308 execv (path, argv); 00309 snmp_log(LOG_ERR,"Forked child unable to re-exec - %s.\n", strerror (errno)); 00310 exit (0); 00311 #endif 00312 } 00313 #endif /* !WIN32 */ 00314 } 00315 #endif /* HAVE_FORK */ 00316 return i; 00317 } 00318 00319 /* 00320 * ********************************************* 00321 */ 00322 #ifdef WIN32 00323 # define WIN32_LEAN_AND_MEAN 00324 # define WIN32IO_IS_STDIO 00325 # define PATHLEN 1024 00326 00327 # include <tchar.h> 00328 # include <windows.h> 00329 00330 /* 00331 * MinGW defines WIN32, but has working dirent stuff. 00332 */ 00333 #ifndef HAVE_DIRENT_H 00334 00335 /* 00336 * The idea here is to read all the directory names into a string table 00337 * * (separated by nulls) and when one of the other dir functions is called 00338 * * return the pointer to the current file name. 00339 */ 00340 DIR * 00341 opendir(const char *filename) 00342 { 00343 DIR *p; 00344 long len; 00345 long idx; 00346 char scannamespc[PATHLEN]; 00347 char *scanname = scannamespc; 00348 struct stat sbuf; 00349 WIN32_FIND_DATA FindData; 00350 HANDLE fh; 00351 00352 /* 00353 * check to see if filename is a directory 00354 */ 00355 if ((stat(filename, &sbuf) < 0) || ((sbuf.st_mode & S_IFDIR) == 0)) { 00356 return NULL; 00357 } 00358 00359 /* 00360 * get the file system characteristics 00361 */ 00362 /* 00363 * if(GetFullPathName(filename, SNMP_MAXPATH, root, &dummy)) { 00364 * * if(dummy = strchr(root, '\\')) 00365 * * *++dummy = '\0'; 00366 * * if(GetVolumeInformation(root, volname, SNMP_MAXPATH, &serial, 00367 * * &maxname, &flags, 0, 0)) { 00368 * * downcase = !(flags & FS_CASE_IS_PRESERVED); 00369 * * } 00370 * * } 00371 * * else { 00372 * * downcase = TRUE; 00373 * * } 00374 */ 00375 00376 /* 00377 * Create the search pattern 00378 */ 00379 strcpy(scanname, filename); 00380 00381 if (strchr("/\\", *(scanname + strlen(scanname) - 1)) == NULL) 00382 strcat(scanname, "/*"); 00383 else 00384 strcat(scanname, "*"); 00385 00386 /* 00387 * do the FindFirstFile call 00388 */ 00389 fh = FindFirstFile(scanname, &FindData); 00390 if (fh == INVALID_HANDLE_VALUE) { 00391 return NULL; 00392 } 00393 00394 /* 00395 * Get us a DIR structure 00396 */ 00397 p = (DIR *) malloc(sizeof(DIR)); 00398 /* 00399 * Newz(1303, p, 1, DIR); 00400 */ 00401 if (p == NULL) 00402 return NULL; 00403 00404 /* 00405 * now allocate the first part of the string table for 00406 * * the filenames that we find. 00407 */ 00408 idx = strlen(FindData.cFileName) + 1; 00409 p->start = (char *) malloc(idx); 00410 /* 00411 * New(1304, p->start, idx, char); 00412 */ 00413 if (p->start == NULL) { 00414 free(p); 00415 return NULL; 00416 } 00417 strcpy(p->start, FindData.cFileName); 00418 /* 00419 * if(downcase) 00420 * * strlwr(p->start); 00421 */ 00422 p->nfiles = 0; 00423 00424 /* 00425 * loop finding all the files that match the wildcard 00426 * * (which should be all of them in this directory!). 00427 * * the variable idx should point one past the null terminator 00428 * * of the previous string found. 00429 */ 00430 while (FindNextFile(fh, &FindData)) { 00431 len = strlen(FindData.cFileName); 00432 /* 00433 * bump the string table size by enough for the 00434 * * new name and it's null terminator 00435 */ 00436 p->start = (char *) realloc((void *) p->start, idx + len + 1); 00437 /* 00438 * Renew(p->start, idx+len+1, char); 00439 */ 00440 if (p->start == NULL) { 00441 free(p); 00442 return NULL; 00443 } 00444 strcpy(&p->start[idx], FindData.cFileName); 00445 /* 00446 * if (downcase) 00447 * * strlwr(&p->start[idx]); 00448 */ 00449 p->nfiles++; 00450 idx += len + 1; 00451 } 00452 FindClose(fh); 00453 p->size = idx; 00454 p->curr = p->start; 00455 return p; 00456 } 00457 00458 00459 /* 00460 * Readdir just returns the current string pointer and bumps the 00461 * * string pointer to the nDllExport entry. 00462 */ 00463 struct direct * 00464 readdir(DIR * dirp) 00465 { 00466 int len; 00467 static int dummy = 0; 00468 00469 if (dirp->curr) { 00470 /* 00471 * first set up the structure to return 00472 */ 00473 len = strlen(dirp->curr); 00474 strcpy(dirp->dirstr.d_name, dirp->curr); 00475 dirp->dirstr.d_namlen = len; 00476 00477 /* 00478 * Fake an inode 00479 */ 00480 dirp->dirstr.d_ino = dummy++; 00481 00482 /* 00483 * Now set up for the nDllExport call to readdir 00484 */ 00485 dirp->curr += len + 1; 00486 if (dirp->curr >= (dirp->start + dirp->size)) { 00487 dirp->curr = NULL; 00488 } 00489 00490 return &(dirp->dirstr); 00491 } else 00492 return NULL; 00493 } 00494 00495 /* 00496 * free the memory allocated by opendir 00497 */ 00498 int 00499 closedir(DIR * dirp) 00500 { 00501 free(dirp->start); 00502 free(dirp); 00503 return 1; 00504 } 00505 #endif /* HAVE_DIRENT_H */ 00506 00507 #ifndef HAVE_GETTIMEOFDAY 00508 00509 int 00510 gettimeofday(struct timeval *tv, struct timezone *tz) 00511 { 00512 struct _timeb timebuffer; 00513 00514 _ftime(&timebuffer); 00515 tv->tv_usec = timebuffer.millitm * 1000; 00516 tv->tv_sec = timebuffer.time; 00517 return (0); 00518 } 00519 #endif /* !HAVE_GETTIMEOFDAY */ 00520 00521 in_addr_t 00522 get_myaddr(void) 00523 { 00524 char local_host[130]; 00525 int result; 00526 LPHOSTENT lpstHostent; 00527 SOCKADDR_IN in_addr, remote_in_addr; 00528 SOCKET hSock; 00529 int nAddrSize = sizeof(SOCKADDR); 00530 00531 in_addr.sin_addr.s_addr = INADDR_ANY; 00532 00533 result = gethostname(local_host, sizeof(local_host)); 00534 if (result == 0) { 00535 lpstHostent = gethostbyname((LPSTR) local_host); 00536 if (lpstHostent) { 00537 in_addr.sin_addr.s_addr = 00538 *((u_long FAR *) (lpstHostent->h_addr)); 00539 return ((in_addr_t) in_addr.sin_addr.s_addr); 00540 } 00541 } 00542 00543 /* 00544 * if we are here, than we don't have host addr 00545 */ 00546 hSock = socket(AF_INET, SOCK_DGRAM, 0); 00547 if (hSock != INVALID_SOCKET) { 00548 /* 00549 * connect to any port and address 00550 */ 00551 remote_in_addr.sin_family = AF_INET; 00552 remote_in_addr.sin_port = htons(IPPORT_ECHO); 00553 remote_in_addr.sin_addr.s_addr = inet_addr("0.0.0.0"); 00554 result = 00555 connect(hSock, (LPSOCKADDR) & remote_in_addr, 00556 sizeof(SOCKADDR)); 00557 if (result != SOCKET_ERROR) { 00558 /* 00559 * get local ip address 00560 */ 00561 getsockname(hSock, (LPSOCKADDR) & in_addr, 00562 (int FAR *) &nAddrSize); 00563 } 00564 closesocket(hSock); 00565 } 00566 return ((in_addr_t) in_addr.sin_addr.s_addr); 00567 } 00568 00569 long 00570 get_uptime(void) 00571 { 00572 long return_value = 0; 00573 DWORD buffersize = (sizeof(PERF_DATA_BLOCK) + 00574 sizeof(PERF_OBJECT_TYPE)), 00575 type = REG_EXPAND_SZ; 00576 PPERF_DATA_BLOCK perfdata = NULL; 00577 00578 /* 00579 * min requirement is one PERF_DATA_BLOCK plus one PERF_OBJECT_TYPE 00580 */ 00581 perfdata = (PPERF_DATA_BLOCK) malloc(buffersize); 00582 if (!perfdata) 00583 return 0; 00584 00585 memset(perfdata, 0, buffersize); 00586 00587 RegQueryValueEx(HKEY_PERFORMANCE_DATA, 00588 "Global", NULL, &type, (LPBYTE) perfdata, &buffersize); 00589 00590 /* 00591 * we can not rely on the return value since there is always more so 00592 * we check the signature 00593 */ 00594 00595 if (wcsncmp(perfdata->Signature, L"PERF", 4) == 0) { 00596 /* 00597 * signature ok, and all we need is in the in the PERF_DATA_BLOCK 00598 */ 00599 return_value = (long) ((perfdata->PerfTime100nSec.QuadPart / 00600 (LONGLONG) 100000)); 00601 } else 00602 return_value = GetTickCount() / 10; 00603 00604 RegCloseKey(HKEY_PERFORMANCE_DATA); 00605 free(perfdata); 00606 00607 return return_value; 00608 } 00609 00610 char * 00611 winsock_startup(void) 00612 { 00613 WORD VersionRequested; 00614 WSADATA stWSAData; 00615 int i; 00616 static char errmsg[100]; 00617 00618 /* winsock 1: use MAKEWORD(1,1) */ 00619 /* winsock 2: use MAKEWORD(2,2) */ 00620 00621 VersionRequested = MAKEWORD(2,2); 00622 i = WSAStartup(VersionRequested, &stWSAData); 00623 if (i != 0) { 00624 if (i == WSAVERNOTSUPPORTED) 00625 sprintf(errmsg, 00626 "Unable to init. socket lib, does not support 1.1"); 00627 else { 00628 sprintf(errmsg, "Socket Startup error %d", i); 00629 } 00630 return (errmsg); 00631 } 00632 return (NULL); 00633 } 00634 00635 void 00636 winsock_cleanup(void) 00637 { 00638 WSACleanup(); 00639 } 00640 00641 #else /* ! WIN32 */ 00642 /*******************************************************************/ 00643 00644 /* 00645 * XXX What if we have multiple addresses? Or no addresses for that matter? 00646 * XXX Could it be computed once then cached? Probably not worth it (not 00647 * used very often). 00648 */ 00649 in_addr_t 00650 get_myaddr(void) 00651 { 00652 int sd, i, lastlen = 0; 00653 struct ifconf ifc; 00654 struct ifreq *ifrp = NULL; 00655 in_addr_t addr; 00656 char *buf = NULL; 00657 00658 if ((sd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { 00659 return 0; 00660 } 00661 00662 /* 00663 * Cope with lots of interfaces and brokenness of ioctl SIOCGIFCONF on 00664 * some platforms; see W. R. Stevens, ``Unix Network Programming Volume 00665 * I'', p.435. 00666 */ 00667 00668 for (i = 8;; i += 8) { 00669 buf = (char *) calloc(i, sizeof(struct ifreq)); 00670 if (buf == NULL) { 00671 close(sd); 00672 return 0; 00673 } 00674 ifc.ifc_len = i * sizeof(struct ifreq); 00675 ifc.ifc_buf = (caddr_t) buf; 00676 00677 if (ioctl(sd, SIOCGIFCONF, (char *) &ifc) < 0) { 00678 if (errno != EINVAL || lastlen != 0) { 00679 /* 00680 * Something has gone genuinely wrong. 00681 */ 00682 free(buf); 00683 close(sd); 00684 return 0; 00685 } 00686 /* 00687 * Otherwise, it could just be that the buffer is too small. 00688 */ 00689 } else { 00690 if (ifc.ifc_len == lastlen) { 00691 /* 00692 * The length is the same as the last time; we're done. 00693 */ 00694 break; 00695 } 00696 lastlen = ifc.ifc_len; 00697 } 00698 free(buf); 00699 } 00700 00701 for (ifrp = ifc.ifc_req; 00702 (char *)ifrp < (char *)ifc.ifc_req + ifc.ifc_len; 00703 #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN 00704 ifrp = (struct ifreq *)(((char *) ifrp) + 00705 sizeof(ifrp->ifr_name) + 00706 ifrp->ifr_addr.sa_len) 00707 #else 00708 ifrp++ 00709 #endif 00710 ) { 00711 if (ifrp->ifr_addr.sa_family != AF_INET) { 00712 continue; 00713 } 00714 addr = ((struct sockaddr_in *) &(ifrp->ifr_addr))->sin_addr.s_addr; 00715 00716 if (ioctl(sd, SIOCGIFFLAGS, (char *) ifrp) < 0) { 00717 continue; 00718 } 00719 if ((ifrp->ifr_flags & IFF_UP) 00720 #ifdef IFF_RUNNING 00721 && (ifrp->ifr_flags & IFF_RUNNING) 00722 #endif /* IFF_RUNNING */ 00723 && !(ifrp->ifr_flags & IFF_LOOPBACK) 00724 && addr != LOOPBACK) { 00725 /* 00726 * I *really* don't understand why this is necessary. Perhaps for 00727 * some broken platform? Leave it for now. JBPN 00728 */ 00729 #ifdef SYS_IOCTL_H_HAS_SIOCGIFADDR 00730 if (ioctl(sd, SIOCGIFADDR, (char *) ifrp) < 0) { 00731 continue; 00732 } 00733 addr = 00734 ((struct sockaddr_in *) &(ifrp->ifr_addr))->sin_addr. 00735 s_addr; 00736 #endif 00737 free(buf); 00738 close(sd); 00739 return addr; 00740 } 00741 } 00742 free(buf); 00743 close(sd); 00744 return 0; 00745 } 00746 00747 00748 #if !defined(solaris2) && !defined(linux) && !defined(cygwin) 00749 /* 00750 * Returns boottime in centiseconds(!). 00751 * Caches this for future use. 00752 */ 00753 long 00754 get_boottime(void) 00755 { 00756 static long boottime_csecs = 0; 00757 #if defined(hpux10) || defined(hpux11) 00758 struct pst_static pst_buf; 00759 #else 00760 struct timeval boottime; 00761 #ifdef NETSNMP_CAN_USE_SYSCTL 00762 int mib[2]; 00763 size_t len; 00764 #elif defined(NETSNMP_CAN_USE_NLIST) 00765 int kmem; 00766 static struct nlist nl[] = { 00767 #if !defined(hpux) 00768 {(char *) "_boottime"}, 00769 #else 00770 {(char *) "boottime"}, 00771 #endif 00772 {(char *) ""} 00773 }; 00774 #endif /* NETSNMP_CAN_USE_SYSCTL */ 00775 #endif /* hpux10 || hpux 11 */ 00776 00777 00778 if (boottime_csecs != 0) 00779 return (boottime_csecs); 00780 00781 #if defined(hpux10) || defined(hpux11) 00782 pstat_getstatic(&pst_buf, sizeof(struct pst_static), 1, 0); 00783 boottime_csecs = pst_buf.boot_time * 100; 00784 #elif NETSNMP_CAN_USE_SYSCTL 00785 mib[0] = CTL_KERN; 00786 mib[1] = KERN_BOOTTIME; 00787 00788 len = sizeof(boottime); 00789 00790 sysctl(mib, 2, &boottime, &len, NULL, 0); 00791 boottime_csecs = (boottime.tv_sec * 100) + (boottime.tv_usec / 10000); 00792 #elif defined(NETSNMP_CAN_USE_NLIST) 00793 if ((kmem = open("/dev/kmem", 0)) < 0) 00794 return 0; 00795 nlist(KERNEL_LOC, nl); 00796 if (nl[0].n_type == 0) { 00797 close(kmem); 00798 return 0; 00799 } 00800 00801 lseek(kmem, (long) nl[0].n_value, L_SET); 00802 read(kmem, &boottime, sizeof(boottime)); 00803 close(kmem); 00804 boottime_csecs = (boottime.tv_sec * 100) + (boottime.tv_usec / 10000); 00805 #else 00806 return 0; 00807 #endif /* hpux10 || hpux 11 */ 00808 00809 return (boottime_csecs); 00810 } 00811 #endif 00812 00813 /* 00814 * Returns uptime in centiseconds(!). 00815 */ 00816 long 00817 get_uptime(void) 00818 { 00819 #if !defined(solaris2) && !defined(linux) && !defined(cygwin) && !defined(aix4) && !defined(aix5) && !defined(aix6) 00820 struct timeval now; 00821 long boottime_csecs, nowtime_csecs; 00822 00823 boottime_csecs = get_boottime(); 00824 if (boottime_csecs == 0) 00825 return 0; 00826 gettimeofday(&now, (struct timezone *) 0); 00827 nowtime_csecs = (now.tv_sec * 100) + (now.tv_usec / 10000); 00828 00829 return (nowtime_csecs - boottime_csecs); 00830 #endif 00831 00832 #if defined(aix4) || defined(aix5) || defined(aix6) 00833 struct nlist nl; 00834 int kmem; 00835 time_t lbolt; 00836 nl.n_name = "lbolt"; 00837 if(knlist(&nl, 1, sizeof(struct nlist)) != 0) return(0); 00838 if(nl.n_type == 0 || nl.n_value == 0) return(0); 00839 if((kmem = open("/dev/mem", 0)) < 0) return 0; 00840 lseek(kmem, (long) nl.n_value, L_SET); 00841 read(kmem, &lbolt, sizeof(lbolt)); 00842 close(kmem); 00843 return(lbolt); 00844 #endif 00845 00846 #ifdef solaris2 00847 kstat_ctl_t *ksc = kstat_open(); 00848 kstat_t *ks; 00849 kid_t kid; 00850 kstat_named_t *named; 00851 u_long lbolt = 0; 00852 00853 if (ksc) { 00854 ks = kstat_lookup(ksc, "unix", -1, "system_misc"); 00855 if (ks) { 00856 kid = kstat_read(ksc, ks, NULL); 00857 if (kid != -1) { 00858 named = kstat_data_lookup(ks, "lbolt"); 00859 if (named) { 00860 #ifdef KSTAT_DATA_UINT32 00861 lbolt = named->value.ui32; 00862 #else 00863 lbolt = named->value.ul; 00864 #endif 00865 } 00866 } 00867 } 00868 kstat_close(ksc); 00869 } 00870 return lbolt; 00871 #endif /* solaris2 */ 00872 00873 #ifdef linux 00874 FILE *in = fopen("/proc/uptime", "r"); 00875 long uptim = 0, a, b; 00876 if (in) { 00877 if (2 == fscanf(in, "%ld.%ld", &a, &b)) 00878 uptim = a * 100 + b; 00879 fclose(in); 00880 } 00881 return uptim; 00882 #endif /* linux */ 00883 00884 #ifdef cygwin 00885 return (0); /* not implemented */ 00886 #endif 00887 } 00888 00889 #endif /* ! WIN32 */ 00890 /*******************************************************************/ 00891 00892 int 00893 netsnmp_gethostbyname_v4(const char* name, in_addr_t *addr_out) 00894 { 00895 00896 #if HAVE_GETADDRINFO 00897 struct addrinfo *addrs = NULL; 00898 struct addrinfo hint; 00899 int err; 00900 00901 memset(&hint, 0, sizeof hint); 00902 hint.ai_flags = 0; 00903 hint.ai_family = PF_INET; 00904 hint.ai_socktype = SOCK_DGRAM; 00905 hint.ai_protocol = 0; 00906 00907 err = getaddrinfo(name, NULL, &hint, &addrs); 00908 if (err != 0) { 00909 #if HAVE_GAI_STRERROR 00910 snmp_log(LOG_ERR, "getaddrinfo: %s %s\n", name, 00911 gai_strerror(err)); 00912 #else 00913 snmp_log(LOG_ERR, "getaddrinfo: %s (error %d)\n", name, 00914 err); 00915 #endif 00916 return -1; 00917 } 00918 if (addrs != NULL) { 00919 memcpy(addr_out, 00920 &((struct sockaddr_in *) addrs->ai_addr)->sin_addr, 00921 sizeof(in_addr_t)); 00922 freeaddrinfo(addrs); 00923 } else { 00924 DEBUGMSGTL(("get_thisaddr", 00925 "Failed to resolve IPv4 hostname\n")); 00926 } 00927 return 0; 00928 00929 #elif HAVE_GETHOSTBYNAME 00930 struct hostent *hp = NULL; 00931 00932 hp = gethostbyname(name); 00933 if (hp == NULL) { 00934 DEBUGMSGTL(("get_thisaddr", 00935 "hostname (couldn't resolve)\n")); 00936 return -1; 00937 } else if (hp->h_addrtype != AF_INET) { 00938 DEBUGMSGTL(("get_thisaddr", 00939 "hostname (not AF_INET!)\n")); 00940 return -1; 00941 } else { 00942 DEBUGMSGTL(("get_thisaddr", 00943 "hostname (resolved okay)\n")); 00944 memcpy(addr_out, hp->h_addr, sizeof(in_addr_t)); 00945 } 00946 return 0; 00947 00948 #elif HAVE_GETIPNODEBYNAME 00949 struct hostent *hp = NULL; 00950 int err; 00951 00952 hp = getipnodebyname(peername, AF_INET, 0, &err); 00953 if (hp == NULL) { 00954 DEBUGMSGTL(("get_thisaddr", 00955 "hostname (couldn't resolve = %d)\n", err)); 00956 return -1; 00957 } 00958 DEBUGMSGTL(("get_thisaddr", 00959 "hostname (resolved okay)\n")); 00960 memcpy(addr_out, hp->h_addr, sizeof(in_addr_t)); 00961 return 0; 00962 00963 #else /* HAVE_GETIPNODEBYNAME */ 00964 return -1; 00965 #endif 00966 } 00967 00968 /*******************************************************************/ 00969 00970 #ifndef HAVE_STRNCASECMP 00971 00972 /* 00973 * test for NULL pointers before and NULL characters after 00974 * * comparing possibly non-NULL strings. 00975 * * WARNING: This function does NOT check for array overflow. 00976 */ 00977 int 00978 strncasecmp(const char *s1, const char *s2, size_t nch) 00979 { 00980 size_t ii; 00981 int res = -1; 00982 00983 if (!s1) { 00984 if (!s2) 00985 return 0; 00986 return (-1); 00987 } 00988 if (!s2) 00989 return (1); 00990 00991 for (ii = 0; (ii < nch) && *s1 && *s2; ii++, s1++, s2++) { 00992 res = (int) (tolower(*s1) - tolower(*s2)); 00993 if (res != 0) 00994 break; 00995 } 00996 00997 if (ii == nch) { 00998 s1--; 00999 s2--; 01000 } 01001 01002 if (!*s1) { 01003 if (!*s2) 01004 return 0; 01005 return (-1); 01006 } 01007 if (!*s2) 01008 return (1); 01009 01010 return (res); 01011 } 01012 01013 int 01014 strcasecmp(const char *s1, const char *s2) 01015 { 01016 return strncasecmp(s1, s2, 1000000); 01017 } 01018 01019 #endif /* HAVE_STRNCASECMP */ 01020 01021 01022 #ifndef HAVE_STRDUP 01023 char * 01024 strdup(const char *src) 01025 { 01026 int len; 01027 char *dst; 01028 01029 len = strlen(src) + 1; 01030 if ((dst = (char *) malloc(len)) == NULL) 01031 return (NULL); 01032 strcpy(dst, src); 01033 return (dst); 01034 } 01035 #endif /* HAVE_STRDUP */ 01036 01037 #ifndef HAVE_SETENV 01038 int 01039 setenv(const char *name, const char *value, int overwrite) 01040 { 01041 char *cp; 01042 int ret; 01043 01044 if (overwrite == 0) { 01045 if (getenv(name)) 01046 return 0; 01047 } 01048 cp = (char *) malloc(strlen(name) + strlen(value) + 2); 01049 if (cp == NULL) 01050 return -1; 01051 sprintf(cp, "%s=%s", name, value); 01052 ret = putenv(cp); 01053 #ifdef WIN32 01054 free(cp); 01055 #endif 01056 return ret; 01057 } 01058 #endif /* HAVE_SETENV */ 01059 01060 /* returns centiseconds */ 01061 int 01062 calculate_time_diff(struct timeval *now, struct timeval *then) 01063 { 01064 struct timeval tmp, diff; 01065 memcpy(&tmp, now, sizeof(struct timeval)); 01066 tmp.tv_sec--; 01067 tmp.tv_usec += 1000000L; 01068 diff.tv_sec = tmp.tv_sec - then->tv_sec; 01069 diff.tv_usec = tmp.tv_usec - then->tv_usec; 01070 if (diff.tv_usec > 1000000L) { 01071 diff.tv_usec -= 1000000L; 01072 diff.tv_sec++; 01073 } 01074 return ((diff.tv_sec * 100) + (diff.tv_usec / 10000)); 01075 } 01076 01077 /* returns diff in rounded seconds */ 01078 u_int 01079 calculate_sectime_diff(struct timeval *now, struct timeval *then) 01080 { 01081 struct timeval tmp, diff; 01082 memcpy(&tmp, now, sizeof(struct timeval)); 01083 tmp.tv_sec--; 01084 tmp.tv_usec += 1000000L; 01085 diff.tv_sec = tmp.tv_sec - then->tv_sec; 01086 diff.tv_usec = tmp.tv_usec - then->tv_usec; 01087 if (diff.tv_usec > 1000000L) { 01088 diff.tv_usec -= 1000000L; 01089 diff.tv_sec++; 01090 } 01091 if (diff.tv_usec >= 500000L) 01092 return diff.tv_sec + 1; 01093 return diff.tv_sec; 01094 } 01095 01096 #ifndef HAVE_STRCASESTR 01097 /* 01098 * only glibc2 has this. 01099 */ 01100 char * 01101 strcasestr(const char *haystack, const char *needle) 01102 { 01103 const char *cp1 = haystack, *cp2 = needle; 01104 const char *cx; 01105 int tstch1, tstch2; 01106 01107 /* 01108 * printf("looking for '%s' in '%s'\n", needle, haystack); 01109 */ 01110 if (cp1 && cp2 && *cp1 && *cp2) 01111 for (cp1 = haystack, cp2 = needle; *cp1;) { 01112 cx = cp1; 01113 cp2 = needle; 01114 do { 01115 /* 01116 * printf("T'%c' ", *cp1); 01117 */ 01118 if (!*cp2) { /* found the needle */ 01119 /* 01120 * printf("\nfound '%s' in '%s'\n", needle, cx); 01121 */ 01122 return (char *) cx; 01123 } 01124 if (!*cp1) 01125 break; 01126 01127 tstch1 = toupper(*cp1); 01128 tstch2 = toupper(*cp2); 01129 if (tstch1 != tstch2) 01130 break; 01131 /* 01132 * printf("M'%c' ", *cp1); 01133 */ 01134 cp1++; 01135 cp2++; 01136 } 01137 while (1); 01138 if (*cp1) 01139 cp1++; 01140 } 01141 /* 01142 * printf("\n"); 01143 */ 01144 if (cp1 && *cp1) 01145 return (char *) cp1; 01146 01147 return NULL; 01148 } 01149 #endif 01150 01151 int 01152 mkdirhier(const char *pathname, mode_t mode, int skiplast) 01153 { 01154 struct stat sbuf; 01155 char *ourcopy = strdup(pathname); 01156 char *entry; 01157 char buf[SNMP_MAXPATH]; 01158 char *st = NULL; 01159 01160 #if defined (WIN32) || defined (cygwin) 01161 /* convert backslash to forward slash */ 01162 for (entry = ourcopy; *entry; entry++) 01163 if (*entry == '\\') 01164 *entry = '/'; 01165 #endif 01166 01167 entry = strtok_r(ourcopy, "/", &st); 01168 01169 buf[0] = '\0'; 01170 01171 #if defined (WIN32) || defined (cygwin) 01172 /* 01173 * Check if first entry contains a drive-letter 01174 * e.g "c:/path" 01175 */ 01176 if ((entry) && (':' == entry[1]) && 01177 (('\0' == entry[2]) || ('/' == entry[2]))) { 01178 strcat(buf, entry); 01179 entry = strtok_r(NULL, "/", &st); 01180 } 01181 #endif 01182 01183 /* 01184 * check to see if filename is a directory 01185 */ 01186 while (entry) { 01187 strcat(buf, "/"); 01188 strcat(buf, entry); 01189 entry = strtok_r(NULL, "/", &st); 01190 if (entry == NULL && skiplast) 01191 break; 01192 if (stat(buf, &sbuf) < 0) { 01193 /* 01194 * DNE, make it 01195 */ 01196 #ifdef WIN32 01197 if (CreateDirectory(buf, NULL) == 0) 01198 #else 01199 if (mkdir(buf, mode) == -1) 01200 #endif 01201 { 01202 free(ourcopy); 01203 return SNMPERR_GENERR; 01204 } else { 01205 snmp_log(LOG_INFO, "Created directory: %s\n", buf); 01206 } 01207 } else { 01208 /* 01209 * exists, is it a file? 01210 */ 01211 if ((sbuf.st_mode & S_IFDIR) == 0) { 01212 /* 01213 * ack! can't make a directory on top of a file 01214 */ 01215 free(ourcopy); 01216 return SNMPERR_GENERR; 01217 } 01218 } 01219 } 01220 free(ourcopy); 01221 return SNMPERR_SUCCESS; 01222 } 01223 01230 const char * 01231 netsnmp_mktemp(void) 01232 { 01233 static char name[32]; 01234 int fd = -1; 01235 01236 strcpy(name, get_temp_file_pattern()); 01237 #ifdef HAVE_MKSTEMP 01238 fd = mkstemp(name); 01239 #else 01240 if (mktemp(name)) { 01241 # ifndef WIN32 01242 fd = open(name, O_CREAT | O_EXCL | O_WRONLY); 01243 # else 01244 /* 01245 * Win32 needs _S_IREAD | _S_IWRITE to set permissions on file 01246 * after closing 01247 */ 01248 fd = _open(name, _O_CREAT, 01249 _S_IREAD | _S_IWRITE | _O_EXCL | _O_WRONLY); 01250 # endif 01251 } 01252 #endif 01253 if (fd >= 0) { 01254 close(fd); 01255 DEBUGMSGTL(("netsnmp_mktemp", "temp file created: %s\n", 01256 name)); 01257 return name; 01258 } 01259 snmp_log(LOG_ERR, "netsnmp_mktemp: error creating file %s\n", 01260 name); 01261 return NULL; 01262 } 01263 01264 /* 01265 * This function was created to differentiate actions 01266 * that are appropriate for Linux 2.4 kernels, but not later kernels. 01267 * 01268 * This function can be used to test kernels on any platform that supports uname(). 01269 * 01270 * If not running a platform that supports uname(), return -1. 01271 * 01272 * If ospname matches, and the release matches up through the prefix, 01273 * return 0. 01274 * If the release is ordered higher, return 1. 01275 * Be aware that "ordered higher" is not a guarantee of correctness. 01276 */ 01277 int 01278 netsnmp_os_prematch(const char *ospmname, 01279 const char *ospmrelprefix) 01280 { 01281 #if HAVE_SYS_UTSNAME_H 01282 static int printOSonce = 1; 01283 struct utsname utsbuf; 01284 if ( 0 != uname(&utsbuf)) 01285 return -1; 01286 01287 if (printOSonce) { 01288 printOSonce = 0; 01289 /* show the four elements that the kernel can be sure of */ 01290 DEBUGMSGT(("daemonize","sysname '%s',\nrelease '%s',\nversion '%s',\nmachine '%s'\n", 01291 utsbuf.sysname, utsbuf.release, utsbuf.version, utsbuf.machine)); 01292 } 01293 if (0 != strcasecmp(utsbuf.sysname, ospmname)) return -1; 01294 01295 /* Required to match only the leading characters */ 01296 return strncasecmp(utsbuf.release, ospmrelprefix, strlen(ospmrelprefix)); 01297 01298 #else 01299 01300 return -1; 01301 01302 #endif /* HAVE_SYS_UTSNAME_H */ 01303 } 01304 01311 int 01312 netsnmp_os_kernel_width(void) 01313 { 01314 #ifdef irix6 01315 char buf[8]; 01316 sysinfo(_MIPS_SI_OS_NAME, buf, 7); 01317 if (strncmp("IRIX64", buf, 6) == 0) { 01318 return 64; 01319 } else if (strncmp("IRIX", buf, 4) == 0) { 01320 return 32; 01321 } else { 01322 return -1; 01323 } 01324 #elif defined(aix4) || defined(aix5) || defined(aix6) 01325 return (__KERNEL_32() ? 32 : (__KERNEL_64() ? 64 : -1)); 01326 #elif defined(osf4) || defined(osf5) || defined(__alpha) 01327 return 64; /* Alpha is always 64bit */ 01328 #else 01329 /* kernel width detection not implemented */ 01330 return -1; 01331 #endif 01332 } 01333 01334 int netsnmp_str_to_uid(const char *useroruid) { 01335 int uid; 01336 #if HAVE_GETPWNAM && HAVE_PWD_H 01337 struct passwd *pwd; 01338 #endif 01339 01340 uid = atoi(useroruid); 01341 01342 if ( uid == 0 ) { 01343 #if HAVE_GETPWNAM && HAVE_PWD_H 01344 pwd = getpwnam( useroruid ); 01345 if (pwd) 01346 uid = pwd->pw_uid; 01347 else 01348 #endif 01349 snmp_log(LOG_WARNING, "Can't identify user (%s).\n", useroruid); 01350 } 01351 return uid; 01352 01353 } 01354 01355 int netsnmp_str_to_gid(const char *grouporgid) { 01356 int gid; 01357 #if HAVE_GETGRNAM && HAVE_GRP_H 01358 struct group *grp; 01359 #endif 01360 01361 gid = atoi(grouporgid); 01362 01363 if ( gid == 0 ) { 01364 #if HAVE_GETGRNAM && HAVE_GRP_H 01365 grp = getgrnam( grouporgid ); 01366 if (grp) 01367 gid = grp->gr_gid; 01368 else 01369 #endif 01370 snmp_log(LOG_WARNING, "Can't identify group (%s).\n", 01371 grouporgid); 01372 } 01373 01374 return gid; 01375 }
Last modified: Wednesday, 01-Aug-2018 04:41:28 UTC
For questions regarding web content and site functionality, please write to the net-snmp-users mail list.