1use itertools::Itertools; use std::collections::{BTreeSet, HashMap};
16use std::io::prelude::*;
17use std::path::{Path, PathBuf};
18use std::str;
19
20use crate::assets::Asset;
21use crate::dh::dh_lib::{autoscript, pkgfile, ScriptFragments};
22use crate::listener::Listener;
23use crate::util::{fname_from_path, MyJoin};
24use crate::{CDResult, CargoDebError};
25
26const LIB_SYSTEMD_SYSTEM_DIR: &str = "usr/lib/systemd/system/";
42const USR_LIB_TMPFILES_D_DIR: &str = "usr/lib/tmpfiles.d/";
43const SYSTEMD_UNIT_FILE_INSTALL_MAPPINGS: [(&str, &str, &str); 12] = [
44 ("", "mount", LIB_SYSTEMD_SYSTEM_DIR),
45 ("", "path", LIB_SYSTEMD_SYSTEM_DIR),
46 ("@", "path", LIB_SYSTEMD_SYSTEM_DIR),
47 ("", "service", LIB_SYSTEMD_SYSTEM_DIR),
48 ("@", "service", LIB_SYSTEMD_SYSTEM_DIR),
49 ("", "socket", LIB_SYSTEMD_SYSTEM_DIR),
50 ("@", "socket", LIB_SYSTEMD_SYSTEM_DIR),
51 ("", "target", LIB_SYSTEMD_SYSTEM_DIR),
52 ("@", "target", LIB_SYSTEMD_SYSTEM_DIR),
53 ("", "timer", LIB_SYSTEMD_SYSTEM_DIR),
54 ("@", "timer", LIB_SYSTEMD_SYSTEM_DIR),
55 ("", "tmpfile", USR_LIB_TMPFILES_D_DIR),
56];
57
58#[derive(Debug, PartialEq, Eq)]
59pub struct InstallRecipe {
60 pub path: PathBuf,
61 pub mode: u32,
62}
63
64pub type PackageUnitFiles = HashMap<PathBuf, InstallRecipe>;
65
66#[derive(Default, Debug)]
120pub struct Options {
121 pub no_enable: bool,
122 pub no_start: bool,
123 pub restart_after_upgrade: bool,
124 pub no_stop_on_upgrade: bool,
125}
126
127pub fn find_units(dir: &Path, main_package: &str, unit_name: Option<&str>) -> PackageUnitFiles {
137 let mut installables = HashMap::new();
138
139 for (package_suffix, unit_type, install_dir) in &SYSTEMD_UNIT_FILE_INSTALL_MAPPINGS {
140 let package_name = &format!("{main_package}{package_suffix}");
141 if let Some(src_path) = pkgfile(dir, main_package, package_name, unit_type, unit_name) {
142 let actual_suffix = match &unit_type[..] {
146 "tmpfile" => "conf",
147 _ => unit_type,
148 };
149
150 let install_filename = if let Some(unit_name) = unit_name {
153 format!("{unit_name}{package_suffix}.{actual_suffix}")
154 } else {
155 format!("{package_name}.{actual_suffix}")
156 };
157
158 let install_path = Path::new(install_dir).join(install_filename);
160
161 installables.insert(src_path, InstallRecipe {
164 path: install_path,
165 mode: 0o644,
166 });
167 }
168 }
169
170 installables
171}
172
173fn is_comment(s: &str) -> bool {
178 matches!(s.chars().next(), Some('#' | ';'))
179}
180
181fn unquote(s: &str) -> &str {
187 if s.len() > 1 &&
188 ((s.starts_with('"') && s.ends_with('"')) ||
189 (s.starts_with('\'') && s.ends_with('\''))) {
190 &s[1..s.len()-1]
191 } else {
192 s
193 }
194}
195
196pub fn generate(package: &str, assets: &[Asset], options: &Options, listener: &dyn Listener) -> CDResult<ScriptFragments> {
218 let mut scripts = ScriptFragments::new();
219
220 let tmp_file_names = assets
225 .iter()
226 .filter(|a| a.c.target_path.starts_with(USR_LIB_TMPFILES_D_DIR))
227 .map(|v| {
228 v.source.path()
229 .and_then(|p| fname_from_path(&p.with_extension("conf")))
230 .ok_or(CargoDebError::Str("dh_installsystemd: invalid source path"))
231 })
232 .collect::<CDResult<Vec<String>>>()?
233 .join(" ");
234
235 if !tmp_file_names.is_empty() {
236 autoscript(&mut scripts, package, "postinst", "postinst-init-tmpfiles",
237 &map!{ "TMPFILES" => tmp_file_names }, false, listener)?;
238 }
239
240 let mut installed_non_template_units: BTreeSet<String> = BTreeSet::new();
248 installed_non_template_units.extend(
249 assets
250 .iter()
251 .filter(|a| a.c.target_path.parent() == Some(LIB_SYSTEMD_SYSTEM_DIR.as_ref()))
252 .filter_map(|a| fname_from_path(a.c.target_path.as_path()))
253 .filter(|fname| !fname.contains('@')),
254 );
255
256 let mut enable_units = BTreeSet::new();
260 let mut start_units = BTreeSet::new();
261 let mut seen = BTreeSet::new();
262
263 let mut units = installed_non_template_units;
266
267 while !units.is_empty() {
271 let mut also_units = BTreeSet::<String>::new();
273
274 for unit in &units {
276 listener.progress("Checking", format!("augmentations needed for systemd unit {unit}"));
277
278 start_units.insert(unit.clone());
280
281 let needle = Path::new(LIB_SYSTEMD_SYSTEM_DIR).join(unit);
283 let data = assets.iter().find(move |&item| item.c.target_path == needle).unwrap().source.data()?;
284 let reader = data.into_owned();
285
286 for line in reader.lines().map(|line| line.unwrap()).filter(|s| !is_comment(s)) {
304 let possible_kv_pair = line.splitn(2, '=').map(|s| s.trim()).next_tuple();
305 if let Some((key, value)) = possible_kv_pair {
306 let other_unit = unquote(value).to_string();
307 match key {
308 "Also" => {
309 if seen.insert(other_unit.clone()) {
318 also_units.insert(other_unit);
319 }
320 },
321 "Alias" => {
322 },
324 _ => (),
325 }
326 } else if line.starts_with("[Install]") {
327 enable_units.insert(unit.clone());
328 }
329 }
330 }
331 units = also_units;
332 }
333
334 if !enable_units.is_empty() {
338 let snippet = if options.no_enable { "postinst-systemd-dont-enable" } else { "postinst-systemd-enable" };
339 for unit in &enable_units {
340 autoscript(&mut scripts, package, "postinst", snippet,
341 &map!{ "UNITFILE" => unit.clone() }, true, listener)?;
342 }
343 autoscript(&mut scripts, package, "postrm", "postrm-systemd",
344 &map!{ "UNITFILES" => enable_units.join(" ") }, false, listener)?;
345 }
346
347 if !start_units.is_empty() {
351 let mut replace = map! { "UNITFILES" => start_units.join(" ") };
352
353 if options.restart_after_upgrade {
354 let snippet = if options.no_start {
355 replace.insert("RESTART_ACTION", "try-restart".into());
356 "postinst-systemd-restartnostart"
357 } else {
358 replace.insert("RESTART_ACTION", "restart".into());
359 "postinst-systemd-restart"
360 };
361 autoscript(&mut scripts, package, "postinst", snippet, &replace, true, listener)?;
362 } else if !options.no_start {
363 autoscript(&mut scripts, package, "postinst", "postinst-systemd-start", &replace, true, listener)?;
365 }
366
367 if options.no_stop_on_upgrade || options.restart_after_upgrade {
368 autoscript(&mut scripts, package, "prerm", "prerm-systemd-restart", &replace, true, listener)?;
370 } else if !options.no_start {
371 autoscript(&mut scripts, package, "prerm", "prerm-systemd", &replace, true, listener)?;
373 }
374
375 autoscript(&mut scripts, package, "postrm", "postrm-systemd-reload-only", &replace, false, listener)?;
378 }
379
380 Ok(scripts)
381}
382
383#[cfg(test)]
384mod tests {
385 use super::*;
386 use crate::assets::{Asset, AssetKind, AssetSource, IsBuilt};
387 use crate::util::tests::{add_test_fs_paths, get_read_count, set_test_fs_path_content};
388 use rstest::*;
389
390 #[test]
391 fn is_comment_detects_comments() {
392 assert!(is_comment("#"));
393 assert!(is_comment("# "));
394 assert!(is_comment("# some comment"));
395 assert!(is_comment(";"));
396 assert!(is_comment("; "));
397 assert!(is_comment("; some comment"));
398 }
399
400 #[test]
401 fn is_comment_detects_non_comments() {
402 assert!(!is_comment(" #"));
403 assert!(!is_comment(" # "));
404 assert!(!is_comment(" # some comment"));
405 assert!(!is_comment(" ;"));
406 assert!(!is_comment(" ; "));
407 assert!(!is_comment(" ; some comment"));
408 }
409
410 #[test]
411 fn unquote_unquotes_matching_single_quotes() {
412 assert_eq!("", unquote("''"));
413 assert_eq!("a", unquote("'a'"));
414 assert_eq!("ab", unquote("'ab'"));
415 }
416
417 #[test]
418 fn unquote_unquotes_matching_double_quotes() {
419 assert_eq!("", unquote(r#""""#));
420 assert_eq!("a", unquote(r#""a""#));
421 assert_eq!("ab", unquote(r#""ab""#));
422 }
423
424 #[test]
425 fn unquote_ignores_embedded_quotes() {
426 assert_eq!("a'b", unquote("'a'b'"));
427 assert_eq!(r#"a"b"#, unquote(r#"'a"b'"#));
428 assert_eq!(r#"a"b"#, unquote(r#""a"b""#));
429 assert_eq!(r#"a'b"#, unquote(r#""a'b""#));
430 }
431
432 #[test]
433 fn unquote_ignores_partial_quotes() {
434 assert_eq!("'", unquote("'"));
435 assert_eq!("'ab", unquote("'ab"));
436 assert_eq!("ab'", unquote("ab'"));
437 assert_eq!("'ab'ab", unquote("'ab'ab"));
438 assert_eq!("ab'ab'", unquote("ab'ab'"));
439 assert_eq!(r#"""#, unquote(r#"""#));
440 assert_eq!(r#""ab"#, unquote(r#""ab"#));
441 assert_eq!(r#"ab""#, unquote(r#"ab""#));
442 assert_eq!(r#""ab"ab"#, unquote(r#""ab"ab"#));
443 assert_eq!(r#"ab"ab""#, unquote(r#"ab"ab""#));
444 }
445
446 #[test]
447 fn unquote_ignores_mismatched_quotes() {
448 assert_eq!(r#""'"#, unquote(r#""'"#));
449 assert_eq!(r#"'""#, unquote(r#"'""#));
450 assert_eq!(r#""a'"#, unquote(r#""a'"#));
451 assert_eq!(r#"'a""#, unquote(r#"'a""#));
452 assert_eq!(r#""ab'"#, unquote(r#""ab'"#));
453 assert_eq!(r#"'ab""#, unquote(r#"'ab""#));
454 }
455
456 #[test]
457 fn find_units_in_empty_dir_finds_nothing() {
458 let pkg_unit_files = find_units(Path::new(""), "mypkg", None);
459 assert!(pkg_unit_files.is_empty());
460 }
461
462 fn assert_eq_found_unit(pkg_unit_files: &PackageUnitFiles, expected_install_path: &str, source_path: &str) {
463 let expected = InstallRecipe {
464 path: PathBuf::from(expected_install_path),
465 mode: 0o644,
466 };
467 let actual = pkg_unit_files.get(&PathBuf::from(source_path)).unwrap();
468 assert_eq!(&expected, actual);
469 }
470
471 #[test]
472 fn find_units_for_package() {
473 let _g = add_test_fs_paths(&[
477 "debian/mypkg.mount",
478 "debian/mypkg@.path",
479 "debian/service", "debian/mypkg@.socket",
481 "debian/mypkg.target",
482 "debian/mypkg@.timer",
483 "debian/mypkg.tmpfile",
484 "debian/mypkg.myunit.service", ]);
486 let pkg_unit_files = find_units(Path::new("debian"), "mypkg", None);
487 assert_eq_found_unit(&pkg_unit_files, "usr/lib/systemd/system/mypkg.mount", "debian/mypkg.mount");
488 assert_eq_found_unit(&pkg_unit_files, "usr/lib/systemd/system/mypkg@.path", "debian/mypkg@.path");
489 assert_eq_found_unit(&pkg_unit_files, "usr/lib/systemd/system/mypkg.service", "debian/service");
490 assert_eq_found_unit(&pkg_unit_files, "usr/lib/systemd/system/mypkg@.socket", "debian/mypkg@.socket");
491 assert_eq_found_unit(&pkg_unit_files, "usr/lib/systemd/system/mypkg.target", "debian/mypkg.target");
492 assert_eq_found_unit(&pkg_unit_files, "usr/lib/systemd/system/mypkg@.timer", "debian/mypkg@.timer");
493 assert_eq_found_unit(&pkg_unit_files, "usr/lib/tmpfiles.d/mypkg.conf", "debian/mypkg.tmpfile");
494 assert_eq!(7, pkg_unit_files.len());
495 }
496
497 #[test]
498 fn find_named_units_for_package() {
499 let _g = add_test_fs_paths(&[
503 "debian/mypkg.myunit.mount",
504 "debian/mypkg@.myunit.path",
505 "debian/service", "debian/mypkg@.myunit.socket",
507 "debian/target", "debian/mypkg@.myunit.timer",
509 "debian/mypkg.tmpfile", "debian/mypkg.myunit.service", ]);
512
513 let _g = add_test_fs_paths(&[
515 "debian/nested/dir/mykpg.myunit.mount",
516 "debian/README.md",
517 "mypkg.myunit.mount",
518 "mypkg.mount",
519 "mount",
520 "postinit",
521 "mypkg.postinit",
522 "mypkg.myunit.postinit",
523 ]);
524
525 let pkg_unit_files = find_units(Path::new("debian"), "mypkg", Some("myunit"));
526 assert_eq_found_unit(&pkg_unit_files, "usr/lib/systemd/system/myunit.mount", "debian/mypkg.myunit.mount");
528 assert_eq_found_unit(&pkg_unit_files, "usr/lib/systemd/system/myunit@.path", "debian/mypkg@.myunit.path");
529 assert_eq_found_unit(&pkg_unit_files, "usr/lib/systemd/system/myunit.service", "debian/mypkg.myunit.service");
530 assert_eq_found_unit(&pkg_unit_files, "usr/lib/systemd/system/myunit@.socket", "debian/mypkg@.myunit.socket");
531 assert_eq_found_unit(&pkg_unit_files, "usr/lib/systemd/system/myunit.target", "debian/target");
532 assert_eq_found_unit(&pkg_unit_files, "usr/lib/systemd/system/myunit@.timer", "debian/mypkg@.myunit.timer");
533
534 assert_eq_found_unit(&pkg_unit_files, "usr/lib/tmpfiles.d/myunit.conf", "debian/mypkg.tmpfile");
536
537 assert_eq!(7, pkg_unit_files.len());
538 }
539
540 #[test]
541 fn generate_with_empty_inputs_does_nothing() {
542 let mut mock_listener = crate::listener::MockListener::new();
543 mock_listener.expect_info().times(0).return_const(());
544
545 let fragments = generate("", &[], &Options::default(), &mock_listener).unwrap();
546
547 assert!(fragments.is_empty());
548 }
549
550 #[test]
551 fn generate_with_arbitrary_asset_does_nothing() {
552 let mut mock_listener = crate::listener::MockListener::new();
553 mock_listener.expect_info().times(0).return_const(());
554
555 let assets = vec![Asset::new(
556 AssetSource::Path(PathBuf::new()),
557 PathBuf::new(),
558 0o0,
559 IsBuilt::No,
560 AssetKind::Any,
561 )];
562
563 let fragments = generate("mypkg", &assets, &Options::default(), &mock_listener).unwrap();
564 assert!(fragments.is_empty());
565 }
566
567 #[test]
568 fn generate_with_invalid_tmp_file_asset_fails() {
569 let mut mock_listener = crate::listener::MockListener::new();
570 mock_listener.expect_info().times(0).return_const(());
571
572 let assets = vec![Asset::new(
573 AssetSource::Path(PathBuf::new()), Path::new("usr/lib/tmpfiles.d/blah").to_path_buf(),
575 0o0,
576 IsBuilt::No,
577 AssetKind::Any,
578 )];
579
580 assert!(generate("mypkg", &assets, &Options::default(), &mock_listener).is_err());
581 }
582
583 #[test]
584 fn generate_with_data_tmp_file_asset_fails() {
585 let mut mock_listener = crate::listener::MockListener::new();
586 mock_listener.expect_info().times(0).return_const(());
587
588 let assets = vec![Asset::new(
589 AssetSource::Data(vec![]), Path::new("usr/lib/tmpfiles.d/blah").to_path_buf(),
591 0o0,
592 IsBuilt::No,
593 AssetKind::Any,
594 )];
595
596 assert!(generate("mypkg", &assets, &Options::default(), &mock_listener).is_err());
597 }
598
599 #[test]
600 fn generate_with_empty_tmp_file_asset() {
601 use crate::dh::dh_lib::get_embedded_autoscript;
602
603 const TMP_FILE_NAME: &str = "my_tmp_file.tmpfile";
604 let tmp_file_path = PathBuf::from(format!("debian/{TMP_FILE_NAME}"));
605
606 let mut mock_listener = crate::listener::MockListener::new();
607 mock_listener.expect_progress().times(1).return_const(());
608
609 let assets = vec![Asset::new(
610 AssetSource::Path(tmp_file_path),
611 Path::new("usr/lib/tmpfiles.d/blah").to_path_buf(),
612 0o0,
613 IsBuilt::No,
614 AssetKind::Any,
615 )];
616
617 let fragments = generate("mypkg", &assets, &Options::default(), &mock_listener).unwrap();
618 assert_eq!(1, fragments.len());
619
620 let (fragment_name, created_text) = fragments.into_iter().next().unwrap();
621
622 assert_eq!("mypkg.postinst.debhelper", fragment_name);
624
625 let autoscript_text = get_embedded_autoscript("postinst-init-tmpfiles");
631 let autoscript_line_count = autoscript_text.lines().count();
632 let created_line_count = created_text.lines().count();
633 assert_eq!(autoscript_line_count + 2, created_line_count);
634
635 let mut lines = created_text.lines();
637 assert!(lines.next().unwrap().starts_with("# Automatically added by"));
638 assert_eq!(lines.nth_back(0).unwrap(), "# End automatically added section");
639
640 let expected_autoscript_text = autoscript_text.replace("#TMPFILES#", TMP_FILE_NAME.replace(".tmpfile", ".conf").as_str());
643 let expected_autoscript_text = expected_autoscript_text.trim_end();
644 let start1 = 1;
645 let end1 = start1 + autoscript_line_count;
646 let created_autoscript_text = created_text.lines().collect::<Vec<&str>>()[start1..end1].join("\n");
647 assert_ne!(expected_autoscript_text, autoscript_text);
648 assert_eq!(expected_autoscript_text, created_autoscript_text);
649 }
650
651 #[test]
652 fn generate_filters_out_template_units() {
653 let mut mock_listener = crate::listener::MockListener::new();
657 mock_listener.expect_info().times(0).return_const(());
658
659 let assets = vec![Asset::new(
660 AssetSource::Path(PathBuf::from("debian/my_unit@.service")),
661 Path::new("usr/lib/systemd/system/").to_path_buf(),
662 0o0,
663 IsBuilt::No,
664 AssetKind::Any,
665 )];
666
667 let fragments = generate("mypkg", &assets, &Options::default(), &mock_listener).unwrap();
668 assert_eq!(0, fragments.len());
669 }
670
671 #[test]
672 fn generate_filters_out_subdir() {
673 let mut mock_listener = crate::listener::MockListener::new();
674 mock_listener.expect_info().times(0).return_const(());
675
676 let assets = vec![Asset::new(
677 AssetSource::Path(PathBuf::from("debian/10-extra-hardening.conf")),
678 Path::new("usr/lib/systemd/system/foobar.service.d/").to_path_buf(),
679 0o0,
680 IsBuilt::No,
681 AssetKind::Any,
682 )];
683
684 let fragments = generate("mypkg", &assets, &Options::default(), &mock_listener).unwrap();
685 assert_eq!(0, fragments.len());
686 }
687
688 #[test]
689 fn generate_acts_only_on_unit_files_with_the_expected_install_path() {
690 let mut mock_listener = crate::listener::MockListener::new();
692 mock_listener.expect_info().times(0).return_const(());
693
694 let assets = vec![Asset::new(
695 AssetSource::Path(PathBuf::from("debian/my_unit.service")),
696 Path::new("some/other/path/").to_path_buf(),
697 0o0,
698 IsBuilt::No,
699 AssetKind::Any,
700 )];
701
702 let fragments = generate("mypkg", &assets, &Options::default(), &mock_listener).unwrap();
703 assert_eq!(0, fragments.len());
704 }
705
706 #[rstest(ip, inst, ne, rau, ns, nsou,
707 case("ult", false, false, false, false, false),
708
709 case("lss", false, false, false, false, false),
710 case("lss", false, false, false, false, true),
711 case("lss", false, false, false, true, false),
712 case("lss", false, false, false, true, true),
713 case("lss", false, false, true, false, false),
714 case("lss", false, false, true, false, true),
715 case("lss", false, false, true, true, false),
716 case("lss", false, false, true, true, true),
717 case("lss", false, true, false, false, false),
718 case("lss", false, true, false, false, true),
719 case("lss", false, true, false, true, false),
720 case("lss", false, true, false, true, true),
721 case("lss", false, true, true, false, false),
722 case("lss", false, true, true, false, true),
723 case("lss", false, true, true, true, false),
724 case("lss", false, true, true, true, true),
725 case("lss", true, false, false, false, false),
726 case("lss", true, false, false, false, true),
727 case("lss", true, false, false, true, false),
728 case("lss", true, false, false, true, true),
729 case("lss", true, false, true, false, false),
730 case("lss", true, false, true, false, true),
731 case("lss", true, false, true, true, false),
732 case("lss", true, false, true, true, true),
733 case("lss", true, true, false, false, false),
734 case("lss", true, true, false, false, true),
735 case("lss", true, true, false, true, false),
736 case("lss", true, true, false, true, true),
737 case("lss", true, true, true, false, false),
738 case("lss", true, true, true, false, true),
739 case("lss", true, true, true, true, false),
740 case("lss", true, true, true, true, true),
741 )]
742 #[test]
743 fn generate_creates_expected_autoscript_fragments(
744 ip: &str,
745 inst: bool,
746 ne: bool,
747 rau: bool,
748 ns: bool,
749 nsou: bool,
750 ) {
751 let unit_file_path = "debian/mypkg.service";
752
753 let install_base_path = match ip {
754 "ult" => "usr/lib/tmpfiles.d",
755 "lss" => "usr/lib/systemd/system",
756 x => panic!("Unsupported install path value '{x}'"),
757 };
758
759 let assets = vec![Asset::new(
761 AssetSource::Path(PathBuf::from(unit_file_path)),
762 format!("{install_base_path}/mypkg.service").into(),
763 0o0,
764 IsBuilt::No,
765 AssetKind::Any,
766 )];
767
768 let options = Options {
769 no_enable: ne,
770 no_start: ns,
771 restart_after_upgrade: rau,
772 no_stop_on_upgrade: nsou,
773 };
774
775 let mut mock_listener = crate::listener::MockListener::new();
777 mock_listener.expect_progress().return_const(());
778
779 let mut unit_file_content = "[Unit]
783Description=A test unit
784
785[Service]
786Type=simple
787".to_owned();
788
789 if inst {
790 unit_file_content.push_str("[Install]
791WantedBy=multi-user.target");
792 }
793
794 set_test_fs_path_content(unit_file_path, unit_file_content);
795
796 let _g = add_test_fs_paths(&[
799 "postinst-init-tmpfiles",
800 "postinst-systemd-dont-enable",
801 "postinst-systemd-enable",
802 "postinst-systemd-restart",
803 "postinst-systemd-restartnostart",
804 "postinst-systemd-start",
805 "postrm-systemd",
806 "postrm-systemd-reload-only",
807 "prerm-systemd",
808 "prerm-systemd-restart",
809 ]);
810
811 let fragments = generate("mypkg", &assets, &options, &mock_listener).unwrap();
813
814 let mut autoscript_fragments_to_check_for = std::collections::HashSet::new();
855
856 match ip {
857 "ult" => {
858 assert_eq!(1, get_read_count("postinst-init-tmpfiles"));
859 autoscript_fragments_to_check_for.insert("postinst.debhelper");
860 },
861 "lss" => {
862 assert_eq!(1, get_read_count(unit_file_path));
863 if inst {
864 if options.no_enable {
865 assert_eq!(1, get_read_count("postinst-systemd-dont-enable"));
866 } else {
867 assert_eq!(1, get_read_count("postinst-systemd-enable"));
868 }
869 assert_eq!(1, get_read_count("postrm-systemd"));
870 autoscript_fragments_to_check_for.insert("postinst.service");
871 autoscript_fragments_to_check_for.insert("postrm.debhelper");
872 }
873 if options.restart_after_upgrade {
874 if options.no_start {
875 assert_eq!(1, get_read_count("postinst-systemd-restartnostart"));
876 } else {
877 assert_eq!(1, get_read_count("postinst-systemd-restart"));
878 }
879 autoscript_fragments_to_check_for.insert("postinst.service");
880 } else if !options.no_start {
881 assert_eq!(1, get_read_count("postinst-systemd-start"));
882 autoscript_fragments_to_check_for.insert("postinst.service");
883 }
884 if options.restart_after_upgrade || options.no_stop_on_upgrade {
885 assert_eq!(1, get_read_count("prerm-systemd-restart"));
886 autoscript_fragments_to_check_for.insert("prerm.service");
887 } else if !options.no_start {
888 assert_eq!(1, get_read_count("prerm-systemd"));
889 autoscript_fragments_to_check_for.insert("prerm.service");
890 }
891 assert_eq!(1, get_read_count("postrm-systemd-reload-only"));
892 autoscript_fragments_to_check_for.insert("postrm.debhelper");
893 },
894 _ => unreachable!(),
895 }
896
897 for autoscript in &autoscript_fragments_to_check_for {
898 let key = format!("mypkg.{autoscript}");
899 assert!(fragments.contains_key(&key), "{}", key);
900 }
901 }
902}