]> git.ipfire.org Git - network.git/blob - src/networkd/zones.c
networkd: Implement enumerating zones on the bus
[network.git] / src / networkd / zones.c
1 /*#############################################################################
2 # #
3 # IPFire.org - A linux based firewall #
4 # Copyright (C) 2023 IPFire Network Development Team #
5 # #
6 # This program is free software: you can redistribute it and/or modify #
7 # it under the terms of the GNU General Public License as published by #
8 # the Free Software Foundation, either version 3 of the License, or #
9 # (at your option) any later version. #
10 # #
11 # This program is distributed in the hope that it will be useful, #
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of #
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
14 # GNU General Public License for more details. #
15 # #
16 # You should have received a copy of the GNU General Public License #
17 # along with this program. If not, see <http://www.gnu.org/licenses/>. #
18 # #
19 #############################################################################*/
20
21 #include <dirent.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <sys/queue.h>
25
26 #include "logging.h"
27 #include "zone.h"
28 #include "zones.h"
29
30 struct nw_zones_entry {
31 struct nw_zone* zone;
32
33 // Link to the other entries
34 STAILQ_ENTRY(nw_zones_entry) nodes;
35 };
36
37 struct nw_zones {
38 int nrefs;
39
40 // Zone Entries
41 STAILQ_HEAD(entries, nw_zones_entry) entries;
42
43 // A counter of the zone entries
44 unsigned int num;
45 };
46
47 static int nw_zones_create(struct nw_zones** zones) {
48 struct nw_zones* z = calloc(1, sizeof(*z));
49 if (!z)
50 return 1;
51
52 // Initialize the reference counter
53 z->nrefs = 1;
54
55 // Initialize entries
56 STAILQ_INIT(&z->entries);
57
58 // Reference the pointer
59 *zones = z;
60
61 return 0;
62 }
63
64 static void nw_zones_free(struct nw_zones* zones) {
65 struct nw_zones_entry* entry = NULL;
66
67 while (!STAILQ_EMPTY(&zones->entries)) {
68 entry = STAILQ_FIRST(&zones->entries);
69
70 // Dereference the zone
71 nw_zone_unref(entry->zone);
72
73 // Remove the entry from the list
74 STAILQ_REMOVE_HEAD(&zones->entries, nodes);
75
76 // Free the entry
77 free(entry);
78 }
79 }
80
81 struct nw_zones* nw_zones_ref(struct nw_zones* zones) {
82 zones->nrefs++;
83
84 return zones;
85 }
86
87 struct nw_zones* nw_zones_unref(struct nw_zones* zones) {
88 if (--zones->nrefs > 0)
89 return zones;
90
91 nw_zones_free(zones);
92 return NULL;
93 }
94
95 static int nw_zones_add_zone(struct nw_zones* zones, struct nw_zone* zone) {
96 // Allocate a new entry
97 struct nw_zones_entry* entry = calloc(1, sizeof(*entry));
98 if (!entry)
99 return 1;
100
101 // Reference the zone
102 entry->zone = nw_zone_ref(zone);
103
104 // Add it to the list
105 STAILQ_INSERT_TAIL(&zones->entries, entry, nodes);
106
107 // Increment the counter
108 zones->num++;
109
110 return 0;
111 }
112
113 static int nw_zones_load_filter(const struct dirent* path) {
114 const char* fn = path->d_name;
115
116 // Ignore everything starting with '.'
117 if (*fn == '.')
118 return 0;
119
120 // Ignore anything that isn't a directory
121 if (path->d_type != DT_DIR)
122 return 0;
123
124 return 1;
125 }
126
127 static int __nw_zones_load(struct nw_zones* zones) {
128 struct dirent** paths = NULL;
129 int n;
130 int r = 0;
131
132 struct nw_zone* zone = NULL;
133
134 // Scan the zones directory
135 n = scandir(CONFIG_DIR "/zones", &paths, nw_zones_load_filter, alphasort);
136 if (n < 0) {
137 ERROR("Could not load zones: %m\n");
138 return 1;
139 }
140
141 DEBUG("Found %d zone(s)\n", n);
142
143 // Load all zones
144 for (int i = 0; i < n; i++) {
145 const char* name = paths[i]->d_name;
146
147 DEBUG("Loading zone '%s'...\n", name);
148
149 // Create a new zone object
150 r = nw_zone_create(&zone, name);
151 if (r)
152 goto ERROR;
153
154 // Store the zone
155 r = nw_zones_add_zone(zones, zone);
156 if (r) {
157 nw_zone_unref(zone);
158 goto ERROR;
159 }
160
161 nw_zone_unref(zone);
162 }
163
164 ERROR:
165 // Free paths
166 if (paths) {
167 for (int i = 0; i < n; i++) {
168 free(paths[i]);
169 }
170 free(paths);
171 }
172
173 return r;
174 }
175
176 int nw_zones_load(struct nw_zones** zones) {
177 int r;
178
179 // Create a new zones object
180 r = nw_zones_create(zones);
181 if (r)
182 return r;
183
184 // Load all zones
185 r = __nw_zones_load(*zones);
186 if (r)
187 goto ERROR;
188
189 return 0;
190
191 ERROR:
192 nw_zones_unref(*zones);
193 return r;
194 }
195
196 size_t nw_zones_num(struct nw_zones* zones) {
197 struct nw_zones_entry* entry = NULL;
198 size_t length = 0;
199
200 // Count all zones
201 STAILQ_FOREACH(entry, &zones->entries, nodes)
202 length++;
203
204 return length;
205 }
206
207 struct nw_zone* nw_zones_get_by_name(struct nw_zones* zones, const char* name) {
208 struct nw_zones_entry* entry = NULL;
209
210 STAILQ_FOREACH(entry, &zones->entries, nodes) {
211 const char* __name = nw_zone_name(entry->zone);
212
213 // If the name matches, return a reference to the zone
214 if (strcmp(name, __name) == 0)
215 return nw_zone_ref(entry->zone);
216 }
217
218 // No match found
219 return NULL;
220 }
221
222 int nw_zones_bus_paths(struct nw_zones* zones, char*** paths) {
223 struct nw_zones_entry* entry = NULL;
224 char* path = NULL;
225
226 // Allocate an array for all paths
227 char** p = calloc(zones->num + 1, sizeof(*p));
228 if (!p)
229 return 1;
230
231 unsigned int i = 0;
232
233 // Walk through all zones
234 STAILQ_FOREACH(entry, &zones->entries, nodes) {
235 // Generate the bus path
236 path = nw_zone_bus_path(entry->zone);
237 if (!path)
238 goto ERROR;
239
240 // Append the bus path to the array
241 p[i++] = path;
242 }
243
244 // Return pointer
245 *paths = p;
246
247 return 0;
248
249 ERROR:
250 if (p) {
251 for (char** e = p; *e; e++)
252 free(*e);
253 free(p);
254 }
255
256 return 1;
257 }