chiark / gitweb /
Fix a few resource leaks in error paths
[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         file = fopen(filename, "re");
34         if (!file) {
35                 if (errno == ENOENT)
36                         return 0;
37                 else
38                         return errno;
39         }
40
41         network = new0(Network, 1);
42         if (!network)
43                 return log_oom();
44
45         network->manager = manager;
46
47         LIST_HEAD_INIT(network->addresses);
48         LIST_HEAD_INIT(network->routes);
49
50         network->addresses_by_section = hashmap_new(uint64_hash_func, uint64_compare_func);
51         if (!network->addresses_by_section)
52                 return log_oom();
53
54         network->routes_by_section = hashmap_new(uint64_hash_func, uint64_compare_func);
55         if (!network->routes_by_section)
56                 return log_oom();
57
58         network->filename = strdup(filename);
59         if (!network->filename)
60                 return log_oom();
61
62         r = config_parse(NULL, filename, file, "Match\0Network\0Address\0Route\0", config_item_perf_lookup,
63                         (void*) network_gperf_lookup, false, false, network);
64         if (r < 0) {
65                 log_warning("Could not parse config file %s: %s", filename, strerror(-r));
66                 return r;
67         } else
68                 log_debug("Parsed configuration file %s", filename);
69
70         LIST_PREPEND(networks, manager->networks, network);
71         network = NULL;
72
73         return 0;
74 }
75
76 int network_load(Manager *manager) {
77         Network *network;
78         char **files, **f;
79         int r;
80
81         assert(manager);
82
83         while ((network = manager->networks))
84                 network_free(network);
85
86         r = conf_files_list_strv(&files, ".network", NULL, (const char **)manager->network_dirs);
87         if (r < 0) {
88                 log_error("failed to enumerate network files: %s", strerror(-r));
89                 return r;
90         }
91
92         STRV_FOREACH_BACKWARDS(f, files) {
93                 r = network_load_one(manager, *f);
94                 if (r < 0)
95                         return r;
96         }
97
98         strv_free(files);
99
100         return 0;
101 }
102
103 void network_free(Network *network) {
104         Route *route;
105         Address *address;
106
107         if (!network)
108                 return;
109
110         free(network->filename);
111
112         free(network->match_mac);
113         free(network->match_path);
114         free(network->match_driver);
115         free(network->match_type);
116         free(network->match_name);
117
118         free(network->description);
119
120         while ((route = network->routes))
121                 route_free(route);
122
123         while ((address = network->addresses))
124                 address_free(address);
125
126         hashmap_free(network->addresses_by_section);
127         hashmap_free(network->routes_by_section);
128
129         LIST_REMOVE(networks, network->manager->networks, network);
130
131         free(network);
132 }
133
134 int network_get(Manager *manager, struct udev_device *device, Network **ret) {
135         Network *network;
136
137         assert(manager);
138         assert(device);
139         assert(ret);
140
141         if (manager_should_reload(manager))
142                 manager_load_config(manager);
143
144         LIST_FOREACH(networks, network, manager->networks) {
145                 if (net_match_config(network->match_mac, network->match_path,
146                                         network->match_driver, network->match_type,
147                                         network->match_name,
148                                         udev_device_get_sysattr_value(device, "address"),
149                                         udev_device_get_property_value(device, "ID_PATH"),
150                                         udev_device_get_driver(device),
151                                         udev_device_get_devtype(device),
152                                         udev_device_get_sysname(device))) {
153                         log_debug("Network file %s applies to link %s",
154                                         network->filename,
155                                         udev_device_get_sysname(device));
156                         *ret = network;
157                         return 0;
158                 }
159         }
160
161         *ret = NULL;
162
163         return -ENOENT;
164 }
165
166 int network_apply(Manager *manager, Network *network, Link *link) {
167         int r;
168
169         log_info("Network '%s' being applied to link '%s'",
170                         network->description, link->ifname);
171
172         link->network = network;
173
174         r = link_configure(link);
175         if (r < 0)
176                 return r;
177
178         return 0;
179 }
180
181 int config_parse_bridge(const char *unit,
182                 const char *filename,
183                 unsigned line,
184                 const char *section,
185                 unsigned section_line,
186                 const char *lvalue,
187                 int ltype,
188                 const char *rvalue,
189                 void *data,
190                 void *userdata) {
191         Network *network = userdata;
192         Bridge *bridge;
193         int r;
194
195         assert(filename);
196         assert(lvalue);
197         assert(rvalue);
198         assert(data);
199
200         r = bridge_get(network->manager, rvalue, &bridge);
201         if (r < 0) {
202                 log_syntax(unit, LOG_ERR, filename, line, EINVAL,
203                            "Bridge is invalid, ignoring assignment: %s", rvalue);
204                 return 0;
205         }
206
207         network->bridge = bridge;
208
209         return 0;
210 }