1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
|
#!perl
# vim:ts=4:sw=4:et
use strict;
use warnings;
use Test::More;
use File::Temp qw(tempfile tempdir); # in core since perl 5.6.1
use File::Path qw(make_path); # in core since Perl 5.001
use File::Basename; # in core since Perl 5
use FindBin; # in core since Perl 5.00307
use Linux::Clone; # neither in core nor in Debian :-/
# ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
# ┃ SETUP: in a new mount namespace, bindmount tmpdirs on /etc/systemd and ┃
# ┃ /var/lib/systemd to start with clean directories yet use the actual ┃
# ┃ locations and code paths. ┃
# ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
my $dsh = "$FindBin::Bin/../script/deb-systemd-helper";
sub _unit_check {
my ($unit_file, $cmd, $cb, $verb) = @_;
my $retval = system("DPKG_MAINTSCRIPT_PACKAGE=test $dsh $cmd $unit_file");
isnt($retval, -1, 'deb-systemd-helper could be executed');
ok(!($retval & 127), 'deb-systemd-helper did not exit due to a signal');
$cb->($retval >> 8, 0, "random unit file $unit_file $verb $cmd");
}
sub is_enabled { _unit_check($_[0], 'is-enabled', \&is, 'is') }
sub isnt_enabled { _unit_check($_[0], 'is-enabled', \&isnt, 'isnt') }
sub is_debian_installed { _unit_check($_[0], 'debian-installed', \&is, 'is') }
sub isnt_debian_installed { _unit_check($_[0], 'debian-installed', \&isnt, 'isnt') }
my $retval = Linux::Clone::unshare Linux::Clone::NEWNS;
BAIL_OUT("Cannot unshare(NEWNS): $!") if $retval != 0;
sub bind_mount_tmp {
my ($dir) = @_;
my $tmp = tempdir(CLEANUP => 1);
system("mount -n --bind $tmp $dir") == 0
or BAIL_OUT("bind-mounting $tmp to $dir failed: $!");
return $tmp;
}
my $etc_systemd = bind_mount_tmp('/etc/systemd');
my $lib_systemd = bind_mount_tmp('/lib/systemd');
my $var_lib_systemd = bind_mount_tmp('/var/lib/systemd');
# ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
# ┃ Create two unit files with random names; one refers to the other (Also=). ┃
# ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
my ($fh1, $random_unit1) = tempfile('unitXXXXX',
SUFFIX => '.service',
TMPDIR => 1,
UNLINK => 1);
close($fh1);
$random_unit1 = basename($random_unit1);
my ($fh2, $random_unit2) = tempfile('unitXXXXX',
SUFFIX => '.service',
TMPDIR => 1,
UNLINK => 1);
close($fh2);
$random_unit2 = basename($random_unit2);
my $servicefile_path1 = "/lib/systemd/system/$random_unit1";
my $servicefile_path2 = "/lib/systemd/system/$random_unit2";
make_path('/lib/systemd/system');
open($fh1, '>', $servicefile_path1);
print $fh1 <<EOT;
[Unit]
Description=test unit
[Service]
ExecStart=/bin/sleep 1
[Install]
WantedBy=multi-user.target
Also=$random_unit2
EOT
close($fh1);
open($fh2, '>', $servicefile_path2);
print $fh2 <<EOT;
[Unit]
Description=test unit
[Service]
ExecStart=/bin/sleep 1
[Install]
WantedBy=multi-user.target
Alias=alias2.service
EOT
close($fh2);
isnt_enabled($random_unit1);
isnt_enabled($random_unit2);
isnt_debian_installed($random_unit1);
isnt_debian_installed($random_unit2);
# ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
# ┃ Verify “enable” creates all symlinks. ┃
# ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
ok(! -d '/etc/systemd/system/multi-user.target.wants',
'multi-user.target.wants does not exist yet');
$retval = system("DPKG_MAINTSCRIPT_PACKAGE=test $dsh enable $random_unit1");
my %links = map { (basename($_), readlink($_)) }
</etc/systemd/system/multi-user.target.wants/*.service>;
is_deeply(
\%links,
{
$random_unit1 => $servicefile_path1,
$random_unit2 => $servicefile_path2,
},
'All expected links present');
my $alias_path = '/etc/systemd/system/alias2.service';
ok(-l $alias_path, 'alias created');
is(readlink($alias_path), $servicefile_path2,
'alias points to the correct service file');
# ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
# ┃ Verify “is-enabled” now returns true. ┃
# ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
is_enabled($random_unit1);
is_enabled($random_unit2);
is_debian_installed($random_unit1);
# $random_unit2 was only enabled _because of_ $random_unit1’s Also= statement
# and thus does not have its own state file.
isnt_debian_installed($random_unit2);
# TODO: cleanup tests?
done_testing;
|