Path: blob/main/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_scalars.c
108735 views
/*-1* Copyright (c) 2005-2006 The FreeBSD Project2* All rights reserved.3*4* Author: Victor Cruceru <[email protected]>5*6* Redistribution of this software and documentation and use in source and7* binary forms, with or without modification, are permitted provided that8* the following conditions are met:9*10* 1. Redistributions of source code or documentation must retain the above11* copyright notice, this list of conditions and the following disclaimer.12* 2. Redistributions in binary form must reproduce the above copyright13* notice, this list of conditions and the following disclaimer in the14* documentation and/or other materials provided with the distribution.15*16* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND17* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE18* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE19* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE20* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL21* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS22* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)23* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT24* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY25* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF26* SUCH DAMAGE.27*/2829/*30* Host Resources MIB scalars implementation for SNMPd.31*/3233#include <sys/param.h>34#include <sys/sysctl.h>3536#include <pwd.h>37#include <stdlib.h>38#include <stdint.h>39#include <string.h>40#include <syslog.h>41#include <utmpx.h>4243#include "hostres_snmp.h"44#include "hostres_oid.h"45#include "hostres_tree.h"4647/* physical memory size in Kb */48static uint64_t phys_mem_size;4950/* boot line (malloced) */51static u_char *boot_line;5253/* maximum number of processes */54static uint32_t max_proc;5556/**57* Free all static data58*/59void60fini_scalars(void)61{6263free(boot_line);64}6566/**67* Get system uptime in hundredths of seconds since the epoch68* Returns 0 in case of an error69*/70static int71OS_getSystemUptime(uint32_t *ut)72{73uint64_t uptime;74struct timespec ts;7576if (clock_gettime(CLOCK_UPTIME, &ts)) {77syslog(LOG_ERR, "clock_gettime failed: %m");78return (SNMP_ERR_GENERR);79}8081uptime = ts.tv_sec * 100 + ts.tv_nsec / 1000000;82if (uptime > UINT32_MAX)83*ut = UINT32_MAX;84else85*ut = (uint32_t)uptime;8687return (SNMP_ERR_NOERROR);88}8990/**91* Get system local date and time in a foramt suitable for DateAndTime TC:92* field octets contents range93* ----- ------ -------- -----94* 1 1-2 year* 0..6553695* 2 3 month 1..1296* 3 4 day 1..3197* 4 5 hour 0..2398* 5 6 minutes 0..5999* 6 7 seconds 0..60100* (use 60 for leap-second)101* 7 8 deci-seconds 0..9102* 8 9 direction from UTC '+' / '-'103* 9 10 hours from UTC* 0..13104* 10 11 minutes from UTC 0..59105*106* * Notes:107* - the value of year is in network-byte order108* - daylight saving time in New Zealand is +13109*110* For example, Tuesday May 26, 1992 at 1:30:15 PM EDT would be111* displayed as:112*113* 1992-5-26,13:30:15.0,-4:0114*115* Returns -1 in case of an error or the length of the string (8 or 11)116* Actually returns always 11 on freebsd117*/118static int119OS_getSystemDate(struct snmp_value *value)120{121u_char s_date_time[11];122struct tm tloc_tm;123time_t tloc_time_t;124struct timeval right_now;125int string_len;126127if (gettimeofday(&right_now, NULL) < 0) {128syslog(LOG_ERR, "gettimeofday failed: %m");129return (SNMP_ERR_GENERR);130}131132tloc_time_t = right_now.tv_sec;133134if (localtime_r(&tloc_time_t, &tloc_tm) == NULL) {135syslog(LOG_ERR, "localtime_r() failed: %m ");136return (SNMP_ERR_GENERR);137}138139string_len = make_date_time(s_date_time, &tloc_tm,140right_now.tv_usec / 100000);141142return (string_get(value, s_date_time, string_len));143}144145/**146* Get kernel boot path. For FreeBSD it seems that no arguments are147* present. Returns NULL if an error occurred. The returned data is a148* pointer to a global storage.149*/150int151OS_getSystemInitialLoadParameters(u_char **params)152{153154if (boot_line == NULL) {155int mib[2] = { CTL_KERN, KERN_BOOTFILE };156char *buf;157size_t buf_len = 0;158159/* get the needed buffer len */160if (sysctl(mib, 2, NULL, &buf_len, NULL, 0) != 0) {161syslog(LOG_ERR,162"sysctl({CTL_KERN,KERN_BOOTFILE}) failed: %m");163return (SNMP_ERR_GENERR);164}165166if ((buf = malloc(buf_len)) == NULL) {167syslog(LOG_ERR, "malloc failed");168return (SNMP_ERR_GENERR);169}170if (sysctl(mib, 2, buf, &buf_len, NULL, 0)) {171syslog(LOG_ERR,172"sysctl({CTL_KERN,KERN_BOOTFILE}) failed: %m");173free(buf);174return (SNMP_ERR_GENERR);175}176177boot_line = buf;178HRDBG("kernel boot file: %s", boot_line);179}180181*params = boot_line;182return (SNMP_ERR_NOERROR);183}184185/**186* Get number of current users which are logged in187*/188static int189OS_getSystemNumUsers(uint32_t *nu)190{191struct utmpx *utmp;192193setutxent();194*nu = 0;195while ((utmp = getutxent()) != NULL) {196if (utmp->ut_type == USER_PROCESS)197(*nu)++;198}199endutxent();200201return (SNMP_ERR_NOERROR);202}203204/**205* Get number of current processes existing into the system206*/207static int208OS_getSystemProcesses(uint32_t *proc_count)209{210int pc;211212if (hr_kd == NULL)213return (SNMP_ERR_GENERR);214215if (kvm_getprocs(hr_kd, KERN_PROC_PROC, 0, &pc) == NULL) {216syslog(LOG_ERR, "kvm_getprocs failed: %m");217return (SNMP_ERR_GENERR);218}219220*proc_count = pc;221return (SNMP_ERR_NOERROR);222}223224/**225* Get maximum number of processes allowed on this system226*/227static int228OS_getSystemMaxProcesses(uint32_t *mproc)229{230231if (max_proc == 0) {232int mib[2] = { CTL_KERN, KERN_MAXPROC };233int mp;234size_t len = sizeof(mp);235236if (sysctl(mib, 2, &mp, &len, NULL, 0) == -1) {237syslog(LOG_ERR, "sysctl KERN_MAXPROC failed: %m");238return (SNMP_ERR_GENERR);239}240max_proc = mp;241}242243*mproc = max_proc;244return (SNMP_ERR_NOERROR);245}246247/*248* Get the physical memory size in Kbytes.249* Returns SNMP error code.250*/251static int252OS_getMemorySize(uint32_t *ms)253{254255if (phys_mem_size == 0) {256int mib[2] = { CTL_HW, HW_PHYSMEM };257u_long physmem;258size_t len = sizeof(physmem);259260if (sysctl(mib, 2, &physmem, &len, NULL, 0) == -1) {261syslog(LOG_ERR,262"sysctl({ CTL_HW, HW_PHYSMEM }) failed: %m");263return (SNMP_ERR_GENERR);264}265266phys_mem_size = physmem / 1024;267}268269if (phys_mem_size > UINT32_MAX)270*ms = UINT32_MAX;271else272*ms = phys_mem_size;273return (SNMP_ERR_NOERROR);274}275276/*277* Try to use the s_date_time parameter as a DateAndTime TC to fill in278* the second parameter.279* Returns 0 on succes and -1 for an error.280* Bug: time zone info is not used281*/282static struct timeval *283OS_checkSystemDateInput(const u_char *str, u_int len)284{285struct tm tm_to_set;286time_t t;287struct timeval *tv;288289if (len != 8 && len != 11)290return (NULL);291292if (str[2] == 0 || str[2] > 12 ||293str[3] == 0 || str[3] > 31 ||294str[4] > 23 || str[5] > 59 || str[6] > 60 || str[7] > 9)295return (NULL);296297tm_to_set.tm_year = ((str[0] << 8) + str[1]) - 1900;298tm_to_set.tm_mon = str[2] - 1;299tm_to_set.tm_mday = str[3];300tm_to_set.tm_hour = str[4];301tm_to_set.tm_min = str[5];302tm_to_set.tm_sec = str[6];303tm_to_set.tm_isdst = 0;304305/* now make UTC from it */306if ((t = timegm(&tm_to_set)) == (time_t)-1)307return (NULL);308309/* now apply timezone if specified */310if (len == 11) {311if (str[9] > 13 || str[10] > 59)312return (NULL);313if (str[8] == '+')314t += 3600 * str[9] + 60 * str[10];315else316t -= 3600 * str[9] + 60 * str[10];317}318319if ((tv = malloc(sizeof(*tv))) == NULL)320return (NULL);321322tv->tv_sec = t;323tv->tv_usec = (int32_t)str[7] * 100000;324325return (tv);326}327328/*329* Set system date and time. Timezone is not changed330*/331static int332OS_setSystemDate(const struct timeval *timeval_to_set)333{334if (settimeofday(timeval_to_set, NULL) == -1) {335syslog(LOG_ERR, "settimeofday failed: %m");336return (SNMP_ERR_GENERR);337}338return (SNMP_ERR_NOERROR);339}340341/*342* prototype of this function was generated by gensnmptree tool in header file343* hostres_tree.h344* Returns SNMP_ERR_NOERROR on success345*/346int347op_hrSystem(struct snmp_context *ctx, struct snmp_value *value,348u_int sub, u_int iidx __unused, enum snmp_op curr_op)349{350int err;351u_char *str;352353switch (curr_op) {354355case SNMP_OP_GET:356switch (value->var.subs[sub - 1]) {357358case LEAF_hrSystemUptime:359return (OS_getSystemUptime(&value->v.uint32));360361case LEAF_hrSystemDate:362return (OS_getSystemDate(value));363364case LEAF_hrSystemInitialLoadDevice:365value->v.uint32 = 0; /* FIXME */366return (SNMP_ERR_NOERROR);367368case LEAF_hrSystemInitialLoadParameters:369if ((err = OS_getSystemInitialLoadParameters(&str)) !=370SNMP_ERR_NOERROR)371return (err);372return (string_get(value, str, -1));373374case LEAF_hrSystemNumUsers:375return (OS_getSystemNumUsers(&value->v.uint32));376377case LEAF_hrSystemProcesses:378return (OS_getSystemProcesses(&value->v.uint32));379380case LEAF_hrSystemMaxProcesses:381return (OS_getSystemMaxProcesses(&value->v.uint32));382}383abort();384385case SNMP_OP_SET:386switch (value->var.subs[sub - 1]) {387388case LEAF_hrSystemDate:389if ((ctx->scratch->ptr1 =390OS_checkSystemDateInput(value->v.octetstring.octets,391value->v.octetstring.len)) == NULL)392return (SNMP_ERR_WRONG_VALUE);393394return (SNMP_ERR_NOERROR);395396case LEAF_hrSystemInitialLoadDevice:397case LEAF_hrSystemInitialLoadParameters:398return (SNMP_ERR_NOT_WRITEABLE);399400}401abort();402403case SNMP_OP_ROLLBACK:404switch (value->var.subs[sub - 1]) {405406case LEAF_hrSystemDate:407free(ctx->scratch->ptr1);408return (SNMP_ERR_NOERROR);409410case LEAF_hrSystemInitialLoadDevice:411case LEAF_hrSystemInitialLoadParameters:412abort();413}414abort();415416case SNMP_OP_COMMIT:417switch (value->var.subs[sub - 1]) {418419case LEAF_hrSystemDate:420(void)OS_setSystemDate(ctx->scratch->ptr1);421free(ctx->scratch->ptr1);422return (SNMP_ERR_NOERROR);423424case LEAF_hrSystemInitialLoadDevice:425case LEAF_hrSystemInitialLoadParameters:426abort();427}428abort();429430case SNMP_OP_GETNEXT:431abort();432}433abort();434}435436/*437* prototype of this function was generated by gensnmptree tool438* in the header file hostres_tree.h439* Returns SNMP_ERR_NOERROR on success440*/441int442op_hrStorage(struct snmp_context *ctx __unused, struct snmp_value *value,443u_int sub, u_int iidx __unused, enum snmp_op curr_op)444{445446/* only GET is possible */447switch (curr_op) {448449case SNMP_OP_GET:450switch (value->var.subs[sub - 1]) {451452case LEAF_hrMemorySize:453return (OS_getMemorySize(&value->v.uint32));454}455abort();456457case SNMP_OP_SET:458return (SNMP_ERR_NOT_WRITEABLE);459460case SNMP_OP_ROLLBACK:461case SNMP_OP_COMMIT:462case SNMP_OP_GETNEXT:463abort();464}465abort();466}467468469