common.[ch]: Implement "strlcat".
[collection4.git] / common.c
1 #include <stdlib.h>
2 #include <stdio.h>
3 #include <string.h>
4 #include <errno.h>
5 #include <sys/types.h>
6 #include <sys/stat.h>
7 #include <unistd.h>
8 #include <dirent.h>
9 #include <assert.h>
10
11 #include "common.h"
12
13 static int foreach_rrd_file (const char *dir, /* {{{ */
14     int (*callback) (const char *, void *),
15     void *user_data)
16 {
17   DIR *dh;
18   struct dirent *entry;
19   int status;
20
21   if (callback == NULL)
22     return (EINVAL);
23
24   dh = opendir (dir);
25   if (dh == NULL)
26     return (errno);
27
28   while ((entry = readdir (dh)) != NULL)
29   {
30     struct stat statbuf;
31     char abspath[PATH_MAX + 1];
32     size_t d_name_len;
33
34     if (entry->d_name[0] == '.')
35       continue;
36
37     d_name_len = strlen (entry->d_name);
38     if (d_name_len <= 4)
39       continue;
40
41     if (strcasecmp (".rrd", entry->d_name + (d_name_len - 4)) != 0)
42       continue;
43
44     snprintf (abspath, sizeof (abspath), "%s/%s", dir, entry->d_name);
45     abspath[sizeof (abspath) - 1] = 0;
46
47     memset (&statbuf, 0, sizeof (statbuf));
48
49     status = stat (abspath, &statbuf);
50     if (status != 0)
51       continue;
52
53     if (!S_ISREG (statbuf.st_mode))
54       continue;
55
56     entry->d_name[d_name_len - 4] = 0;
57
58     status = (*callback) (entry->d_name, user_data);
59     if (status != 0)
60       break;
61   } /* while (readdir) */
62
63   closedir (dh);
64   return (status);
65 } /* }}} int foreach_rrd_file */
66
67 static int foreach_dir (const char *dir, /* {{{ */
68     int (*callback) (const char *, void *),
69     void *user_data)
70 {
71   DIR *dh;
72   struct dirent *entry;
73   int status;
74
75   if (callback == NULL)
76     return (EINVAL);
77
78   dh = opendir (dir);
79   if (dh == NULL)
80     return (errno);
81
82   while ((entry = readdir (dh)) != NULL)
83   {
84     struct stat statbuf;
85     char abspath[PATH_MAX + 1];
86
87     if (entry->d_name[0] == '.')
88       continue;
89
90     snprintf (abspath, sizeof (abspath), "%s/%s", dir, entry->d_name);
91     abspath[sizeof (abspath) - 1] = 0;
92
93     memset (&statbuf, 0, sizeof (statbuf));
94
95     status = stat (abspath, &statbuf);
96     if (status != 0)
97       continue;
98
99     if (!S_ISDIR (statbuf.st_mode))
100       continue;
101
102     status = (*callback) (entry->d_name, user_data);
103     if (status != 0)
104       break;
105   } /* while (readdir) */
106
107   closedir (dh);
108   return (status);
109 } /* }}} int foreach_dir */
110
111 int foreach_type (const char *host, const char *plugin, /* {{{ */
112     callback_type_t callback, void *user_data)
113 {
114   char abspath[PATH_MAX + 1];
115
116   if ((host == NULL) || (plugin == NULL))
117     return (EINVAL);
118
119   snprintf (abspath, sizeof (abspath), "%s/%s/%s", DATA_DIR, host, plugin);
120   abspath[sizeof (abspath) - 1] = 0;
121
122   return (foreach_rrd_file (abspath, callback, user_data));
123 } /* }}} int foreach_type */
124
125 int foreach_plugin (const char *host, /* {{{ */
126     callback_plugin_t callback,
127     void *user_data)
128 {
129   char abspath[PATH_MAX + 1];
130
131   if (host == NULL)
132     return (EINVAL);
133
134   snprintf (abspath, sizeof (abspath), "%s/%s", DATA_DIR, host);
135   abspath[sizeof (abspath) - 1] = 0;
136
137   return (foreach_dir (abspath, callback, user_data));
138 } /* }}} int foreach_plugin */
139
140 int foreach_host (callback_host_t callback, /* {{{ */
141     void *user_data)
142 {
143   return (foreach_dir (DATA_DIR, callback, user_data));
144 } /* }}} int foreach_host */
145
146 size_t c_strlcat (char *dst, const char *src, size_t size) /* {{{ */
147 {
148   size_t retval;
149   size_t dst_len;
150   size_t src_len;
151
152   dst_len = strlen (dst);
153   src_len = strlen (src);
154   retval = dst_len + src_len;
155
156   if ((dst_len + 1) >= size)
157     return (retval);
158
159   dst  += dst_len;
160   size -= dst_len;
161   assert (size >= 2);
162
163   /* Result will be truncated. */
164   if (src_len >= size)
165     src_len = size - 1;
166
167   memcpy (dst, src, src_len);
168   dst[src_len] = 0;
169
170   return (retval);
171 } /* }}} size_t c_strlcat */
172
173
174
175 /* vim: set sw=2 sts=2 et fdm=marker : */