src/dp_rrdtool.c: Adapt to new callback prototype.
[collection4.git] / src / filesystem.c
1 /**
2  * collection4 - filesystem.c
3  * Copyright (C) 2010  Florian octo Forster
4  * 
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  * 
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  * 
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor,
18  * Boston, MA  02110-1301  USA
19  *
20  * Authors:
21  *   Florian octo Forster <ff at octo.it>
22  **/
23
24 #include <stdlib.h>
25 #include <unistd.h>
26 #include <stdio.h>
27 #include <string.h>
28 #include <errno.h>
29 #include <limits.h>
30 #include <sys/types.h>
31 #include <sys/stat.h>
32 #include <dirent.h>
33
34 #include "filesystem.h"
35
36 struct fs_scan_dir_data_s /* {{{ */
37 {
38   fs_ident_cb_t callback;
39   void *user_data;
40
41   char *host;
42   char *plugin;
43   char *plugin_instance;
44   char *type;
45   char *type_instance;
46 }; /* }}} */
47 typedef struct fs_scan_dir_data_s fs_scan_dir_data_t;
48
49 typedef int (*callback_type_t)   (const char *type,   void *user_data);
50 typedef int (*callback_plugin_t) (const char *base_dir,
51     const char *plugin, void *user_data);
52 typedef int (*callback_host_t)   (const char *base_dir,
53     const char *host,   void *user_data);
54
55 /*
56  * Directory and file walking functions
57  */
58 static int foreach_rrd_file (const char *dir, /* {{{ */
59     int (*callback) (const char *, void *),
60     void *user_data)
61 {
62   DIR *dh;
63   struct dirent *entry;
64   int status;
65
66   if (callback == NULL)
67     return (EINVAL);
68
69   dh = opendir (dir);
70   if (dh == NULL)
71     return (errno);
72
73   while ((entry = readdir (dh)) != NULL)
74   {
75     struct stat statbuf;
76     char abspath[PATH_MAX + 1];
77     size_t d_name_len;
78
79     if (entry->d_name[0] == '.')
80       continue;
81
82     d_name_len = strlen (entry->d_name);
83     if (d_name_len <= 4)
84       continue;
85
86     if (strcasecmp (".rrd", entry->d_name + (d_name_len - 4)) != 0)
87       continue;
88
89     snprintf (abspath, sizeof (abspath), "%s/%s", dir, entry->d_name);
90     abspath[sizeof (abspath) - 1] = 0;
91
92     memset (&statbuf, 0, sizeof (statbuf));
93
94     status = stat (abspath, &statbuf);
95     if (status != 0)
96       continue;
97
98     if (!S_ISREG (statbuf.st_mode))
99       continue;
100
101     entry->d_name[d_name_len - 4] = 0;
102
103     status = (*callback) (entry->d_name, user_data);
104     if (status != 0)
105       break;
106   } /* while (readdir) */
107
108   closedir (dh);
109   return (status);
110 } /* }}} int foreach_rrd_file */
111
112 static int foreach_type (const char *host, const char *plugin, /* {{{ */
113     callback_type_t callback, void *user_data)
114 {
115   char abspath[PATH_MAX + 1];
116
117   if ((host == NULL) || (plugin == NULL))
118     return (EINVAL);
119
120   snprintf (abspath, sizeof (abspath), "%s/%s/%s", DATA_DIR, host, plugin);
121   abspath[sizeof (abspath) - 1] = 0;
122
123   return (foreach_rrd_file (abspath, callback, user_data));
124 } /* }}} int foreach_type */
125
126 static int foreach_plugin (const char *host, /* {{{ */
127     callback_plugin_t callback,
128     void *user_data)
129 {
130   char abspath[PATH_MAX + 1];
131
132   if (host == NULL)
133     return (EINVAL);
134
135   snprintf (abspath, sizeof (abspath), "%s/%s", DATA_DIR, host);
136   abspath[sizeof (abspath) - 1] = 0;
137
138   return (fs_foreach_dir (abspath, callback, user_data));
139 } /* }}} int foreach_plugin */
140
141 static int foreach_host (callback_host_t callback, /* {{{ */
142     void *user_data)
143 {
144   return (fs_foreach_dir (DATA_DIR, callback, user_data));
145 } /* }}} int foreach_host */
146
147 /*
148  * Functions building "fs_scan_dir_data_t" and calling the user-supplied
149  * callback eventually.
150  */
151 static int scan_type (const char *type, void *user_data) /* {{{ */
152 {
153   fs_scan_dir_data_t *data = user_data;
154   graph_ident_t *ident;
155   int status;
156
157   if ((type == NULL) || (data == NULL))
158     return (EINVAL);
159
160   if ((data->type != NULL) || (data->type_instance != NULL))
161     return (EINVAL);
162
163   data->type = strdup (type);
164   if (data->type == NULL)
165     return (ENOMEM);
166
167   data->type_instance = strchr (data->type, '-');
168   if (data->type_instance != NULL)
169   {
170     *data->type_instance = 0;
171     data->type_instance++;
172   }
173   else
174   {
175     data->type_instance = data->type + strlen (data->type);
176   }
177
178   ident = ident_create (data->host,
179       data->plugin, data->plugin_instance,
180       data->type, data->type_instance);
181   if (ident == NULL)
182   {
183     status = -1;
184   }
185   else
186   {
187     status = (*data->callback) (ident, data->user_data);
188     ident_destroy (ident);
189   }
190
191   free (data->type);
192   data->type = NULL;
193   data->type_instance = NULL;
194
195   return (status);
196 } /* }}} int scan_type */
197
198 static int scan_plugin (__attribute__((unused)) const char *base_dir, /* {{{ */
199     const char *plugin, void *user_data)
200 {
201   fs_scan_dir_data_t *data = user_data;
202   int status;
203
204   if ((plugin == NULL) || (data == NULL))
205     return (EINVAL);
206
207   if ((data->plugin != NULL) || (data->plugin_instance != NULL))
208     return (EINVAL);
209
210   data->plugin = strdup (plugin);
211   if (data->plugin == NULL)
212     return (ENOMEM);
213
214   data->plugin_instance = strchr (data->plugin, '-');
215   if (data->plugin_instance != NULL)
216   {
217     *data->plugin_instance = 0;
218     data->plugin_instance++;
219   }
220   else
221   {
222     data->plugin_instance = data->plugin + strlen (data->plugin);
223   }
224
225   status = foreach_type (data->host, plugin, scan_type, data);
226
227   free (data->plugin);
228   data->plugin = NULL;
229   data->plugin_instance = NULL;
230
231   return (status);
232 } /* }}} int scan_plugin */
233
234 static int scan_host (__attribute__((unused)) const char *base_dir, /* {{{ */
235     const char *host, void *user_data)
236 {
237   fs_scan_dir_data_t *data = user_data;
238   int status;
239
240   if ((host == NULL) || (data == NULL))
241     return (EINVAL);
242
243   if (data->host != NULL)
244     return (EINVAL);
245
246   data->host = strdup (host);
247   if (data->host == NULL)
248     return (ENOMEM);
249
250   status =  foreach_plugin (host, scan_plugin, data);
251
252   free (data->host);
253   data->host = NULL;
254
255   return (status);
256 } /* }}} int scan_host */
257
258 /*
259  * Public function
260  */
261 int fs_foreach_dir (const char *base_dir, /* {{{ */
262     int (*callback) (const char *base_dir, const char *entry, void *),
263     void *user_data)
264 {
265   DIR *dh;
266   struct dirent *entry;
267   int status = 0;
268
269   if (callback == NULL)
270     return (EINVAL);
271
272   dh = opendir (base_dir);
273   if (dh == NULL)
274     return (errno);
275
276   while ((entry = readdir (dh)) != NULL)
277   {
278     struct stat statbuf;
279     char abspath[PATH_MAX + 1];
280
281     if (entry->d_name[0] == '.')
282       continue;
283
284     snprintf (abspath, sizeof (abspath), "%s/%s", base_dir, entry->d_name);
285     abspath[sizeof (abspath) - 1] = 0;
286
287     memset (&statbuf, 0, sizeof (statbuf));
288
289     status = stat (abspath, &statbuf);
290     if (status != 0)
291       continue;
292
293     if (!S_ISDIR (statbuf.st_mode))
294       continue;
295
296     status = (*callback) (base_dir, entry->d_name, user_data);
297     if (status != 0)
298       break;
299   } /* while (readdir) */
300
301   closedir (dh);
302   return (status);
303 } /* }}} int fs_foreach_dir */
304
305 int fs_foreach_file (const char *base_dir, /* {{{ */
306     int (*callback) (const char *base_dir, const char *entry, void *),
307     void *user_data)
308 {
309   DIR *dh;
310   struct dirent *entry;
311   int status = 0;
312
313   if (callback == NULL)
314     return (EINVAL);
315
316   dh = opendir (base_dir);
317   if (dh == NULL)
318     return (errno);
319
320   while ((entry = readdir (dh)) != NULL)
321   {
322     struct stat statbuf;
323     char abspath[PATH_MAX + 1];
324
325     if (entry->d_name[0] == '.')
326       continue;
327
328     snprintf (abspath, sizeof (abspath), "%s/%s", base_dir, entry->d_name);
329     abspath[sizeof (abspath) - 1] = 0;
330
331     memset (&statbuf, 0, sizeof (statbuf));
332
333     status = stat (abspath, &statbuf);
334     if (status != 0)
335       continue;
336
337     if (!S_ISREG (statbuf.st_mode))
338       continue;
339
340     status = (*callback) (base_dir, entry->d_name, user_data);
341     if (status != 0)
342       break;
343   } /* while (readdir) */
344
345   closedir (dh);
346   return (status);
347 } /* }}} int fs_foreach_file */
348
349 int fs_scan (fs_ident_cb_t callback, void *user_data) /* {{{ */
350 {
351   fs_scan_dir_data_t data;
352
353   memset (&data, 0, sizeof (data));
354   data.callback = callback;
355   data.user_data = user_data;
356
357   data.host = NULL;
358   data.plugin = NULL;
359   data.plugin_instance = NULL;
360   data.type = NULL;
361   data.type_instance = NULL;
362
363   foreach_host (scan_host, &data);
364
365   return (0);
366 } /* }}} int fs_scan */
367
368 /* vim: set sw=2 sts=2 et fdm=marker : */