hostres_scalars.c revision 154249
1154133Sharti/*- 2154133Sharti * Copyright (c) 2005-2006 The FreeBSD Project 3154133Sharti * All rights reserved. 4154133Sharti * 5154133Sharti * Author: Victor Cruceru <soc-victor@freebsd.org> 6154133Sharti * 7154133Sharti * Redistribution of this software and documentation and use in source and 8154133Sharti * binary forms, with or without modification, are permitted provided that 9154133Sharti * the following conditions are met: 10154133Sharti * 11154133Sharti * 1. Redistributions of source code or documentation must retain the above 12154133Sharti * copyright notice, this list of conditions and the following disclaimer. 13154133Sharti * 2. Redistributions in binary form must reproduce the above copyright 14154133Sharti * notice, this list of conditions and the following disclaimer in the 15154133Sharti * documentation and/or other materials provided with the distribution. 16154133Sharti * 17154133Sharti * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18154133Sharti * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19154133Sharti * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20154133Sharti * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21154133Sharti * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22154133Sharti * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23154133Sharti * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24154133Sharti * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25154133Sharti * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26154133Sharti * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27154133Sharti * SUCH DAMAGE. 28154133Sharti * 29154133Sharti * $FreeBSD: head/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_scalars.c 154249 2006-01-12 07:44:40Z harti $ 30154133Sharti */ 31154133Sharti 32154133Sharti/* 33154133Sharti * Host Resources MIB scalars implementation for SNMPd. 34154133Sharti */ 35154133Sharti 36154133Sharti#include <sys/types.h> 37154133Sharti#include <sys/sysctl.h> 38154133Sharti 39154133Sharti#include <pwd.h> 40154133Sharti#include <stdlib.h> 41154133Sharti#include <stdint.h> 42154133Sharti#include <string.h> 43154133Sharti#include <syslog.h> 44154133Sharti#include <utmp.h> 45154133Sharti 46154133Sharti#include "hostres_snmp.h" 47154133Sharti#include "hostres_oid.h" 48154133Sharti#include "hostres_tree.h" 49154133Sharti 50154133Sharti/* file pointer to keep an open instance of utmp */ 51154133Shartistatic FILE *utmp_fp; 52154133Sharti 53154133Sharti/* boot timestamp in centi-seconds */ 54154133Shartistatic uint64_t kernel_boot; 55154133Sharti 56154133Sharti/* physical memory size in Kb */ 57154133Shartistatic uint64_t phys_mem_size; 58154133Sharti 59154133Sharti/* boot line (malloced) */ 60154133Shartistatic u_char *boot_line; 61154133Sharti 62154133Sharti/* maximum number of processes */ 63154133Shartistatic uint32_t max_proc; 64154133Sharti 65154133Sharti/** 66154133Sharti * Free all static data 67154133Sharti */ 68154133Shartivoid 69154133Shartifini_scalars(void) 70154133Sharti{ 71154133Sharti 72154133Sharti free(boot_line); 73154133Sharti 74154133Sharti if (utmp_fp != NULL) 75154133Sharti (void)fclose(utmp_fp); 76154133Sharti} 77154133Sharti 78154133Sharti/** 79154133Sharti * Get system uptime in hundredths of seconds since the epoch 80154133Sharti * Returns 0 in case of an error 81154133Sharti */ 82154133Shartistatic int 83154133ShartiOS_getSystemUptime(uint32_t *ut) 84154133Sharti{ 85154133Sharti struct timeval right_now; 86154133Sharti uint64_t now; 87154133Sharti 88154133Sharti if (kernel_boot == 0) { 89154133Sharti /* first time, do the sysctl */ 90154133Sharti struct timeval kernel_boot_timestamp; 91154133Sharti int mib[2] = { CTL_KERN, KERN_BOOTTIME }; 92154133Sharti size_t len = sizeof(kernel_boot_timestamp); 93154133Sharti 94154133Sharti if (sysctl(mib, 2, &kernel_boot_timestamp, 95154133Sharti &len, NULL, 0) == -1) { 96154133Sharti syslog(LOG_ERR, "sysctl KERN_BOOTTIME failed: %m"); 97154133Sharti return (SNMP_ERR_GENERR); 98154133Sharti } 99154133Sharti 100154249Sharti HRDBG("boot timestamp from kernel: {%lld, %ld}", 101154249Sharti (long long)kernel_boot_timestamp.tv_sec, 102154249Sharti (long)kernel_boot_timestamp.tv_usec); 103154133Sharti 104154133Sharti kernel_boot = ((uint64_t)kernel_boot_timestamp.tv_sec * 100) + 105154133Sharti (kernel_boot_timestamp.tv_usec / 10000); 106154133Sharti } 107154133Sharti 108154133Sharti if (gettimeofday(&right_now, NULL) < 0) { 109154133Sharti syslog(LOG_ERR, "gettimeofday failed: %m"); 110154133Sharti return (SNMP_ERR_GENERR); 111154133Sharti } 112154133Sharti now = ((uint64_t)right_now.tv_sec * 100) + (right_now.tv_usec / 10000); 113154133Sharti 114154133Sharti if (now - kernel_boot > UINT32_MAX) 115154133Sharti *ut = UINT32_MAX; 116154133Sharti else 117154133Sharti *ut = now - kernel_boot; 118154133Sharti 119154133Sharti return (SNMP_ERR_NOERROR); 120154133Sharti} 121154133Sharti 122154133Sharti/** 123154133Sharti * Get system local date and time in a foramt suitable for DateAndTime TC: 124154133Sharti * field octets contents range 125154133Sharti * ----- ------ -------- ----- 126154133Sharti * 1 1-2 year* 0..65536 127154133Sharti * 2 3 month 1..12 128154133Sharti * 3 4 day 1..31 129154133Sharti * 4 5 hour 0..23 130154133Sharti * 5 6 minutes 0..59 131154133Sharti * 6 7 seconds 0..60 132154133Sharti * (use 60 for leap-second) 133154133Sharti * 7 8 deci-seconds 0..9 134154133Sharti * 8 9 direction from UTC '+' / '-' 135154133Sharti * 9 10 hours from UTC* 0..13 136154133Sharti * 10 11 minutes from UTC 0..59 137154133Sharti * 138154133Sharti * * Notes: 139154133Sharti * - the value of year is in network-byte order 140154133Sharti * - daylight saving time in New Zealand is +13 141154133Sharti * 142154133Sharti * For example, Tuesday May 26, 1992 at 1:30:15 PM EDT would be 143154133Sharti * displayed as: 144154133Sharti * 145154133Sharti * 1992-5-26,13:30:15.0,-4:0 146154133Sharti * 147154133Sharti * Returns -1 in case of an error or the length of the string (8 or 11) 148154133Sharti * Actually returns always 11 on freebsd 149154133Sharti */ 150154133Shartistatic int 151154133ShartiOS_getSystemDate(struct snmp_value *value) 152154133Sharti{ 153154133Sharti u_char s_date_time[11]; 154154133Sharti struct tm tloc_tm; 155154133Sharti time_t tloc_time_t; 156154133Sharti struct timeval right_now; 157154133Sharti int string_len; 158154133Sharti 159154133Sharti if (gettimeofday(&right_now, NULL) < 0) { 160154133Sharti syslog(LOG_ERR, "gettimeofday failed: %m"); 161154133Sharti return (SNMP_ERR_GENERR); 162154133Sharti } 163154133Sharti 164154133Sharti tloc_time_t = right_now.tv_sec; 165154133Sharti 166154133Sharti if (localtime_r(&tloc_time_t, &tloc_tm) == NULL) { 167154133Sharti syslog(LOG_ERR, "localtime_r() failed: %m "); 168154133Sharti return (SNMP_ERR_GENERR); 169154133Sharti } 170154133Sharti 171154133Sharti string_len = make_date_time(s_date_time, &tloc_tm, 172154133Sharti right_now.tv_usec / 100000); 173154133Sharti 174154133Sharti return (string_get(value, s_date_time, string_len)); 175154133Sharti} 176154133Sharti 177154133Sharti/** 178154133Sharti * Get kernel boot path. For FreeBSD it seems that no arguments are 179154133Sharti * present. Returns NULL if an error occured. The returned data is a 180154133Sharti * pointer to a global strorage. 181154133Sharti */ 182154133Shartiint 183154133ShartiOS_getSystemInitialLoadParameters(u_char **params) 184154133Sharti{ 185154133Sharti 186154133Sharti if (boot_line == NULL) { 187154133Sharti int mib[2] = { CTL_KERN, KERN_BOOTFILE }; 188154133Sharti char *buf; 189154133Sharti size_t buf_len = 0; 190154133Sharti 191154133Sharti /* get the needed buffer len */ 192154133Sharti if (sysctl(mib, 2, NULL, &buf_len, NULL, 0) != 0) { 193154133Sharti syslog(LOG_ERR, 194154133Sharti "sysctl({CTL_KERN,KERN_BOOTFILE}) failed: %m"); 195154133Sharti return (SNMP_ERR_GENERR); 196154133Sharti } 197154133Sharti 198154133Sharti if ((buf = malloc(buf_len)) == NULL) { 199154133Sharti syslog(LOG_ERR, "malloc failed"); 200154133Sharti return (SNMP_ERR_GENERR); 201154133Sharti } 202154133Sharti if (sysctl(mib, 2, buf, &buf_len, NULL, 0)) { 203154133Sharti syslog(LOG_ERR, 204154133Sharti "sysctl({CTL_KERN,KERN_BOOTFILE}) failed: %m"); 205154133Sharti free(buf); 206154133Sharti return (SNMP_ERR_GENERR); 207154133Sharti } 208154133Sharti 209154133Sharti boot_line = buf; 210154133Sharti HRDBG("kernel boot file: %s", boot_line); 211154133Sharti } 212154133Sharti 213154133Sharti *params = boot_line; 214154133Sharti return (SNMP_ERR_NOERROR); 215154133Sharti} 216154133Sharti 217154133Sharti/** 218154133Sharti * Get number of current users which are logged in 219154133Sharti */ 220154133Shartistatic int 221154133ShartiOS_getSystemNumUsers(uint32_t *nu) 222154133Sharti{ 223154133Sharti struct utmp utmp; 224154133Sharti static int first_time = 1; 225154133Sharti 226154133Sharti if (utmp_fp == NULL) { 227154133Sharti if (!first_time) 228154133Sharti return (SNMP_ERR_GENERR); 229154133Sharti first_time = 0; 230154133Sharti if ((utmp_fp = fopen(_PATH_UTMP, "r")) == NULL) { 231154133Sharti syslog(LOG_ERR, "fopen(%s) failed: %m", _PATH_UTMP); 232154133Sharti return (SNMP_ERR_GENERR); 233154133Sharti } 234154133Sharti } 235154133Sharti 236154133Sharti /* start with the begining of the utmp file */ 237154133Sharti (void)rewind(utmp_fp); 238154133Sharti 239154133Sharti *nu = 0; 240154133Sharti while (fread(&utmp, sizeof(utmp), 1, utmp_fp) == 1) { 241154133Sharti if (utmp.ut_name[0] != '\0' && utmp.ut_line[0] != '\0') { 242154133Sharti if (getpwnam(utmp.ut_name) == NULL) 243154133Sharti continue; 244154133Sharti (*nu)++; 245154133Sharti } 246154133Sharti } 247154133Sharti 248154133Sharti return (SNMP_ERR_NOERROR); 249154133Sharti} 250154133Sharti 251154133Sharti/** 252154133Sharti * Get number of current processes existing into the system 253154133Sharti */ 254154133Shartistatic int 255154133ShartiOS_getSystemProcesses(uint32_t *proc_count) 256154133Sharti{ 257154133Sharti int pc; 258154133Sharti 259154133Sharti if (hr_kd == NULL) 260154133Sharti return (SNMP_ERR_GENERR); 261154133Sharti 262154133Sharti if (kvm_getprocs(hr_kd, KERN_PROC_ALL, 0, &pc) == NULL) { 263154133Sharti syslog(LOG_ERR, "kvm_getprocs failed: %m"); 264154133Sharti return (SNMP_ERR_GENERR); 265154133Sharti } 266154133Sharti 267154133Sharti *proc_count = pc; 268154133Sharti return (SNMP_ERR_NOERROR); 269154133Sharti} 270154133Sharti 271154133Sharti/** 272154133Sharti * Get maximum number of processes allowed on this system 273154133Sharti */ 274154133Shartistatic int 275154133ShartiOS_getSystemMaxProcesses(uint32_t *mproc) 276154133Sharti{ 277154133Sharti 278154133Sharti if (max_proc == 0) { 279154133Sharti int mib[2] = { CTL_KERN, KERN_MAXPROC }; 280154133Sharti int mp; 281154133Sharti size_t len = sizeof(mp); 282154133Sharti 283154133Sharti if (sysctl(mib, 2, &mp, &len, NULL, 0) == -1) { 284154133Sharti syslog(LOG_ERR, "sysctl KERN_MAXPROC failed: %m"); 285154133Sharti return (SNMP_ERR_GENERR); 286154133Sharti } 287154133Sharti max_proc = mp; 288154133Sharti } 289154133Sharti 290154133Sharti *mproc = max_proc; 291154133Sharti return (SNMP_ERR_NOERROR); 292154133Sharti} 293154133Sharti 294154133Sharti/* 295154133Sharti * Get the physical memeory size in Kbytes. 296154133Sharti * Returns SNMP error code. 297154133Sharti */ 298154133Shartistatic int 299154133ShartiOS_getMemorySize(uint32_t *ms) 300154133Sharti{ 301154133Sharti 302154133Sharti if (phys_mem_size == 0) { 303154133Sharti int mib[2] = { CTL_HW, HW_PHYSMEM }; 304154133Sharti u_long physmem; 305154133Sharti size_t len = sizeof(physmem); 306154133Sharti 307154133Sharti if (sysctl(mib, 2, &physmem, &len, NULL, 0) == -1) { 308154133Sharti syslog(LOG_ERR, 309154133Sharti "sysctl({ CTL_HW, HW_PHYSMEM }) failed: %m"); 310154133Sharti return (SNMP_ERR_GENERR); 311154133Sharti } 312154133Sharti 313154133Sharti phys_mem_size = physmem / 1024; 314154133Sharti } 315154133Sharti 316154133Sharti if (phys_mem_size > UINT32_MAX) 317154133Sharti *ms = UINT32_MAX; 318154133Sharti else 319154133Sharti *ms = phys_mem_size; 320154133Sharti return (SNMP_ERR_NOERROR); 321154133Sharti} 322154133Sharti 323154133Sharti/* 324154133Sharti * Try to use the s_date_time parameter as a DateAndTime TC to fill in 325154133Sharti * the second parameter. 326154133Sharti * Returns 0 on succes and -1 for an error. 327154133Sharti * Bug: time zone info is not used 328154133Sharti */ 329154133Shartistatic struct timeval * 330154133ShartiOS_checkSystemDateInput(const u_char *str, u_int len) 331154133Sharti{ 332154133Sharti struct tm tm_to_set; 333154133Sharti time_t t; 334154133Sharti struct timeval *tv; 335154133Sharti 336154133Sharti if (len != 8 && len != 11) 337154133Sharti return (NULL); 338154133Sharti 339154133Sharti if (str[2] == 0 || str[2] > 12 || 340154133Sharti str[3] == 0 || str[3] > 31 || 341154133Sharti str[4] > 23 || str[5] > 59 || str[6] > 60 || str[7] > 9) 342154133Sharti return (NULL); 343154133Sharti 344154133Sharti tm_to_set.tm_year = ((str[0] << 8) + str[1]) - 1900; 345154133Sharti tm_to_set.tm_mon = str[2] - 1; 346154133Sharti tm_to_set.tm_mday = str[3]; 347154133Sharti tm_to_set.tm_hour = str[4]; 348154133Sharti tm_to_set.tm_min = str[5]; 349154133Sharti tm_to_set.tm_sec = str[6]; 350154133Sharti tm_to_set.tm_isdst = 0; 351154133Sharti 352154133Sharti /* now make UTC from it */ 353154133Sharti if ((t = timegm(&tm_to_set)) == (time_t)-1) 354154133Sharti return (NULL); 355154133Sharti 356154133Sharti /* now apply timezone if specified */ 357154133Sharti if (len == 11) { 358154133Sharti if (str[9] > 13 || str[10] > 59) 359154133Sharti return (NULL); 360154133Sharti if (str[8] == '+') 361154133Sharti t += 3600 * str[9] + 60 * str[10]; 362154133Sharti else 363154133Sharti t -= 3600 * str[9] + 60 * str[10]; 364154133Sharti } 365154133Sharti 366154133Sharti if ((tv = malloc(sizeof(*tv))) == NULL) 367154133Sharti return (NULL); 368154133Sharti 369154133Sharti tv->tv_sec = t; 370154133Sharti tv->tv_usec = (int32_t)str[7] * 100000; 371154133Sharti 372154133Sharti return (tv); 373154133Sharti} 374154133Sharti 375154133Sharti/* 376154133Sharti * Set system date and time. Timezone is not changed 377154133Sharti */ 378154133Shartistatic int 379154133ShartiOS_setSystemDate(const struct timeval *timeval_to_set) 380154133Sharti{ 381154133Sharti if (settimeofday(timeval_to_set, NULL) == -1) { 382154133Sharti syslog(LOG_ERR, "settimeofday failed: %m"); 383154133Sharti return (SNMP_ERR_GENERR); 384154133Sharti } 385154133Sharti return (SNMP_ERR_NOERROR); 386154133Sharti} 387154133Sharti 388154133Sharti/* 389154133Sharti * prototype of this function was genrated by gensnmptree tool in header file 390154133Sharti * hostres_tree.h 391154133Sharti * Returns SNMP_ERR_NOERROR on success 392154133Sharti */ 393154133Shartiint 394154133Shartiop_hrSystem(struct snmp_context *ctx, struct snmp_value *value, 395154133Sharti u_int sub, u_int iidx __unused, enum snmp_op curr_op) 396154133Sharti{ 397154133Sharti int err; 398154133Sharti u_char *str; 399154133Sharti 400154133Sharti switch (curr_op) { 401154133Sharti 402154133Sharti case SNMP_OP_GET: 403154133Sharti switch (value->var.subs[sub - 1]) { 404154133Sharti 405154133Sharti case LEAF_hrSystemUptime: 406154133Sharti return (OS_getSystemUptime(&value->v.uint32)); 407154133Sharti 408154133Sharti case LEAF_hrSystemDate: 409154133Sharti return (OS_getSystemDate(value)); 410154133Sharti 411154133Sharti case LEAF_hrSystemInitialLoadDevice: 412154133Sharti value->v.uint32 = 0; /* FIXME */ 413154133Sharti return (SNMP_ERR_NOERROR); 414154133Sharti 415154133Sharti case LEAF_hrSystemInitialLoadParameters: 416154133Sharti if ((err = OS_getSystemInitialLoadParameters(&str)) != 417154133Sharti SNMP_ERR_NOERROR) 418154133Sharti return (err); 419154133Sharti return (string_get(value, str, -1)); 420154133Sharti 421154133Sharti case LEAF_hrSystemNumUsers: 422154133Sharti return (OS_getSystemNumUsers(&value->v.uint32)); 423154133Sharti 424154133Sharti case LEAF_hrSystemProcesses: 425154133Sharti return (OS_getSystemProcesses(&value->v.uint32)); 426154133Sharti 427154133Sharti case LEAF_hrSystemMaxProcesses: 428154133Sharti return (OS_getSystemMaxProcesses(&value->v.uint32)); 429154133Sharti } 430154133Sharti abort(); 431154133Sharti 432154133Sharti case SNMP_OP_SET: 433154133Sharti switch (value->var.subs[sub - 1]) { 434154133Sharti 435154133Sharti case LEAF_hrSystemDate: 436154133Sharti if ((ctx->scratch->ptr1 = 437154133Sharti OS_checkSystemDateInput(value->v.octetstring.octets, 438154133Sharti value->v.octetstring.len)) == NULL) 439154133Sharti return (SNMP_ERR_WRONG_VALUE); 440154133Sharti 441154133Sharti return (SNMP_ERR_NOERROR); 442154133Sharti 443154133Sharti case LEAF_hrSystemInitialLoadDevice: 444154133Sharti case LEAF_hrSystemInitialLoadParameters: 445154133Sharti return (SNMP_ERR_NOT_WRITEABLE); 446154133Sharti 447154133Sharti } 448154133Sharti abort(); 449154133Sharti 450154133Sharti case SNMP_OP_ROLLBACK: 451154133Sharti switch (value->var.subs[sub - 1]) { 452154133Sharti 453154133Sharti case LEAF_hrSystemDate: 454154133Sharti free(ctx->scratch->ptr1); 455154133Sharti return (SNMP_ERR_NOERROR); 456154133Sharti 457154133Sharti case LEAF_hrSystemInitialLoadDevice: 458154133Sharti case LEAF_hrSystemInitialLoadParameters: 459154133Sharti abort(); 460154133Sharti } 461154133Sharti abort(); 462154133Sharti 463154133Sharti case SNMP_OP_COMMIT: 464154133Sharti switch (value->var.subs[sub - 1]) { 465154133Sharti 466154133Sharti case LEAF_hrSystemDate: 467154133Sharti (void)OS_setSystemDate(ctx->scratch->ptr1); 468154133Sharti free(ctx->scratch->ptr1); 469154133Sharti return (SNMP_ERR_NOERROR); 470154133Sharti 471154133Sharti case LEAF_hrSystemInitialLoadDevice: 472154133Sharti case LEAF_hrSystemInitialLoadParameters: 473154133Sharti abort(); 474154133Sharti } 475154133Sharti abort(); 476154133Sharti 477154133Sharti case SNMP_OP_GETNEXT: 478154133Sharti abort(); 479154133Sharti } 480154133Sharti abort(); 481154133Sharti} 482154133Sharti 483154133Sharti/* 484154133Sharti * prototype of this function was genrated by gensnmptree tool 485154133Sharti * in the header file hostres_tree.h 486154133Sharti * Returns SNMP_ERR_NOERROR on success 487154133Sharti */ 488154133Shartiint 489154133Shartiop_hrStorage(struct snmp_context *ctx __unused, struct snmp_value *value, 490154133Sharti u_int sub, u_int iidx __unused, enum snmp_op curr_op) 491154133Sharti{ 492154133Sharti 493154133Sharti /* only GET is possible */ 494154133Sharti switch (curr_op) { 495154133Sharti 496154133Sharti case SNMP_OP_GET: 497154133Sharti switch (value->var.subs[sub - 1]) { 498154133Sharti 499154133Sharti case LEAF_hrMemorySize: 500154133Sharti return (OS_getMemorySize(&value->v.uint32)); 501154133Sharti } 502154133Sharti abort(); 503154133Sharti 504154133Sharti case SNMP_OP_SET: 505154133Sharti return (SNMP_ERR_NOT_WRITEABLE); 506154133Sharti 507154133Sharti case SNMP_OP_ROLLBACK: 508154133Sharti case SNMP_OP_COMMIT: 509154133Sharti case SNMP_OP_GETNEXT: 510154133Sharti abort(); 511154133Sharti } 512154133Sharti abort(); 513154133Sharti} 514