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 **/
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>
34 #include "filesystem.h"
36 struct fs_scan_dir_data_s /* {{{ */
37 {
38 fs_ident_cb_t callback;
39 void *user_data;
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;
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);
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;
66 if (callback == NULL)
67 return (EINVAL);
69 dh = opendir (dir);
70 if (dh == NULL)
71 return (errno);
73 while ((entry = readdir (dh)) != NULL)
74 {
75 struct stat statbuf;
76 char abspath[PATH_MAX + 1];
77 size_t d_name_len;
79 if (entry->d_name[0] == '.')
80 continue;
82 d_name_len = strlen (entry->d_name);
83 if (d_name_len <= 4)
84 continue;
86 if (strcasecmp (".rrd", entry->d_name + (d_name_len - 4)) != 0)
87 continue;
89 snprintf (abspath, sizeof (abspath), "%s/%s", dir, entry->d_name);
90 abspath[sizeof (abspath) - 1] = 0;
92 memset (&statbuf, 0, sizeof (statbuf));
94 status = stat (abspath, &statbuf);
95 if (status != 0)
96 continue;
98 if (!S_ISREG (statbuf.st_mode))
99 continue;
101 entry->d_name[d_name_len - 4] = 0;
103 status = (*callback) (entry->d_name, user_data);
104 if (status != 0)
105 break;
106 } /* while (readdir) */
108 closedir (dh);
109 return (status);
110 } /* }}} int foreach_rrd_file */
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];
117 if ((host == NULL) || (plugin == NULL))
118 return (EINVAL);
120 snprintf (abspath, sizeof (abspath), "%s/%s/%s", DATA_DIR, host, plugin);
121 abspath[sizeof (abspath) - 1] = 0;
123 return (foreach_rrd_file (abspath, callback, user_data));
124 } /* }}} int foreach_type */
126 static int foreach_plugin (const char *host, /* {{{ */
127 callback_plugin_t callback,
128 void *user_data)
129 {
130 char abspath[PATH_MAX + 1];
132 if (host == NULL)
133 return (EINVAL);
135 snprintf (abspath, sizeof (abspath), "%s/%s", DATA_DIR, host);
136 abspath[sizeof (abspath) - 1] = 0;
138 return (fs_foreach_dir (abspath, callback, user_data));
139 } /* }}} int foreach_plugin */
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 */
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;
157 if ((type == NULL) || (data == NULL))
158 return (EINVAL);
160 if ((data->type != NULL) || (data->type_instance != NULL))
161 return (EINVAL);
163 data->type = strdup (type);
164 if (data->type == NULL)
165 return (ENOMEM);
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 }
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 }
191 free (data->type);
192 data->type = NULL;
193 data->type_instance = NULL;
195 return (status);
196 } /* }}} int scan_type */
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;
204 if ((plugin == NULL) || (data == NULL))
205 return (EINVAL);
207 if ((data->plugin != NULL) || (data->plugin_instance != NULL))
208 return (EINVAL);
210 data->plugin = strdup (plugin);
211 if (data->plugin == NULL)
212 return (ENOMEM);
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 }
225 status = foreach_type (data->host, plugin, scan_type, data);
227 free (data->plugin);
228 data->plugin = NULL;
229 data->plugin_instance = NULL;
231 return (status);
232 } /* }}} int scan_plugin */
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;
240 if ((host == NULL) || (data == NULL))
241 return (EINVAL);
243 if (data->host != NULL)
244 return (EINVAL);
246 data->host = strdup (host);
247 if (data->host == NULL)
248 return (ENOMEM);
250 status = foreach_plugin (host, scan_plugin, data);
252 free (data->host);
253 data->host = NULL;
255 return (status);
256 } /* }}} int scan_host */
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;
269 if (callback == NULL)
270 return (EINVAL);
272 dh = opendir (base_dir);
273 if (dh == NULL)
274 return (errno);
276 while ((entry = readdir (dh)) != NULL)
277 {
278 struct stat statbuf;
279 char abspath[PATH_MAX + 1];
281 if (entry->d_name[0] == '.')
282 continue;
284 snprintf (abspath, sizeof (abspath), "%s/%s", base_dir, entry->d_name);
285 abspath[sizeof (abspath) - 1] = 0;
287 memset (&statbuf, 0, sizeof (statbuf));
289 status = stat (abspath, &statbuf);
290 if (status != 0)
291 continue;
293 if (!S_ISDIR (statbuf.st_mode))
294 continue;
296 status = (*callback) (base_dir, entry->d_name, user_data);
297 if (status != 0)
298 break;
299 } /* while (readdir) */
301 closedir (dh);
302 return (status);
303 } /* }}} int fs_foreach_dir */
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;
313 if (callback == NULL)
314 return (EINVAL);
316 dh = opendir (base_dir);
317 if (dh == NULL)
318 return (errno);
320 while ((entry = readdir (dh)) != NULL)
321 {
322 struct stat statbuf;
323 char abspath[PATH_MAX + 1];
325 if (entry->d_name[0] == '.')
326 continue;
328 snprintf (abspath, sizeof (abspath), "%s/%s", base_dir, entry->d_name);
329 abspath[sizeof (abspath) - 1] = 0;
331 memset (&statbuf, 0, sizeof (statbuf));
333 status = stat (abspath, &statbuf);
334 if (status != 0)
335 continue;
337 if (!S_ISREG (statbuf.st_mode))
338 continue;
340 status = (*callback) (base_dir, entry->d_name, user_data);
341 if (status != 0)
342 break;
343 } /* while (readdir) */
345 closedir (dh);
346 return (status);
347 } /* }}} int fs_foreach_file */
349 int fs_scan (fs_ident_cb_t callback, void *user_data) /* {{{ */
350 {
351 fs_scan_dir_data_t data;
353 memset (&data, 0, sizeof (data));
354 data.callback = callback;
355 data.user_data = user_data;
357 data.host = NULL;
358 data.plugin = NULL;
359 data.plugin_instance = NULL;
360 data.type = NULL;
361 data.type_instance = NULL;
363 foreach_host (scan_host, &data);
365 return (0);
366 } /* }}} int fs_scan */
368 /* vim: set sw=2 sts=2 et fdm=marker : */