Package: init-system-helpers
Version: 1.29

Systemd unit names can have valid \ escape characters. See
systemd-escape(1) for examples. When a unit references a another unit
with escaped characters, init-system-helpers handles them incorrectly.
For example, a unit file having WantedBy=foo\x2dbar.target will have
an /etc/systemd/system/foox2dbar.target.wants directory created
without the x escaped by \.

The attached patch fixes this.

--
Dan Nicholson  |  +1.206.437.0833  |  Endless
From 4d2c003bd4f7739d1d075e7f7e067292030e47ce Mon Sep 17 00:00:00 2001
From: Dan Nicholson <nichol...@endlessm.com>
Date: Thu, 7 Apr 2016 11:08:23 -0700
Subject: [PATCH] script: Handle \ escapes in unit names properly

Unit names can contain valid \ escapes in systemd. See systemd-escape(1)
for examples. Text::ParseWords::shellwords breaks that since it strips \
in addition to quotes. Use quotewords directly with keep set and strip
the leading/trailing quotes as necessary.
---
 debian/changelog          |  7 +++++++
 script/deb-systemd-helper | 14 ++++++++++----
 script/dh_systemd_enable  |  1 -
 script/dh_systemd_start   | 10 ++++++++--
 4 files changed, 25 insertions(+), 7 deletions(-)

diff --git a/debian/changelog b/debian/changelog
index e5e0ce5..bd16993 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -11,6 +11,13 @@ init-system-helpers (1.30) UNRELEASED; urgency=medium
   * dh_systemd_*: Add DH promise to avoid being called for no reason.
   * Update Vcs-* fields to use https.
 
+  [ Dan Nicholson ]
+  * deb-systemd-helper, dh_systemd_start: Use Text::ParseWords::quotewords
+    rather than shellwords since the latter will strip valid \ escapes
+    from unit names. The returned values then need to have leading and
+    trailing quotes stripped.
+  * dh_systemd_enable: Drop unused Text::ParseWords use.
+
  -- Felipe Sateler <fsate...@debian.org>  Fri, 11 Mar 2016 18:48:39 -0300
 
 init-system-helpers (1.29) unstable; urgency=medium
diff --git a/script/deb-systemd-helper b/script/deb-systemd-helper
index 2a87cb4..dc10b0c 100755
--- a/script/deb-systemd-helper
+++ b/script/deb-systemd-helper
@@ -85,7 +85,7 @@ use warnings;
 use File::Path qw(make_path); # in core since Perl 5.001
 use File::Basename; # in core since Perl 5
 use File::Temp qw(tempfile); # in core since Perl 5.6.1
-use Text::ParseWords qw(shellwords); # in core since Perl 5
+use Text::ParseWords qw(quotewords); # in core since Perl 5
 use Getopt::Long; # in core since Perl 5
 # Make Data::Dumper::Dumper available if present (not present on systems that
 # only have perl-base, not perl).
@@ -183,13 +183,17 @@ sub get_link_closure {
 
     my $unit_name = basename($service_path);
 
+    # Use quotewords to split, but keep characters and remove
+    # leading/trailing quotes since \ is valid in systemd unit names.
+    # See systemd-escape(1).
     open my $fh, '<', $service_path or error("unable to read $service_path");
     while (my $line = <$fh>) {
         chomp($line);
         my $service_link;
 
         if ($line =~ /^\s*(WantedBy|RequiredBy)=(.+)$/i) {
-            for my $value (shellwords($2)) {
+            for my $value (quotewords('\s+', 1, $2)) {
+                $value =~ s/^(["'])(.*)\g1$/$2/;
                 my $wants_dir = "/etc/systemd/system/$value";
                 $wants_dir .= '.wants' if $1 eq 'WantedBy';
                 $wants_dir .= '.requires' if $1 eq 'RequiredBy';
@@ -198,7 +202,8 @@ sub get_link_closure {
         }
 
         if ($line =~ /^\s*Also=(.+)$/i) {
-            for my $value (shellwords($1)) {
+            for my $value (quotewords('\s+', 1, $1)) {
+                $value =~ s/^(["'])(.*)\g1$/$2/;
                 if ($value ne $unit_name) {
                     push @links, get_link_closure($value, find_unit($value));
                 }
@@ -206,7 +211,8 @@ sub get_link_closure {
         }
 
         if ($line =~ /^\s*Alias=(.+)$/i) {
-            for my $value (shellwords($1)) {
+            for my $value (quotewords('\s+', 1, $1)) {
+                $value =~ s/^(["'])(.*)\g1$/$2/;
                 if ($value ne $unit_name) {
                     push @links, { dest => $service_path, src => "/etc/systemd/system/$1" };
                 }
diff --git a/script/dh_systemd_enable b/script/dh_systemd_enable
index 39955c4..a45615b 100755
--- a/script/dh_systemd_enable
+++ b/script/dh_systemd_enable
@@ -9,7 +9,6 @@ dh_systemd_enable - enable/disable systemd unit files
 use strict;
 use Debian::Debhelper::Dh_Lib;
 use File::Find;
-use Text::ParseWords qw(shellwords); # in core since Perl 5
 
 =head1 SYNOPSIS
 
diff --git a/script/dh_systemd_start b/script/dh_systemd_start
index 4e22d59..8b14d8e 100755
--- a/script/dh_systemd_start
+++ b/script/dh_systemd_start
@@ -9,7 +9,7 @@ dh_systemd_start - start/stop/restart systemd unit files
 use strict;
 use Debian::Debhelper::Dh_Lib;
 use File::Find;
-use Text::ParseWords qw(shellwords); # in core since Perl 5
+use Text::ParseWords qw(quotewords); # in core since Perl 5
 use Cwd qw(getcwd abs_path);
 
 =head1 SYNOPSIS
@@ -107,8 +107,14 @@ sub extract_key {
 	while (my $line = <$fh>) {
 		chomp($line);
 
+		# Use quotewords to split, but keep characters and
+		# remove leading/trailing quotes since \ is valid in
+		# systemd unit names. See systemd-escape(1).
 		if ($line =~ /^\s*$key=(.+)$/i) {
-			@values = (@values, shellwords($1));
+			for my $value (quotewords('\s+', 1, $1)) {
+				$value =~ s/^(["'])(.*)\g1$/$2/;
+				push @values, $value;
+			}
 		}
 	}
 	close($fh);
-- 
2.5.5

Reply via email to