1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright (C) 2013 Tom Gundersen <teg@jklm.no>
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.
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.
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/>.
22 #include "link-config.h"
27 #include "path-util.h"
28 #include "conf-parser.h"
29 #include "conf-files.h"
31 struct link_config_ctx {
32 LIST_HEAD(link_config, links);
35 usec_t *link_dirs_ts_usec;
38 int link_config_ctx_new(link_config_ctx **ret) {
44 ctx = new0(link_config_ctx, 1);
48 LIST_HEAD_INIT(ctx->links);
50 ctx->link_dirs = strv_new("/etc/net/links",
54 if (!ctx->link_dirs) {
55 log_error("failed to build link config directory array");
56 link_config_ctx_free(ctx);
59 if (!path_strv_canonicalize_uniq(ctx->link_dirs)) {
60 log_error("failed to canonicalize link config directories\n");
61 link_config_ctx_free(ctx);
65 ctx->link_dirs_ts_usec = calloc(strv_length(ctx->link_dirs), sizeof(usec_t));
66 if(!ctx->link_dirs_ts_usec) {
67 link_config_ctx_free(ctx);
75 static void link_configs_free(link_config_ctx *ctx) {
76 link_config *link, *link_next;
81 LIST_FOREACH_SAFE(links, link, link_next, ctx->links) {
83 free(link->match_path);
84 free(link->match_driver);
85 free(link->match_type);
86 free(link->description);
92 void link_config_ctx_free(link_config_ctx *ctx) {
96 strv_free(ctx->link_dirs);
97 free(ctx->link_dirs_ts_usec);
98 link_configs_free(ctx);
105 static int load_link(link_config_ctx *ctx, const char *filename) {
110 file = fopen(filename, "re");
118 link = new0(link_config, 1);
124 r = config_parse(NULL, filename, file, "Match\0Link\0Ethernet\0", config_item_perf_lookup,
125 (void*) link_config_gperf_lookup, false, false, link);
127 log_warning("Colud not parse config file %s: %s", filename, strerror(-r));
130 log_info("Parsed configuration file %s", filename);
132 link->filename = strdup(filename);
134 LIST_PREPEND(links, ctx->links, link);
143 int link_config_load(link_config_ctx *ctx) {
147 link_configs_free(ctx);
149 /* update timestamps */
150 paths_check_timestamp(ctx->link_dirs, ctx->link_dirs_ts_usec, true);
152 r = conf_files_list_strv(&files, ".link", NULL, (const char **)ctx->link_dirs);
154 log_error("failed to enumerate link files: %s", strerror(-r));
158 STRV_FOREACH_BACKWARDS(f, files) {
159 r = load_link(ctx, *f);
167 bool link_config_should_reload(link_config_ctx *ctx) {
168 return paths_check_timestamp(ctx->link_dirs, ctx->link_dirs_ts_usec, false);
171 static bool match_config(link_config *match, struct udev_device *device) {
172 const char *property;
174 if (match->match_mac) {
175 property = udev_device_get_sysattr_value(device, "address");
176 if (!property || !streq(match->match_mac, property)) {
177 log_debug("Device MAC address (%s) did not match MACAddress=%s", property, match->match_mac);
182 if (match->match_path) {
183 property = udev_device_get_property_value(device, "ID_PATH");
184 if (!property || !streq(match->match_path, property)) {
185 log_debug("Device's persistent path (%s) did not match Path=%s", property, match->match_path);
190 if (match->match_driver) {
191 property = udev_device_get_driver(device);
192 if (!property || !streq(match->match_driver, property)) {
193 log_debug("Device driver (%s) did not match Driver=%s", property, match->match_driver);
198 if (match->match_type) {
199 property = udev_device_get_devtype(device);
200 if (!property || !streq(match->match_type, property)) {
201 log_debug("Device type (%s) did not match Type=%s", property, match->match_type);
209 int link_config_get(link_config_ctx *ctx, struct udev_device *device, link_config **ret) {
212 LIST_FOREACH(links, link, ctx->links) {
213 if (!match_config(link, device)) {
214 log_info("Config file %s does not apply to device %s", link->filename, udev_device_get_sysname(device));
216 log_info("Config file %s applies to device %s", link->filename, udev_device_get_sysname(device));
225 int link_config_apply(link_config_ctx *ctx, link_config *config, struct udev_device *device) {
229 name = udev_device_get_sysname(device);
233 log_info("Configuring %s", name);
235 if (config->description) {
236 r = udev_device_set_sysattr_value(device, "ifalias", config->description);
238 log_warning("Could not set description of %s to '%s': %s", name, config->description, strerror(-r));
240 log_info("Set link description of %s to '%s'", name, config->description);