From dcebc9bae4dcc3e844f01558c6127fc0d8745c8e Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Thu, 26 Oct 2017 17:12:44 +0200 Subject: [PATCH] core: when a unit template is specified in SYSTEMD_WANTS=, instantiate it with sysfs path This should make cases like the user's setup in #7109 a lot easier to handle, as in that case we'll do the right escaping automatically. --- man/systemd.device.xml | 71 +++++++++++++++++++++++--------------------------- src/core/device.c | 25 +++++++++++++++--- 2 files changed, 54 insertions(+), 42 deletions(-) diff --git a/man/systemd.device.xml b/man/systemd.device.xml index 6edf109..e121e15 100644 --- a/man/systemd.device.xml +++ b/man/systemd.device.xml @@ -112,35 +112,36 @@ The udev Database - The settings of device units may either be configured via - unit files, or directly from the udev database (which is - recommended). The following udev device properties are understood - by systemd: + Unit settings of device units may either be configured via unit files, or directly from the udev + database. The following udev device properties are understood by the service manager: SYSTEMD_WANTS= SYSTEMD_USER_WANTS= - Adds dependencies of type - Wants from the device unit to all listed - units. The first form is used by the system systemd instance, - the second by user systemd instances. Those settings may be - used to activate arbitrary units when a specific device - becomes available. - - Note that this and the other tags are not taken into - account unless the device is tagged with the - systemd string in the udev database, - because otherwise the device is not exposed as a systemd unit - (see above). - - Note that systemd will only act on - Wants dependencies when a device first - becomes active. It will not act on them if they are added to - devices that are already active. Use - SYSTEMD_READY= (see below) to influence on - which udev event to trigger the dependencies. - + Adds dependencies of type Wants= from the device unit to the specified + units. SYSTEMD_WANTS= is read by the system service manager, + SYSTEMD_USER_WANTS= by user service manager instances. These properties may be used to + activate arbitrary units when a specific device becomes available. + + Note that this and the other udev device properties are not taken into account unless the device is + tagged with the systemd tag in the udev database, because otherwise the device is not + exposed as a systemd unit (see above). + + Note that systemd will only act on Wants= dependencies when a device first becomes + active. It will not act on them if they are added to devices that are already active. Use + SYSTEMD_READY= (see below) to configure when a udev device shall be considered active, and + thus when to trigger the dependencies. + + + + The specified property value should be a space-separated list of valid unit names. If a unit template + name is specified (that is, a unit name containing an @ character indicating a unit name to + use for multiple instantiation, but with an empty instance name following the @), it will be + automatically instantiated by the device's sysfs path (that is: the path is escaped and + inserted as instance name into the template unit name). This is useful in order to instantiate a specific + template unit once for each device that appears and matches specific properties. @@ -152,20 +153,14 @@ SYSTEMD_READY= - If set to 0, systemd will consider this device - unplugged even if it shows up in the udev tree. If this - property is unset or set to 1, the device will be considered - plugged if it is visible in the udev tree. This property has - no influence on the behavior when a device disappears from the - udev tree. - - This option is useful to support devices that initially - show up in an uninitialized state in the tree, and for which a - changed event is generated the moment they - are fully set up. Note that SYSTEMD_WANTS= - (see above) is not acted on as long as - SYSTEMD_READY=0 is set for a - device. + If set to 0, systemd will consider this device unplugged even if it shows up in the udev + tree. If this property is unset or set to 1, the device will be considered plugged if it is visible in the udev + tree. + + This option is useful for devices that initially show up in an uninitialized state in the tree, and for + which a changed event is generated the moment they are fully set up. Note that + SYSTEMD_WANTS= (see above) is not acted on as long as SYSTEMD_READY=0 is + set for a device. diff --git a/src/core/device.c b/src/core/device.c index bfab494..a015075 100644 --- a/src/core/device.c +++ b/src/core/device.c @@ -277,11 +277,28 @@ static int device_add_udev_wants(Unit *u, struct udev_device *dev) { if (r == -ENOMEM) return log_oom(); if (r < 0) - return log_unit_error_errno(u, r, "Failed to add parse %s: %m", property); + return log_unit_error_errno(u, r, "Failed to parse property %s with value %s: %m", property, wants); - r = unit_name_mangle(word, UNIT_NAME_NOGLOB, &k); - if (r < 0) - return log_unit_error_errno(u, r, "Failed to mangle unit name \"%s\": %m", word); + if (unit_name_is_valid(word, UNIT_NAME_TEMPLATE) && DEVICE(u)->sysfs) { + _cleanup_free_ char *escaped = NULL; + + /* If the unit name is specified as template, then automatically fill in the sysfs path of the + * device as instance name, properly escaped. */ + + r = unit_name_path_escape(DEVICE(u)->sysfs, &escaped); + if (r < 0) + return log_unit_error_errno(u, r, "Failed to escape %s: %m", DEVICE(u)->sysfs); + + r = unit_name_replace_instance(word, escaped, &k); + if (r < 0) + return log_unit_error_errno(u, r, "Failed to build %s instance of template %s: %m", escaped, word); + } else { + /* If this is not a template, then let's mangle it so, that it becomes a valid unit name. */ + + r = unit_name_mangle(word, UNIT_NAME_NOGLOB, &k); + if (r < 0) + return log_unit_error_errno(u, r, "Failed to mangle unit name \"%s\": %m", word); + } r = unit_add_dependency_by_name(u, UNIT_WANTS, k, NULL, true, UNIT_DEPENDENCY_UDEV); if (r < 0) -- 2.7.4