e7479e894673defa93964af0a3cb0d9ca023f236
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 #define STAT_FILE "/proc/stat"
29 /* Using /proc filesystem to retrieve the boot time, Linux only. */
30 /* #endif KERNEL_LINUX */
32 #elif HAVE_LIBKSTAT
33 /* Using kstats chain to retrieve the boot time on Solaris / OpenSolaris systems
34 */
35 /* #endif HAVE_LIBKSTAT */
37 #elif HAVE_SYS_SYSCTL_H
38 #include <sys/sysctl.h>
39 /* Using sysctl interface to retrieve the boot time on *BSD / Darwin / OS X
40 * systems */
41 /* #endif HAVE_SYS_SYSCTL_H */
43 #elif HAVE_PERFSTAT
44 #include <libperfstat.h>
45 #include <sys/protosw.h>
46 /* Using perfstat_cpu_total to retrive the boot time in AIX */
47 /* #endif HAVE_PERFSTAT */
49 #else
50 #error "No applicable input method."
51 #endif
53 /*
54 * Global variables
55 */
56 /* boottime always used, no OS distinction */
57 static time_t boottime;
59 #if HAVE_LIBKSTAT
60 extern kstat_ctl_t *kc;
61 #endif /* #endif HAVE_LIBKSTAT */
63 static void uptime_submit(gauge_t uptime) {
64 value_t values[1];
65 value_list_t vl = VALUE_LIST_INIT;
67 values[0].gauge = uptime;
69 vl.values = values;
70 vl.values_len = 1;
72 sstrncpy(vl.host, hostname_g, sizeof(vl.host));
73 sstrncpy(vl.plugin, "uptime", sizeof(vl.plugin));
74 sstrncpy(vl.type, "uptime", sizeof(vl.type));
76 plugin_dispatch_values(&vl);
77 }
79 static int uptime_init(void) /* {{{ */
80 {
81 /*
82 * On most unix systems the uptime is calculated by looking at the boot
83 * time (stored in unix time, since epoch) and the current one. We are
84 * going to do the same, reading the boot time value while executing
85 * the uptime_init function (there is no need to read, every time the
86 * plugin_read is called, a value that won't change). However, since
87 * uptime_init is run only once, if the function fails in retrieving
88 * the boot time, the plugin is unregistered and there is no chance to
89 * try again later. Nevertheless, this is very unlikely to happen.
90 */
92 #if KERNEL_LINUX
93 unsigned long starttime;
94 char buffer[1024];
95 int ret;
96 FILE *fh;
98 ret = 0;
100 fh = fopen(STAT_FILE, "r");
102 if (fh == NULL) {
103 char errbuf[1024];
104 ERROR("uptime plugin: Cannot open " STAT_FILE ": %s",
105 sstrerror(errno, errbuf, sizeof(errbuf)));
106 return (-1);
107 }
109 while (fgets(buffer, 1024, fh) != NULL) {
110 /* look for the btime string and read the value */
111 ret = sscanf(buffer, "btime %lu", &starttime);
112 /* avoid further loops if btime has been found and read
113 * correctly (hopefully) */
114 if (ret == 1)
115 break;
116 }
118 fclose(fh);
120 /* loop done, check if no value has been found/read */
121 if (ret != 1) {
122 ERROR("uptime plugin: No value read from " STAT_FILE "");
123 return (-1);
124 }
126 boottime = (time_t)starttime;
128 if (boottime == 0) {
129 ERROR("uptime plugin: btime read from " STAT_FILE ", "
130 "but `boottime' is zero!");
131 return (-1);
132 }
133 /* #endif KERNEL_LINUX */
135 #elif HAVE_LIBKSTAT
136 kstat_t *ksp;
137 kstat_named_t *knp;
139 ksp = NULL;
140 knp = NULL;
142 /* kstats chain already opened by update_kstat (using *kc), verify everything
143 * went fine. */
144 if (kc == NULL) {
145 ERROR("uptime plugin: kstat chain control structure not available.");
146 return (-1);
147 }
149 ksp = kstat_lookup(kc, "unix", 0, "system_misc");
150 if (ksp == NULL) {
151 ERROR("uptime plugin: Cannot find unix:0:system_misc kstat.");
152 return (-1);
153 }
155 if (kstat_read(kc, ksp, NULL) < 0) {
156 ERROR("uptime plugin: kstat_read failed.");
157 return (-1);
158 }
160 knp = (kstat_named_t *)kstat_data_lookup(ksp, "boot_time");
161 if (knp == NULL) {
162 ERROR("uptime plugin: kstat_data_lookup (boot_time) failed.");
163 return (-1);
164 }
166 boottime = (time_t)knp->value.ui32;
168 if (boottime == 0) {
169 ERROR("uptime plugin: kstat_data_lookup returned success, "
170 "but `boottime' is zero!");
171 return (-1);
172 }
173 /* #endif HAVE_LIBKSTAT */
175 #elif HAVE_SYS_SYSCTL_H
176 struct timeval boottv = {0};
177 size_t boottv_len;
178 int status;
180 int mib[] = {CTL_KERN, KERN_BOOTTIME};
182 boottv_len = sizeof(boottv);
184 status = sysctl(mib, STATIC_ARRAY_SIZE(mib), &boottv, &boottv_len,
185 /* new_value = */ NULL, /* new_length = */ 0);
186 if (status != 0) {
187 char errbuf[1024];
188 ERROR("uptime plugin: No value read from sysctl interface: %s",
189 sstrerror(errno, errbuf, sizeof(errbuf)));
190 return (-1);
191 }
193 boottime = boottv.tv_sec;
195 if (boottime == 0) {
196 ERROR("uptime plugin: sysctl(3) returned success, "
197 "but `boottime' is zero!");
198 return (-1);
199 }
200 /* #endif HAVE_SYS_SYSCTL_H */
202 #elif HAVE_PERFSTAT
203 int status;
204 perfstat_cpu_total_t cputotal;
205 int hertz;
207 status = perfstat_cpu_total(NULL, &cputotal, sizeof(perfstat_cpu_total_t), 1);
208 if (status < 0) {
209 char errbuf[1024];
210 ERROR("uptime plugin: perfstat_cpu_total: %s",
211 sstrerror(errno, errbuf, sizeof(errbuf)));
212 return (-1);
213 }
215 hertz = sysconf(_SC_CLK_TCK);
216 if (hertz <= 0)
217 hertz = HZ;
219 boottime = time(NULL) - cputotal.lbolt / hertz;
220 #endif /* HAVE_PERFSTAT */
222 return (0);
223 } /* }}} int uptime_init */
225 static int uptime_read(void) {
226 gauge_t uptime;
227 time_t elapsed;
229 /* calculate the amount of time elapsed since boot, AKA uptime */
230 elapsed = time(NULL) - boottime;
232 uptime = (gauge_t)elapsed;
234 uptime_submit(uptime);
236 return (0);
237 }
239 void module_register(void) {
240 plugin_register_init("uptime", uptime_init);
241 plugin_register_read("uptime", uptime_read);
242 } /* void module_register */