summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/libsystemd/sd-device/device-private.h2
-rw-r--r--src/libsystemd/sd-device/sd-device.c36
-rw-r--r--src/udev/udev-rules.c25
-rwxr-xr-xtest/udev-test.pl30
4 files changed, 72 insertions, 21 deletions
diff --git a/src/libsystemd/sd-device/device-private.h b/src/libsystemd/sd-device/device-private.h
index 740c58438c..b903d1afd6 100644
--- a/src/libsystemd/sd-device/device-private.h
+++ b/src/libsystemd/sd-device/device-private.h
@@ -38,7 +38,7 @@ void device_set_db_persist(sd_device *device);
void device_set_devlink_priority(sd_device *device, int priority);
int device_ensure_usec_initialized(sd_device *device, sd_device *device_old);
int device_add_devlink(sd_device *device, const char *devlink);
-void device_remove_devlink(sd_device *device, const char *devlink);
+int device_remove_devlink(sd_device *device, const char *devlink);
bool device_has_devlink(sd_device *device, const char *devlink);
int device_add_property(sd_device *device, const char *property, const char *value);
int device_add_propertyf(sd_device *device, const char *key, const char *format, ...) _printf_(3, 4);
diff --git a/src/libsystemd/sd-device/sd-device.c b/src/libsystemd/sd-device/sd-device.c
index e86ec3e75b..2a5defca65 100644
--- a/src/libsystemd/sd-device/sd-device.c
+++ b/src/libsystemd/sd-device/sd-device.c
@@ -1473,34 +1473,58 @@ int device_add_tag(sd_device *device, const char *tag, bool both) {
return 0;
}
+static char *prefix_dev(const char *p) {
+ assert(p);
+
+ if (path_startswith(p, "/dev/"))
+ return strdup(p);
+
+ return path_join("/dev/", p);
+}
+
int device_add_devlink(sd_device *device, const char *devlink) {
+ char *p;
int r;
assert(device);
assert(devlink);
- r = set_put_strdup(&device->devlinks, devlink);
+ if (!path_is_safe(devlink))
+ return -EINVAL;
+
+ p = prefix_dev(devlink);
+ if (!p)
+ return -ENOMEM;
+
+ path_simplify(p);
+
+ r = set_ensure_consume(&device->devlinks, &path_hash_ops_free, p);
if (r < 0)
return r;
device->devlinks_generation++;
device->property_devlinks_outdated = true;
- return 0;
+ return r; /* return 1 when newly added, 0 when already exists */
}
-void device_remove_devlink(sd_device *device, const char *devlink) {
- _cleanup_free_ char *s = NULL;
+int device_remove_devlink(sd_device *device, const char *devlink) {
+ _cleanup_free_ char *p = NULL, *s = NULL;
assert(device);
assert(devlink);
- s = set_remove(device->devlinks, devlink);
+ p = prefix_dev(devlink);
+ if (!p)
+ return -ENOMEM;
+
+ s = set_remove(device->devlinks, p);
if (!s)
- return;
+ return 0; /* does not exist */
device->devlinks_generation++;
device->property_devlinks_outdated = true;
+ return 1; /* removed */
}
bool device_has_devlink(sd_device *device, const char *devlink) {
diff --git a/src/udev/udev-rules.c b/src/udev/udev-rules.c
index 58c5c81574..68f0a363be 100644
--- a/src/udev/udev-rules.c
+++ b/src/udev/udev-rules.c
@@ -2574,9 +2574,9 @@ static int udev_rule_apply_token_to_event(
count, token->value);
for (const char *p = buf;;) {
- _cleanup_free_ char *word = NULL, *path = NULL;
+ _cleanup_free_ char *path = NULL;
- r = extract_first_word(&p, &word, NULL, EXTRACT_RETAIN_ESCAPE);
+ r = extract_first_word(&p, &path, NULL, EXTRACT_RETAIN_ESCAPE);
if (r == -ENOMEM)
return log_oom();
if (r < 0) {
@@ -2586,19 +2586,22 @@ static int udev_rule_apply_token_to_event(
if (r == 0)
break;
- path = path_join("/dev/", word);
- if (!path)
- return log_oom();
-
if (token->op == OP_REMOVE) {
- device_remove_devlink(dev, path);
- log_event_debug(dev, token, "Dropped SYMLINK '%s'", path);
+ r = device_remove_devlink(dev, path);
+ if (r == -ENOMEM)
+ return log_oom();
+ if (r < 0)
+ log_event_warning_errno(dev, token, r, "Failed to remove devlink '%s', ignoring: %m", path);
+ else if (r > 0)
+ log_event_debug(dev, token, "Dropped SYMLINK '%s'", path);
} else {
r = device_add_devlink(dev, path);
+ if (r == -ENOMEM)
+ return log_oom();
if (r < 0)
- return log_event_error_errno(dev, token, r, "Failed to add devlink '%s': %m", path);
-
- log_event_debug(dev, token, "Added SYMLINK '%s'", path);
+ log_event_warning_errno(dev, token, r, "Failed to add devlink '%s', ignoring: %m", path);
+ else if (r > 0)
+ log_event_debug(dev, token, "Added SYMLINK '%s'", path);
}
}
break;
diff --git a/test/udev-test.pl b/test/udev-test.pl
index a493485fc1..9b3641b3d9 100755
--- a/test/udev-test.pl
+++ b/test/udev-test.pl
@@ -212,13 +212,37 @@ EOF
{
devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
exp_links => ["boot_disk1", "boot_diskXY1"],
- not_exp_links => ["boot_diskXX1", "hoge"],
+ not_exp_links => ["boot_diskXX1"],
}],
rules => <<EOF
SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", ATTRS{model}=="ST910021AS", ATTRS{scsi_level}=="6", ATTRS{rev}=="4.06", ATTRS{type}=="0", ATTRS{queue_depth}=="32", SYMLINK+="boot_diskXX%n"
SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", ATTRS{model}=="ST910021AS", ATTRS{scsi_level}=="6", ATTRS{rev}=="4.06", ATTRS{type}=="0", ATTRS{queue_depth}=="1", SYMLINK+="boot_diskXY%n"
-SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", ATTRS{model}=="ST910021AS", ATTRS{scsi_level}=="6", ATTRS{rev}=="4.06", ATTRS{type}=="0", SYMLINK+="boot_disk%n", SYMLINK+="hoge"
-SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", ATTRS{model}=="ST910021AS", ATTRS{scsi_level}=="6", ATTRS{rev}=="4.06", ATTRS{type}=="0", SYMLINK-="hoge"
+SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", ATTRS{model}=="ST910021AS", ATTRS{scsi_level}=="6", ATTRS{rev}=="4.06", ATTRS{type}=="0", SYMLINK+="boot_disk%n"
+EOF
+ },
+ {
+ desc => "SYMLINK tests",
+ devices => [
+ {
+ devpath => "/devices/pci0000:00/0000:00:1f.2/host0/target0:0:0/0:0:0:0/block/sda/sda1",
+ exp_links => ["link1", "link2/foo", "link3/aaa/bbb",
+ "default___replace_test/foo_aaa",
+ "string_escape___replace/foo_bbb",
+ "env_with_space",
+ "default/replace/mode_foo__hoge",
+ "replace_env_harder_foo__hoge"],
+ not_exp_links => ["removed", "unsafe/../../path"],
+ }],
+ rules => <<EOF
+SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", ATTRS{model}=="ST910021AS", SYMLINK+="removed"
+SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", ATTRS{model}=="ST910021AS", SYMLINK-="removed"
+SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", ATTRS{model}=="ST910021AS", SYMLINK+="unsafe/../../path"
+SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", ATTRS{model}=="ST910021AS", SYMLINK+="link1 link2/foo link3/aaa/bbb"
+SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", ATTRS{model}=="ST910021AS", SYMLINK+="default?;;replace%%test/foo'aaa"
+SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", ATTRS{model}=="ST910021AS", OPTIONS="string_escape=replace", SYMLINK+="string_escape replace/foo%%bbb"
+SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", ATTRS{model}=="ST910021AS", ENV{.HOGE}="env with space", SYMLINK+="%E{.HOGE}"
+SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", ATTRS{model}=="ST910021AS", ENV{.HOGE}="default/replace/mode?foo;;hoge", SYMLINK+="%E{.HOGE}"
+SUBSYSTEMS=="scsi", ATTRS{vendor}=="ATA", ATTRS{model}=="ST910021AS", OPTIONS="string_escape=replace", ENV{.HOGE}="replace/env/harder?foo;;hoge", SYMLINK+="%E{.HOGE}"
EOF
},
{