Merge branch 'collectd-5.5' into collectd-5.6
[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
29 #include "common.h"
30 #include "plugin.h"
31 #include "utils_ignorelist.h"
32
33 #if !KERNEL_LINUX
34 # error "No applicable input method."
35 #endif
36
37 #define SNMP_FILE "/proc/net/snmp"
38 #define NETSTAT_FILE "/proc/net/netstat"
39
40 /*
41  * Global variables
42  */
43 static const char *config_keys[] =
44 {
45   "Value",
46   "IgnoreSelected",
47 };
48 static int config_keys_num = STATIC_ARRAY_SIZE (config_keys);
49
50 static ignorelist_t *values_list = NULL;
51
52 /*
53  * Functions
54  */
55 static void submit (const char *protocol_name,
56     const char *str_key, const char *str_value)
57 {
58   value_t values[1];
59   value_list_t vl = VALUE_LIST_INIT;
60   int status;
61
62   status = parse_value (str_value, values, DS_TYPE_DERIVE);
63   if (status != 0)
64   {
65     ERROR ("protocols plugin: Parsing string as integer failed: %s",
66         str_value);
67     return;
68   }
69
70   vl.values = values;
71   vl.values_len = 1;
72   sstrncpy (vl.host, hostname_g, sizeof (vl.host));
73   sstrncpy (vl.plugin, "protocols", sizeof (vl.plugin));
74   sstrncpy (vl.plugin_instance, protocol_name, sizeof (vl.plugin_instance));
75   sstrncpy (vl.type, "protocol_counter", sizeof (vl.type));
76   sstrncpy (vl.type_instance, str_key, sizeof (vl.type_instance));
77
78   plugin_dispatch_values (&vl);
79 } /* void submit */
80
81 static int read_file (const char *path)
82 {
83   FILE *fh;
84   char key_buffer[4096];
85   char value_buffer[4096];
86   char *key_ptr;
87   char *value_ptr;
88   char *key_fields[256];
89   char *value_fields[256];
90   int key_fields_num;
91   int value_fields_num;
92   int status;
93   int i;
94
95   fh = fopen (path, "r");
96   if (fh == NULL)
97   {
98     ERROR ("protocols plugin: fopen (%s) failed: %s.",
99         path, sstrerror (errno, key_buffer, sizeof (key_buffer)));
100     return (-1);
101   }
102
103   status = -1;
104   while (42)
105   {
106     clearerr (fh);
107     key_ptr = fgets (key_buffer, sizeof (key_buffer), fh);
108     if (key_ptr == NULL)
109     {
110       if (feof (fh) != 0)
111       {
112         status = 0;
113         break;
114       }
115       else if (ferror (fh) != 0)
116       {
117         ERROR ("protocols plugin: Reading from %s failed.", path);
118         break;
119       }
120       else
121       {
122         ERROR ("protocols plugin: fgets failed for an unknown reason.");
123         break;
124       }
125     } /* if (key_ptr == NULL) */
126
127     value_ptr = fgets (value_buffer, sizeof (value_buffer), fh);
128     if (value_ptr == NULL)
129     {
130       ERROR ("protocols plugin: read_file (%s): Could not read values line.",
131           path);
132       break;
133     }
134
135     key_ptr = strchr (key_buffer, ':');
136     if (key_ptr == NULL)
137     {
138       ERROR ("protocols plugin: Could not find protocol name in keys line.");
139       break;
140     }
141     *key_ptr = 0;
142     key_ptr++;
143
144     value_ptr = strchr (value_buffer, ':');
145     if (value_ptr == NULL)
146     {
147       ERROR ("protocols plugin: Could not find protocol name "
148           "in values line.");
149       break;
150     }
151     *value_ptr = 0;
152     value_ptr++;
153
154     if (strcmp (key_buffer, value_buffer) != 0)
155     {
156       ERROR ("protocols plugin: Protocol names in keys and values lines "
157           "don't match: `%s' vs. `%s'.",
158           key_buffer, value_buffer);
159       break;
160     }
161
162
163     key_fields_num = strsplit (key_ptr,
164         key_fields, STATIC_ARRAY_SIZE (key_fields));
165     value_fields_num = strsplit (value_ptr,
166         value_fields, STATIC_ARRAY_SIZE (value_fields));
167
168     if (key_fields_num != value_fields_num)
169     {
170       ERROR ("protocols plugin: Number of fields in keys and values lines "
171           "don't match: %i vs %i.",
172           key_fields_num, value_fields_num);
173       break;
174     }
175
176     for (i = 0; i < key_fields_num; i++)
177     {
178       if (values_list != NULL)
179       {
180         char match_name[2 * DATA_MAX_NAME_LEN];
181
182         ssnprintf (match_name, sizeof (match_name), "%s:%s",
183             key_buffer, key_fields[i]);
184
185         if (ignorelist_match (values_list, match_name))
186           continue;
187       } /* if (values_list != NULL) */
188
189       submit (key_buffer, key_fields[i], value_fields[i]);
190     } /* for (i = 0; i < key_fields_num; i++) */
191   } /* while (42) */
192
193   fclose (fh);
194
195   return (status);
196 } /* int read_file */
197
198 static int protocols_read (void)
199 {
200   int status;
201   int success = 0;
202
203   status = read_file (SNMP_FILE);
204   if (status == 0)
205     success++;
206
207   status = read_file (NETSTAT_FILE);
208   if (status == 0)
209     success++;
210
211   if (success == 0)
212     return (-1);
213
214   return (0);
215 } /* int protocols_read */
216
217 static int protocols_config (const char *key, const char *value)
218 {
219   if (values_list == NULL)
220     values_list = ignorelist_create (/* invert = */ 1);
221
222   if (strcasecmp (key, "Value") == 0)
223   {
224     ignorelist_add (values_list, value);
225   }
226   else if (strcasecmp (key, "IgnoreSelected") == 0)
227   {
228     int invert = 1;
229     if (IS_TRUE (value))
230       invert = 0;
231     ignorelist_set_invert (values_list, invert);
232   }
233   else
234   {
235     return (-1);
236   }
237
238   return (0);
239 } /* int protocols_config */
240
241 void module_register (void)
242 {
243   plugin_register_config ("protocols", protocols_config,
244       config_keys, config_keys_num);
245   plugin_register_read ("protocols", protocols_read);
246 } /* void module_register */
247
248 /* vim: set sw=2 sts=2 et : */