1 #include <stdlib.h>
2 #include <unistd.h>
3 #include <stdio.h>
4 #include <string.h>
5 #include <errno.h>
6 #include <limits.h>
7 #include <sys/types.h>
8 #include <sys/stat.h>
9 #include <dirent.h>
11 #include "filesystem.h"
13 struct fs_scan_dir_data_s /* {{{ */
14 {
15 fs_ident_cb_t callback;
16 void *user_data;
18 char *host;
19 char *plugin;
20 char *plugin_instance;
21 char *type;
22 char *type_instance;
23 }; /* }}} */
24 typedef struct fs_scan_dir_data_s fs_scan_dir_data_t;
26 typedef int (*callback_type_t) (const char *type, void *user_data);
27 typedef int (*callback_plugin_t) (const char *plugin, void *user_data);
28 typedef int (*callback_host_t) (const char *host, void *user_data);
30 /*
31 * Directory and file walking functions
32 */
33 static int foreach_rrd_file (const char *dir, /* {{{ */
34 int (*callback) (const char *, void *),
35 void *user_data)
36 {
37 DIR *dh;
38 struct dirent *entry;
39 int status;
41 if (callback == NULL)
42 return (EINVAL);
44 dh = opendir (dir);
45 if (dh == NULL)
46 return (errno);
48 while ((entry = readdir (dh)) != NULL)
49 {
50 struct stat statbuf;
51 char abspath[PATH_MAX + 1];
52 size_t d_name_len;
54 if (entry->d_name[0] == '.')
55 continue;
57 d_name_len = strlen (entry->d_name);
58 if (d_name_len <= 4)
59 continue;
61 if (strcasecmp (".rrd", entry->d_name + (d_name_len - 4)) != 0)
62 continue;
64 snprintf (abspath, sizeof (abspath), "%s/%s", dir, entry->d_name);
65 abspath[sizeof (abspath) - 1] = 0;
67 memset (&statbuf, 0, sizeof (statbuf));
69 status = stat (abspath, &statbuf);
70 if (status != 0)
71 continue;
73 if (!S_ISREG (statbuf.st_mode))
74 continue;
76 entry->d_name[d_name_len - 4] = 0;
78 status = (*callback) (entry->d_name, user_data);
79 if (status != 0)
80 break;
81 } /* while (readdir) */
83 closedir (dh);
84 return (status);
85 } /* }}} int foreach_rrd_file */
87 static int foreach_dir (const char *dir, /* {{{ */
88 int (*callback) (const char *, void *),
89 void *user_data)
90 {
91 DIR *dh;
92 struct dirent *entry;
93 int status = 0;
95 if (callback == NULL)
96 return (EINVAL);
98 dh = opendir (dir);
99 if (dh == NULL)
100 return (errno);
102 while ((entry = readdir (dh)) != NULL)
103 {
104 struct stat statbuf;
105 char abspath[PATH_MAX + 1];
107 if (entry->d_name[0] == '.')
108 continue;
110 snprintf (abspath, sizeof (abspath), "%s/%s", dir, entry->d_name);
111 abspath[sizeof (abspath) - 1] = 0;
113 memset (&statbuf, 0, sizeof (statbuf));
115 status = stat (abspath, &statbuf);
116 if (status != 0)
117 continue;
119 if (!S_ISDIR (statbuf.st_mode))
120 continue;
122 status = (*callback) (entry->d_name, user_data);
123 if (status != 0)
124 break;
125 } /* while (readdir) */
127 closedir (dh);
128 return (status);
129 } /* }}} int foreach_dir */
131 static int foreach_type (const char *host, const char *plugin, /* {{{ */
132 callback_type_t callback, void *user_data)
133 {
134 char abspath[PATH_MAX + 1];
136 if ((host == NULL) || (plugin == NULL))
137 return (EINVAL);
139 snprintf (abspath, sizeof (abspath), "%s/%s/%s", DATA_DIR, host, plugin);
140 abspath[sizeof (abspath) - 1] = 0;
142 return (foreach_rrd_file (abspath, callback, user_data));
143 } /* }}} int foreach_type */
145 static int foreach_plugin (const char *host, /* {{{ */
146 callback_plugin_t callback,
147 void *user_data)
148 {
149 char abspath[PATH_MAX + 1];
151 if (host == NULL)
152 return (EINVAL);
154 snprintf (abspath, sizeof (abspath), "%s/%s", DATA_DIR, host);
155 abspath[sizeof (abspath) - 1] = 0;
157 return (foreach_dir (abspath, callback, user_data));
158 } /* }}} int foreach_plugin */
160 static int foreach_host (callback_host_t callback, /* {{{ */
161 void *user_data)
162 {
163 return (foreach_dir (DATA_DIR, callback, user_data));
164 } /* }}} int foreach_host */
166 /*
167 * Functions building "fs_scan_dir_data_t" and calling the user-supplied
168 * callback eventually.
169 */
170 static int scan_type (const char *type, void *user_data) /* {{{ */
171 {
172 fs_scan_dir_data_t *data = user_data;
173 graph_ident_t *ident;
174 int status;
176 if ((type == NULL) || (data == NULL))
177 return (EINVAL);
179 if ((data->type != NULL) || (data->type_instance != NULL))
180 return (EINVAL);
182 data->type = strdup (type);
183 if (data->type == NULL)
184 return (ENOMEM);
186 data->type_instance = strchr (data->type, '-');
187 if (data->type_instance != NULL)
188 {
189 *data->type_instance = 0;
190 data->type_instance++;
191 }
192 else
193 {
194 data->type_instance = data->type + strlen (data->type);
195 }
197 ident = ident_create (data->host,
198 data->plugin, data->plugin_instance,
199 data->type, data->type_instance);
200 if (ident == NULL)
201 {
202 status = -1;
203 }
204 else
205 {
206 status = (*data->callback) (ident, data->user_data);
207 ident_destroy (ident);
208 }
210 free (data->type);
211 data->type = NULL;
212 data->type_instance = NULL;
214 return (status);
215 } /* }}} int scan_type */
217 static int scan_plugin (const char *plugin, void *user_data) /* {{{ */
218 {
219 fs_scan_dir_data_t *data = user_data;
220 int status;
222 if ((plugin == NULL) || (data == NULL))
223 return (EINVAL);
225 if ((data->plugin != NULL) || (data->plugin_instance != NULL))
226 return (EINVAL);
228 data->plugin = strdup (plugin);
229 if (data->plugin == NULL)
230 return (ENOMEM);
232 data->plugin_instance = strchr (data->plugin, '-');
233 if (data->plugin_instance != NULL)
234 {
235 *data->plugin_instance = 0;
236 data->plugin_instance++;
237 }
238 else
239 {
240 data->plugin_instance = data->plugin + strlen (data->plugin);
241 }
243 status = foreach_type (data->host, plugin, scan_type, data);
245 free (data->plugin);
246 data->plugin = NULL;
247 data->plugin_instance = NULL;
249 return (status);
250 } /* }}} int scan_plugin */
252 static int scan_host (const char *host, void *user_data) /* {{{ */
253 {
254 fs_scan_dir_data_t *data = user_data;
255 int status;
257 if ((host == NULL) || (data == NULL))
258 return (EINVAL);
260 if (data->host != NULL)
261 return (EINVAL);
263 data->host = strdup (host);
264 if (data->host == NULL)
265 return (ENOMEM);
267 status = foreach_plugin (host, scan_plugin, data);
269 free (data->host);
270 data->host = NULL;
272 return (status);
273 } /* }}} int scan_host */
275 /*
276 * Public function
277 */
278 int fs_scan (fs_ident_cb_t callback, void *user_data) /* {{{ */
279 {
280 fs_scan_dir_data_t data;
282 memset (&data, 0, sizeof (data));
283 data.callback = callback;
284 data.user_data = user_data;
286 data.host = NULL;
287 data.plugin = NULL;
288 data.plugin_instance = NULL;
289 data.type = NULL;
290 data.type_instance = NULL;
292 foreach_host (scan_host, &data);
294 return (0);
295 } /* }}} int fs_scan */
297 /* vim: set sw=2 sts=2 et fdm=marker : */