summaryrefslogtreecommitdiff
path: root/src/udev
diff options
context:
space:
mode:
Diffstat (limited to 'src/udev')
-rw-r--r--src/udev/net/.gitignore1
l---------src/udev/net/Makefile1
-rw-r--r--src/udev/net/link-config-gperf.gperf21
-rw-r--r--src/udev/net/link-config.c244
-rw-r--r--src/udev/net/link-config.h55
-rw-r--r--src/udev/udev-builtin-net_link.c96
-rw-r--r--src/udev/udev-builtin.c1
-rw-r--r--src/udev/udev.h2
8 files changed, 421 insertions, 0 deletions
diff --git a/src/udev/net/.gitignore b/src/udev/net/.gitignore
new file mode 100644
index 0000000000..9ca85bacc9
--- /dev/null
+++ b/src/udev/net/.gitignore
@@ -0,0 +1 @@
+/link-config-gperf.c
diff --git a/src/udev/net/Makefile b/src/udev/net/Makefile
new file mode 120000
index 0000000000..94aaae2c4d
--- /dev/null
+++ b/src/udev/net/Makefile
@@ -0,0 +1 @@
+../../Makefile \ No newline at end of file
diff --git a/src/udev/net/link-config-gperf.gperf b/src/udev/net/link-config-gperf.gperf
new file mode 100644
index 0000000000..c567e6dfaa
--- /dev/null
+++ b/src/udev/net/link-config-gperf.gperf
@@ -0,0 +1,21 @@
+%{
+#include <stddef.h>
+#include "conf-parser.h"
+#include "link-config.h"
+%}
+struct ConfigPerfItem;
+%null_strings
+%language=ANSI-C
+%define slot-name section_and_lvalue
+%define hash-function-name link_config_gperf_hash
+%define lookup-function-name link_config_gperf_lookup
+%readonly-tables
+%omit-struct-type
+%struct-type
+%includes
+%%
+Match.MACAddress, config_parse_string, 0, offsetof(link_config, match_mac)
+Match.Path, config_parse_string, 0, offsetof(link_config, match_path)
+Match.Driver, config_parse_string, 0, offsetof(link_config, match_driver)
+Match.Type, config_parse_string, 0, offsetof(link_config, match_type)
+Link.Description, config_parse_string, 0, offsetof(link_config, description)
diff --git a/src/udev/net/link-config.c b/src/udev/net/link-config.c
new file mode 100644
index 0000000000..7686d87f80
--- /dev/null
+++ b/src/udev/net/link-config.c
@@ -0,0 +1,244 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright (C) 2013 Tom Gundersen <teg@jklm.no>
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "link-config.h"
+
+#include "util.h"
+#include "log.h"
+#include "strv.h"
+#include "path-util.h"
+#include "conf-parser.h"
+#include "conf-files.h"
+
+struct link_config_ctx {
+ LIST_HEAD(link_config, links);
+
+ char **link_dirs;
+ usec_t *link_dirs_ts_usec;
+};
+
+int link_config_ctx_new(link_config_ctx **ret) {
+ link_config_ctx *ctx;
+
+ if (!ret)
+ return -EINVAL;
+
+ ctx = new0(link_config_ctx, 1);
+ if (!ctx)
+ return -ENOMEM;
+
+ LIST_HEAD_INIT(ctx->links);
+
+ ctx->link_dirs = strv_new("/etc/net/links",
+ "/run/net/links",
+ "/usr/lib/net/links",
+ NULL);
+ if (!ctx->link_dirs) {
+ log_error("failed to build link config directory array");
+ link_config_ctx_free(ctx);
+ return -ENOMEM;
+ }
+ if (!path_strv_canonicalize_uniq(ctx->link_dirs)) {
+ log_error("failed to canonicalize link config directories\n");
+ link_config_ctx_free(ctx);
+ return -ENOMEM;
+ }
+
+ ctx->link_dirs_ts_usec = calloc(strv_length(ctx->link_dirs), sizeof(usec_t));
+ if(!ctx->link_dirs_ts_usec) {
+ link_config_ctx_free(ctx);
+ return -ENOMEM;
+ }
+
+ *ret = ctx;
+ return 0;
+}
+
+static void link_configs_free(link_config_ctx *ctx) {
+ link_config *link, *link_next;
+
+ if (!ctx)
+ return;
+
+ LIST_FOREACH_SAFE(links, link, link_next, ctx->links) {
+ free(link->filename);
+ free(link->match_path);
+ free(link->match_driver);
+ free(link->match_type);
+ free(link->description);
+
+ free(link);
+ }
+}
+
+void link_config_ctx_free(link_config_ctx *ctx) {
+ if (!ctx)
+ return;
+
+ strv_free(ctx->link_dirs);
+ free(ctx->link_dirs_ts_usec);
+ link_configs_free(ctx);
+
+ free(ctx);
+
+ return;
+}
+
+static int load_link(link_config_ctx *ctx, const char *filename) {
+ link_config *link;
+ FILE *file;
+ int r;
+
+ file = fopen(filename, "re");
+ if (!file) {
+ if (errno == ENOENT)
+ return 0;
+ else
+ return errno;
+ }
+
+ link = new0(link_config, 1);
+ if (!link) {
+ r = log_oom();
+ goto failure;
+ }
+
+ r = config_parse(NULL, filename, file, "Match\0Link\0Ethernet\0", config_item_perf_lookup,
+ (void*) link_config_gperf_lookup, false, false, link);
+ if (r < 0) {
+ log_warning("Colud not parse config file %s: %s", filename, strerror(-r));
+ goto failure;
+ } else
+ log_info("Parsed configuration file %s", filename);
+
+ link->filename = strdup(filename);
+
+ LIST_PREPEND(links, ctx->links, link);
+
+ return 0;
+
+failure:
+ free(link);
+ return r;
+}
+
+int link_config_load(link_config_ctx *ctx) {
+ int r;
+ char **files, **f;
+
+ link_configs_free(ctx);
+
+ /* update timestamps */
+ paths_check_timestamp(ctx->link_dirs, ctx->link_dirs_ts_usec, true);
+
+ r = conf_files_list_strv(&files, ".link", NULL, (const char **)ctx->link_dirs);
+ if (r < 0) {
+ log_error("failed to enumerate link files: %s", strerror(-r));
+ return r;
+ }
+
+ STRV_FOREACH_BACKWARDS(f, files) {
+ r = load_link(ctx, *f);
+ if (r < 0)
+ return r;
+ }
+
+ return 0;
+}
+
+bool link_config_should_reload(link_config_ctx *ctx) {
+ return paths_check_timestamp(ctx->link_dirs, ctx->link_dirs_ts_usec, false);
+}
+
+static bool match_config(link_config *match, struct udev_device *device) {
+ const char *property;
+
+ if (match->match_mac) {
+ property = udev_device_get_sysattr_value(device, "address");
+ if (!property || !streq(match->match_mac, property)) {
+ log_debug("Device MAC address (%s) did not match MACAddress=%s", property, match->match_mac);
+ return 0;
+ }
+ }
+
+ if (match->match_path) {
+ property = udev_device_get_property_value(device, "ID_PATH");
+ if (!property || !streq(match->match_path, property)) {
+ log_debug("Device's persistent path (%s) did not match Path=%s", property, match->match_path);
+ return 0;
+ }
+ }
+
+ if (match->match_driver) {
+ property = udev_device_get_driver(device);
+ if (!property || !streq(match->match_driver, property)) {
+ log_debug("Device driver (%s) did not match Driver=%s", property, match->match_driver);
+ return 0;
+ }
+ }
+
+ if (match->match_type) {
+ property = udev_device_get_devtype(device);
+ if (!property || !streq(match->match_type, property)) {
+ log_debug("Device type (%s) did not match Type=%s", property, match->match_type);
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+int link_config_get(link_config_ctx *ctx, struct udev_device *device, link_config **ret) {
+ link_config *link;
+
+ LIST_FOREACH(links, link, ctx->links) {
+ if (!match_config(link, device)) {
+ log_info("Config file %s does not apply to device %s", link->filename, udev_device_get_sysname(device));
+ } else {
+ log_info("Config file %s applies to device %s", link->filename, udev_device_get_sysname(device));
+ *ret = link;
+ return 0;
+ }
+ }
+
+ return -ENOENT;
+}
+
+int link_config_apply(link_config_ctx *ctx, link_config *config, struct udev_device *device) {
+ const char *name;
+ int r;
+
+ name = udev_device_get_sysname(device);
+ if (!name)
+ return -EINVAL;
+
+ log_info("Configuring %s", name);
+
+ if (config->description) {
+ r = udev_device_set_sysattr_value(device, "ifalias", config->description);
+ if (r < 0)
+ log_warning("Could not set description of %s to '%s': %s", name, config->description, strerror(-r));
+ else
+ log_info("Set link description of %s to '%s'", name, config->description);
+ }
+
+ return 0;
+}
diff --git a/src/udev/net/link-config.h b/src/udev/net/link-config.h
new file mode 100644
index 0000000000..da5608ce4c
--- /dev/null
+++ b/src/udev/net/link-config.h
@@ -0,0 +1,55 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright (C) 2013 Tom Gundersen <teg@jklm.no>
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#pragma once
+
+#include "libudev.h"
+#include "util.h"
+#include "list.h"
+
+
+typedef struct link_config_ctx link_config_ctx;
+typedef struct link_config link_config;
+
+struct link_config {
+ char *filename;
+
+ char *match_mac;
+ char *match_path;
+ char *match_driver;
+ char *match_type;
+
+ char *description;
+
+ LIST_FIELDS(link_config, links);
+};
+
+int link_config_ctx_new(link_config_ctx **ret);
+void link_config_ctx_free(link_config_ctx *ctx);
+
+int link_config_load(link_config_ctx *ctx);
+bool link_config_should_reload(link_config_ctx *ctx);
+
+int link_config_get(link_config_ctx *ctx, struct udev_device *device, struct link_config **ret);
+int link_config_apply(link_config_ctx *ctx, struct link_config *config, struct udev_device *device);
+
+/* gperf lookup function */
+const struct ConfigPerfItem* link_config_gperf_lookup(const char *key, unsigned length);
diff --git a/src/udev/udev-builtin-net_link.c b/src/udev/udev-builtin-net_link.c
new file mode 100644
index 0000000000..d7cbe6a016
--- /dev/null
+++ b/src/udev/udev-builtin-net_link.c
@@ -0,0 +1,96 @@
+/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
+
+/***
+ This file is part of systemd.
+
+ Copyright 2013 Tom Gundersen
+
+ systemd is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Lesser General Public License as published by
+ the Free Software Foundation; either version 2.1 of the License, or
+ (at your option) any later version.
+
+ systemd is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public License
+ along with systemd; If not, see <http://www.gnu.org/licenses/>.
+***/
+
+#include "link-config.h"
+#include "udev.h"
+#include "log.h"
+
+link_config_ctx *ctx;
+
+static int builtin_net_link(struct udev_device *dev, int argc, char **argv, bool test) {
+ link_config *link;
+ int r;
+
+ if (argc > 1) {
+ log_error("This program takes no arguments.");
+ return EXIT_FAILURE;
+ }
+
+ r = link_config_get(ctx, dev, &link);
+ if (r < 0) {
+ if (r == -ENOENT) {
+ log_info("No matching link configuration found");
+ return EXIT_SUCCESS;
+ } else {
+ log_error("Could not get link config");
+ return EXIT_FAILURE;
+ }
+ }
+
+ r = link_config_apply(ctx, link, dev);
+ if (r < 0) {
+ log_error("Could not apply link config");
+ return EXIT_FAILURE;
+ }
+
+ return EXIT_SUCCESS;
+}
+
+static int builtin_net_link_init(struct udev *udev) {
+ int r;
+
+ if (ctx)
+ return 0;
+
+ r = link_config_ctx_new(&ctx);
+ if (r < 0)
+ return r;
+
+ r = link_config_load(ctx);
+ if (r < 0)
+ return r;
+
+ log_debug("Created link configuration context");
+ return 0;
+}
+
+static void builtin_net_link_exit(struct udev *udev) {
+ link_config_ctx_free(ctx);
+ log_debug("Unloaded link configuration context");
+}
+
+static bool builtin_net_link_validate(struct udev *udev) {
+ log_debug("Check if link configuration needs reloading");
+ if (!ctx)
+ return false;
+
+ return link_config_should_reload(ctx);
+}
+
+const struct udev_builtin udev_builtin_net_link = {
+ .name = "net_link",
+ .cmd = builtin_net_link,
+ .init = builtin_net_link_init,
+ .exit = builtin_net_link_exit,
+ .validate = builtin_net_link_validate,
+ .help = "configure network link",
+ .run_once = false,
+};
diff --git a/src/udev/udev-builtin.c b/src/udev/udev-builtin.c
index 6b3a518c2e..85901e8ee3 100644
--- a/src/udev/udev-builtin.c
+++ b/src/udev/udev-builtin.c
@@ -44,6 +44,7 @@ static const struct udev_builtin *builtins[] = {
[UDEV_BUILTIN_KMOD] = &udev_builtin_kmod,
#endif
[UDEV_BUILTIN_NET_ID] = &udev_builtin_net_id,
+ [UDEV_BUILTIN_NET_LINK] = &udev_builtin_net_link,
[UDEV_BUILTIN_PATH_ID] = &udev_builtin_path_id,
[UDEV_BUILTIN_USB_ID] = &udev_builtin_usb_id,
#ifdef HAVE_ACL
diff --git a/src/udev/udev.h b/src/udev/udev.h
index 29e96d637e..7cca8b8c83 100644
--- a/src/udev/udev.h
+++ b/src/udev/udev.h
@@ -153,6 +153,7 @@ enum udev_builtin_cmd {
UDEV_BUILTIN_KMOD,
#endif
UDEV_BUILTIN_NET_ID,
+ UDEV_BUILTIN_NET_LINK,
UDEV_BUILTIN_PATH_ID,
UDEV_BUILTIN_USB_ID,
#ifdef HAVE_ACL
@@ -183,6 +184,7 @@ extern const struct udev_builtin udev_builtin_keyboard;
extern const struct udev_builtin udev_builtin_kmod;
#endif
extern const struct udev_builtin udev_builtin_net_id;
+extern const struct udev_builtin udev_builtin_net_link;
extern const struct udev_builtin udev_builtin_path_id;
extern const struct udev_builtin udev_builtin_usb_id;
extern const struct udev_builtin udev_builtin_uaccess;