/* Portions of this file are subject to the following copyright(s). See * the Net-SNMP's COPYING file for more details and other copyrights * that may apply: */ /* * Portions of this file are copyrighted by: * Copyright © 2003 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms specified in the COPYING file * distributed with the Net-SNMP package. */ /* * Host Resources MIB - system group implementation - hr_system.c * */ #include #include #if HAVE_STRING_H #include #else #include #endif #include #include #include #include "host.h" #include "host_res.h" #include "hr_system.h" #include #ifdef HAVE_SYS_PROC_H #include #include "sys/proc.h" #endif #ifndef mingw32 #if HAVE_UTMPX_H #include #else #include #endif #endif /* mingw32 */ #include #include #if HAVE_LM_H #include #endif #ifdef linux #ifdef HAVE_LINUX_TASKS_H #include #else /* * If this file doesn't exist, then there is no hard limit on the number * of processes, so return 0 for hrSystemMaxProcesses. */ #define NR_TASKS 0 #endif #endif #if defined(hpux10) || defined(hpux11) #include #endif #if defined(solaris2) #include #include #include #include #include #include #include #endif #ifdef HAVE_SYS_SYSCTL_H #include #endif netsnmp_feature_require(date_n_time); #if !defined(UTMP_FILE) && defined(_PATH_UTMP) #define UTMP_FILE _PATH_UTMP #endif #if defined(UTMP_FILE) && !HAVE_UTMPX_H void setutent(void); void endutent(void); struct utmp *getutent(void); #endif /* UTMP_FILE */ /********************* * * Kernel & interface information, * and internal forward declarations * *********************/ #if defined(solaris2) static struct openpromio * op_malloc(size_t size); static void op_free(struct openpromio *op); #ifndef NETSNMP_NO_WRITE_SUPPORT static int set_solaris_bootcommand_parameter(int action, u_char * var_val, u_char var_val_type, size_t var_val_len, u_char * statP, oid * name, size_t name_len); #endif /* !NETSNMP_NO_WRITE_SUPPORT */ static int set_solaris_eeprom_parameter(const char *key, const char *value, size_t value_len); static int get_solaris_eeprom_parameter(const char *parameter, char *output); static long get_max_solaris_processes(void); #endif static int get_load_dev(void); static int count_users(void); extern int count_processes(void); #if USING_HOST_DATA_ACCESS_SWRUN_MODULE static int count_kthreads = 1; static void parse_count_kthreads(const char *token, const char *line) { count_kthreads = atoi(line); } #endif /********************* * * Initialisation & common implementation functions * *********************/ #define HRSYS_UPTIME 1 #define HRSYS_DATE 2 #define HRSYS_LOAD_DEV 3 #define HRSYS_LOAD_PARAM 4 #define HRSYS_USERS 5 #define HRSYS_PROCS 6 #define HRSYS_MAXPROCS 7 #if defined(solaris2) #ifndef NETSNMP_NO_WRITE_SUPPORT struct variable2 hrsystem_variables[] = { {HRSYS_UPTIME, ASN_TIMETICKS, NETSNMP_OLDAPI_RONLY, var_hrsys, 1, {1}}, {HRSYS_DATE, ASN_OCTET_STR, NETSNMP_OLDAPI_RWRITE, var_hrsys, 1, {2}}, {HRSYS_LOAD_DEV, ASN_INTEGER, NETSNMP_OLDAPI_RONLY, var_hrsys, 1, {3}}, {HRSYS_LOAD_PARAM, ASN_OCTET_STR, NETSNMP_OLDAPI_RWRITE, var_hrsys, 1, {4}}, {HRSYS_USERS, ASN_GAUGE, NETSNMP_OLDAPI_RONLY, var_hrsys, 1, {5}}, {HRSYS_PROCS, ASN_GAUGE, NETSNMP_OLDAPI_RONLY, var_hrsys, 1, {6}}, {HRSYS_MAXPROCS, ASN_INTEGER, NETSNMP_OLDAPI_RONLY, var_hrsys, 1, {7}} }; #else /* !NETSNMP_NO_WRITE_SUPPORT */ struct variable2 hrsystem_variables[] = { {HRSYS_UPTIME, ASN_TIMETICKS, NETSNMP_OLDAPI_RONLY, var_hrsys, 1, {1}}, {HRSYS_DATE, ASN_OCTET_STR, NETSNMP_OLDAPI_RONLY, var_hrsys, 1, {2}}, {HRSYS_LOAD_DEV, ASN_INTEGER, NETSNMP_OLDAPI_RONLY, var_hrsys, 1, {3}}, {HRSYS_LOAD_PARAM, ASN_OCTET_STR, NETSNMP_OLDAPI_RONLY, var_hrsys, 1, {4}}, {HRSYS_USERS, ASN_GAUGE, NETSNMP_OLDAPI_RONLY, var_hrsys, 1, {5}}, {HRSYS_PROCS, ASN_GAUGE, NETSNMP_OLDAPI_RONLY, var_hrsys, 1, {6}}, {HRSYS_MAXPROCS, ASN_INTEGER, NETSNMP_OLDAPI_RONLY, var_hrsys, 1, {7}} }; #endif /* !NETSNMP_NO_WRITE_SUPPORT */ #else struct variable2 hrsystem_variables[] = { {HRSYS_UPTIME, ASN_TIMETICKS, NETSNMP_OLDAPI_RONLY, var_hrsys, 1, {1}}, {HRSYS_DATE, ASN_OCTET_STR, NETSNMP_OLDAPI_RONLY, var_hrsys, 1, {2}}, {HRSYS_LOAD_DEV, ASN_INTEGER, NETSNMP_OLDAPI_RONLY, var_hrsys, 1, {3}}, {HRSYS_LOAD_PARAM, ASN_OCTET_STR, NETSNMP_OLDAPI_RONLY, var_hrsys, 1, {4}}, {HRSYS_USERS, ASN_GAUGE, NETSNMP_OLDAPI_RONLY, var_hrsys, 1, {5}}, {HRSYS_PROCS, ASN_GAUGE, NETSNMP_OLDAPI_RONLY, var_hrsys, 1, {6}}, {HRSYS_MAXPROCS, ASN_INTEGER, NETSNMP_OLDAPI_RONLY, var_hrsys, 1, {7}} }; #endif oid hrsystem_variables_oid[] = { 1, 3, 6, 1, 2, 1, 25, 1 }; void init_hr_system(void) { #ifdef NPROC_SYMBOL auto_nlist(NPROC_SYMBOL, 0, 0); #endif #if USING_HOST_DATA_ACCESS_SWRUN_MODULE snmpd_register_const_config_handler("count_kthreads", parse_count_kthreads, NULL, "0|1 0 to exclude kernel threads from hrSystemProcesses.0"); #endif REGISTER_MIB("host/hr_system", hrsystem_variables, variable2, hrsystem_variables_oid); } /* end init_hr_system */ /* * header_hrsys(... * Arguments: * vp IN - pointer to variable entry that points here * name IN/OUT - IN/name requested, OUT/name found * length IN/OUT - length of IN/OUT oid's * exact IN - TRUE if an exact match was requested * var_len OUT - length of variable or 0 if function returned * write_method */ int header_hrsys(struct variable *vp, oid * name, size_t * length, int exact, size_t * var_len, WriteMethod ** write_method) { #define HRSYS_NAME_LENGTH 9 oid newname[MAX_OID_LEN]; int result; DEBUGMSGTL(("host/hr_system", "var_hrsys: ")); DEBUGMSGOID(("host/hr_system", name, *length)); DEBUGMSG(("host/hr_system", " %d\n", exact)); memcpy((char *) newname, (char *) vp->name, vp->namelen * sizeof(oid)); newname[HRSYS_NAME_LENGTH] = 0; result = snmp_oid_compare(name, *length, newname, vp->namelen + 1); if ((exact && (result != 0)) || (!exact && (result >= 0))) return (MATCH_FAILED); memcpy((char *) name, (char *) newname, (vp->namelen + 1) * sizeof(oid)); *length = vp->namelen + 1; *write_method = (WriteMethod*)0; *var_len = sizeof(long); /* default to 'long' results */ return (MATCH_SUCCEEDED); } /* end header_hrsys */ /********************* * * System specific implementation functions * *********************/ u_char * var_hrsys(struct variable * vp, oid * name, size_t * length, int exact, size_t * var_len, WriteMethod ** write_method) { static char string[129]; /* per MIB, max size is 128 */ #if defined(solaris2) /* max size of nvram property */ char bootparam[8192]; #endif time_t now; #ifdef linux FILE *fp; #endif #if NETSNMP_CAN_USE_SYSCTL && defined(CTL_KERN) && defined(KERN_MAXPROC) static int maxproc_mib[] = { CTL_KERN, KERN_MAXPROC }; size_t buf_size; #endif #if defined(hpux10) || defined(hpux11) struct pst_static pst_buf; #endif if (header_hrsys(vp, name, length, exact, var_len, write_method) == MATCH_FAILED) return NULL; switch (vp->magic) { case HRSYS_UPTIME: long_return = get_uptime(); return (u_char *) & long_return; case HRSYS_DATE: #if defined(HAVE_MKTIME) && defined(HAVE_STIME) #ifndef NETSNMP_NO_WRITE_SUPPORT *write_method=ns_set_time; #endif /* !NETSNMP_NO_WRITE_SUPPORT */ #endif time(&now); return (u_char *) date_n_time(&now, var_len); case HRSYS_LOAD_DEV: long_return = get_load_dev(); return (u_char *) & long_return; case HRSYS_LOAD_PARAM: #ifdef linux if((fp = fopen("/proc/cmdline", "r")) != NULL) { NETSNMP_IGNORE_RESULT(fgets(string, sizeof(string), fp)); fclose(fp); } else { return NULL; } #elif defined(solaris2) #ifndef NETSNMP_NO_WRITE_SUPPORT *write_method=set_solaris_bootcommand_parameter; #endif /* !NETSNMP_NO_WRITE_SUPPORT */ if ( get_solaris_eeprom_parameter("boot-command",bootparam) ) { snmp_log(LOG_ERR,"unable to lookup boot-command from eeprom\n"); return NULL; } strlcpy(string,bootparam,sizeof(string)); #else #if NETSNMP_NO_DUMMY_VALUES return NULL; #endif sprintf(string, "ask Dave"); /* XXX */ #endif *var_len = strlen(string); return (u_char *) string; case HRSYS_USERS: long_return = count_users(); return (u_char *) & long_return; case HRSYS_PROCS: #if USING_HOST_DATA_ACCESS_SWRUN_MODULE long_return = swrun_count_processes(count_kthreads); #elif USING_HOST_HR_SWRUN_MODULE long_return = count_processes(); #else #if NETSNMP_NO_DUMMY_VALUES return NULL; #endif long_return = 0; #endif return (u_char *) & long_return; case HRSYS_MAXPROCS: #if defined(NR_TASKS) long_return = NR_TASKS; /* */ #elif NETSNMP_CAN_USE_SYSCTL && defined(CTL_KERN) && defined(KERN_MAXPROC) { int nproc = 0; buf_size = sizeof(nproc); if (sysctl(maxproc_mib, 2, &nproc, &buf_size, NULL, 0) < 0) return NULL; long_return = nproc; } #elif defined(hpux10) || defined(hpux11) pstat_getstatic(&pst_buf, sizeof(struct pst_static), 1, 0); long_return = pst_buf.max_proc; #elif defined(solaris2) long_return = get_max_solaris_processes(); if (long_return == -1) return NULL; #elif defined(NPROC_SYMBOL) { int nproc = 0; auto_nlist(NPROC_SYMBOL, (char *) &nproc, sizeof(nproc)); long_return = nproc; } #else #if NETSNMP_NO_DUMMY_VALUES return NULL; #endif long_return = 0; #endif return (u_char *) & long_return; default: DEBUGMSGTL(("snmpd", "unknown sub-id %d in var_hrsys\n", vp->magic)); } return NULL; } /* end var_hrsys */ /********************* * * Internal implementation functions * *********************/ #if defined(solaris2) /* functions for malloc and freeing openpromio structure */ static struct openpromio * op_malloc(size_t size) { struct openpromio *op; op=malloc(sizeof(struct openpromio) + size); if(op == NULL) { snmp_log(LOG_ERR,"unable to malloc memory\n"); return NULL; } memset(op, 0, sizeof(struct openpromio)+size); op->oprom_size=size; return op; } static void op_free(struct openpromio *op) { free(op); } #ifndef NETSNMP_NO_WRITE_SUPPORT static int set_solaris_bootcommand_parameter(int action, u_char * var_val, u_char var_val_type, size_t var_val_len, u_char * statP, oid * name, size_t name_len) { static char old_value[1024],*p_old_value=old_value; int status=0; switch (action) { case RESERVE1: /* check type */ if (var_val_type != ASN_OCTET_STR) { snmp_log(LOG_ERR,"write to set_solaris_bootcommand_parameter not ASN_OCTET_STR\n"); return SNMP_ERR_WRONGTYPE; } break; case RESERVE2: { /* create copy of old value */ if(statP) { int old_val_len = strlen((const char *)statP); if(old_val_len >= sizeof(old_value)) { p_old_value=(char *)malloc(old_val_len+1); if(p_old_value==NULL) { snmp_log(LOG_ERR,"unable to malloc memory\n"); return SNMP_ERR_GENERR; } } strlcpy(p_old_value, (const char *)statP, old_val_len+1); } else { p_old_value=NULL; } break; } case ACTION: { status=set_solaris_eeprom_parameter("boot-command",(char *)var_val,var_val_len); if(status!=0) return SNMP_ERR_GENERR; break; } case UNDO: { /* revert to old value */ if(p_old_value) { status=set_solaris_eeprom_parameter("boot-command",(char *)p_old_value,strlen(p_old_value)); p_old_value=old_value; if(status!=0) return SNMP_ERR_GENERR; } break; } case FREE: case COMMIT: /* free memory if necessary */ if(p_old_value != old_value) { free(p_old_value); p_old_value=old_value; } break; } return SNMP_ERR_NOERROR; } #endif /* !NETSNMP_NO_WRITE_SUPPORT */ static int set_solaris_eeprom_parameter(const char *key, const char *value, size_t var_val_len) { int status=0; char buffer[1024],*pbuffer=buffer; if( strlen(key)+strlen(value)+16 > sizeof(buffer) ) { pbuffer=(char *)malloc(strlen(key)+strlen(value)+16); } sprintf(pbuffer, "eeprom %s=\"%.*s\"\n", key, var_val_len, value); status=system(pbuffer); if(pbuffer!=buffer) free(pbuffer); return status; } static int get_solaris_eeprom_parameter(const char *parameter, char *outbuffer) { int fd=0,status=0; struct openpromio *openprominfo=NULL; fd=open("/dev/openprom",O_RDONLY); if ( fd == -1 ) { snmp_log_perror("/dev/openprom"); return 1; } openprominfo = op_malloc(8192); if(!openprominfo) return 1; strcpy(openprominfo->oprom_array,parameter); status=ioctl(fd,OPROMGETOPT,openprominfo); if ( status == -1 ) { snmp_log_perror("/dev/openprom"); close(fd); op_free(openprominfo); return 1; } strcpy(outbuffer,openprominfo->oprom_array); op_free(openprominfo); /* close file */ close(fd); return(0); } static long get_max_solaris_processes(void) { kstat_ctl_t *ksc=NULL; kstat_t *ks=NULL; struct var v; static long maxprocs=-1; /* assume only necessary to compute once, since /etc/system must be modified */ if (maxprocs >= 0) return maxprocs; ksc = kstat_open(); if (ksc) { ks = kstat_lookup(ksc, NETSNMP_REMOVE_CONST(char *, "unix"), 0, NETSNMP_REMOVE_CONST(char *, "var")); if (ks && kstat_read(ksc, ks, &v) != -1) maxprocs = v.v_proc; kstat_close(ksc); } return maxprocs; } #endif #if defined(HAVE_MKTIME) && defined(HAVE_STIME) #ifndef NETSNMP_NO_WRITE_SUPPORT int ns_set_time(int action, u_char * var_val, u_char var_val_type, size_t var_val_len, u_char * statP, oid * name, size_t name_len) { static time_t oldtime=0; switch (action) { case RESERVE1: /* check type */ if (var_val_type != ASN_OCTET_STR) { snmp_log(LOG_ERR,"write to ns_set_time not ASN_OCTET_STR\n"); return SNMP_ERR_WRONGTYPE; } if (var_val_len != 8 && var_val_len!=11) { snmp_log(LOG_ERR,"write to ns_set_time not a proper length\n"); return SNMP_ERR_WRONGVALUE; } break; case RESERVE2: break; case FREE: break; case ACTION: { long status=0; time_t seconds=0; struct tm newtimetm; int hours_from_utc= 0; int minutes_from_utc= 0; if (var_val_len == 11) { /* timezone inforamation was present */ hours_from_utc=(int)var_val[9]; minutes_from_utc=(int)var_val[10]; } newtimetm.tm_sec=(int)var_val[6]; newtimetm.tm_min=(int)var_val[5]; newtimetm.tm_hour=(int)var_val[4]; newtimetm.tm_mon=(int)var_val[2]-1; newtimetm.tm_year=256*(int)var_val[0]+(int)var_val[1]-1900; newtimetm.tm_mday=(int)var_val[3]; /* determine if day light savings time in effect DST */ if (hours_from_utc*60*60+minutes_from_utc*60 == (timezone >= 0 ? timezone : -timezone)) { newtimetm.tm_isdst=0; } else { newtimetm.tm_isdst=1; } /* create copy of old value */ oldtime=time(NULL); seconds=mktime(&newtimetm); if(seconds == (time_t)-1) { snmp_log(LOG_ERR, "Unable to convert time value\n"); return SNMP_ERR_GENERR; } #ifdef HAVE_STIME status=stime(&seconds); #else status=-1; #endif if(status!=0) { snmp_log(LOG_ERR, "Unable to set time\n"); return SNMP_ERR_GENERR; } break; } case UNDO: { /* revert to old value */ int status=0; if(oldtime != 0) { #ifdef HAVE_STIME status=stime(&oldtime); #else status=-1; #endif oldtime=0; if(status!=0) { snmp_log(LOG_ERR, "Unable to set time\n"); return SNMP_ERR_GENERR; } } break; } case COMMIT: { oldtime=0; break; } } return SNMP_ERR_NOERROR; } #endif /* !NETSNMP_NO_WRITE_SUPPORT */ #endif /* * Return the DeviceIndex corresponding * to the boot device */ static int get_load_dev(void) { return (HRDEV_DISK << HRDEV_TYPE_SHIFT); /* XXX */ } /* end get_load_dev */ static int count_users(void) { int total = 0; #ifndef WIN32 #if HAVE_UTMPX_H #define setutent setutxent #define pututline pututxline #define getutent getutxent #define endutent endutxent struct utmpx *utmp_p; #else struct utmp *utmp_p; #endif setutent(); while ((utmp_p = getutent()) != NULL) { #ifndef UTMP_HAS_NO_TYPE if (utmp_p->ut_type != USER_PROCESS) continue; #endif #ifndef UTMP_HAS_NO_PID /* This block of code skips zombie user PIDs in the utmp/utmpx file that would otherwise be counted as a current user, but leaves updating the actual utmp/utmpx file to the system. */ if (kill(utmp_p->ut_pid, 0) == -1 && errno == ESRCH) { continue; } #endif ++total; } endutent(); #else /* WIN32 */ /* * TODO - Error checking. */ LPWKSTA_INFO_102 wkinfo; NET_API_STATUS nstatus; nstatus = NetWkstaGetInfo(NULL, 102, (LPBYTE*)&wkinfo); if (nstatus != NERR_Success) { return 0; } total = (int)wkinfo->wki102_logged_on_users; NetApiBufferFree(wkinfo); #endif /* WIN32 */ return total; } #if defined(UTMP_FILE) && !HAVE_UTMPX_H static FILE *utmp_file; static struct utmp utmp_rec; void setutent(void) { if (utmp_file) fclose(utmp_file); utmp_file = fopen(UTMP_FILE, "r"); } void endutent(void) { if (utmp_file) { fclose(utmp_file); utmp_file = NULL; } } struct utmp * getutent(void) { if (!utmp_file) return NULL; while (fread(&utmp_rec, sizeof(utmp_rec), 1, utmp_file) == 1) if (*utmp_rec.ut_name && *utmp_rec.ut_line) return &utmp_rec; return NULL; } #endif /* UTMP_FILE */