chiark / gitweb /
networkd: do not deference null pointer in cleanup
[elogind.git] / src / network / networkd-network.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2013 Tom Gundersen <teg@jklm.no>
7
8   systemd is free software; you can redistribute it and/or modify it
9   under the terms of the GNU Lesser General Public License as published by
10   the Free Software Foundation; either version 2.1 of the License, or
11   (at your option) any later version.
12
13   systemd is distributed in the hope that it will be useful, but
14   WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16   Lesser General Public License for more details.
17
18   You should have received a copy of the GNU Lesser General Public License
19   along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include "networkd.h"
23 #include "net-util.h"
24 #include "path-util.h"
25 #include "conf-files.h"
26 #include "conf-parser.h"
27
28 static int network_load_one(Manager *manager, const char *filename) {
29         _cleanup_network_free_ Network *network = NULL;
30         _cleanup_fclose_ FILE *file = NULL;
31         int r;
32
33         assert(manager);
34         assert(filename);
35
36         file = fopen(filename, "re");
37         if (!file) {
38                 if (errno == ENOENT)
39                         return 0;
40                 else
41                         return errno;
42         }
43
44         network = new0(Network, 1);
45         if (!network)
46                 return log_oom();
47
48         network->manager = manager;
49
50         LIST_HEAD_INIT(network->static_addresses);
51         LIST_HEAD_INIT(network->static_routes);
52
53         network->addresses_by_section = hashmap_new(uint64_hash_func, uint64_compare_func);
54         if (!network->addresses_by_section)
55                 return log_oom();
56
57         network->routes_by_section = hashmap_new(uint64_hash_func, uint64_compare_func);
58         if (!network->routes_by_section)
59                 return log_oom();
60
61         network->filename = strdup(filename);
62         if (!network->filename)
63                 return log_oom();
64
65         r = config_parse(NULL, filename, file, "Match\0Network\0Address\0Route\0", config_item_perf_lookup,
66                         (void*) network_gperf_lookup, false, false, network);
67         if (r < 0) {
68                 log_warning("Could not parse config file %s: %s", filename, strerror(-r));
69                 return r;
70         }
71
72         LIST_PREPEND(networks, manager->networks, network);
73         network = NULL;
74
75         return 0;
76 }
77
78 int network_load(Manager *manager) {
79         Network *network;
80         char **files, **f;
81         int r;
82
83         assert(manager);
84
85         while ((network = manager->networks))
86                 network_free(network);
87
88         r = conf_files_list_strv(&files, ".network", NULL, (const char **)manager->network_dirs);
89         if (r < 0) {
90                 log_error("Failed to enumerate network files: %s", strerror(-r));
91                 return r;
92         }
93
94         STRV_FOREACH_BACKWARDS(f, files) {
95                 r = network_load_one(manager, *f);
96                 if (r < 0)
97                         return r;
98         }
99
100         strv_free(files);
101
102         return 0;
103 }
104
105 void network_free(Network *network) {
106         Route *route;
107         Address *address;
108
109         if (!network)
110                 return;
111
112         assert(network->manager);
113
114         free(network->filename);
115
116         free(network->match_mac);
117         free(network->match_path);
118         free(network->match_driver);
119         free(network->match_type);
120         free(network->match_name);
121
122         free(network->description);
123
124         while ((route = network->static_routes))
125                 route_free(route);
126
127         while ((address = network->static_addresses))
128                 address_free(address);
129
130         hashmap_free(network->addresses_by_section);
131         hashmap_free(network->routes_by_section);
132
133         if (network->manager->networks)
134                 LIST_REMOVE(networks, network->manager->networks, network);
135
136         free(network);
137 }
138
139 int network_get(Manager *manager, struct udev_device *device, Network **ret) {
140         Network *network;
141
142         assert(manager);
143         assert(device);
144         assert(ret);
145
146         if (manager_should_reload(manager))
147                 manager_load_config(manager);
148
149         LIST_FOREACH(networks, network, manager->networks) {
150                 if (net_match_config(network->match_mac, network->match_path,
151                                         network->match_driver, network->match_type,
152                                         network->match_name,
153                                         udev_device_get_sysattr_value(device, "address"),
154                                         udev_device_get_property_value(device, "ID_PATH"),
155                                         udev_device_get_driver(device),
156                                         udev_device_get_devtype(device),
157                                         udev_device_get_sysname(device))) {
158                         log_debug("%s: found matching network '%s'",
159                                         udev_device_get_sysname(device),
160                                         network->filename);
161                         *ret = network;
162                         return 0;
163                 }
164         }
165
166         *ret = NULL;
167
168         return -ENOENT;
169 }
170
171 int network_apply(Manager *manager, Network *network, Link *link) {
172         int r;
173
174         link->network = network;
175
176         r = link_configure(link);
177         if (r < 0)
178                 return r;
179
180         return 0;
181 }
182
183 int config_parse_bridge(const char *unit,
184                 const char *filename,
185                 unsigned line,
186                 const char *section,
187                 unsigned section_line,
188                 const char *lvalue,
189                 int ltype,
190                 const char *rvalue,
191                 void *data,
192                 void *userdata) {
193         Network *network = userdata;
194         Bridge *bridge;
195         int r;
196
197         assert(filename);
198         assert(lvalue);
199         assert(rvalue);
200         assert(data);
201
202         r = bridge_get(network->manager, rvalue, &bridge);
203         if (r < 0) {
204                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
205                            "Bridge is invalid, ignoring assignment: %s", rvalue);
206                 return 0;
207         }
208
209         network->bridge = bridge;
210
211         return 0;
212 }