Merge branch 'sb/iptables'
[collectd.git] / src / irq.c
1 /**
2  * collectd - src/irq.c
3  * Copyright (C) 2007  Peter Holik
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; either version 2 of the License, or (at your
8  * option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful, but
11  * WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License along
16  * with this program; if not, write to the Free Software Foundation, Inc.,
17  * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
18  *
19  * Authors:
20  *   Peter Holik <peter at holik.at>
21  **/
22
23 #include "collectd.h"
24 #include "common.h"
25 #include "plugin.h"
26 #include "configfile.h"
27
28 #define MODULE_NAME "irq"
29
30 #if KERNEL_LINUX
31 # define IRQ_HAVE_READ 1
32 #else
33 # define IRQ_HAVE_READ 0
34 #endif
35
36 #define BUFSIZE 128
37
38 /*
39  * (Module-)Global variables
40  */
41 static char *irq_file   = "irq/irq-%s.rrd";
42
43 static char *config_keys[] =
44 {
45         "Irq",
46         "IgnoreSelected",
47         NULL
48 };
49 static int config_keys_num = 2;
50
51 static char *ds_def[] =
52 {
53         "DS:value:COUNTER:"COLLECTD_HEARTBEAT":0:65535",
54         NULL
55 };
56 static int ds_num = 1;
57
58 static unsigned int *irq_list;
59 static unsigned int irq_list_num;
60
61 /* 
62  * irq_list_action:
63  * 0 => default is to collect selected irqs
64  * 1 => ignore selcted irqs
65  */
66 static int irq_list_action;
67
68 static int irq_config (char *key, char *value)
69 {
70         if (strcasecmp (key, "Irq") == 0)
71         {
72                 unsigned int *temp;
73                 unsigned int irq;
74                 char *endptr;
75
76                 temp = (unsigned int *) realloc (irq_list, (irq_list_num + 1) * sizeof (unsigned int *));
77                 if (temp == NULL)
78                 {
79                         fprintf (stderr, "irq plugin: Cannot allocate more memory.\n");
80                         syslog (LOG_ERR, "irq plugin: Cannot allocate more memory.");
81                         return (1);
82                 }
83                 irq_list = temp;
84
85                 /* Clear errno, because we need it to see if an error occured. */
86                 errno = 0;
87
88                 irq = strtol(value, &endptr, 10);
89                 if ((endptr == value) || (errno != 0))
90                 {
91                         fprintf (stderr, "irq plugin: Irq value is not a "
92                                         "number: `%s'\n", value);
93                         syslog (LOG_ERR, "irq plugin: Irq value is not a "
94                                         "number: `%s'", value);
95                         return (1);
96                 }
97                 irq_list[irq_list_num] = irq;
98                 irq_list_num++;
99         }
100         else if (strcasecmp (key, "IgnoreSelected") == 0)
101         {
102                 if ((strcasecmp (value, "True") == 0)
103                                 || (strcasecmp (value, "Yes") == 0)
104                                 || (strcasecmp (value, "On") == 0))
105                         irq_list_action = 1;
106                 else
107                         irq_list_action = 0;
108         }
109         else
110         {
111                 return (-1);
112         }
113         return (0);
114 }
115
116 /*
117  * Check if this interface/instance should be ignored. This is called from
118  * both, `submit' and `write' to give client and server the ability to
119  * ignore certain stuff..
120  */
121 static int check_ignore_irq (const unsigned int irq)
122 {
123         int i;
124
125         if (irq_list_num < 1)
126                 return (0);
127
128         for (i = 0; i < irq_list_num; i++)
129                 if (irq == irq_list[i])
130                         return (irq_list_action);
131
132         return (1 - irq_list_action);
133 }
134
135 static void irq_write (char *host, char *inst, char *value)
136 {
137         char file[BUFSIZE];
138         int status;
139
140         if (check_ignore_irq (atoi(inst)))
141                 return;
142
143         status = snprintf (file, BUFSIZE, irq_file, inst);
144         if (status < 1)
145                 return;
146         else if (status >= BUFSIZE)
147                 return;
148
149         rrd_update_file (host, file, value, ds_def, ds_num);
150 }
151
152 #if IRQ_HAVE_READ
153 static void irq_submit (unsigned int irq, unsigned int value)
154 {
155         char value_str[32];
156         char type_str[16];
157         int  status;
158
159         if (check_ignore_irq (irq))
160                 return;
161
162         status = snprintf (value_str, 32, "%u:%u",
163                                 (unsigned int) curtime, value);
164         if ((status >= 32) || (status < 1))
165                 return;
166
167         status = snprintf (type_str, 16, "%u", irq);
168         if ((status >= 16) || (status < 1))
169                 return;
170
171         plugin_submit (MODULE_NAME, type_str, value_str);
172 } /* void irq_submit */
173
174 static void irq_read (void)
175 {
176 #if KERNEL_LINUX
177
178 #undef BUFSIZE
179 #define BUFSIZE 256
180
181         FILE *fh;
182         char buffer[BUFSIZE];
183         unsigned int irq;
184         unsigned int irq_value;
185         long value;
186         char *endptr;
187         int i;
188
189         char *fields[64];
190         int fields_num;
191
192         if ((fh = fopen ("/proc/interrupts", "r")) == NULL)
193         {
194                 syslog (LOG_WARNING, "irq plugin: fopen (/proc/interrupts): %s",
195                                 strerror (errno));
196                 return;
197         }
198         while (fgets (buffer, BUFSIZE, fh) != NULL)
199         {
200                 fields_num = strsplit (buffer, fields, 64);
201                 if (fields_num < 2)
202                         continue;
203
204                 errno = 0;    /* To distinguish success/failure after call */
205                 irq = strtol (fields[0], &endptr, 10);
206
207                 if ((endptr == fields[0]) || (errno != 0) || (*endptr != ':'))
208                         continue;
209
210                 irq_value = 0;
211                 for (i = 1; i < fields_num; i++)
212                 {
213                         errno = 0;
214                         value = strtol (fields[i], &endptr, 10);
215
216                         if ((*endptr != '\0') || (errno != 0))
217                                 break;
218
219                         irq_value += value;
220                 } /* for (i) */
221
222                 irq_submit (irq, irq_value);
223         }
224         fclose (fh);
225 #endif /* KERNEL_LINUX */
226 } /* void irq_read */
227 #else
228 #define irq_read NULL
229 #endif /* IRQ_HAVE_READ */
230
231 void module_register (void)
232 {
233         plugin_register (MODULE_NAME, NULL, irq_read, irq_write);
234         cf_register (MODULE_NAME, irq_config, config_keys, config_keys_num);
235 }
236
237 #undef BUFSIZE
238 #undef MODULE_NAME