Code

Merge branch 'collectd-4.6'
[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  **/
22 #include "collectd.h"
23 #include "common.h"
24 #include "plugin.h"
26 #if KERNEL_LINUX
27 # define UPTIME_FILE "/proc/uptime"
28 /* No need for includes, using /proc filesystem, Linux only. */
29 /* #endif KERNEL_LINUX */
31 #elif HAVE_LIBKSTAT
32 /* Using kstats chain to retrieve the boot time, this applies to:
33  * - Solaris / OpenSolaris
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, this applies to:
40  * - *BSD
41  * - Darwin / OS X
42  */
43 /* #endif HAVE_SYS_SYSCTL_H */
45 #else
46 # error "No applicable input method."
47 #endif
49 /* 
50  * Global variables
51  */
52 #if KERNEL_LINUX
53 /* global variables not needed */
54 /* #endif KERNEL_LINUX */
56 #elif HAVE_LIBKSTAT
57 static time_t boottime;
58 extern kstat_ctl_t *kc;
59 /* #endif HAVE_LIBKSTAT */
61 #elif HAVE_SYS_SYSCTL_H
62 static time_t boottime;
63 #endif
65 static void uptime_submit (gauge_t uptime)
66 {
67         value_t values[1];
68         value_list_t vl = VALUE_LIST_INIT;
70         values[0].gauge = uptime;
72         vl.values = values;
73         vl.values_len = 1;
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));
79         plugin_dispatch_values (&vl);
80 }
82 #if !defined(KERNEL_LINUX) || !KERNEL_LINUX
83 static int uptime_init (void)
84 {
85 /*      NOTE
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  */
98 # if HAVE_LIBKSTAT
99         kstat_t *ksp;
100         kstat_named_t *knp;
102         ksp = NULL;
103         knp = NULL;
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         }
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         }
119         if (kstat_read (kc, ksp, NULL) < 0)
120         {
121                 ERROR ("uptime plugin: kstat_read failed.");
122                 return (-1);
123         }
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         }
132         boottime = (time_t) knp->value.ui32;
133 /* #endif HAVE_LIBKSTAT */
135 # elif HAVE_SYS_SYSCTL_H
136         struct timeval boottv;
137         size_t boottv_len;
138         int status;
140         int mib[2];
142         mib[0] = CTL_KERN;
143         mib[1] = KERN_BOOTTIME;
145         memset (&boottv, 0, sizeof (boottv));
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         {
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         }
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 */
167         return (0);
170 #endif /* !KERNEL_LINUX */
172 static int uptime_read (void)
174         gauge_t uptime;
176 #if KERNEL_LINUX
177         FILE *fh;
179         fh = fopen (UPTIME_FILE, "r");
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         }
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         }
196         fclose (fh);
197 /* #endif KERNEL_LINUX */
199 #elif HAVE_LIBKSTAT || HAVE_SYS_SYSCTL_H
200         time_t elapsed;
202         elapsed = time (NULL) - boottime;
204         uptime = (gauge_t) elapsed;
205 #endif /* HAVE_LIBKSTAT || HAVE_SYS_SYSCTL_H */
207         uptime_submit (uptime);
209         return (0);
212 void module_register (void)
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 */