From c87d0661a0e26cdca6207f3ccd81013b85824745 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Thu, 27 Aug 2020 09:58:58 +0200 Subject: [PATCH 01/10] test-path: remove unnecessary check test points to an array, so it canont be NULL at this point. --- src/test/test-path.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/test-path.c b/src/test/test-path.c index 1075f31bc6..cf89d89482 100644 --- a/src/test/test-path.c +++ b/src/test/test-path.c @@ -350,7 +350,7 @@ int main(int argc, char *argv[]) { assert_se(set_unit_path(test_path) >= 0); assert_se(runtime_dir = setup_fake_runtime_dir()); - for (const test_function_t *test = tests; test && *test; test++) { + for (const test_function_t *test = tests; *test; test++) { Manager *m = NULL; int r; From 839bdf2505d8f6a1e75cab125b91573ef5fd06c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Thu, 27 Aug 2020 17:26:49 +0200 Subject: [PATCH 02/10] meson: add "develop mode" config switch --- meson.build | 3 +++ meson_options.txt | 3 +++ 2 files changed, 6 insertions(+) diff --git a/meson.build b/meson.build index cd2b02488b..36ed7a47be 100644 --- a/meson.build +++ b/meson.build @@ -38,6 +38,9 @@ relative_source_path = run_command('realpath', project_source_root).stdout().strip() conf.set_quoted('RELATIVE_SOURCE_PATH', relative_source_path) +conf.set10('DEVELOPER_MODE', get_option('mode') == 'developer', + description : 'enable additional checks only suitable in development') + want_ossfuzz = get_option('oss-fuzz') want_libfuzzer = get_option('llvm-fuzz') if want_ossfuzz + want_libfuzzer > 1 diff --git a/meson_options.txt b/meson_options.txt index fd73d5e681..1ad0969a1a 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -4,6 +4,9 @@ option('version-tag', type : 'string', description : 'override the git version string') +option('mode', type : 'combo', choices : ['default', 'developer'], + description : 'enable additional checks suitable for systemd development') + option('split-usr', type : 'combo', choices : ['auto', 'true', 'false'], description : '''/bin, /sbin aren't symlinks into /usr''') option('split-bin', type : 'combo', choices : ['auto', 'true', 'false'], From b7be416f55eda143b0e8f4a8ded8649c92e77d4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Thu, 27 Aug 2020 18:22:45 +0200 Subject: [PATCH 03/10] basic/missing_capability: clean up our defines and check that our fallback is up-to-date There is little point in #defining and #undefining CAP_LAST_CAP multiple times. The check is only done in developer mode. After all, it's not an error to compile on a newer kernel, and we shouldn't even warn in that case. --- src/basic/missing_capability.h | 35 ++++++++++++++++++---------------- src/test/test-capability.c | 2 ++ 2 files changed, 21 insertions(+), 16 deletions(-) diff --git a/src/basic/missing_capability.h b/src/basic/missing_capability.h index b31e736390..c52cd44933 100644 --- a/src/basic/missing_capability.h +++ b/src/basic/missing_capability.h @@ -5,32 +5,35 @@ /* 3a101b8de0d39403b2c7e5c23fd0b005668acf48 (3.16) */ #ifndef CAP_AUDIT_READ -#define CAP_AUDIT_READ 37 - -#undef CAP_LAST_CAP -#define CAP_LAST_CAP CAP_AUDIT_READ +# define CAP_AUDIT_READ 37 #endif /* 980737282232b752bb14dab96d77665c15889c36 (5.8) */ #ifndef CAP_PERFMON -#define CAP_PERFMON 38 - -#undef CAP_LAST_CAP -#define CAP_LAST_CAP CAP_PERFMON +# define CAP_PERFMON 38 #endif /* a17b53c4a4b55ec322c132b6670743612229ee9c (5.8) */ #ifndef CAP_BPF -#define CAP_BPF 39 - -#undef CAP_LAST_CAP -#define CAP_LAST_CAP CAP_BPF +# define CAP_BPF 39 #endif /* 124ea650d3072b005457faed69909221c2905a1f (5.9) */ #ifndef CAP_CHECKPOINT_RESTORE -#define CAP_CHECKPOINT_RESTORE 40 - -#undef CAP_LAST_CAP -#define CAP_LAST_CAP CAP_CHECKPOINT_RESTORE +# define CAP_CHECKPOINT_RESTORE 40 +#endif + +#define SYSTEMD_CAP_LAST_CAP CAP_CHECKPOINT_RESTORE + +#ifdef CAP_LAST_CAP +# if CAP_LAST_CAP > SYSTEMD_CAP_LAST_CAP +# if DEVELOPER_MODE && defined(TEST_CAPABILITY_C) +# warning "The capability list here is outdated" +# endif +# else +# undef CAP_LAST_CAP +# endif +#endif +#ifndef CAP_LAST_CAP +# define CAP_LAST_CAP SYSTEMD_CAP_LAST_CAP #endif diff --git a/src/test/test-capability.c b/src/test/test-capability.c index 249323f8cf..2d47c77f46 100644 --- a/src/test/test-capability.c +++ b/src/test/test-capability.c @@ -7,6 +7,8 @@ #include #include +#define TEST_CAPABILITY_C + #include "alloc-util.h" #include "capability-util.h" #include "errno-util.h" From af4c7dc26936334f32b40bcd97bc6d8405011f68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Thu, 27 Aug 2020 19:21:21 +0200 Subject: [PATCH 04/10] update-dbus-docs: print statistics at the end Right now: org.freedesktop.LogControl1.xml: 3/3 org.freedesktop.home1.xml: 44/44 org.freedesktop.hostname1.xml: 21/21 org.freedesktop.import1.xml: 17/19 org.freedesktop.locale1.xml: 10/10 org.freedesktop.login1.xml: 172/172 org.freedesktop.machine1.xml: 49/65 org.freedesktop.resolve1.xml: 25/61 org.freedesktop.systemd1.xml: 214/1468 org.freedesktop.timedate1.xml: 12/12 total: 567/1875 :( --- tools/update-dbus-docs.py | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/tools/update-dbus-docs.py b/tools/update-dbus-docs.py index f95faaaf22..8aa3742f60 100755 --- a/tools/update-dbus-docs.py +++ b/tools/update-dbus-docs.py @@ -120,9 +120,11 @@ def document_has_elem_with_text(document, elem, item_repr): else: return False -def check_documented(document, declarations): +def check_documented(document, declarations, stats): missing = [] for klass, items in declarations.items(): + stats['total'] += len(items) + for item in items: if klass == 'method': elem = 'function' @@ -141,6 +143,8 @@ def check_documented(document, declarations): print(f'{klass} {item} is not documented :(') missing.append((klass, item)) + stats['missing'] += len(missing) + return missing def xml_to_text(destination, xml, *, only_interface=None): @@ -165,7 +169,7 @@ def xml_to_text(destination, xml, *, only_interface=None): return file.getvalue(), declarations, interfaces -def subst_output(document, programlisting): +def subst_output(document, programlisting, stats): executable = programlisting.get('executable', None) if executable is None: # Not our thing @@ -189,7 +193,7 @@ def subst_output(document, programlisting): programlisting.text = '\n' + new_text + ' ' if declarations: - missing = check_documented(document, declarations) + missing = check_documented(document, declarations, stats) parent = programlisting.getparent() # delete old comments @@ -253,9 +257,11 @@ def process(page): if xml.tag != 'refentry': return + stats = collections.Counter() + pls = xml.findall('.//programlisting') for pl in pls: - subst_output(xml, pl) + subst_output(xml, pl, stats) out_text = etree.tostring(xml, encoding='unicode') # massage format to avoid some lxml whitespace handling idiosyncrasies @@ -267,6 +273,8 @@ def process(page): with open(page, 'w') as out: out.write(out_text) + return stats + if __name__ == '__main__': pages = sys.argv[1:] @@ -279,5 +287,13 @@ if __name__ == '__main__': if not os.path.exists(f'{build_dir}/systemd'): exit(f"{build_dir}/systemd doesn't exist. Use --build-dir=.") - for page in pages: - process(page) + stats = {page.split('/')[-1] : process(page) for page in pages} + + # Let's print all statistics at the end + mlen = max(len(page) for page in stats) + total = 'total', sum(stats.values(), start=collections.Counter()) + for page, counts in sorted(stats.items()) + [total]: + m = counts['missing'] + t = counts['total'] + p = page + ':' + print(f'{p:{mlen + 1}} {t - m}/{t}') From 0f5cea021252e1524776c992fb6a7bb1d55b1b51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Thu, 27 Aug 2020 19:27:18 +0200 Subject: [PATCH 05/10] update-dbus-docs: use argparse --- tools/update-dbus-docs.py | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/tools/update-dbus-docs.py b/tools/update-dbus-docs.py index 8aa3742f60..bfe55220c1 100755 --- a/tools/update-dbus-docs.py +++ b/tools/update-dbus-docs.py @@ -1,6 +1,7 @@ #!/usr/bin/env python3 # SPDX-License-Identifier: LGPL-2.1+ +import argparse import collections import sys import os @@ -178,7 +179,7 @@ def subst_output(document, programlisting, stats): node = programlisting.get('node') interface = programlisting.get('interface') - argv = [f'{build_dir}/{executable}', f'--bus-introspect={interface}'] + argv = [f'{opts.build_dir}/{executable}', f'--bus-introspect={interface}'] print(f'COMMAND: {shlex.join(argv)}') try: @@ -275,19 +276,19 @@ def process(page): return stats +def parse_args(): + p = argparse.ArgumentParser() + p.add_argument('--build-dir', default='build') + p.add_argument('pages', nargs='+') + return p.parse_args() + if __name__ == '__main__': - pages = sys.argv[1:] + opts = parse_args() - if pages[0].startswith('--build-dir='): - build_dir = pages[0].partition('=')[2] - pages = pages[1:] - else: - build_dir = 'build' + if not os.path.exists(f'{opts.build_dir}/systemd'): + exit(f"{opts.build_dir}/systemd doesn't exist. Use --build-dir=.") - if not os.path.exists(f'{build_dir}/systemd'): - exit(f"{build_dir}/systemd doesn't exist. Use --build-dir=.") - - stats = {page.split('/')[-1] : process(page) for page in pages} + stats = {page.split('/')[-1] : process(page) for page in opts.pages} # Let's print all statistics at the end mlen = max(len(page) for page in stats) From 1b584f38a85fc9eba35780b7454970f72621db7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Thu, 27 Aug 2020 19:55:55 +0200 Subject: [PATCH 06/10] update-dbus-docs: add test mode --- tools/update-dbus-docs.py | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/tools/update-dbus-docs.py b/tools/update-dbus-docs.py index bfe55220c1..448206cf95 100755 --- a/tools/update-dbus-docs.py +++ b/tools/update-dbus-docs.py @@ -271,13 +271,16 @@ def process(page): out_text[out_text.find(' Date: Thu, 27 Aug 2020 20:10:01 +0200 Subject: [PATCH 07/10] test: verify that dbus docs are fresh This makes use of the developer mode switch: the test is only done if the user opted-in into developer mode. Before the man/update-dbus-docs was using the argument form where we don't need to run find_command(), but that doesn't work with test(),, so find_command() is used and we get one more line in the config log. --- man/meson.build | 10 ++++++++-- meson.build | 1 + 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/man/meson.build b/man/meson.build index 3a7143a4b6..3c2c7023ed 100644 --- a/man/meson.build +++ b/man/meson.build @@ -202,11 +202,17 @@ if dbus_docs.length() > 0 custom_target( 'update-dbus-docs', output : 'update-dbus-docs', - command : ['python3', - '@0@/tools/update-dbus-docs.py'.format(project_source_root), + command : [update_dbus_docs_py, '--build-dir=@0@'.format(project_build_root), '@INPUT@'], input : dbus_docs) + + if conf.get('DEVELOPER_MODE') == 1 + test('dbus-docs-fresh', + update_dbus_docs_py, + args : ['--build-dir=@0@'.format(project_build_root), + '--test'] + dbus_docs) + endif endif ############################################################ diff --git a/meson.build b/meson.build index 36ed7a47be..6837540313 100644 --- a/meson.build +++ b/meson.build @@ -1637,6 +1637,7 @@ make_directive_index_py = find_program('tools/make-directive-index.py') make_man_index_py = find_program('tools/make-man-index.py') syscall_names_update_sh = find_program('tools/syscall-names-update.sh') xml_helper_py = find_program('tools/xml_helper.py') +update_dbus_docs_py = find_program('tools/update-dbus-docs.py') ############################################################ From 04aa6fa8cd08546e8ae6257db60174ad6d7e3689 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Thu, 27 Aug 2020 20:15:30 +0200 Subject: [PATCH 08/10] update-dbus-docs: omit verbose output when in --test mode It makes the ninja output listing very long for no good purpose. --- tools/update-dbus-docs.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tools/update-dbus-docs.py b/tools/update-dbus-docs.py index 448206cf95..0bbc4aab45 100755 --- a/tools/update-dbus-docs.py +++ b/tools/update-dbus-docs.py @@ -15,8 +15,6 @@ PARSER = etree.XMLParser(no_network=True, strip_cdata=False, resolve_entities=False) -PRINT_ERRORS = True - class NoCommand(Exception): pass @@ -38,7 +36,7 @@ def print_method(declarations, elem, *, prefix, file, is_signal=False): argname = arg.get('name') if argname is None: - if PRINT_ERRORS: + if opts.print_errors: print(f'method {name}: argument {num+1} has no name', file=sys.stderr) argname = 'UNNAMED' @@ -140,7 +138,7 @@ def check_documented(document, declarations, stats): assert False, (klass, item) if not document_has_elem_with_text(document, elem, item_repr): - if PRINT_ERRORS: + if opts.print_errors: print(f'{klass} {item} is not documented :(') missing.append((klass, item)) @@ -283,7 +281,9 @@ def parse_args(): help='only verify that everything is up2date') p.add_argument('--build-dir', default='build') p.add_argument('pages', nargs='+') - return p.parse_args() + opts = p.parse_args() + opts.print_errors = not opts.test + return opts if __name__ == '__main__': opts = parse_args() From c91e3116f40f9d7867cda8952408b1eb182b87bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Thu, 27 Aug 2020 20:18:05 +0200 Subject: [PATCH 09/10] update-dbus-docs: add hint --- tools/update-dbus-docs.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tools/update-dbus-docs.py b/tools/update-dbus-docs.py index 0bbc4aab45..3500d9ce5e 100755 --- a/tools/update-dbus-docs.py +++ b/tools/update-dbus-docs.py @@ -308,4 +308,5 @@ if __name__ == '__main__': print(f'{p:{mlen + 1}} {t - m}/{t} {c}') if opts.test and outdated: - exit(f'Outdated pages: {", ".join(outdated)}') + exit(f'Outdated pages: {", ".join(outdated)}\n' + f'Hint: ninja -C {opts.build_dir} man/update-dbus-docs') From e4b2cea32afe1eb21c1c76c1741e863f787a87e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20J=C4=99drzejewski-Szmek?= Date: Thu, 27 Aug 2020 20:20:08 +0200 Subject: [PATCH 10/10] man: update dbus doc stubs For 4e39995371738b04d98d27b0d34ea8fe09ec9fab and bb0c0d6f29236645c8beb7ba662b2c4e7b241407. --- man/org.freedesktop.systemd1.xml | 96 ++++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) diff --git a/man/org.freedesktop.systemd1.xml b/man/org.freedesktop.systemd1.xml index cee79700ef..97629c0470 100644 --- a/man/org.freedesktop.systemd1.xml +++ b/man/org.freedesktop.systemd1.xml @@ -2567,6 +2567,10 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice { @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly b RemoveIPC = ...; @org.freedesktop.DBus.Property.EmitsChangedSignal("const") + readonly a(say) SetCredential = [...]; + @org.freedesktop.DBus.Property.EmitsChangedSignal("const") + readonly a(ss) LoadCredential = [...]; + @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly as SupplementaryGroups = ['...', ...]; @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly s PAMName = '...'; @@ -2673,6 +2677,10 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice { @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly s KeyringMode = '...'; @org.freedesktop.DBus.Property.EmitsChangedSignal("const") + readonly s ProtectProc = '...'; + @org.freedesktop.DBus.Property.EmitsChangedSignal("const") + readonly s ProcSubset = '...'; + @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly b ProtectHostname = ...; @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly s NetworkNamespacePath = '...'; @@ -3068,6 +3076,10 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice { + + + + @@ -3172,6 +3184,10 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice { + + + + @@ -3616,6 +3632,10 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice { + + + + @@ -3722,6 +3742,10 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2eservice { + + + + @@ -4236,6 +4260,10 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket { @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly b RemoveIPC = ...; @org.freedesktop.DBus.Property.EmitsChangedSignal("const") + readonly a(say) SetCredential = [...]; + @org.freedesktop.DBus.Property.EmitsChangedSignal("const") + readonly a(ss) LoadCredential = [...]; + @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly as SupplementaryGroups = ['...', ...]; @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly s PAMName = '...'; @@ -4342,6 +4370,10 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket { @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly s KeyringMode = '...'; @org.freedesktop.DBus.Property.EmitsChangedSignal("const") + readonly s ProtectProc = '...'; + @org.freedesktop.DBus.Property.EmitsChangedSignal("const") + readonly s ProcSubset = '...'; + @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly b ProtectHostname = ...; @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly s NetworkNamespacePath = '...'; @@ -4757,6 +4789,10 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket { + + + + @@ -4861,6 +4897,10 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket { + + + + @@ -5303,6 +5343,10 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket { + + + + @@ -5409,6 +5453,10 @@ node /org/freedesktop/systemd1/unit/avahi_2ddaemon_2esocket { + + + + @@ -5859,6 +5907,10 @@ node /org/freedesktop/systemd1/unit/home_2emount { @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly b RemoveIPC = ...; @org.freedesktop.DBus.Property.EmitsChangedSignal("const") + readonly a(say) SetCredential = [...]; + @org.freedesktop.DBus.Property.EmitsChangedSignal("const") + readonly a(ss) LoadCredential = [...]; + @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly as SupplementaryGroups = ['...', ...]; @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly s PAMName = '...'; @@ -5965,6 +6017,10 @@ node /org/freedesktop/systemd1/unit/home_2emount { @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly s KeyringMode = '...'; @org.freedesktop.DBus.Property.EmitsChangedSignal("const") + readonly s ProtectProc = '...'; + @org.freedesktop.DBus.Property.EmitsChangedSignal("const") + readonly s ProcSubset = '...'; + @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly b ProtectHostname = ...; @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly s NetworkNamespacePath = '...'; @@ -6310,6 +6366,10 @@ node /org/freedesktop/systemd1/unit/home_2emount { + + + + @@ -6414,6 +6474,10 @@ node /org/freedesktop/systemd1/unit/home_2emount { + + + + @@ -6778,6 +6842,10 @@ node /org/freedesktop/systemd1/unit/home_2emount { + + + + @@ -6884,6 +6952,10 @@ node /org/freedesktop/systemd1/unit/home_2emount { + + + + @@ -7453,6 +7525,10 @@ node /org/freedesktop/systemd1/unit/dev_2dsda3_2eswap { @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly b RemoveIPC = ...; @org.freedesktop.DBus.Property.EmitsChangedSignal("const") + readonly a(say) SetCredential = [...]; + @org.freedesktop.DBus.Property.EmitsChangedSignal("const") + readonly a(ss) LoadCredential = [...]; + @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly as SupplementaryGroups = ['...', ...]; @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly s PAMName = '...'; @@ -7559,6 +7635,10 @@ node /org/freedesktop/systemd1/unit/dev_2dsda3_2eswap { @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly s KeyringMode = '...'; @org.freedesktop.DBus.Property.EmitsChangedSignal("const") + readonly s ProtectProc = '...'; + @org.freedesktop.DBus.Property.EmitsChangedSignal("const") + readonly s ProcSubset = '...'; + @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly b ProtectHostname = ...; @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly s NetworkNamespacePath = '...'; @@ -7890,6 +7970,10 @@ node /org/freedesktop/systemd1/unit/dev_2dsda3_2eswap { + + + + @@ -7994,6 +8078,10 @@ node /org/freedesktop/systemd1/unit/dev_2dsda3_2eswap { + + + + @@ -8344,6 +8432,10 @@ node /org/freedesktop/systemd1/unit/dev_2dsda3_2eswap { + + + + @@ -8450,6 +8542,10 @@ node /org/freedesktop/systemd1/unit/dev_2dsda3_2eswap { + + + +