chiark / gitweb /
networkd: make sure Network and Link can always be freed
[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
49         r = config_parse(NULL, filename, file, "Match\0Network\0", config_item_perf_lookup,
50                         (void*) network_gperf_lookup, false, false, network);
51         if (r < 0) {
52                 log_warning("Could not parse config file %s: %s", filename, strerror(-r));
53                 return r;
54         } else
55                 log_debug("Parsed configuration file %s", filename);
56
57         network->filename = strdup(filename);
58         if (!network->filename)
59                 return log_oom();
60
61         LIST_PREPEND(networks, manager->networks, network);
62         network = NULL;
63
64         return 0;
65 }
66
67 int network_load(Manager *manager) {
68         Network *network;
69         char **files, **f;
70         int r;
71
72         assert(manager);
73
74         while ((network = manager->networks))
75                 network_free(network);
76
77         /* update timestamp */
78         paths_check_timestamp(manager->network_dirs, &manager->network_dirs_ts_usec, true);
79
80         r = conf_files_list_strv(&files, ".network", NULL, (const char **)manager->network_dirs);
81         if (r < 0) {
82                 log_error("failed to enumerate network files: %s", strerror(-r));
83                 return r;
84         }
85
86         STRV_FOREACH_BACKWARDS(f, files) {
87                 r = network_load_one(manager, *f);
88                 if (r < 0)
89                         return r;
90         }
91
92         strv_free(files);
93
94         return 0;
95 }
96
97 bool network_should_reload(Manager *manager) {
98         return paths_check_timestamp(manager->network_dirs, &manager->network_dirs_ts_usec, false);
99 }
100
101 void network_free(Network *network) {
102         Route *route;
103         Address *address;
104
105         if (!network)
106                 return;
107
108         free(network->filename);
109
110         free(network->match_mac);
111         free(network->match_path);
112         free(network->match_driver);
113         free(network->match_type);
114         free(network->match_name);
115
116         free(network->description);
117
118         while ((route = network->routes))
119                 route_free(route);
120
121         while ((address = network->addresses))
122                 address_free(address);
123
124         LIST_REMOVE(networks, network->manager->networks, network);
125
126         free(network);
127 }
128
129 int network_get(Manager *manager, struct udev_device *device, Network **ret) {
130         Network *network;
131
132         assert(manager);
133         assert(device);
134         assert(ret);
135
136         if (network_should_reload(manager))
137                 network_load(manager);
138
139         LIST_FOREACH(networks, network, manager->networks) {
140                 if (net_match_config(network->match_mac, network->match_path,
141                                         network->match_driver, network->match_type,
142                                         network->match_name,
143                                         udev_device_get_sysattr_value(device, "address"),
144                                         udev_device_get_property_value(device, "ID_PATH"),
145                                         udev_device_get_driver(device),
146                                         udev_device_get_devtype(device),
147                                         udev_device_get_sysname(device))) {
148                         log_debug("Network file %s applies to link %s",
149                                         network->filename,
150                                         udev_device_get_sysname(device));
151                         *ret = network;
152                         return 0;
153                 }
154         }
155
156         *ret = NULL;
157
158         return -ENOENT;
159 }
160
161 int network_apply(Manager *manager, Network *network, Link *link) {
162         int r;
163
164         log_info("Network '%s' being applied to link '%u'",
165                         network->description, (unsigned) link->ifindex);
166
167         link->network = network;
168
169         r = link_configure(link);
170         if (r < 0)
171                 return r;
172
173         return 0;
174 }