You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

402 lines
21 KiB

  1. #!perl
  2. # vim:ts=4:sw=4:et
  3. use strict;
  4. use warnings;
  5. use Test::More;
  6. use File::Temp qw(tempfile tempdir); # in core since perl 5.6.1
  7. use File::Path qw(make_path); # in core since Perl 5.001
  8. use File::Basename; # in core since Perl 5
  9. use FindBin; # in core since Perl 5.00307
  10. use Linux::Clone; # neither in core nor in Debian :-/
  11. # ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
  12. # ┃ SETUP: in a new mount namespace, bindmount tmpdirs on /etc/systemd and ┃
  13. # ┃ /var/lib/systemd to start with clean directories yet use the actual ┃
  14. # ┃ locations and code paths. ┃
  15. # ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
  16. my $dsh = "$FindBin::Bin/../script/deb-systemd-helper";
  17. sub _unit_check {
  18. my ($unit_file, $cmd, $cb, $verb) = @_;
  19. my $retval = system("DPKG_MAINTSCRIPT_PACKAGE=test $dsh $cmd '$unit_file'");
  20. isnt($retval, -1, 'deb-systemd-helper could be executed');
  21. ok(!($retval & 127), 'deb-systemd-helper did not exit due to a signal');
  22. $cb->($retval >> 8, 0, "random unit file $verb $cmd");
  23. }
  24. sub is_enabled { _unit_check($_[0], 'is-enabled', \&is, 'is') }
  25. sub isnt_enabled { _unit_check($_[0], 'is-enabled', \&isnt, 'isnt') }
  26. sub is_debian_installed { _unit_check($_[0], 'debian-installed', \&is, 'is') }
  27. sub isnt_debian_installed { _unit_check($_[0], 'debian-installed', \&isnt, 'isnt') }
  28. my $retval = Linux::Clone::unshare Linux::Clone::NEWNS;
  29. BAIL_OUT("Cannot unshare(NEWNS): $!") if $retval != 0;
  30. sub bind_mount_tmp {
  31. my ($dir) = @_;
  32. my $tmp = tempdir(CLEANUP => 1);
  33. system("mount -n --bind $tmp $dir") == 0
  34. or BAIL_OUT("bind-mounting $tmp to $dir failed: $!");
  35. return $tmp;
  36. }
  37. unless ($ENV{'TEST_ON_REAL_SYSTEM'}) {
  38. my $etc_systemd = bind_mount_tmp('/etc/systemd');
  39. my $lib_systemd = bind_mount_tmp('/lib/systemd');
  40. my $var_lib_systemd = bind_mount_tmp('/var/lib/systemd');
  41. }
  42. # ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
  43. # ┃ Verify “is-enabled” is not true for a random, non-existing unit file. ┃
  44. # ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
  45. my ($fh, $random_unit) = tempfile('unit\x2dXXXXX',
  46. SUFFIX => '.service',
  47. TMPDIR => 1,
  48. UNLINK => 1);
  49. close($fh);
  50. $random_unit = basename($random_unit);
  51. isnt_enabled($random_unit);
  52. isnt_debian_installed($random_unit);
  53. # ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
  54. # ┃ Verify “is-enabled” is not true for a random, existing unit file. ┃
  55. # ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
  56. my $servicefile_path = "/lib/systemd/system/$random_unit";
  57. make_path('/lib/systemd/system');
  58. open($fh, '>', $servicefile_path);
  59. print $fh <<'EOT';
  60. [Unit]
  61. Description=test unit
  62. [Service]
  63. ExecStart=/bin/sleep 1
  64. [Install]
  65. WantedBy=multi-user.target
  66. EOT
  67. close($fh);
  68. isnt_enabled($random_unit);
  69. isnt_debian_installed($random_unit);
  70. # ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
  71. # ┃ Verify “enable” creates the requested symlinks. ┃
  72. # ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
  73. unless ($ENV{'TEST_ON_REAL_SYSTEM'}) {
  74. # This might exist if we don't start from a fresh directory
  75. ok(! -d '/etc/systemd/system/multi-user.target.wants',
  76. 'multi-user.target.wants does not exist yet');
  77. }
  78. $retval = system("DPKG_MAINTSCRIPT_PACKAGE=test $dsh enable '$random_unit'");
  79. is($retval, 0, "enable command succeeded");
  80. my $symlink_path = "/etc/systemd/system/multi-user.target.wants/$random_unit";
  81. ok(-l $symlink_path, "$random_unit was enabled");
  82. is(readlink($symlink_path), $servicefile_path,
  83. "symlink points to $servicefile_path");
  84. # ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
  85. # ┃ Verify “is-enabled” now returns true. ┃
  86. # ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
  87. is_enabled($random_unit);
  88. is_debian_installed($random_unit);
  89. # ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
  90. # ┃ Verify deleting the symlinks and running “enable” again does not ┃
  91. # ┃ re-create the symlinks. ┃
  92. # ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
  93. unlink($symlink_path);
  94. ok(! -l $symlink_path, 'symlink deleted');
  95. isnt_enabled($random_unit);
  96. is_debian_installed($random_unit);
  97. $retval = system("DPKG_MAINTSCRIPT_PACKAGE=test $dsh enable '$random_unit'");
  98. is($retval, 0, "enable command succeeded");
  99. isnt_enabled($random_unit);
  100. # ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
  101. # ┃ Verify “disable” when purging deletes the statefile. ┃
  102. # ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
  103. my $statefile = "/var/lib/systemd/deb-systemd-helper-enabled/$random_unit.dsh-also";
  104. ok(-f $statefile, 'state file exists');
  105. $retval = system("DPKG_MAINTSCRIPT_PACKAGE=test _DEB_SYSTEMD_HELPER_PURGE=1 $dsh disable '$random_unit'");
  106. is($retval, 0, "disable command succeeded");
  107. ok(! -f $statefile, 'state file does not exist anymore after purging');
  108. isnt_debian_installed($random_unit);
  109. # ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
  110. # ┃ Verify “enable” after purging does re-create the symlinks. ┃
  111. # ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
  112. ok(! -l $symlink_path, 'symlink does not exist yet');
  113. isnt_enabled($random_unit);
  114. $retval = system("DPKG_MAINTSCRIPT_PACKAGE=test $dsh enable '$random_unit'");
  115. is($retval, 0, "enable command succeeded");
  116. is_enabled($random_unit);
  117. is_debian_installed($random_unit);
  118. # ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
  119. # ┃ Verify “disable” removes the symlinks. ┃
  120. # ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
  121. $retval = system("DPKG_MAINTSCRIPT_PACKAGE=test _DEB_SYSTEMD_HELPER_PURGE=1 $dsh disable '$random_unit'");
  122. is($retval, 0, "disable command succeeded");
  123. isnt_enabled($random_unit);
  124. # ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
  125. # ┃ Verify “enable” after purging does re-create the symlinks. ┃
  126. # ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
  127. ok(! -l $symlink_path, 'symlink does not exist yet');
  128. isnt_enabled($random_unit);
  129. $retval = system("DPKG_MAINTSCRIPT_PACKAGE=test $dsh enable '$random_unit'");
  130. is($retval, 0, "enable command succeeded");
  131. is_enabled($random_unit);
  132. is_debian_installed($random_unit);
  133. # ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
  134. # ┃ Verify the “purge” verb works. ┃
  135. # ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
  136. $retval = system("DPKG_MAINTSCRIPT_PACKAGE=test $dsh purge '$random_unit'");
  137. is($retval, 0, "purge command succeeded");
  138. isnt_enabled($random_unit);
  139. isnt_debian_installed($random_unit);
  140. # ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
  141. # ┃ Verify “enable” after purging does re-create the symlinks. ┃
  142. # ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
  143. ok(! -l $symlink_path, 'symlink does not exist yet');
  144. isnt_enabled($random_unit);
  145. $retval = system("DPKG_MAINTSCRIPT_PACKAGE=test $dsh enable '$random_unit'");
  146. is($retval, 0, "enable command succeeded");
  147. is_enabled($random_unit);
  148. is_debian_installed($random_unit);
  149. # ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
  150. # ┃ Verify “mask” (when enabled) results in the symlink pointing to /dev/null ┃
  151. # ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
  152. my $mask_path = "/etc/systemd/system/$random_unit";
  153. ok(! -l $mask_path, 'mask link does not exist yet');
  154. $retval = system("DPKG_MAINTSCRIPT_PACKAGE=test $dsh mask '$random_unit'");
  155. is($retval, 0, "mask command succeeded");
  156. ok(-l $mask_path, 'mask link exists');
  157. is(readlink($mask_path), '/dev/null', 'service masked');
  158. $retval = system("DPKG_MAINTSCRIPT_PACKAGE=test $dsh unmask '$random_unit'");
  159. is($retval, 0, "unmask command succeeded");
  160. ok(! -e $mask_path, 'mask link does not exist anymore');
  161. # ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
  162. # ┃ Verify “mask” (when disabled) works the same way ┃
  163. # ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
  164. $retval = system("DPKG_MAINTSCRIPT_PACKAGE=test $dsh disable '$random_unit'");
  165. is($retval, 0, "disable command succeeded");
  166. ok(! -e $symlink_path, 'symlink no longer exists');
  167. $retval = system("DPKG_MAINTSCRIPT_PACKAGE=test $dsh mask '$random_unit'");
  168. is($retval, 0, "mask command succeeded");
  169. ok(-l $mask_path, 'mask link exists');
  170. is(readlink($mask_path), '/dev/null', 'service masked');
  171. $retval = system("DPKG_MAINTSCRIPT_PACKAGE=test $dsh unmask '$random_unit'");
  172. is($retval, 0, "unmask command succeeded");
  173. ok(! -e $mask_path, 'symlink no longer exists');
  174. # ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
  175. # ┃ Verify “mask”/unmask don’t do anything when the user already masked. ┃
  176. # ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
  177. ok(! -l $mask_path, 'mask link does not exist yet');
  178. symlink('/dev/null', $mask_path);
  179. ok(-l $mask_path, 'mask link exists');
  180. is(readlink($mask_path), '/dev/null', 'service masked');
  181. $retval = system("DPKG_MAINTSCRIPT_PACKAGE=test $dsh mask '$random_unit'");
  182. is($retval, 0, "mask command succeeded");
  183. ok(-l $mask_path, 'mask link exists');
  184. is(readlink($mask_path), '/dev/null', 'service still masked');
  185. $retval = system("DPKG_MAINTSCRIPT_PACKAGE=test $dsh unmask '$random_unit'");
  186. is($retval, 0, "unmask command succeeded");
  187. ok(-l $mask_path, 'mask link exists');
  188. is(readlink($mask_path), '/dev/null', 'service still masked');
  189. # ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
  190. # ┃ Verify “mask”/unmask don’t do anything when the user copied the .service. ┃
  191. # ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
  192. unlink($mask_path);
  193. open($fh, '>', $mask_path);
  194. print $fh <<'EOT';
  195. [Unit]
  196. Description=test unit
  197. [Service]
  198. ExecStart=/bin/sleep 1
  199. [Install]
  200. WantedBy=multi-user.target
  201. EOT
  202. close($fh);
  203. ok(-e $mask_path, 'local service file exists');
  204. ok(! -l $mask_path, 'local service file is not a symlink');
  205. $retval = system("DPKG_MAINTSCRIPT_PACKAGE=test $dsh mask '$random_unit'");
  206. isnt($retval, -1, 'deb-systemd-helper could be executed');
  207. ok(!($retval & 127), 'deb-systemd-helper did not exit due to a signal');
  208. is($retval >> 8, 0, 'deb-systemd-helper exited with exit code 0');
  209. ok(-e $mask_path, 'local service file still exists');
  210. ok(! -l $mask_path, 'local service file is still not a symlink');
  211. $retval = system("DPKG_MAINTSCRIPT_PACKAGE=test $dsh unmask '$random_unit'");
  212. isnt($retval, -1, 'deb-systemd-helper could be executed');
  213. ok(!($retval & 127), 'deb-systemd-helper did not exit due to a signal');
  214. is($retval >> 8, 0, 'deb-systemd-helper exited with exit code 0');
  215. ok(-e $mask_path, 'local service file still exists');
  216. ok(! -l $mask_path, 'local service file is still not a symlink');
  217. unlink($mask_path);
  218. # ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
  219. # ┃ Verify Alias= handling. ┃
  220. # ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
  221. $retval = system("DPKG_MAINTSCRIPT_PACKAGE=test $dsh purge '$random_unit'");
  222. is($retval, 0, "purge command succeeded");
  223. open($fh, '>', $servicefile_path);
  224. print $fh <<'EOT';
  225. [Unit]
  226. Description=test unit
  227. [Service]
  228. ExecStart=/bin/sleep 1
  229. [Install]
  230. WantedBy=multi-user.target
  231. Alias=foo\x2dtest.service
  232. EOT
  233. close($fh);
  234. isnt_enabled($random_unit);
  235. isnt_enabled('foo\x2dtest.service');
  236. my $alias_path = '/etc/systemd/system/foo\x2dtest.service';
  237. ok(! -l $alias_path, 'alias link does not exist yet');
  238. $retval = system("DPKG_MAINTSCRIPT_PACKAGE=test $dsh enable '$random_unit'");
  239. is($retval, 0, "enable command succeeded");
  240. is(readlink($alias_path), $servicefile_path, 'correct alias link');
  241. is_enabled($random_unit);
  242. ok(! -l $mask_path, 'mask link does not exist yet');
  243. $retval = system("DPKG_MAINTSCRIPT_PACKAGE=test $dsh mask '$random_unit'");
  244. is($retval, 0, "mask command succeeded");
  245. is(readlink($alias_path), $servicefile_path, 'correct alias link');
  246. is(readlink($mask_path), '/dev/null', 'service masked');
  247. $retval = system("DPKG_MAINTSCRIPT_PACKAGE=test $dsh unmask '$random_unit'");
  248. is($retval, 0, "unmask command succeeded");
  249. is(readlink($alias_path), $servicefile_path, 'correct alias link');
  250. ok(! -l $mask_path, 'mask link does not exist any more');
  251. $retval = system("DPKG_MAINTSCRIPT_PACKAGE=test $dsh disable '$random_unit'");
  252. isnt_enabled($random_unit);
  253. ok(! -l $alias_path, 'alias link does not exist any more');
  254. # ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
  255. # ┃ Verify Alias/mask with removed package (as in postrm) ┃
  256. # ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
  257. $retval = system("DPKG_MAINTSCRIPT_PACKAGE=test $dsh purge '$random_unit'");
  258. is($retval, 0, "purge command succeeded");
  259. $retval = system("DPKG_MAINTSCRIPT_PACKAGE=test $dsh enable '$random_unit'");
  260. is($retval, 0, "enable command succeeded");
  261. is(readlink($alias_path), $servicefile_path, 'correct alias link');
  262. unlink($servicefile_path);
  263. $retval = system("DPKG_MAINTSCRIPT_PACKAGE=test $dsh mask '$random_unit'");
  264. is($retval, 0, "mask command succeeded with uninstalled unit");
  265. is(readlink($alias_path), $servicefile_path, 'correct alias link');
  266. is(readlink($mask_path), '/dev/null', 'service masked');
  267. $retval = system("DPKG_MAINTSCRIPT_PACKAGE=test $dsh purge '$random_unit'");
  268. is($retval, 0, "purge command succeeded with uninstalled unit");
  269. ok(! -l $alias_path, 'alias link does not exist any more');
  270. is(readlink($mask_path), '/dev/null', 'service masked');
  271. $retval = system("DPKG_MAINTSCRIPT_PACKAGE=test $dsh unmask '$random_unit'");
  272. is($retval, 0, "unmask command succeeded with uninstalled unit");
  273. ok(! -l $mask_path, 'mask link does not exist any more');
  274. # ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
  275. # ┃ Verify Alias= to the same unit name ┃
  276. # ┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛
  277. open($fh, '>', $servicefile_path);
  278. print $fh <<"EOT";
  279. [Unit]
  280. Description=test unit
  281. [Service]
  282. ExecStart=/bin/sleep 1
  283. [Install]
  284. WantedBy=multi-user.target
  285. Alias=$random_unit
  286. EOT
  287. close($fh);
  288. isnt_enabled($random_unit);
  289. isnt_enabled('foo\x2dtest.service');
  290. # note that in this case $alias_path and $mask_path are identical
  291. $retval = system("DPKG_MAINTSCRIPT_PACKAGE=test $dsh enable '$random_unit'");
  292. is($retval, 0, "enable command succeeded");
  293. is_enabled($random_unit);
  294. # systemctl enable does create the alias link even if it's not needed
  295. #ok(! -l $mask_path, 'mask link does not exist yet');
  296. unlink($servicefile_path);
  297. $retval = system("DPKG_MAINTSCRIPT_PACKAGE=test $dsh mask '$random_unit'");
  298. is($retval, 0, "mask command succeeded");
  299. is(readlink($mask_path), '/dev/null', 'service masked');
  300. $retval = system("DPKG_MAINTSCRIPT_PACKAGE=test $dsh unmask '$random_unit'");
  301. is($retval, 0, "unmask command succeeded");
  302. ok(! -l $mask_path, 'mask link does not exist any more');
  303. $retval = system("DPKG_MAINTSCRIPT_PACKAGE=test $dsh purge '$random_unit'");
  304. isnt_enabled($random_unit);
  305. ok(! -l $mask_path, 'mask link does not exist any more');
  306. done_testing;