6e1c651a886d332ae89b89842b527da78de4fae4
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 *plugin, void *user_data);
51 typedef int (*callback_host_t) (const char *host, void *user_data);
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;
64 if (callback == NULL)
65 return (EINVAL);
67 dh = opendir (dir);
68 if (dh == NULL)
69 return (errno);
71 while ((entry = readdir (dh)) != NULL)
72 {
73 struct stat statbuf;
74 char abspath[PATH_MAX + 1];
75 size_t d_name_len;
77 if (entry->d_name[0] == '.')
78 continue;
80 d_name_len = strlen (entry->d_name);
81 if (d_name_len <= 4)
82 continue;
84 if (strcasecmp (".rrd", entry->d_name + (d_name_len - 4)) != 0)
85 continue;
87 snprintf (abspath, sizeof (abspath), "%s/%s", dir, entry->d_name);
88 abspath[sizeof (abspath) - 1] = 0;
90 memset (&statbuf, 0, sizeof (statbuf));
92 status = stat (abspath, &statbuf);
93 if (status != 0)
94 continue;
96 if (!S_ISREG (statbuf.st_mode))
97 continue;
99 entry->d_name[d_name_len - 4] = 0;
101 status = (*callback) (entry->d_name, user_data);
102 if (status != 0)
103 break;
104 } /* while (readdir) */
106 closedir (dh);
107 return (status);
108 } /* }}} int foreach_rrd_file */
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;
118 if (callback == NULL)
119 return (EINVAL);
121 dh = opendir (dir);
122 if (dh == NULL)
123 return (errno);
125 while ((entry = readdir (dh)) != NULL)
126 {
127 struct stat statbuf;
128 char abspath[PATH_MAX + 1];
130 if (entry->d_name[0] == '.')
131 continue;
133 snprintf (abspath, sizeof (abspath), "%s/%s", dir, entry->d_name);
134 abspath[sizeof (abspath) - 1] = 0;
136 memset (&statbuf, 0, sizeof (statbuf));
138 status = stat (abspath, &statbuf);
139 if (status != 0)
140 continue;
142 if (!S_ISDIR (statbuf.st_mode))
143 continue;
145 status = (*callback) (entry->d_name, user_data);
146 if (status != 0)
147 break;
148 } /* while (readdir) */
150 closedir (dh);
151 return (status);
152 } /* }}} int foreach_dir */
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];
159 if ((host == NULL) || (plugin == NULL))
160 return (EINVAL);
162 snprintf (abspath, sizeof (abspath), "%s/%s/%s", DATA_DIR, host, plugin);
163 abspath[sizeof (abspath) - 1] = 0;
165 return (foreach_rrd_file (abspath, callback, user_data));
166 } /* }}} int foreach_type */
168 static int foreach_plugin (const char *host, /* {{{ */
169 callback_plugin_t callback,
170 void *user_data)
171 {
172 char abspath[PATH_MAX + 1];
174 if (host == NULL)
175 return (EINVAL);
177 snprintf (abspath, sizeof (abspath), "%s/%s", DATA_DIR, host);
178 abspath[sizeof (abspath) - 1] = 0;
180 return (foreach_dir (abspath, callback, user_data));
181 } /* }}} int foreach_plugin */
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 */
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;
199 if ((type == NULL) || (data == NULL))
200 return (EINVAL);
202 if ((data->type != NULL) || (data->type_instance != NULL))
203 return (EINVAL);
205 data->type = strdup (type);
206 if (data->type == NULL)
207 return (ENOMEM);
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 }
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 }
233 free (data->type);
234 data->type = NULL;
235 data->type_instance = NULL;
237 return (status);
238 } /* }}} int scan_type */
240 static int scan_plugin (const char *plugin, void *user_data) /* {{{ */
241 {
242 fs_scan_dir_data_t *data = user_data;
243 int status;
245 if ((plugin == NULL) || (data == NULL))
246 return (EINVAL);
248 if ((data->plugin != NULL) || (data->plugin_instance != NULL))
249 return (EINVAL);
251 data->plugin = strdup (plugin);
252 if (data->plugin == NULL)
253 return (ENOMEM);
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 }
266 status = foreach_type (data->host, plugin, scan_type, data);
268 free (data->plugin);
269 data->plugin = NULL;
270 data->plugin_instance = NULL;
272 return (status);
273 } /* }}} int scan_plugin */
275 static int scan_host (const char *host, void *user_data) /* {{{ */
276 {
277 fs_scan_dir_data_t *data = user_data;
278 int status;
280 if ((host == NULL) || (data == NULL))
281 return (EINVAL);
283 if (data->host != NULL)
284 return (EINVAL);
286 data->host = strdup (host);
287 if (data->host == NULL)
288 return (ENOMEM);
290 status = foreach_plugin (host, scan_plugin, data);
292 free (data->host);
293 data->host = NULL;
295 return (status);
296 } /* }}} int scan_host */
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;
305 memset (&data, 0, sizeof (data));
306 data.callback = callback;
307 data.user_data = user_data;
309 data.host = NULL;
310 data.plugin = NULL;
311 data.plugin_instance = NULL;
312 data.type = NULL;
313 data.type_instance = NULL;
315 foreach_host (scan_host, &data);
317 return (0);
318 } /* }}} int fs_scan */
320 /* vim: set sw=2 sts=2 et fdm=marker : */