2 * Copyright (c) 2005-2006 The FreeBSD Project
5 * Author: Victor Cruceru <soc-victor@freebsd.org>
7 * Redistribution of this software and documentation and use in source and
8 * binary forms, with or without modification, are permitted provided that
9 * the following conditions are met:
11 * 1. Redistributions of source code or documentation must retain the above
12 * copyright notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * Host Resources MIB scalars implementation for SNMPd.
36 #include <sys/types.h>
37 #include <sys/sysctl.h>
46 #include "hostres_snmp.h"
47 #include "hostres_oid.h"
48 #include "hostres_tree.h"
50 /* file pointer to keep an open instance of utmp */
53 /* boot timestamp in centi-seconds */
54 static uint64_t kernel_boot;
56 /* physical memory size in Kb */
57 static uint64_t phys_mem_size;
59 /* boot line (malloced) */
60 static u_char *boot_line;
62 /* maximum number of processes */
63 static uint32_t max_proc;
66 * Free all static data
75 (void)fclose(utmp_fp);
79 * Get system uptime in hundredths of seconds since the epoch
80 * Returns 0 in case of an error
83 OS_getSystemUptime(uint32_t *ut)
85 struct timeval right_now;
88 if (kernel_boot == 0) {
89 /* first time, do the sysctl */
90 struct timeval kernel_boot_timestamp;
91 int mib[2] = { CTL_KERN, KERN_BOOTTIME };
92 size_t len = sizeof(kernel_boot_timestamp);
94 if (sysctl(mib, 2, &kernel_boot_timestamp,
95 &len, NULL, 0) == -1) {
96 syslog(LOG_ERR, "sysctl KERN_BOOTTIME failed: %m");
97 return (SNMP_ERR_GENERR);
100 HRDBG("boot timestamp from kernel: {%lld, %ld}",
101 (long long)kernel_boot_timestamp.tv_sec,
102 (long)kernel_boot_timestamp.tv_usec);
104 kernel_boot = ((uint64_t)kernel_boot_timestamp.tv_sec * 100) +
105 (kernel_boot_timestamp.tv_usec / 10000);
108 if (gettimeofday(&right_now, NULL) < 0) {
109 syslog(LOG_ERR, "gettimeofday failed: %m");
110 return (SNMP_ERR_GENERR);
112 now = ((uint64_t)right_now.tv_sec * 100) + (right_now.tv_usec / 10000);
114 if (now - kernel_boot > UINT32_MAX)
117 *ut = now - kernel_boot;
119 return (SNMP_ERR_NOERROR);
123 * Get system local date and time in a foramt suitable for DateAndTime TC:
124 * field octets contents range
125 * ----- ------ -------- -----
126 * 1 1-2 year* 0..65536
132 * (use 60 for leap-second)
133 * 7 8 deci-seconds 0..9
134 * 8 9 direction from UTC '+' / '-'
135 * 9 10 hours from UTC* 0..13
136 * 10 11 minutes from UTC 0..59
139 * - the value of year is in network-byte order
140 * - daylight saving time in New Zealand is +13
142 * For example, Tuesday May 26, 1992 at 1:30:15 PM EDT would be
145 * 1992-5-26,13:30:15.0,-4:0
147 * Returns -1 in case of an error or the length of the string (8 or 11)
148 * Actually returns always 11 on freebsd
151 OS_getSystemDate(struct snmp_value *value)
153 u_char s_date_time[11];
156 struct timeval right_now;
159 if (gettimeofday(&right_now, NULL) < 0) {
160 syslog(LOG_ERR, "gettimeofday failed: %m");
161 return (SNMP_ERR_GENERR);
164 tloc_time_t = right_now.tv_sec;
166 if (localtime_r(&tloc_time_t, &tloc_tm) == NULL) {
167 syslog(LOG_ERR, "localtime_r() failed: %m ");
168 return (SNMP_ERR_GENERR);
171 string_len = make_date_time(s_date_time, &tloc_tm,
172 right_now.tv_usec / 100000);
174 return (string_get(value, s_date_time, string_len));
178 * Get kernel boot path. For FreeBSD it seems that no arguments are
179 * present. Returns NULL if an error occured. The returned data is a
180 * pointer to a global strorage.
183 OS_getSystemInitialLoadParameters(u_char **params)
186 if (boot_line == NULL) {
187 int mib[2] = { CTL_KERN, KERN_BOOTFILE };
191 /* get the needed buffer len */
192 if (sysctl(mib, 2, NULL, &buf_len, NULL, 0) != 0) {
194 "sysctl({CTL_KERN,KERN_BOOTFILE}) failed: %m");
195 return (SNMP_ERR_GENERR);
198 if ((buf = malloc(buf_len)) == NULL) {
199 syslog(LOG_ERR, "malloc failed");
200 return (SNMP_ERR_GENERR);
202 if (sysctl(mib, 2, buf, &buf_len, NULL, 0)) {
204 "sysctl({CTL_KERN,KERN_BOOTFILE}) failed: %m");
206 return (SNMP_ERR_GENERR);
210 HRDBG("kernel boot file: %s", boot_line);
214 return (SNMP_ERR_NOERROR);
218 * Get number of current users which are logged in
221 OS_getSystemNumUsers(uint32_t *nu)
224 static int first_time = 1;
226 if (utmp_fp == NULL) {
228 return (SNMP_ERR_GENERR);
230 if ((utmp_fp = fopen(_PATH_UTMP, "r")) == NULL) {
231 syslog(LOG_ERR, "fopen(%s) failed: %m", _PATH_UTMP);
232 return (SNMP_ERR_GENERR);
236 /* start with the begining of the utmp file */
237 (void)rewind(utmp_fp);
240 while (fread(&utmp, sizeof(utmp), 1, utmp_fp) == 1) {
241 if (utmp.ut_name[0] != '\0' && utmp.ut_line[0] != '\0') {
242 if (getpwnam(utmp.ut_name) == NULL)
248 return (SNMP_ERR_NOERROR);
252 * Get number of current processes existing into the system
255 OS_getSystemProcesses(uint32_t *proc_count)
260 return (SNMP_ERR_GENERR);
262 if (kvm_getprocs(hr_kd, KERN_PROC_ALL, 0, &pc) == NULL) {
263 syslog(LOG_ERR, "kvm_getprocs failed: %m");
264 return (SNMP_ERR_GENERR);
268 return (SNMP_ERR_NOERROR);
272 * Get maximum number of processes allowed on this system
275 OS_getSystemMaxProcesses(uint32_t *mproc)
279 int mib[2] = { CTL_KERN, KERN_MAXPROC };
281 size_t len = sizeof(mp);
283 if (sysctl(mib, 2, &mp, &len, NULL, 0) == -1) {
284 syslog(LOG_ERR, "sysctl KERN_MAXPROC failed: %m");
285 return (SNMP_ERR_GENERR);
291 return (SNMP_ERR_NOERROR);
295 * Get the physical memeory size in Kbytes.
296 * Returns SNMP error code.
299 OS_getMemorySize(uint32_t *ms)
302 if (phys_mem_size == 0) {
303 int mib[2] = { CTL_HW, HW_PHYSMEM };
305 size_t len = sizeof(physmem);
307 if (sysctl(mib, 2, &physmem, &len, NULL, 0) == -1) {
309 "sysctl({ CTL_HW, HW_PHYSMEM }) failed: %m");
310 return (SNMP_ERR_GENERR);
313 phys_mem_size = physmem / 1024;
316 if (phys_mem_size > UINT32_MAX)
320 return (SNMP_ERR_NOERROR);
324 * Try to use the s_date_time parameter as a DateAndTime TC to fill in
325 * the second parameter.
326 * Returns 0 on succes and -1 for an error.
327 * Bug: time zone info is not used
329 static struct timeval *
330 OS_checkSystemDateInput(const u_char *str, u_int len)
336 if (len != 8 && len != 11)
339 if (str[2] == 0 || str[2] > 12 ||
340 str[3] == 0 || str[3] > 31 ||
341 str[4] > 23 || str[5] > 59 || str[6] > 60 || str[7] > 9)
344 tm_to_set.tm_year = ((str[0] << 8) + str[1]) - 1900;
345 tm_to_set.tm_mon = str[2] - 1;
346 tm_to_set.tm_mday = str[3];
347 tm_to_set.tm_hour = str[4];
348 tm_to_set.tm_min = str[5];
349 tm_to_set.tm_sec = str[6];
350 tm_to_set.tm_isdst = 0;
352 /* now make UTC from it */
353 if ((t = timegm(&tm_to_set)) == (time_t)-1)
356 /* now apply timezone if specified */
358 if (str[9] > 13 || str[10] > 59)
361 t += 3600 * str[9] + 60 * str[10];
363 t -= 3600 * str[9] + 60 * str[10];
366 if ((tv = malloc(sizeof(*tv))) == NULL)
370 tv->tv_usec = (int32_t)str[7] * 100000;
376 * Set system date and time. Timezone is not changed
379 OS_setSystemDate(const struct timeval *timeval_to_set)
381 if (settimeofday(timeval_to_set, NULL) == -1) {
382 syslog(LOG_ERR, "settimeofday failed: %m");
383 return (SNMP_ERR_GENERR);
385 return (SNMP_ERR_NOERROR);
389 * prototype of this function was genrated by gensnmptree tool in header file
391 * Returns SNMP_ERR_NOERROR on success
394 op_hrSystem(struct snmp_context *ctx, struct snmp_value *value,
395 u_int sub, u_int iidx __unused, enum snmp_op curr_op)
403 switch (value->var.subs[sub - 1]) {
405 case LEAF_hrSystemUptime:
406 return (OS_getSystemUptime(&value->v.uint32));
408 case LEAF_hrSystemDate:
409 return (OS_getSystemDate(value));
411 case LEAF_hrSystemInitialLoadDevice:
412 value->v.uint32 = 0; /* FIXME */
413 return (SNMP_ERR_NOERROR);
415 case LEAF_hrSystemInitialLoadParameters:
416 if ((err = OS_getSystemInitialLoadParameters(&str)) !=
419 return (string_get(value, str, -1));
421 case LEAF_hrSystemNumUsers:
422 return (OS_getSystemNumUsers(&value->v.uint32));
424 case LEAF_hrSystemProcesses:
425 return (OS_getSystemProcesses(&value->v.uint32));
427 case LEAF_hrSystemMaxProcesses:
428 return (OS_getSystemMaxProcesses(&value->v.uint32));
433 switch (value->var.subs[sub - 1]) {
435 case LEAF_hrSystemDate:
436 if ((ctx->scratch->ptr1 =
437 OS_checkSystemDateInput(value->v.octetstring.octets,
438 value->v.octetstring.len)) == NULL)
439 return (SNMP_ERR_WRONG_VALUE);
441 return (SNMP_ERR_NOERROR);
443 case LEAF_hrSystemInitialLoadDevice:
444 case LEAF_hrSystemInitialLoadParameters:
445 return (SNMP_ERR_NOT_WRITEABLE);
450 case SNMP_OP_ROLLBACK:
451 switch (value->var.subs[sub - 1]) {
453 case LEAF_hrSystemDate:
454 free(ctx->scratch->ptr1);
455 return (SNMP_ERR_NOERROR);
457 case LEAF_hrSystemInitialLoadDevice:
458 case LEAF_hrSystemInitialLoadParameters:
464 switch (value->var.subs[sub - 1]) {
466 case LEAF_hrSystemDate:
467 (void)OS_setSystemDate(ctx->scratch->ptr1);
468 free(ctx->scratch->ptr1);
469 return (SNMP_ERR_NOERROR);
471 case LEAF_hrSystemInitialLoadDevice:
472 case LEAF_hrSystemInitialLoadParameters:
477 case SNMP_OP_GETNEXT:
484 * prototype of this function was genrated by gensnmptree tool
485 * in the header file hostres_tree.h
486 * Returns SNMP_ERR_NOERROR on success
489 op_hrStorage(struct snmp_context *ctx __unused, struct snmp_value *value,
490 u_int sub, u_int iidx __unused, enum snmp_op curr_op)
493 /* only GET is possible */
497 switch (value->var.subs[sub - 1]) {
499 case LEAF_hrMemorySize:
500 return (OS_getMemorySize(&value->v.uint32));
505 return (SNMP_ERR_NOT_WRITEABLE);
507 case SNMP_OP_ROLLBACK:
509 case SNMP_OP_GETNEXT: