d51aa391a09040229113c4accae5bb387375b897
1 /**
2 * collectd - src/uptime.c
3 * Copyright (C) 2009 Marco Chiappero
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; only version 2 of the License is applicable.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17 *
18 * Authors:
19 * Marco Chiappero <marco at absence.it>
20 **/
22 #include "collectd.h"
24 #include "common.h"
25 #include "plugin.h"
27 #if KERNEL_LINUX
28 #include <sys/sysinfo.h>
29 /* #endif KERNEL_LINUX */
31 #elif HAVE_LIBKSTAT
32 /* Using kstats chain to retrieve the boot time on Solaris / OpenSolaris systems
33 */
34 /* #endif HAVE_LIBKSTAT */
36 #elif HAVE_SYS_SYSCTL_H
37 #include <sys/sysctl.h>
38 /* Using sysctl interface to retrieve the boot time on *BSD / Darwin / OS X
39 * systems */
40 /* #endif HAVE_SYS_SYSCTL_H */
42 #elif HAVE_PERFSTAT
43 #include <libperfstat.h>
44 #include <sys/protosw.h>
45 /* Using perfstat_cpu_total to retrive the boot time in AIX */
46 /* #endif HAVE_PERFSTAT */
48 #else
49 #error "No applicable input method."
50 #endif
52 /*
53 * Global variables
54 */
56 #if HAVE_LIBKSTAT
57 extern kstat_ctl_t *kc;
58 #endif /* #endif HAVE_LIBKSTAT */
60 static void uptime_submit(gauge_t value) {
61 value_list_t vl = VALUE_LIST_INIT;
63 vl.values = &(value_t){.gauge = value};
64 vl.values_len = 1;
66 sstrncpy(vl.plugin, "uptime", sizeof(vl.plugin));
67 sstrncpy(vl.type, "uptime", sizeof(vl.type));
69 plugin_dispatch_values(&vl);
70 }
72 /*
73 * On most unix systems the uptime is calculated by looking at the boot
74 * time (stored in unix time, since epoch) and the current one. We are
75 * going to do the same, reading the boot time value while executing
76 * the uptime_init function (there is no need to read, every time the
77 * plugin_read is called, a value that won't change). However, since
78 * uptime_init is run only once, if the function fails in retrieving
79 * the boot time, the plugin is unregistered and there is no chance to
80 * try again later. Nevertheless, this is very unlikely to happen.
81 */
82 static time_t uptime_get_sys(void) { /* {{{ */
83 time_t result;
84 #if KERNEL_LINUX
85 struct sysinfo info;
86 int status;
88 status = sysinfo(&info);
89 if (status != 0) {
90 char errbuf[1024];
91 ERROR("uptime plugin: Error calling sysinfo: %s",
92 sstrerror(errno, errbuf, sizeof(errbuf)));
93 return -1;
94 }
96 result = (time_t)info.uptime;
97 /* #endif KERNEL_LINUX */
99 #elif HAVE_LIBKSTAT
100 kstat_t *ksp;
101 kstat_named_t *knp;
103 ksp = NULL;
104 knp = NULL;
106 /* kstats chain already opened by update_kstat (using *kc), verify everything
107 * went fine. */
108 if (kc == NULL) {
109 ERROR("uptime plugin: kstat chain control structure not available.");
110 return -1;
111 }
113 ksp = kstat_lookup(kc, "unix", 0, "system_misc");
114 if (ksp == NULL) {
115 ERROR("uptime plugin: Cannot find unix:0:system_misc kstat.");
116 return -1;
117 }
119 if (kstat_read(kc, ksp, NULL) < 0) {
120 ERROR("uptime plugin: kstat_read failed.");
121 return -1;
122 }
124 knp = (kstat_named_t *)kstat_data_lookup(ksp, "boot_time");
125 if (knp == NULL) {
126 ERROR("uptime plugin: kstat_data_lookup (boot_time) failed.");
127 return -1;
128 }
130 if (knp->value.ui32 == 0) {
131 ERROR("uptime plugin: kstat_data_lookup returned success, "
132 "but `boottime' is zero!");
133 return -1;
134 }
136 result = time(NULL) - (time_t)knp->value.ui32;
137 /* #endif HAVE_LIBKSTAT */
139 #elif HAVE_SYS_SYSCTL_H
140 struct timeval boottv = {0};
141 size_t boottv_len;
142 int status;
144 int mib[] = {CTL_KERN, KERN_BOOTTIME};
146 boottv_len = sizeof(boottv);
148 status = sysctl(mib, STATIC_ARRAY_SIZE(mib), &boottv, &boottv_len,
149 /* new_value = */ NULL, /* new_length = */ 0);
150 if (status != 0) {
151 char errbuf[1024];
152 ERROR("uptime plugin: No value read from sysctl interface: %s",
153 sstrerror(errno, errbuf, sizeof(errbuf)));
154 return -1;
155 }
157 if (boottv.tv_sec == 0) {
158 ERROR("uptime plugin: sysctl(3) returned success, "
159 "but `boottime' is zero!");
160 return -1;
161 }
163 result = time(NULL) - boottv.tv_sec;
164 /* #endif HAVE_SYS_SYSCTL_H */
166 #elif HAVE_PERFSTAT
167 int status;
168 perfstat_cpu_total_t cputotal;
169 int hertz;
171 status = perfstat_cpu_total(NULL, &cputotal, sizeof(perfstat_cpu_total_t), 1);
172 if (status < 0) {
173 char errbuf[1024];
174 ERROR("uptime plugin: perfstat_cpu_total: %s",
175 sstrerror(errno, errbuf, sizeof(errbuf)));
176 return -1;
177 }
179 hertz = sysconf(_SC_CLK_TCK);
180 if (hertz <= 0)
181 hertz = HZ;
183 result = cputotal.lbolt / hertz;
184 #endif /* HAVE_PERFSTAT */
186 return result;
187 } /* }}} int uptime_get_sys */
189 static int uptime_read(void) {
190 gauge_t uptime;
191 time_t elapsed;
193 /* calculate the amount of time elapsed since boot, AKA uptime */
194 elapsed = uptime_get_sys();
196 uptime = (gauge_t)elapsed;
198 uptime_submit(uptime);
200 return 0;
201 }
203 void module_register(void) {
204 plugin_register_read("uptime", uptime_read);
205 } /* void module_register */