src/graph_list.[ch]: Implement "gl_search".
[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 *plugin, void *user_data);
51 typedef int (*callback_host_t)   (const char *host,   void *user_data);
52
53 /*
54  * Directory and file walking functions
55  */
56 static int foreach_rrd_file (const char *dir, /* {{{ */
57     int (*callback) (const char *, void *),
58     void *user_data)
59 {
60   DIR *dh;
61   struct dirent *entry;
62   int status;
63
64   if (callback == NULL)
65     return (EINVAL);
66
67   dh = opendir (dir);
68   if (dh == NULL)
69     return (errno);
70
71   while ((entry = readdir (dh)) != NULL)
72   {
73     struct stat statbuf;
74     char abspath[PATH_MAX + 1];
75     size_t d_name_len;
76
77     if (entry->d_name[0] == '.')
78       continue;
79
80     d_name_len = strlen (entry->d_name);
81     if (d_name_len <= 4)
82       continue;
83
84     if (strcasecmp (".rrd", entry->d_name + (d_name_len - 4)) != 0)
85       continue;
86
87     snprintf (abspath, sizeof (abspath), "%s/%s", dir, entry->d_name);
88     abspath[sizeof (abspath) - 1] = 0;
89
90     memset (&statbuf, 0, sizeof (statbuf));
91
92     status = stat (abspath, &statbuf);
93     if (status != 0)
94       continue;
95
96     if (!S_ISREG (statbuf.st_mode))
97       continue;
98
99     entry->d_name[d_name_len - 4] = 0;
100
101     status = (*callback) (entry->d_name, user_data);
102     if (status != 0)
103       break;
104   } /* while (readdir) */
105
106   closedir (dh);
107   return (status);
108 } /* }}} int foreach_rrd_file */
109
110 static int foreach_dir (const char *dir, /* {{{ */
111     int (*callback) (const char *, void *),
112     void *user_data)
113 {
114   DIR *dh;
115   struct dirent *entry;
116   int status = 0;
117
118   if (callback == NULL)
119     return (EINVAL);
120
121   dh = opendir (dir);
122   if (dh == NULL)
123     return (errno);
124
125   while ((entry = readdir (dh)) != NULL)
126   {
127     struct stat statbuf;
128     char abspath[PATH_MAX + 1];
129
130     if (entry->d_name[0] == '.')
131       continue;
132
133     snprintf (abspath, sizeof (abspath), "%s/%s", dir, entry->d_name);
134     abspath[sizeof (abspath) - 1] = 0;
135
136     memset (&statbuf, 0, sizeof (statbuf));
137
138     status = stat (abspath, &statbuf);
139     if (status != 0)
140       continue;
141
142     if (!S_ISDIR (statbuf.st_mode))
143       continue;
144
145     status = (*callback) (entry->d_name, user_data);
146     if (status != 0)
147       break;
148   } /* while (readdir) */
149
150   closedir (dh);
151   return (status);
152 } /* }}} int foreach_dir */
153
154 static int foreach_type (const char *host, const char *plugin, /* {{{ */
155     callback_type_t callback, void *user_data)
156 {
157   char abspath[PATH_MAX + 1];
158
159   if ((host == NULL) || (plugin == NULL))
160     return (EINVAL);
161
162   snprintf (abspath, sizeof (abspath), "%s/%s/%s", DATA_DIR, host, plugin);
163   abspath[sizeof (abspath) - 1] = 0;
164
165   return (foreach_rrd_file (abspath, callback, user_data));
166 } /* }}} int foreach_type */
167
168 static int foreach_plugin (const char *host, /* {{{ */
169     callback_plugin_t callback,
170     void *user_data)
171 {
172   char abspath[PATH_MAX + 1];
173
174   if (host == NULL)
175     return (EINVAL);
176
177   snprintf (abspath, sizeof (abspath), "%s/%s", DATA_DIR, host);
178   abspath[sizeof (abspath) - 1] = 0;
179
180   return (foreach_dir (abspath, callback, user_data));
181 } /* }}} int foreach_plugin */
182
183 static int foreach_host (callback_host_t callback, /* {{{ */
184     void *user_data)
185 {
186   return (foreach_dir (DATA_DIR, callback, user_data));
187 } /* }}} int foreach_host */
188
189 /*
190  * Functions building "fs_scan_dir_data_t" and calling the user-supplied
191  * callback eventually.
192  */
193 static int scan_type (const char *type, void *user_data) /* {{{ */
194 {
195   fs_scan_dir_data_t *data = user_data;
196   graph_ident_t *ident;
197   int status;
198
199   if ((type == NULL) || (data == NULL))
200     return (EINVAL);
201
202   if ((data->type != NULL) || (data->type_instance != NULL))
203     return (EINVAL);
204
205   data->type = strdup (type);
206   if (data->type == NULL)
207     return (ENOMEM);
208
209   data->type_instance = strchr (data->type, '-');
210   if (data->type_instance != NULL)
211   {
212     *data->type_instance = 0;
213     data->type_instance++;
214   }
215   else
216   {
217     data->type_instance = data->type + strlen (data->type);
218   }
219
220   ident = ident_create (data->host,
221       data->plugin, data->plugin_instance,
222       data->type, data->type_instance);
223   if (ident == NULL)
224   {
225     status = -1;
226   }
227   else
228   {
229     status = (*data->callback) (ident, data->user_data);
230     ident_destroy (ident);
231   }
232
233   free (data->type);
234   data->type = NULL;
235   data->type_instance = NULL;
236
237   return (status);
238 } /* }}} int scan_type */
239
240 static int scan_plugin (const char *plugin, void *user_data) /* {{{ */
241 {
242   fs_scan_dir_data_t *data = user_data;
243   int status;
244
245   if ((plugin == NULL) || (data == NULL))
246     return (EINVAL);
247
248   if ((data->plugin != NULL) || (data->plugin_instance != NULL))
249     return (EINVAL);
250
251   data->plugin = strdup (plugin);
252   if (data->plugin == NULL)
253     return (ENOMEM);
254
255   data->plugin_instance = strchr (data->plugin, '-');
256   if (data->plugin_instance != NULL)
257   {
258     *data->plugin_instance = 0;
259     data->plugin_instance++;
260   }
261   else
262   {
263     data->plugin_instance = data->plugin + strlen (data->plugin);
264   }
265
266   status = foreach_type (data->host, plugin, scan_type, data);
267
268   free (data->plugin);
269   data->plugin = NULL;
270   data->plugin_instance = NULL;
271
272   return (status);
273 } /* }}} int scan_plugin */
274
275 static int scan_host (const char *host, void *user_data) /* {{{ */
276 {
277   fs_scan_dir_data_t *data = user_data;
278   int status;
279
280   if ((host == NULL) || (data == NULL))
281     return (EINVAL);
282
283   if (data->host != NULL)
284     return (EINVAL);
285
286   data->host = strdup (host);
287   if (data->host == NULL)
288     return (ENOMEM);
289
290   status =  foreach_plugin (host, scan_plugin, data);
291
292   free (data->host);
293   data->host = NULL;
294
295   return (status);
296 } /* }}} int scan_host */
297
298 /*
299  * Public function
300  */
301 int fs_scan (fs_ident_cb_t callback, void *user_data) /* {{{ */
302 {
303   fs_scan_dir_data_t data;
304
305   memset (&data, 0, sizeof (data));
306   data.callback = callback;
307   data.user_data = user_data;
308
309   data.host = NULL;
310   data.plugin = NULL;
311   data.plugin_instance = NULL;
312   data.type = NULL;
313   data.type_instance = NULL;
314
315   foreach_host (scan_host, &data);
316
317   return (0);
318 } /* }}} int fs_scan */
319
320 /* vim: set sw=2 sts=2 et fdm=marker : */