summaryrefslogtreecommitdiffstats
path: root/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_scalars.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr.sbin/bsnmpd/modules/snmp_hostres/hostres_scalars.c')
-rw-r--r--usr.sbin/bsnmpd/modules/snmp_hostres/hostres_scalars.c492
1 files changed, 492 insertions, 0 deletions
diff --git a/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_scalars.c b/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_scalars.c
new file mode 100644
index 0000000..87b78e8
--- /dev/null
+++ b/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_scalars.c
@@ -0,0 +1,492 @@
+/*-
+ * Copyright (c) 2005-2006 The FreeBSD Project
+ * All rights reserved.
+ *
+ * Author: Victor Cruceru <soc-victor@freebsd.org>
+ *
+ * Redistribution of this software and documentation and use in source and
+ * binary forms, with or without modification, are permitted provided that
+ * the following conditions are met:
+ *
+ * 1. Redistributions of source code or documentation must retain the above
+ * copyright notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+/*
+ * Host Resources MIB scalars implementation for SNMPd.
+ */
+
+#include <sys/types.h>
+#include <sys/sysctl.h>
+
+#include <pwd.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <syslog.h>
+#include <utmpx.h>
+
+#include "hostres_snmp.h"
+#include "hostres_oid.h"
+#include "hostres_tree.h"
+
+/* boot timestamp in centi-seconds */
+static uint64_t kernel_boot;
+
+/* physical memory size in Kb */
+static uint64_t phys_mem_size;
+
+/* boot line (malloced) */
+static u_char *boot_line;
+
+/* maximum number of processes */
+static uint32_t max_proc;
+
+/**
+ * Free all static data
+ */
+void
+fini_scalars(void)
+{
+
+ free(boot_line);
+}
+
+/**
+ * Get system uptime in hundredths of seconds since the epoch
+ * Returns 0 in case of an error
+ */
+static int
+OS_getSystemUptime(uint32_t *ut)
+{
+ struct timeval right_now;
+ uint64_t now;
+
+ if (kernel_boot == 0) {
+ /* first time, do the sysctl */
+ struct timeval kernel_boot_timestamp;
+ int mib[2] = { CTL_KERN, KERN_BOOTTIME };
+ size_t len = sizeof(kernel_boot_timestamp);
+
+ if (sysctl(mib, 2, &kernel_boot_timestamp,
+ &len, NULL, 0) == -1) {
+ syslog(LOG_ERR, "sysctl KERN_BOOTTIME failed: %m");
+ return (SNMP_ERR_GENERR);
+ }
+
+ HRDBG("boot timestamp from kernel: {%lld, %ld}",
+ (long long)kernel_boot_timestamp.tv_sec,
+ (long)kernel_boot_timestamp.tv_usec);
+
+ kernel_boot = ((uint64_t)kernel_boot_timestamp.tv_sec * 100) +
+ (kernel_boot_timestamp.tv_usec / 10000);
+ }
+
+ if (gettimeofday(&right_now, NULL) < 0) {
+ syslog(LOG_ERR, "gettimeofday failed: %m");
+ return (SNMP_ERR_GENERR);
+ }
+ now = ((uint64_t)right_now.tv_sec * 100) + (right_now.tv_usec / 10000);
+
+ if (now - kernel_boot > UINT32_MAX)
+ *ut = UINT32_MAX;
+ else
+ *ut = now - kernel_boot;
+
+ return (SNMP_ERR_NOERROR);
+}
+
+/**
+ * Get system local date and time in a foramt suitable for DateAndTime TC:
+ * field octets contents range
+ * ----- ------ -------- -----
+ * 1 1-2 year* 0..65536
+ * 2 3 month 1..12
+ * 3 4 day 1..31
+ * 4 5 hour 0..23
+ * 5 6 minutes 0..59
+ * 6 7 seconds 0..60
+ * (use 60 for leap-second)
+ * 7 8 deci-seconds 0..9
+ * 8 9 direction from UTC '+' / '-'
+ * 9 10 hours from UTC* 0..13
+ * 10 11 minutes from UTC 0..59
+ *
+ * * Notes:
+ * - the value of year is in network-byte order
+ * - daylight saving time in New Zealand is +13
+ *
+ * For example, Tuesday May 26, 1992 at 1:30:15 PM EDT would be
+ * displayed as:
+ *
+ * 1992-5-26,13:30:15.0,-4:0
+ *
+ * Returns -1 in case of an error or the length of the string (8 or 11)
+ * Actually returns always 11 on freebsd
+ */
+static int
+OS_getSystemDate(struct snmp_value *value)
+{
+ u_char s_date_time[11];
+ struct tm tloc_tm;
+ time_t tloc_time_t;
+ struct timeval right_now;
+ int string_len;
+
+ if (gettimeofday(&right_now, NULL) < 0) {
+ syslog(LOG_ERR, "gettimeofday failed: %m");
+ return (SNMP_ERR_GENERR);
+ }
+
+ tloc_time_t = right_now.tv_sec;
+
+ if (localtime_r(&tloc_time_t, &tloc_tm) == NULL) {
+ syslog(LOG_ERR, "localtime_r() failed: %m ");
+ return (SNMP_ERR_GENERR);
+ }
+
+ string_len = make_date_time(s_date_time, &tloc_tm,
+ right_now.tv_usec / 100000);
+
+ return (string_get(value, s_date_time, string_len));
+}
+
+/**
+ * Get kernel boot path. For FreeBSD it seems that no arguments are
+ * present. Returns NULL if an error occurred. The returned data is a
+ * pointer to a global storage.
+ */
+int
+OS_getSystemInitialLoadParameters(u_char **params)
+{
+
+ if (boot_line == NULL) {
+ int mib[2] = { CTL_KERN, KERN_BOOTFILE };
+ char *buf;
+ size_t buf_len = 0;
+
+ /* get the needed buffer len */
+ if (sysctl(mib, 2, NULL, &buf_len, NULL, 0) != 0) {
+ syslog(LOG_ERR,
+ "sysctl({CTL_KERN,KERN_BOOTFILE}) failed: %m");
+ return (SNMP_ERR_GENERR);
+ }
+
+ if ((buf = malloc(buf_len)) == NULL) {
+ syslog(LOG_ERR, "malloc failed");
+ return (SNMP_ERR_GENERR);
+ }
+ if (sysctl(mib, 2, buf, &buf_len, NULL, 0)) {
+ syslog(LOG_ERR,
+ "sysctl({CTL_KERN,KERN_BOOTFILE}) failed: %m");
+ free(buf);
+ return (SNMP_ERR_GENERR);
+ }
+
+ boot_line = buf;
+ HRDBG("kernel boot file: %s", boot_line);
+ }
+
+ *params = boot_line;
+ return (SNMP_ERR_NOERROR);
+}
+
+/**
+ * Get number of current users which are logged in
+ */
+static int
+OS_getSystemNumUsers(uint32_t *nu)
+{
+ struct utmpx *utmp;
+
+ setutxent();
+ *nu = 0;
+ while ((utmp = getutxent()) != NULL) {
+ if (utmp->ut_type == USER_PROCESS)
+ (*nu)++;
+ }
+ endutxent();
+
+ return (SNMP_ERR_NOERROR);
+}
+
+/**
+ * Get number of current processes existing into the system
+ */
+static int
+OS_getSystemProcesses(uint32_t *proc_count)
+{
+ int pc;
+
+ if (hr_kd == NULL)
+ return (SNMP_ERR_GENERR);
+
+ if (kvm_getprocs(hr_kd, KERN_PROC_ALL, 0, &pc) == NULL) {
+ syslog(LOG_ERR, "kvm_getprocs failed: %m");
+ return (SNMP_ERR_GENERR);
+ }
+
+ *proc_count = pc;
+ return (SNMP_ERR_NOERROR);
+}
+
+/**
+ * Get maximum number of processes allowed on this system
+ */
+static int
+OS_getSystemMaxProcesses(uint32_t *mproc)
+{
+
+ if (max_proc == 0) {
+ int mib[2] = { CTL_KERN, KERN_MAXPROC };
+ int mp;
+ size_t len = sizeof(mp);
+
+ if (sysctl(mib, 2, &mp, &len, NULL, 0) == -1) {
+ syslog(LOG_ERR, "sysctl KERN_MAXPROC failed: %m");
+ return (SNMP_ERR_GENERR);
+ }
+ max_proc = mp;
+ }
+
+ *mproc = max_proc;
+ return (SNMP_ERR_NOERROR);
+}
+
+/*
+ * Get the physical memeory size in Kbytes.
+ * Returns SNMP error code.
+ */
+static int
+OS_getMemorySize(uint32_t *ms)
+{
+
+ if (phys_mem_size == 0) {
+ int mib[2] = { CTL_HW, HW_PHYSMEM };
+ u_long physmem;
+ size_t len = sizeof(physmem);
+
+ if (sysctl(mib, 2, &physmem, &len, NULL, 0) == -1) {
+ syslog(LOG_ERR,
+ "sysctl({ CTL_HW, HW_PHYSMEM }) failed: %m");
+ return (SNMP_ERR_GENERR);
+ }
+
+ phys_mem_size = physmem / 1024;
+ }
+
+ if (phys_mem_size > UINT32_MAX)
+ *ms = UINT32_MAX;
+ else
+ *ms = phys_mem_size;
+ return (SNMP_ERR_NOERROR);
+}
+
+/*
+ * Try to use the s_date_time parameter as a DateAndTime TC to fill in
+ * the second parameter.
+ * Returns 0 on succes and -1 for an error.
+ * Bug: time zone info is not used
+ */
+static struct timeval *
+OS_checkSystemDateInput(const u_char *str, u_int len)
+{
+ struct tm tm_to_set;
+ time_t t;
+ struct timeval *tv;
+
+ if (len != 8 && len != 11)
+ return (NULL);
+
+ if (str[2] == 0 || str[2] > 12 ||
+ str[3] == 0 || str[3] > 31 ||
+ str[4] > 23 || str[5] > 59 || str[6] > 60 || str[7] > 9)
+ return (NULL);
+
+ tm_to_set.tm_year = ((str[0] << 8) + str[1]) - 1900;
+ tm_to_set.tm_mon = str[2] - 1;
+ tm_to_set.tm_mday = str[3];
+ tm_to_set.tm_hour = str[4];
+ tm_to_set.tm_min = str[5];
+ tm_to_set.tm_sec = str[6];
+ tm_to_set.tm_isdst = 0;
+
+ /* now make UTC from it */
+ if ((t = timegm(&tm_to_set)) == (time_t)-1)
+ return (NULL);
+
+ /* now apply timezone if specified */
+ if (len == 11) {
+ if (str[9] > 13 || str[10] > 59)
+ return (NULL);
+ if (str[8] == '+')
+ t += 3600 * str[9] + 60 * str[10];
+ else
+ t -= 3600 * str[9] + 60 * str[10];
+ }
+
+ if ((tv = malloc(sizeof(*tv))) == NULL)
+ return (NULL);
+
+ tv->tv_sec = t;
+ tv->tv_usec = (int32_t)str[7] * 100000;
+
+ return (tv);
+}
+
+/*
+ * Set system date and time. Timezone is not changed
+ */
+static int
+OS_setSystemDate(const struct timeval *timeval_to_set)
+{
+ if (settimeofday(timeval_to_set, NULL) == -1) {
+ syslog(LOG_ERR, "settimeofday failed: %m");
+ return (SNMP_ERR_GENERR);
+ }
+ return (SNMP_ERR_NOERROR);
+}
+
+/*
+ * prototype of this function was genrated by gensnmptree tool in header file
+ * hostres_tree.h
+ * Returns SNMP_ERR_NOERROR on success
+ */
+int
+op_hrSystem(struct snmp_context *ctx, struct snmp_value *value,
+ u_int sub, u_int iidx __unused, enum snmp_op curr_op)
+{
+ int err;
+ u_char *str;
+
+ switch (curr_op) {
+
+ case SNMP_OP_GET:
+ switch (value->var.subs[sub - 1]) {
+
+ case LEAF_hrSystemUptime:
+ return (OS_getSystemUptime(&value->v.uint32));
+
+ case LEAF_hrSystemDate:
+ return (OS_getSystemDate(value));
+
+ case LEAF_hrSystemInitialLoadDevice:
+ value->v.uint32 = 0; /* FIXME */
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_hrSystemInitialLoadParameters:
+ if ((err = OS_getSystemInitialLoadParameters(&str)) !=
+ SNMP_ERR_NOERROR)
+ return (err);
+ return (string_get(value, str, -1));
+
+ case LEAF_hrSystemNumUsers:
+ return (OS_getSystemNumUsers(&value->v.uint32));
+
+ case LEAF_hrSystemProcesses:
+ return (OS_getSystemProcesses(&value->v.uint32));
+
+ case LEAF_hrSystemMaxProcesses:
+ return (OS_getSystemMaxProcesses(&value->v.uint32));
+ }
+ abort();
+
+ case SNMP_OP_SET:
+ switch (value->var.subs[sub - 1]) {
+
+ case LEAF_hrSystemDate:
+ if ((ctx->scratch->ptr1 =
+ OS_checkSystemDateInput(value->v.octetstring.octets,
+ value->v.octetstring.len)) == NULL)
+ return (SNMP_ERR_WRONG_VALUE);
+
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_hrSystemInitialLoadDevice:
+ case LEAF_hrSystemInitialLoadParameters:
+ return (SNMP_ERR_NOT_WRITEABLE);
+
+ }
+ abort();
+
+ case SNMP_OP_ROLLBACK:
+ switch (value->var.subs[sub - 1]) {
+
+ case LEAF_hrSystemDate:
+ free(ctx->scratch->ptr1);
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_hrSystemInitialLoadDevice:
+ case LEAF_hrSystemInitialLoadParameters:
+ abort();
+ }
+ abort();
+
+ case SNMP_OP_COMMIT:
+ switch (value->var.subs[sub - 1]) {
+
+ case LEAF_hrSystemDate:
+ (void)OS_setSystemDate(ctx->scratch->ptr1);
+ free(ctx->scratch->ptr1);
+ return (SNMP_ERR_NOERROR);
+
+ case LEAF_hrSystemInitialLoadDevice:
+ case LEAF_hrSystemInitialLoadParameters:
+ abort();
+ }
+ abort();
+
+ case SNMP_OP_GETNEXT:
+ abort();
+ }
+ abort();
+}
+
+/*
+ * prototype of this function was genrated by gensnmptree tool
+ * in the header file hostres_tree.h
+ * Returns SNMP_ERR_NOERROR on success
+ */
+int
+op_hrStorage(struct snmp_context *ctx __unused, struct snmp_value *value,
+ u_int sub, u_int iidx __unused, enum snmp_op curr_op)
+{
+
+ /* only GET is possible */
+ switch (curr_op) {
+
+ case SNMP_OP_GET:
+ switch (value->var.subs[sub - 1]) {
+
+ case LEAF_hrMemorySize:
+ return (OS_getMemorySize(&value->v.uint32));
+ }
+ abort();
+
+ case SNMP_OP_SET:
+ return (SNMP_ERR_NOT_WRITEABLE);
+
+ case SNMP_OP_ROLLBACK:
+ case SNMP_OP_COMMIT:
+ case SNMP_OP_GETNEXT:
+ abort();
+ }
+ abort();
+}
OpenPOWER on IntegriCloud