{GPL, other}: Relicense to MIT license.
[collectd.git] / src / protocols.c
1 /**
2  * collectd - src/protocols.c
3  * Copyright (C) 2009,2010  Florian octo Forster
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included in
13  * all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21  * DEALINGS IN THE SOFTWARE.
22  *
23  * Authors:
24  *   Florian octo Forster <octo at collectd.org>
25  **/
26
27 #include "collectd.h"
28 #include "common.h"
29 #include "plugin.h"
30 #include "utils_ignorelist.h"
31
32 #if !KERNEL_LINUX
33 # error "No applicable input method."
34 #endif
35
36 #define SNMP_FILE "/proc/net/snmp"
37 #define NETSTAT_FILE "/proc/net/netstat"
38
39 /*
40  * Global variables
41  */
42 static const char *config_keys[] =
43 {
44   "Value",
45   "IgnoreSelected",
46 };
47 static int config_keys_num = STATIC_ARRAY_SIZE (config_keys);
48
49 static ignorelist_t *values_list = NULL;
50
51 /* 
52  * Functions
53  */
54 static void submit (const char *protocol_name,
55     const char *str_key, const char *str_value)
56 {
57   value_t values[1];
58   value_list_t vl = VALUE_LIST_INIT;
59   int status;
60
61   status = parse_value (str_value, values, DS_TYPE_DERIVE);
62   if (status != 0)
63   {
64     ERROR ("protocols plugin: Parsing string as integer failed: %s",
65         str_value);
66     return;
67   }
68
69   vl.values = values;
70   vl.values_len = 1;
71   sstrncpy (vl.host, hostname_g, sizeof (vl.host));
72   sstrncpy (vl.plugin, "protocols", sizeof (vl.plugin));
73   sstrncpy (vl.plugin_instance, protocol_name, sizeof (vl.plugin_instance));
74   sstrncpy (vl.type, "protocol_counter", sizeof (vl.type));
75   sstrncpy (vl.type_instance, str_key, sizeof (vl.type_instance));
76
77   plugin_dispatch_values (&vl);
78 } /* void submit */
79
80 static int read_file (const char *path)
81 {
82   FILE *fh;
83   char key_buffer[4096];
84   char value_buffer[4096];
85   char *key_ptr;
86   char *value_ptr;
87   char *key_fields[256];
88   char *value_fields[256];
89   int key_fields_num;
90   int value_fields_num;
91   int status;
92   int i;
93
94   fh = fopen (path, "r");
95   if (fh == NULL)
96   {
97     ERROR ("protocols plugin: fopen (%s) failed: %s.",
98         path, sstrerror (errno, key_buffer, sizeof (key_buffer)));
99     return (-1);
100   }
101
102   status = -1;
103   while (42)
104   {
105     clearerr (fh);
106     key_ptr = fgets (key_buffer, sizeof (key_buffer), fh);
107     if (key_ptr == NULL)
108     {
109       if (feof (fh) != 0)
110       {
111         status = 0;
112         break;
113       }
114       else if (ferror (fh) != 0)
115       {
116         ERROR ("protocols plugin: Reading from %s failed.", path);
117         break;
118       }
119       else
120       {
121         ERROR ("protocols plugin: fgets failed for an unknown reason.");
122         break;
123       }
124     } /* if (key_ptr == NULL) */
125
126     value_ptr = fgets (value_buffer, sizeof (value_buffer), fh);
127     if (value_ptr == NULL)
128     {
129       ERROR ("protocols plugin: read_file (%s): Could not read values line.",
130           path);
131       break;
132     }
133
134     key_ptr = strchr (key_buffer, ':');
135     if (key_ptr == NULL)
136     {
137       ERROR ("protocols plugin: Could not find protocol name in keys line.");
138       break;
139     }
140     *key_ptr = 0;
141     key_ptr++;
142
143     value_ptr = strchr (value_buffer, ':');
144     if (value_ptr == NULL)
145     {
146       ERROR ("protocols plugin: Could not find protocol name "
147           "in values line.");
148       break;
149     }
150     *value_ptr = 0;
151     value_ptr++;
152
153     if (strcmp (key_buffer, value_buffer) != 0)
154     {
155       ERROR ("protocols plugin: Protocol names in keys and values lines "
156           "don't match: `%s' vs. `%s'.",
157           key_buffer, value_buffer);
158       break;
159     }
160
161
162     key_fields_num = strsplit (key_ptr,
163         key_fields, STATIC_ARRAY_SIZE (key_fields));
164     value_fields_num = strsplit (value_ptr,
165         value_fields, STATIC_ARRAY_SIZE (value_fields));
166
167     if (key_fields_num != value_fields_num)
168     {
169       ERROR ("protocols plugin: Number of fields in keys and values lines "
170           "don't match: %i vs %i.",
171           key_fields_num, value_fields_num);
172       break;
173     }
174
175     for (i = 0; i < key_fields_num; i++)
176     {
177       if (values_list != NULL)
178       {
179         char match_name[2 * DATA_MAX_NAME_LEN];
180
181         ssnprintf (match_name, sizeof (match_name), "%s:%s",
182             key_buffer, key_fields[i]);
183
184         if (ignorelist_match (values_list, match_name))
185           continue;
186       } /* if (values_list != NULL) */
187
188       submit (key_buffer, key_fields[i], value_fields[i]);
189     } /* for (i = 0; i < key_fields_num; i++) */
190   } /* while (42) */
191
192   fclose (fh);
193
194   return (status);
195 } /* int read_file */
196
197 static int protocols_read (void)
198 {
199   int status;
200   int success = 0;
201
202   status = read_file (SNMP_FILE);
203   if (status == 0)
204     success++;
205
206   status = read_file (NETSTAT_FILE);
207   if (status == 0)
208     success++;
209
210   if (success == 0)
211     return (-1);
212
213   return (0);
214 } /* int protocols_read */
215
216 static int protocols_config (const char *key, const char *value)
217 {
218   if (values_list == NULL)
219     values_list = ignorelist_create (/* invert = */ 1);
220
221   if (strcasecmp (key, "Value") == 0)
222   {
223     ignorelist_add (values_list, value);
224   }
225   else if (strcasecmp (key, "IgnoreSelected") == 0)
226   {
227     int invert = 1;
228     if (IS_TRUE (value))
229       invert = 0;
230     ignorelist_set_invert (values_list, invert);
231   }
232   else
233   {
234     return (-1);
235   }
236
237   return (0);
238 } /* int protocols_config */
239
240 void module_register (void)
241 {
242   plugin_register_config ("protocols", protocols_config,
243       config_keys, config_keys_num);
244   plugin_register_read ("protocols", protocols_read);
245 } /* void module_register */
246
247 /* vim: set sw=2 sts=2 et : */