uptime plugin: Shuffle some preprocessor stuff around.
[collectd.git] / src / uptime.c
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  **/
21
22 #include "collectd.h"
23 #include "common.h"
24 #include "plugin.h"
25
26 #if KERNEL_LINUX
27 # define UPTIME_FILE "/proc/uptime"
28 /* No need for includes, using /proc filesystem, Linux only. */
29 /* #endif KERNEL_LINUX */
30
31 #elif HAVE_LIBKSTAT
32 /* Using kstats chain to retrieve the boot time, this applies to:
33  * - Solaris / OpenSolaris
34  */
35 /* #endif HAVE_LIBKSTAT */
36
37 #elif HAVE_SYS_SYSCTL_H
38 # include <sys/sysctl.h>
39 /* Using sysctl interface to retrieve the boot time, this applies to:
40  * - *BSD
41  * - Darwin / OS X
42  */
43 /* #endif HAVE_SYS_SYSCTL_H */
44
45 #else
46 # error "No applicable input method."
47 #endif
48
49 /* 
50  * Global variables
51  */
52 #if KERNEL_LINUX
53 /* global variables not needed */
54 /* #endif KERNEL_LINUX */
55
56 #elif HAVE_LIBKSTAT
57 static time_t boottime;
58 extern kstat_ctl_t *kc;
59 /* #endif HAVE_LIBKSTAT */
60
61 #elif HAVE_SYS_SYSCTL_H
62 static time_t boottime;
63 #endif
64
65 static void uptime_submit (gauge_t uptime)
66 {
67         value_t values[1];
68         value_list_t vl = VALUE_LIST_INIT;
69
70         values[0].gauge = uptime;
71
72         vl.values = values;
73         vl.values_len = 1;
74
75         sstrncpy (vl.host, hostname_g, sizeof (vl.host));
76         sstrncpy (vl.plugin, "uptime", sizeof (vl.plugin));
77         sstrncpy (vl.type, "uptime", sizeof (vl.type));
78
79         plugin_dispatch_values (&vl);
80 }
81
82 #if !defined(KERNEL_LINUX) || !KERNEL_LINUX
83 static int uptime_init (void)
84 {
85 /*      NOTE
86
87         On unix systems other than Linux there is no /proc filesystem which
88         calculates the uptime every time we call a read for the /proc/uptime
89         file, the only information available is the boot time (in unix time,
90         since epoch). Hence there is no need to read, every time the
91         plugin_read is called, a value that won't change: this is a right
92         task for the uptime_init function. However, since uptime_init is run
93         only once, if the function fails in retrieving the boot time, the
94         plugin is unregistered and there is no chance to try again later.
95         Nevertheless, this is very unlikely to happen.
96  */
97
98 # if HAVE_LIBKSTAT
99         kstat_t *ksp;
100         kstat_named_t *knp;
101
102         ksp = NULL;
103         knp = NULL;
104
105         /* kstats chain already opened by update_kstat (using *kc), let's verify everything went fine. */
106         if (kc == NULL)
107         {
108                 ERROR ("uptime plugin: kstat chain control structure not available.");
109                 return (-1);
110         }
111
112         ksp = kstat_lookup (kc, "unix", 0, "system_misc");
113         if (ksp == NULL)
114         {
115                 ERROR ("uptime plugin: Cannot find unix:0:system_misc kstat.");
116                 return (-1);
117         }
118
119         if (kstat_read (kc, ksp, NULL) < 0)
120         {
121                 ERROR ("uptime plugin: kstat_read failed.");
122                 return (-1);
123         }
124
125         knp = (kstat_named_t *) kstat_data_lookup (ksp, "boot_time");
126         if (knp == NULL)
127         {
128                 ERROR ("uptime plugin: kstat_data_lookup (boot_time) failed.");
129                 return (-1);
130         }
131
132         boottime = (time_t) knp->value.ui32;
133 /* #endif HAVE_LIBKSTAT */
134
135 # elif HAVE_SYS_SYSCTL_H
136         struct timeval boottv;
137         size_t boottv_len;
138         int status;
139
140         int mib[2];
141
142         mib[0] = CTL_KERN;
143         mib[1] = KERN_BOOTTIME;
144
145         memset (&boottv, 0, sizeof (boottv));
146         boottv_len = sizeof (boottv);
147
148         status = sysctl (mib, STATIC_ARRAY_SIZE (mib), &boottv, &boottv_len,
149                         /* new_value = */ NULL, /* new_length = */ 0);
150         if (status != 0)
151         {
152                 char errbuf[1024];
153                 ERROR ("uptime plugin: No value read from sysctl interface: %s",
154                         sstrerror (errno, errbuf, sizeof (errbuf)));
155                 return (-1);
156         }
157
158         boottime = boottv.tv_sec;
159         if (boottime == 0)
160         {
161                 ERROR ("uptime plugin: sysctl(3) returned success, "
162                                 "but `boottime' is zero!");
163                 return (-1);
164         }
165 #endif /* HAVE_SYS_SYSCTL_H */
166
167         return (0);
168
169 }
170 #endif /* !KERNEL_LINUX */
171
172 static int uptime_read (void)
173 {
174         gauge_t uptime;
175
176 #if KERNEL_LINUX
177         FILE *fh;
178
179         fh = fopen (UPTIME_FILE, "r");
180
181         if (fh == NULL)
182         {
183                 char errbuf[1024];
184                 ERROR ("uptime plugin: Cannot open "UPTIME_FILE": %s",
185                         sstrerror (errno, errbuf, sizeof (errbuf)));
186                 return (-1);
187         }
188
189         if ( fscanf (fh, "%lf", &uptime) < 1 )
190         {
191                 WARNING ("uptime plugin: No value read from "UPTIME_FILE);
192                 fclose (fh);
193                 return (-1);
194         }
195
196         fclose (fh);
197 /* #endif KERNEL_LINUX */
198
199 #elif HAVE_LIBKSTAT || HAVE_SYS_SYSCTL_H
200         time_t elapsed;
201
202         elapsed = time (NULL) - boottime;
203
204         uptime = (gauge_t) elapsed;
205 #endif /* HAVE_LIBKSTAT || HAVE_SYS_SYSCTL_H */
206
207         uptime_submit (uptime);
208
209         return (0);
210 }
211
212 void module_register (void)
213 {
214 #if !defined(KERNEL_LINUX) || !KERNEL_LINUX
215         plugin_register_init ("uptime", uptime_init);
216 #endif
217         plugin_register_read ("uptime", uptime_read);
218 } /* void module_register */