summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 04:42:34 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 04:42:34 +0000
commit1d6d8671262dc6b2a4e02e4a1878d91b86647054 (patch)
tree802f631f1abc6181cc842079844c15d37a54b14f
parentInitial commit. (diff)
downloaddh-nss-1d6d8671262dc6b2a4e02e4a1878d91b86647054.tar.xz
dh-nss-1d6d8671262dc6b2a4e02e4a1878d91b86647054.zip
Adding upstream version 1.7.upstream/1.7upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
-rw-r--r--Makefile9
-rw-r--r--README.md25
-rw-r--r--autoscripts/postinst-nss6
-rw-r--r--autoscripts/postinst-nss-db5
-rw-r--r--autoscripts/postrm-nss8
-rw-r--r--autoscripts/postrm-nss-db6
-rw-r--r--autoscripts/preinst-nss4
-rwxr-xr-xdh_installnss459
-rw-r--r--installnss.pm7
-rw-r--r--t/Test/DH.pm205
-rw-r--r--t/dh_installnss/debian/changelog5
-rw-r--r--t/dh_installnss/debian/compat1
-rw-r--r--t/dh_installnss/debian/control89
-rw-r--r--t/dh_installnss/debian/foo-after1.nss1
-rw-r--r--t/dh_installnss/debian/foo-after2.nss1
-rw-r--r--t/dh_installnss/debian/foo-before1.nss1
-rw-r--r--t/dh_installnss/debian/foo-before2.nss1
-rw-r--r--t/dh_installnss/debian/foo-empty1.nss0
-rw-r--r--t/dh_installnss/debian/foo-empty2.nss3
-rw-r--r--t/dh_installnss/debian/foo-example.nss3
-rw-r--r--t/dh_installnss/debian/foo-first1.nss2
-rw-r--r--t/dh_installnss/debian/foo-first2.nss1
-rw-r--r--t/dh_installnss/debian/foo-first3.nss2
-rw-r--r--t/dh_installnss/debian/foo-last1.nss1
-rw-r--r--t/dh_installnss/debian/foo-last2.nss1
-rw-r--r--t/dh_installnss/debian/foo-last3.nss2
-rw-r--r--t/dh_installnss/debian/foo-multidb1.nss4
-rw-r--r--t/dh_installnss/debian/foo-newdb1.nss1
-rw-r--r--t/dh_installnss/debian/foo-newdb2.nss3
-rw-r--r--t/dh_installnss/debian/foo-newdb3.nss3
-rw-r--r--t/dh_installnss/debian/foo-other.nss1
-rw-r--r--t/dh_installnss/debian/foo-remove-only1.nss2
-rw-r--r--t/dh_installnss/debian/foo-skip.nss2
-rw-r--r--t/dh_installnss/debian/foo-substring.nss2
-rwxr-xr-xt/dh_installnss/dh_installnss.t652
-rw-r--r--t/dh_installnss/nsswitch.conf.template17
36 files changed, 1535 insertions, 0 deletions
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..f7d8e14
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,9 @@
+all: dh_installnss.1
+
+dh_installnss.1: dh_installnss
+ pod2man --utf8 $< > $@
+
+update-version:
+ sed -E -i dh_installnss -e '/^our \$$VERSION = .*;$$/ s/= .*;$$/= "'"$$(dpkg-parsechangelog -S Version)"'";/'
+
+.PHONY: all update-version
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..229841a
--- /dev/null
+++ b/README.md
@@ -0,0 +1,25 @@
+# `dh_installnss` - enable NSS services
+
+`dh_installnss` is a debhelper program that is responsible for injecting
+NSS (Name Service Switch) services into `/etc/nsswitch.conf`.
+
+## Example
+
+An example `debian/nss` file could look like this:
+
+ hosts before=dns mdns4
+ hosts before=mdns4 mdns4_minimal [NOTFOUND=return]
+ hosts remove-only mdns # In case the user manually added it
+
+After the installation of this package, the original configuration of
+the `hosts` database in `/etc/nsswitch.conf` will change from:
+
+ hosts: files dns
+
+to:
+
+ hosts: files mdns4_minimal [NOTFOUND=return] mdns4 dns
+
+## Documentation
+
+Detailed documentation can be found in `dh_installnss(1)`.
diff --git a/autoscripts/postinst-nss b/autoscripts/postinst-nss
new file mode 100644
index 0000000..9f67154
--- /dev/null
+++ b/autoscripts/postinst-nss
@@ -0,0 +1,6 @@
+if [ "$1" = "configure" ] && [ -f "${DPKG_ROOT}/etc/nsswitch.conf.nss.${DPKG_MAINTSCRIPT_PACKAGE}-will-install" ] && [ -e "${DPKG_ROOT}/etc/nsswitch.conf" ] ; then
+ if ! grep -q -E #SERVICE_PATTERNS# "${DPKG_ROOT}/etc/nsswitch.conf" ; then
+ #OPERATIONS#
+ fi
+ rm "${DPKG_ROOT}/etc/nsswitch.conf.nss.${DPKG_MAINTSCRIPT_PACKAGE}-will-install"
+fi
diff --git a/autoscripts/postinst-nss-db b/autoscripts/postinst-nss-db
new file mode 100644
index 0000000..3814202
--- /dev/null
+++ b/autoscripts/postinst-nss-db
@@ -0,0 +1,5 @@
+if [ "$1" = "configure" ] && [ -e "${DPKG_ROOT}/etc/nsswitch.conf" ] ; then
+ if ! grep -q -E '^#DB#:' "${DPKG_ROOT}/etc/nsswitch.conf" ; then
+ echo "#DB#: " >> "${DPKG_ROOT}/etc/nsswitch.conf"
+ fi
+fi
diff --git a/autoscripts/postrm-nss b/autoscripts/postrm-nss
new file mode 100644
index 0000000..da94344
--- /dev/null
+++ b/autoscripts/postrm-nss
@@ -0,0 +1,8 @@
+: "${DPKG_MAINTSCRIPT_PACKAGE_INSTCOUNT:=$(dpkg-query -f '${db:Status-Abbrev}\n' -W "$DPKG_MAINTSCRIPT_PACKAGE" | grep -c '^i')}"
+if { [ "$1" = "remove" ] || [ "$1" = "purge" ] ; } && [ -e "${DPKG_ROOT}/etc/nsswitch.conf" ] && [ "$DPKG_MAINTSCRIPT_PACKAGE_INSTCOUNT" -eq 0 ] ; then
+ sed -E -i "${DPKG_ROOT}/etc/nsswitch.conf" \
+ -e ':a /^#DB#:\s.*#/ s/(^[^#]+)\s(#SERVICE_NAMES#)\s+\[!?[A-Za-z]+=[A-Za-z]+\](\s|#)/\1\3/g ; t a' \
+ -e ':b /^#DB#:\s.*#/ s/(^[^#]+)\s(#SERVICE_NAMES#)(\s|#)/\1\3/g ; t b' \
+ -e ':c /^#DB#:\s[^#]*$/ s/\s(#SERVICE_NAMES#)\s+\[!?[A-Za-z]+=[A-Za-z]+\](\s|$)/\2/g ; t c' \
+ -e ':d /^#DB#:\s[^#]*$/ s/\s(#SERVICE_NAMES#)(\s|$)/\2/g ; t d'
+fi
diff --git a/autoscripts/postrm-nss-db b/autoscripts/postrm-nss-db
new file mode 100644
index 0000000..c5a9e70
--- /dev/null
+++ b/autoscripts/postrm-nss-db
@@ -0,0 +1,6 @@
+: "${DPKG_MAINTSCRIPT_PACKAGE_INSTCOUNT:=$(dpkg-query -f '${db:Status-Abbrev}\n' -W "$DPKG_MAINTSCRIPT_PACKAGE" | grep -c '^i')}"
+if { [ "$1" = "remove" ] || [ "$1" = "purge" ] ; } && [ -e "${DPKG_ROOT}/etc/nsswitch.conf" ] && [ "$DPKG_MAINTSCRIPT_PACKAGE_INSTCOUNT" -eq 0 ] ; then
+ if grep -q -E '^#DB#:\s*$' "${DPKG_ROOT}/etc/nsswitch.conf" ; then
+ sed -E -i "${DPKG_ROOT}/etc/nsswitch.conf" -e '/^#DB#:/d'
+ fi
+fi
diff --git a/autoscripts/preinst-nss b/autoscripts/preinst-nss
new file mode 100644
index 0000000..a21bc7a
--- /dev/null
+++ b/autoscripts/preinst-nss
@@ -0,0 +1,4 @@
+if [ "$1" = install ]; then
+ # Signal to postinst that the NSS services should be installed, even if the package has been removed but not purged.
+ touch "${DPKG_ROOT}/etc/nsswitch.conf.nss.${DPKG_MAINTSCRIPT_PACKAGE}-will-install"
+fi
diff --git a/dh_installnss b/dh_installnss
new file mode 100755
index 0000000..6ae712a
--- /dev/null
+++ b/dh_installnss
@@ -0,0 +1,459 @@
+#!/usr/bin/perl
+
+=head1 NAME
+
+dh_installnss - enable NSS services
+
+=cut
+
+use strict;
+use warnings;
+use Debian::Debhelper::Dh_Lib;
+
+our $VERSION = "1.7";
+
+=head1 SYNOPSIS
+
+B<dh_installnss> [S<I<debhelper options>>]
+
+=head1 DESCRIPTION
+
+B<dh_installnss> is a debhelper program that is responsible for injecting
+NSS (Name Service Switch) services into F</etc/nsswitch.conf>.
+
+=head1 FILES
+
+=over 4
+
+=item debian/I<package>.nss
+
+Lists the services to inject into F</etc/nsswitch.conf> when a package is
+configured and to remove when a package is removed or purged.
+
+Each line in that file (a I<directive>) should be of the form
+
+I<db> I<position> I<service> I<action> I<condition>
+
+where the fields contain the following pieces of information:
+
+=over
+
+=item I<db>
+
+The NSS database in which the service will be added.
+Usually C<hosts>.
+
+=item I<position>
+
+Where to add the NSS service.
+
+Possible values are C<first>, C<last>, C<before=I<service>>,
+C<after=I<service>>, plus the pseudo-positions C<remove-only>,
+C<database-add> and C<database-require>.
+
+The pseudo-position C<remove-only> is used to mark services that are not
+going to be added during the installation of the package, but that will
+be removed during its deinstallation (e.g., legacy services).
+
+The pseudo-position C<database-add> is used to request the addition of a
+non-standard NSS database to F</etc/nsswitch.conf> during the installation
+of the package and its removal during the deinstallation of the package.
+When C<database-add> is used, all other fields in the directive should
+be left empty.
+
+The pseudo-position C<database-require> is used to announce that one
+or more services in the I<nss> file will be installed under a
+non-standard NSS database added by another package.
+When C<database-require> is used, all other fields in the directive
+should be left empty.
+
+=item I<service>
+
+The name of the NSS service to add.
+
+=item I<action>
+
+Optional action specification C<[STATE=ACTION]>.
+
+=item I<condition>
+
+Optional set of conditions to better define when
+a service should (or should not) be installed.
+
+Only one kind of condition is currently defined:
+C<skip-if-present=I<service,service,...>>.
+
+=back
+
+Additionally, text between a C<#> character and the end of line is ignored.
+
+=back
+
+=head1 EXAMPLES
+
+An example F<debian/nss> file could look like this:
+
+ hosts before=dns mdns4
+ hosts before=mdns4 mdns4_minimal [NOTFOUND=return]
+ hosts remove-only mdns # In case the user manually added it
+
+After the installation of this package, the original configuration of
+the B<hosts> database in B</etc/nsswitch.conf> will change from:
+
+ hosts: files dns
+
+to:
+
+ hosts: files mdns4_minimal [NOTFOUND=return] mdns4 dns
+
+=head1 CAVEATS
+
+=head2 Non-standard NSS databases
+
+Directives in a F<I<package>.nss> file can reference a non-standard
+NSS database only if that database has been first declared with a
+C<database-add> or C<database-require> directive in the same file.
+
+Non-standard NSS databases are all databases that are not defined in
+F</etc/nsswitch.conf> as shipped by the package B<base-files>.
+
+If a directive references an undeclared non-standard NSS database
+(e.g., C<somedb>), B<dh_installnss> will exit with the error message
+C<Unknown NSS database 'somedb'>.
+
+A non-standard NSS database can be declared by at most one installed
+package.
+In other words, if the directives in the B<nss> files of two packages
+A and B reference the same non-standard NSS database C<somedb> and
+both packages can be installed at the same time, one of the following
+two solutions must be implemented:
+
+=over
+
+=item 1.
+
+Package A supplies the C<somedb database-add> directive, package B
+I<Pre-Depend>s on A and uses a C<somedb database-require> directive.
+
+=item 2.
+
+The shared package C supplies the C<somedb database-add> directive,
+both package A and B I<Pre-Depend> on C and use a
+C<somedb database-require> directive.
+
+=back
+
+=cut
+
+use constant NSS_DATABASES => qw(passwd group shadow gshadow hosts networks protocols services ethers rpc netgroup);
+use constant POSITIONS => qw(first last before after remove-only database database-add database-require); # TODO: remove 'database' in v2
+use constant SERVICE_NAME_RE => qr/^[a-zA-Z0-9+:\@_-]+$/;
+use constant ACTION_RE => qr/^\[!?[A-Za-z]+=[A-Za-z]+\]$/;
+use constant CONDITION_TESTS => qw(skip-if-present);
+
+init();
+
+# PROMISE: DH NOOP WITHOUT nss cli-options()
+
+sub process {
+ foreach my $package (getpackages()) {
+ my @dbs_extra_add = ();
+ my @dbs_extra_require = ();
+ my @service_names = ();
+ my @inst_lines = ();
+ my %db_services = ();
+
+ my $nss = pkgfile($package, "nss") or next;
+ open(my $fd, $nss) or die("open($nss): $!");
+ foreach my $line (<$fd>) {
+ $line =~ s/#.*$//; # Remove comments.
+ chomp($line);
+ next if ($line eq "");
+
+ my ($db, $service_name, $position, $inst_line) = process_line($line, $package, $nss, $., \@dbs_extra_add, \@dbs_extra_require);
+
+ if (($position eq "database-add") || ($position eq "database")) { # TODO: remove 'database' in v2
+ # Collect names of extra NSS databases to be added.
+ if (! grep { $_ eq $db } @dbs_extra_add) {
+ push(@dbs_extra_add, $db);
+ }
+ next;
+ }
+
+ if (($position eq "database-require")) {
+ # Collect names of known non-standard NSS databases.
+ if (! grep { $_ eq $db } @dbs_extra_require) {
+ push(@dbs_extra_require, $db);
+ }
+ next;
+ }
+
+ # Collect the names of NSS services installed by this package,
+ # as well as their installation command lines.
+ if (! grep { $_ eq $service_name } @service_names) {
+ push(@service_names, $service_name);
+ }
+ push(@inst_lines, $inst_line) unless ($position eq "remove-only");
+
+ # Collect the names of the NSS services that will be removed
+ # when this package will be uninstalled.
+ # The services are grouped by NSS DB.
+ if (! exists $db_services{$db}) { @{$db_services{$db}} = (); }
+ if (! grep { $_ eq $service_name } @{$db_services{$db}}) {
+ push(@{$db_services{$db}}, $service_name);
+ }
+ }
+ close($fd);
+
+ if (!@dbs_extra_add && !@inst_lines && !%db_services) {
+ warning("$nss exists but contains no actionable directives.");
+ }
+
+ # Generate the required debhelper snippets.
+ output_autoscripts($package, \@dbs_extra_add, \@inst_lines, \%db_services);
+ }
+}
+
+sub process_line {
+ my ($line, $package, $nss_file, $line_num, $dbs_extra_add, $dbs_extra_require) = @_;
+
+ my ($db, $position, $service, $action, $condition) = split(" ", $line);
+ $service //= "";
+ $action //= "";
+ $condition //= "";
+
+ # Turn before=service into pos=before, anchor=service.
+ ($position, my $anchors) = split("=", $position);
+ $anchors //= "";
+
+ # Use $action as condition if it does not look like a proper action.
+ if (substr($action, 0, 1) ne "[") {
+ $condition = $action;
+ $action = "";
+ }
+
+ validate_line($nss_file, $line_num, $db, $position, $service, $action, $condition, $dbs_extra_add, $dbs_extra_require);
+
+ my $comment = comment_for_line($package, $db, $service, $position, $anchors, $action, $condition);
+ my $inst_operation = inst_operation_expr($package, $db, $service, $position, $anchors, $action, $condition);
+ my $inst_line = "$comment\n\t\t$inst_operation";
+
+ return $db, $service, $position, $inst_line;
+}
+
+sub validate_line {
+ my ($nss_file, $line_num, $db, $position, $service, $action, $condition, $dbs_extra_add, $dbs_extra_require) = @_;
+ my @dbs_extra_add = @{$dbs_extra_add};
+ my @dbs_extra_require = @{$dbs_extra_require};
+
+ if (! grep({ $_ eq $db } NSS_DATABASES)) {
+ if (!($position eq "database-add" || $position eq "database-require" || $position eq "database") # TODO: remove 'database' in v2
+ && ! grep({$_ eq $db } (@dbs_extra_add, @dbs_extra_require))) {
+ error("Unknown NSS database '$db' [$nss_file:$line_num]");
+ }
+ }
+
+ if (! grep({ $_ eq $position } POSITIONS)) {
+ error("Unknown position '$position' [$nss_file:$line_num]");
+ }
+
+ if ($position eq "database-add" || $position eq "database-require" || $position eq "database") { # TODO: remove database' in v2
+ if ($position eq "database") { # TODO: remove check in v2
+ warning("Outdated 'database' directive will be removed in dh-nss v2. Use 'database-add' instead. [$nss_file:$line_num]");
+ }
+ return;
+ }
+
+ if ($service !~ SERVICE_NAME_RE) {
+ warning("Malformed service name '$service' [$nss_file:$line_num]");
+ }
+
+ if ($action && $action !~ ACTION_RE) {
+ warning("Malformed action specification '$action' [$nss_file:$line_num]");
+ }
+
+ if ($condition) {
+ my ($cond_test, $cond_value) = split("=", $condition);
+ if ($cond_test && !grep({ $_ eq $cond_test } CONDITION_TESTS)) {
+ error("Invalid condition test '$cond_test' (part of '$condition') [$nss_file:$line_num]");
+ }
+ if ($cond_test eq "skip-if-present") {
+ foreach my $cond_service (split(",", $cond_value)) {
+ if ($cond_service !~ SERVICE_NAME_RE) {
+ warning("Invalid condition value '$cond_value' (part of '$condition') [$nss_file:$line_num]");
+ last;
+ }
+ }
+ }
+ }
+}
+
+sub comment_for_line {
+ my ($package, $db, $service, $position, $anchors, $action, $condition) = @_;
+
+ my $comment = "# Installing $db/$service$action from $package in position $position";
+ if ($anchors ne "") { $comment .= "=$anchors"; }
+ if ($condition ne "") { $comment .= " ($condition)"; }
+
+ return $comment;
+}
+
+sub inst_operation_expr {
+ my ($package, $db, $service, $position, $anchors, $action, $condition) = @_;
+
+ my $anchors_expr = anchors_expr($anchors);
+
+ my $condition_expr = cond_expr($db, $condition);
+
+ # Prepare a sed-ready string with the service name.
+ my $service_complete = $service;
+ $service_complete .= " $action" if ($action ne "");
+ $service_complete =~ s/(\[|\])/\\$1/g; # Escape `[` and `]`.
+
+ # Choose the right sed invocation for the required position.
+ my $sed_cmd = 'sed -E -i "${DPKG_ROOT}/etc/nsswitch.conf"';
+ if ($position eq "first") {
+ $sed_cmd .= " -e '/^$db:\\s/ s/(:\\s+)/\\1$service_complete /'";
+ } elsif ($position eq "last") {
+ $sed_cmd .= " -e '/^$db:\\s[^#]*\$/ s/\$/ $service_complete/'";
+ $sed_cmd .= " -e '/^$db:\\s.*#/ s/#/ $service_complete #/'";
+ } elsif ($position eq "before") {
+ $sed_cmd .= " -e '/^$db:\\s[^#]*\$/ s/(\\s)($anchors_expr)(\\s|\$)/\\1$service_complete \\2 /'" ;
+ $sed_cmd .= " -e '/^$db:\\s.*#/ s/(\\s)($anchors_expr)(\\s|#)/\\1$service_complete \\2 /'" ;
+ $sed_cmd .= " -e 's/ \$//'";
+ } elsif ($position eq "after") {
+ $sed_cmd .= " -e '/^$db:\\s[^#]*\$/ s/(\\s)($anchors_expr)(\\s|\$)/\\1\\2 $service_complete /'";
+ $sed_cmd .= " -e '/^$db:\\s.*#/ s/(\\s)($anchors_expr)(\\s|#)/\\1\\2 $service_complete \\3/'";
+ $sed_cmd .= " -e 's/ \$//'";
+ } elsif ($position eq "remove-only") {
+ $sed_cmd = "";
+ }
+
+ if ($condition_expr ne "") {
+ $sed_cmd = "if $condition_expr ; then\n\t\t\t$sed_cmd\n\t\tfi";
+ }
+
+ return $sed_cmd;
+}
+
+sub anchors_expr {
+ my ($anchors_str) = @_;
+ if (! defined($anchors_str)) { return "" };
+
+ my @anchors_res;
+ foreach my $anchor (split(",", $anchors_str)) {
+ my $anchor_re = "$anchor(\\s+\\[[^]]+\\])?";
+ push(@anchors_res, $anchor_re) ;
+ }
+
+ my $anchors_expr = join("|", @anchors_res);
+
+ return $anchors_expr;
+}
+
+sub cond_expr {
+ my ($db, $cond_str) = @_;
+ if ($cond_str eq "") { return "" };
+
+ my $cond_expr = "grep -q -E ";
+ if ($cond_str =~ /^skip-if-present=/ ) {
+ my $services = $cond_str =~ s/^skip-if-present=//r;
+ $services =~ s/,/|/g;
+ $cond_expr = "! $cond_expr";
+ $cond_expr .= "'^$db:.*\\s($services)(\\s|\$)'"
+ } else {
+ error("Cannot parse condition $cond_str");
+ }
+
+ $cond_expr .= ' "${DPKG_ROOT}/etc/nsswitch.conf"';
+ return $cond_expr
+}
+
+sub service_patterns_expr {
+ my ($db_services) = @_;
+ my %db_services = %{$db_services};
+
+ my @exprs = "";
+ my @dbs = sort(keys %db_services);
+ foreach my $db (@dbs) {
+ my $db_services_expr = $db_services{$db};
+ my $expr = "-e '^$db:[^#]*\\s($db_services_expr)(\\s|#|\$)'";
+ push(@exprs, $expr);
+ }
+
+ my $service_patterns_expr = join(" ", @exprs);
+
+ return $service_patterns_expr;
+}
+
+sub output_autoscripts {
+ my ($package, $dbs_extra_add, $inst_lines, $db_services) = @_;
+ my @dbs_extra_add = @{$dbs_extra_add};
+ my @inst_lines = @{$inst_lines};
+ my %db_services = %{$db_services};
+
+ # Turn the lists of database-specific services into regular expressions.
+ my @dbs = sort(keys %db_services);
+ foreach my $db (@dbs) {
+ my @db_services = @{$db_services{$db}};
+ my $db_services_expr = join("|", @db_services);
+ $db_services{$db} = $db_services_expr;
+ }
+
+ # Aggregate the target databases and service regular expressions into
+ # grep-compatible guard expressions.
+ my $service_patterns_expr = service_patterns_expr(\%db_services);
+
+ # Add a snippet in preinst to detect installation of non-purged packages.
+ autoscript($package, "preinst", "preinst-nss");
+
+ # Generate one snippet for each extra NSS databases to be added.
+ foreach my $db_extra (@dbs_extra_add) {
+ autoscript($package, "postinst", "postinst-nss-db", {
+ "DB" => $db_extra,
+ });
+ }
+
+ # Generate a single snippet with a sequence of installation instructions.
+ if (@inst_lines) {
+ my $inst_lines_expr = join("\n\t\t", @inst_lines);
+ autoscript($package, "postinst", "postinst-nss", {
+ "SERVICE_PATTERNS" => $service_patterns_expr,
+ "OPERATIONS" => $inst_lines_expr,
+ });
+ }
+
+ # Generate one snippet for each extra NSS databases to be removed.
+ # NOTE: DB removal must happen after service removal, however debhelper
+ # adds the `postrm` snippets in reverse order. For this reason the
+ # snippets for the extra DBs must be added first.
+ foreach my $db_extra (@dbs_extra_add) {
+ autoscript($package, "postrm", "postrm-nss-db", {
+ "DB" => $db_extra,
+ });
+ }
+
+ # Generate one snippet for each NSS DB, removing only the services
+ # related to that DB.
+ foreach my $db (@dbs) {
+ my $db_services_expr = $db_services{$db};
+ autoscript($package, "postrm", "postrm-nss", {
+ "DB" => $db,
+ "SERVICE_NAMES" => $db_services_expr,
+ });
+ }
+}
+
+process();
+
+=head1 SEE ALSO
+
+L<debhelper(7)>
+
+This program is a debhelper addon.
+
+=head1 AUTHOR
+
+Gioele Barabucci <gioele@svario.it>
+
+=cut
diff --git a/installnss.pm b/installnss.pm
new file mode 100644
index 0000000..dc2e044
--- /dev/null
+++ b/installnss.pm
@@ -0,0 +1,7 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+use Debian::Debhelper::Dh_Lib;
+
+insert_after("dh_install", "dh_installnss");
diff --git a/t/Test/DH.pm b/t/Test/DH.pm
new file mode 100644
index 0000000..7fa30bf
--- /dev/null
+++ b/t/Test/DH.pm
@@ -0,0 +1,205 @@
+package Test::DH;
+
+use strict;
+use warnings;
+
+use Test::More;
+
+use Cwd qw(getcwd realpath);
+use Errno qw(EEXIST);
+use Exporter qw(import);
+
+use File::Temp qw(tempdir);
+use File::Path qw(remove_tree make_path);
+use File::Basename qw(dirname);
+
+our $ROOT_DIR;
+
+BEGIN {
+ my $res = realpath(__FILE__) or die('Cannot resolve ' . __FILE__ . ": $!");
+ $ROOT_DIR = dirname(dirname(dirname($res)));
+};
+
+use lib "$ROOT_DIR/lib";
+
+# These should be done before Dh_lib is loaded.
+BEGIN {
+ $ENV{PATH} = "$ROOT_DIR:$ENV{PATH}" if $ENV{PATH} !~ m{\Q$ROOT_DIR\E/?:};
+ $ENV{PERL5LIB} = join(':', "${ROOT_DIR}/lib", (grep {defined} $ENV{PERL5LIB}))
+ if not $ENV{PERL5LIB} or $ENV{PERL5LIB} !~ m{\Q$ROOT_DIR\E(?:/lib)?/?:};
+ $ENV{DH_DATAFILES} = "${ROOT_DIR}/t/fixtures:${ROOT_DIR}";
+ # Nothing in the tests requires root.
+ $ENV{DEB_RULES_REQUIRES_ROOT} = 'no';
+ # Disable colors for good measure
+ $ENV{DH_COLORS} = 'never';
+ $ENV{DPKG_COLORS} = 'never';
+
+ # Drop DEB_BUILD_PROFILES and DEB_BUILD_OPTIONS so they don't interfere
+ delete($ENV{DEB_BUILD_PROFILES});
+ delete($ENV{DEB_BUILD_OPTIONS});
+};
+
+use Debian::Debhelper::Dh_Lib qw(!dirname);
+
+our @EXPORT = qw(
+ each_compat_up_to_and_incl_subtest each_compat_subtest
+ each_compat_from_and_above_subtest run_dh_tool
+ create_empty_file readlines
+ error find_script non_deprecated_compat_levels
+ each_compat_from_x_to_and_incl_y_subtest
+);
+
+our ($TEST_DH_COMPAT);
+
+my $START_DIR = getcwd();
+my $TEST_DIR;
+
+sub run_dh_tool {
+ my (@cmd) = @_;
+ my $compat = $TEST_DH_COMPAT;
+ my $options = ref($cmd[0]) ? shift(@cmd) : {};
+ my $pid;
+
+ $pid = fork() // BAIL_OUT("fork failed: $!");
+ if (not $pid) {
+ $ENV{DH_COMPAT} = $compat;
+ $ENV{DH_INTERNAL_TESTSUITE_SILENT_WARNINGS} = 1;
+ if (defined(my $env = $options->{env})) {
+ for my $k (sort(keys(%{$env}))) {
+ if (defined($env->{$k})) {
+ $ENV{$k} = $env->{$k};
+ } else {
+ delete($ENV{$k});
+ }
+ }
+ }
+ if ($options->{quiet}) {
+ open(STDOUT, '>', '/dev/null') or error("Reopen stdout: $!");
+ open(STDERR, '>', '/dev/null') or error("Reopen stderr: $!");
+ } else {
+ # If run under prove/TAP, we don't want to confuse the test runner.
+ open(STDOUT, '>&', *STDERR) or error("Redirect stdout to stderr: $!");
+ }
+ exec(@cmd);
+ }
+ waitpid($pid, 0) == $pid or BAIL_OUT("waitpid($pid) failed: $!");
+ return 1 if not $?;
+ return 0;
+}
+
+sub _prepare_test_root {
+ my $dir = tempdir(CLEANUP => 1);
+ if (not mkdir("$dir/debian", 0777)) {
+ error("mkdir $dir/debian failed: $!")
+ if $! != EEXIST;
+ } else {
+ # auto seed it
+ my @files = qw(
+ debian/control
+ debian/compat
+ debian/changelog
+ );
+ for my $file (@files) {
+ install_file($file, "${dir}/${file}");
+ }
+ if (@::TEST_DH_EXTRA_TEMPLATE_FILES) {
+ my $test_dir = ($TEST_DIR //= dirname($0));
+ my $fixture_dir = $::TEST_DH_FIXTURE_DIR // '.';
+ my $actual_dir = "$test_dir/$fixture_dir";
+ for my $file (@::TEST_DH_EXTRA_TEMPLATE_FILES) {
+ if (index($file, '/') > -1) {
+ my $install_dir = dirname($file);
+ install_dir($install_dir);
+ }
+ install_file("${actual_dir}/${file}", "${dir}/${file}");
+ }
+ }
+ }
+ return $dir;
+}
+
+sub each_compat_from_x_to_and_incl_y_subtest($$&) {
+ my ($compat, $high_compat, $code) = @_;
+ my $lowest = Debian::Debhelper::Dh_Lib::MIN_COMPAT_LEVEL;
+ my $highest = Debian::Debhelper::Dh_Lib::MAX_COMPAT_LEVEL;
+ error("compat $compat is no longer support! Min compat $lowest")
+ if $compat < $lowest;
+ error("$high_compat is from the future! Max known is $highest")
+ if $high_compat > $highest;
+ subtest '' => sub {
+ # Keep $dir alive until the test is over
+ my $dir = _prepare_test_root;
+ chdir($dir) or error("chdir($dir): $!");
+ while ($compat <= $high_compat) {
+ local $TEST_DH_COMPAT = $compat;
+ $code->($compat);
+ ++$compat;
+ }
+ chdir($START_DIR) or error("chdir($START_DIR): $!");
+ };
+ return;
+}
+
+sub each_compat_up_to_and_incl_subtest($&) {
+ unshift(@_, Debian::Debhelper::Dh_Lib::MIN_COMPAT_LEVEL);
+ goto \&each_compat_from_x_to_and_incl_y_subtest;
+}
+
+sub each_compat_from_and_above_subtest($&) {
+ splice(@_, 1, 0, Debian::Debhelper::Dh_Lib::MAX_COMPAT_LEVEL);
+ goto \&each_compat_from_x_to_and_incl_y_subtest;
+}
+
+sub each_compat_subtest(&) {
+ unshift(@_,
+ Debian::Debhelper::Dh_Lib::MIN_COMPAT_LEVEL,
+ Debian::Debhelper::Dh_Lib::MAX_COMPAT_LEVEL);
+ goto \&each_compat_from_x_to_and_incl_y_subtest;
+}
+
+sub create_empty_file {
+ my ($file, $chmod) = @_;
+ open(my $fd, '>', $file) or die("open($file): $!\n");
+ close($fd) or die("close($file): $!\n");
+ if (defined($chmod)) {
+ chmod($chmod, $file)
+ or die(sprintf('chmod(%04o, %s): %s', $chmod, $file, $!));
+ }
+ return 1;
+}
+
+sub readlines {
+ my ($h) = @_;
+ my @lines = <$h>;
+ close $h;
+ chop @lines;
+ return \@lines;
+}
+
+# In *inst order (find_script will shuffle them around for *rm order)
+my @SNIPPET_FILE_TEMPLATES = (
+ 'debian/#PACKAGE#.#SCRIPT#.debhelper',
+ 'debian/.debhelper/generated/#PACKAGE#/#SCRIPT#.service',
+);
+
+sub find_script {
+ my ($package, $script) = @_;
+ my @files;
+ for my $template (@SNIPPET_FILE_TEMPLATES) {
+ my $file = ($template =~ s/#PACKAGE#/$package/r);
+ $file =~ s/#SCRIPT#/$script/;
+ push(@files, $file) if -f $file;
+ }
+ if ($script eq 'postrm' or $script eq 'prerm') {
+ @files = reverse(@files);
+ }
+ return @files;
+}
+
+sub non_deprecated_compat_levels() {
+ my $start = Debian::Debhelper::Dh_Lib::LOWEST_NON_DEPRECATED_COMPAT_LEVEL;
+ my $end = Debian::Debhelper::Dh_Lib::MAX_COMPAT_LEVEL;
+ return ($start..$end);
+}
+
+1;
diff --git a/t/dh_installnss/debian/changelog b/t/dh_installnss/debian/changelog
new file mode 100644
index 0000000..5850f0e
--- /dev/null
+++ b/t/dh_installnss/debian/changelog
@@ -0,0 +1,5 @@
+foo (1.0-1) unstable; urgency=low
+
+ * Initial release. (Closes: #XXXXXX)
+
+ -- Test <testing@nowhere> Mon, 11 Jul 2016 18:10:59 +0200
diff --git a/t/dh_installnss/debian/compat b/t/dh_installnss/debian/compat
new file mode 100644
index 0000000..60d3b2f
--- /dev/null
+++ b/t/dh_installnss/debian/compat
@@ -0,0 +1 @@
+15
diff --git a/t/dh_installnss/debian/control b/t/dh_installnss/debian/control
new file mode 100644
index 0000000..8e137f7
--- /dev/null
+++ b/t/dh_installnss/debian/control
@@ -0,0 +1,89 @@
+Source: foo
+Section: misc
+Priority: optional
+Maintainer: Test <testing@example.org>
+Standards-Version: 3.9.8
+
+Package: foo-before1
+Architecture: all
+Description: package foo-before1
+
+Package: foo-before2
+Architecture: all
+Description: package foo-before2
+
+Package: foo-after1
+Architecture: all
+Description: package foo-after1
+
+Package: foo-after2
+Architecture: all
+Description: package foo-after2
+
+Package: foo-empty1
+Architecture: all
+Description: package foo-empty1
+
+Package: foo-empty2
+Architecture: all
+Description: package foo-empty2
+
+Package: foo-first1
+Architecture: all
+Description: package foo-first1
+
+Package: foo-first2
+Architecture: all
+Description: package foo-first2
+
+Package: foo-first3
+Architecture: all
+Description: package foo-first3
+
+Package: foo-last1
+Architecture: all
+Description: package foo-last1
+
+Package: foo-last2
+Architecture: all
+Description: package foo-last2
+
+Package: foo-last3
+Architecture: all
+Description: package foo-last3
+
+Package: foo-multidb1
+Architecture: all
+Description: package foo-multidb1
+
+Package: foo-newdb1
+Architecture: all
+Description: package foo-newdb1
+
+Package: foo-newdb2
+Architecture: all
+Description: package foo-newdb2
+
+Package: foo-newdb3
+Architecture: all
+Description: package foo-newdb3
+
+Package: foo-remove-only1
+Architecture: all
+Description: package foo-remove-only1
+
+Package: foo-other
+Architecture: all
+Description: package foo-other
+
+Package: foo-example
+Architecture: all
+Description: package foo-example
+
+Package: foo-skip
+Architecture: all
+Description: package foo-skip
+
+Package: foo-substring
+Architecture: all
+Description: package foo-substring
diff --git a/t/dh_installnss/debian/foo-after1.nss b/t/dh_installnss/debian/foo-after1.nss
new file mode 100644
index 0000000..aa65c17
--- /dev/null
+++ b/t/dh_installnss/debian/foo-after1.nss
@@ -0,0 +1 @@
+hosts after=dns foo
diff --git a/t/dh_installnss/debian/foo-after2.nss b/t/dh_installnss/debian/foo-after2.nss
new file mode 100644
index 0000000..0c0d053
--- /dev/null
+++ b/t/dh_installnss/debian/foo-after2.nss
@@ -0,0 +1 @@
+hosts after=dns,files foo
diff --git a/t/dh_installnss/debian/foo-before1.nss b/t/dh_installnss/debian/foo-before1.nss
new file mode 100644
index 0000000..d0d65a9
--- /dev/null
+++ b/t/dh_installnss/debian/foo-before1.nss
@@ -0,0 +1 @@
+hosts before=dns foo
diff --git a/t/dh_installnss/debian/foo-before2.nss b/t/dh_installnss/debian/foo-before2.nss
new file mode 100644
index 0000000..cdfd74d
--- /dev/null
+++ b/t/dh_installnss/debian/foo-before2.nss
@@ -0,0 +1 @@
+hosts before=dns,resolve foo
diff --git a/t/dh_installnss/debian/foo-empty1.nss b/t/dh_installnss/debian/foo-empty1.nss
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/t/dh_installnss/debian/foo-empty1.nss
diff --git a/t/dh_installnss/debian/foo-empty2.nss b/t/dh_installnss/debian/foo-empty2.nss
new file mode 100644
index 0000000..40afa03
--- /dev/null
+++ b/t/dh_installnss/debian/foo-empty2.nss
@@ -0,0 +1,3 @@
+# only comments here
+
+# and empty lines
diff --git a/t/dh_installnss/debian/foo-example.nss b/t/dh_installnss/debian/foo-example.nss
new file mode 100644
index 0000000..7708ddd
--- /dev/null
+++ b/t/dh_installnss/debian/foo-example.nss
@@ -0,0 +1,3 @@
+hosts before=dns mdns4
+hosts before=mdns4 mdns4_minimal [NOTFOUND=return]
+hosts remove-only mdns # In case the user manually added it
diff --git a/t/dh_installnss/debian/foo-first1.nss b/t/dh_installnss/debian/foo-first1.nss
new file mode 100644
index 0000000..8e29dd7
--- /dev/null
+++ b/t/dh_installnss/debian/foo-first1.nss
@@ -0,0 +1,2 @@
+#DB POS MODULE (ACTION?) (CONDITION?)
+hosts first foo
diff --git a/t/dh_installnss/debian/foo-first2.nss b/t/dh_installnss/debian/foo-first2.nss
new file mode 100644
index 0000000..10a78de
--- /dev/null
+++ b/t/dh_installnss/debian/foo-first2.nss
@@ -0,0 +1 @@
+hosts first foo [NOTFOUND=return]
diff --git a/t/dh_installnss/debian/foo-first3.nss b/t/dh_installnss/debian/foo-first3.nss
new file mode 100644
index 0000000..9c80174
--- /dev/null
+++ b/t/dh_installnss/debian/foo-first3.nss
@@ -0,0 +1,2 @@
+hosts first foo2
+hosts first foo2 [NOTFOUND=return]
diff --git a/t/dh_installnss/debian/foo-last1.nss b/t/dh_installnss/debian/foo-last1.nss
new file mode 100644
index 0000000..defa945
--- /dev/null
+++ b/t/dh_installnss/debian/foo-last1.nss
@@ -0,0 +1 @@
+hosts last foo
diff --git a/t/dh_installnss/debian/foo-last2.nss b/t/dh_installnss/debian/foo-last2.nss
new file mode 100644
index 0000000..e6ad245
--- /dev/null
+++ b/t/dh_installnss/debian/foo-last2.nss
@@ -0,0 +1 @@
+hosts last foo [NOTFOUND=return]
diff --git a/t/dh_installnss/debian/foo-last3.nss b/t/dh_installnss/debian/foo-last3.nss
new file mode 100644
index 0000000..cb85368
--- /dev/null
+++ b/t/dh_installnss/debian/foo-last3.nss
@@ -0,0 +1,2 @@
+hosts last foo2
+hosts last foo2 [NOTFOUND=return]
diff --git a/t/dh_installnss/debian/foo-multidb1.nss b/t/dh_installnss/debian/foo-multidb1.nss
new file mode 100644
index 0000000..8dc899c
--- /dev/null
+++ b/t/dh_installnss/debian/foo-multidb1.nss
@@ -0,0 +1,4 @@
+shadow first foo
+shadow last foo2
+group first foo
+passwd last baz
diff --git a/t/dh_installnss/debian/foo-newdb1.nss b/t/dh_installnss/debian/foo-newdb1.nss
new file mode 100644
index 0000000..606d085
--- /dev/null
+++ b/t/dh_installnss/debian/foo-newdb1.nss
@@ -0,0 +1 @@
+mydb database-add
diff --git a/t/dh_installnss/debian/foo-newdb2.nss b/t/dh_installnss/debian/foo-newdb2.nss
new file mode 100644
index 0000000..2d38f54
--- /dev/null
+++ b/t/dh_installnss/debian/foo-newdb2.nss
@@ -0,0 +1,3 @@
+mydb database-add
+
+mydb first foo
diff --git a/t/dh_installnss/debian/foo-newdb3.nss b/t/dh_installnss/debian/foo-newdb3.nss
new file mode 100644
index 0000000..7bd7149
--- /dev/null
+++ b/t/dh_installnss/debian/foo-newdb3.nss
@@ -0,0 +1,3 @@
+mydb database-require
+
+mydb first bar
diff --git a/t/dh_installnss/debian/foo-other.nss b/t/dh_installnss/debian/foo-other.nss
new file mode 100644
index 0000000..6f3c135
--- /dev/null
+++ b/t/dh_installnss/debian/foo-other.nss
@@ -0,0 +1 @@
+hosts last foo
diff --git a/t/dh_installnss/debian/foo-remove-only1.nss b/t/dh_installnss/debian/foo-remove-only1.nss
new file mode 100644
index 0000000..816ad1e
--- /dev/null
+++ b/t/dh_installnss/debian/foo-remove-only1.nss
@@ -0,0 +1,2 @@
+hosts first foo
+hosts remove-only resolve
diff --git a/t/dh_installnss/debian/foo-skip.nss b/t/dh_installnss/debian/foo-skip.nss
new file mode 100644
index 0000000..0002201
--- /dev/null
+++ b/t/dh_installnss/debian/foo-skip.nss
@@ -0,0 +1,2 @@
+hosts first foo skip-if-present=other1,other2
+hosts first foo2 skip-if-present=other3
diff --git a/t/dh_installnss/debian/foo-substring.nss b/t/dh_installnss/debian/foo-substring.nss
new file mode 100644
index 0000000..5843e2b
--- /dev/null
+++ b/t/dh_installnss/debian/foo-substring.nss
@@ -0,0 +1,2 @@
+hosts before=dns foo
+hosts first foo_extra
diff --git a/t/dh_installnss/dh_installnss.t b/t/dh_installnss/dh_installnss.t
new file mode 100755
index 0000000..95cfecd
--- /dev/null
+++ b/t/dh_installnss/dh_installnss.t
@@ -0,0 +1,652 @@
+#!/usr/bin/perl
+use strict;
+use warnings;
+
+use Test::More;
+use Cwd qw(abs_path);
+use File::Basename qw(dirname);
+use File::Path qw(make_path);
+use lib dirname(dirname(abs_path(__FILE__)));
+use Test::DH;
+use Debian::Debhelper::Dh_Lib qw(!dirname);
+
+plan(tests => 1);
+
+my $test_dir = abs_path(dirname(__FILE__));
+my $dpkg_root = "debian/foo";
+
+our @TEST_DH_EXTRA_TEMPLATE_FILES = (qw(
+ debian/changelog
+ debian/control
+ debian/foo-after1.nss
+ debian/foo-after2.nss
+ debian/foo-before1.nss
+ debian/foo-before2.nss
+ debian/foo-empty1.nss
+ debian/foo-empty2.nss
+ debian/foo-example.nss
+ debian/foo-first1.nss
+ debian/foo-first2.nss
+ debian/foo-first3.nss
+ debian/foo-last1.nss
+ debian/foo-last2.nss
+ debian/foo-last3.nss
+ debian/foo-multidb1.nss
+ debian/foo-newdb1.nss
+ debian/foo-newdb2.nss
+ debian/foo-newdb3.nss
+ debian/foo-other.nss
+ debian/foo-remove-only1.nss
+ debian/foo-skip.nss
+ debian/foo-substring.nss
+));
+
+each_compat_subtest {
+ make_path(qw(debian/foo debian/foo/etc));
+ ok(run_dh_tool("dh_installnss"));
+
+ $ENV{"DPKG_ROOT"} = "$dpkg_root";
+ $ENV{"DPKG_MAINTSCRIPT_PACKAGE_INSTCOUNT"} = 0;
+
+ subtest "skips installation if no /etc/nsswitch.conf" => sub {
+ unlink("$dpkg_root/etc/nsswitch.conf");
+ exec_script_ok("foo-first1", "preinst", "install");
+ exec_script_ok("foo-first1", "postinst", "configure");
+ ok(!-e "$dpkg_root/etc/nsswitch.conf");
+ };
+
+ subtest "respects skip-if-present" => sub {
+ place_nsswitch_file("hosts", "files other2 dns");
+ exec_script_ok("foo-skip", "preinst", "install");
+ exec_script_ok("foo-skip", "postinst", "configure");
+ is(db_line("hosts"), "hosts: foo2 files other2 dns");
+ exec_script_ok("foo-skip", "postrm", "remove");
+ is(db_line("hosts"), "hosts: files other2 dns");
+ };
+
+ subtest "position=first" => sub {
+ subtest "adds in first position" => sub {
+ place_nsswitch_file("hosts", "files other2 dns");
+ exec_script_ok("foo-first1", "preinst", "install");
+ exec_script_ok("foo-first1", "postinst", "configure");
+ is(db_line("hosts"), "hosts: foo files other2 dns");
+ exec_script_ok("foo-first1", "postrm", "remove");
+ is(db_line("hosts"), "hosts: files other2 dns");
+ };
+
+ subtest "adds in first position (in presence of comments)" => sub {
+ place_nsswitch_file("hosts", "files other2 dns # comment");
+ exec_script_ok("foo-first1", "preinst", "install");
+ exec_script_ok("foo-first1", "postinst", "configure");
+ is(db_line("hosts"), "hosts: foo files other2 dns # comment");
+ exec_script_ok("foo-first1", "postrm", "remove");
+ is(db_line("hosts"), "hosts: files other2 dns # comment");
+ };
+
+ subtest "adds in first position (in presence of service in comment)" => sub {
+ place_nsswitch_file("hosts", "files other2 dns # foo in comment");
+ exec_script_ok("foo-first1", "preinst", "install");
+ exec_script_ok("foo-first1", "postinst", "configure");
+ is(db_line("hosts"), "hosts: foo files other2 dns # foo in comment");
+ exec_script_ok("foo-first1", "postrm", "remove");
+ is(db_line("hosts"), "hosts: files other2 dns # foo in comment");
+ };
+
+ subtest "adds in first position (with action)" => sub {
+ place_nsswitch_file("hosts", "files other2 dns");
+ exec_script_ok("foo-first2", "preinst", "install");
+ exec_script_ok("foo-first2", "postinst", "configure");
+ is(db_line("hosts"), "hosts: foo [NOTFOUND=return] files other2 dns");
+ exec_script_ok("foo-first2", "postrm", "remove");
+ is(db_line("hosts"), "hosts: files other2 dns");
+ };
+
+ subtest "adds in first position (multiple times)" => sub {
+ place_nsswitch_file("hosts", "files other2 dns");
+ exec_script_ok("foo-first3", "preinst", "install");
+ exec_script_ok("foo-first3", "postinst", "configure");
+ is(db_line("hosts"), "hosts: foo2 [NOTFOUND=return] foo2 files other2 dns");
+ exec_script_ok("foo-first3", "postrm", "remove");
+ is(db_line("hosts"), "hosts: files other2 dns");
+ };
+
+ subtest "does not add if already present in line (service name)" => sub {
+ place_nsswitch_file("hosts", "files foo dns");
+ exec_script_ok("foo-first1", "preinst", "install");
+ exec_script_ok("foo-first1", "postinst", "configure");
+ is(db_line("hosts"), "hosts: files foo dns");
+ exec_script_ok("foo-first1", "postrm", "remove");
+ is(db_line("hosts"), "hosts: files dns");
+ };
+
+ subtest "does not add if already present in line (service first)" => sub {
+ place_nsswitch_file("hosts", "foo files dns");
+ exec_script_ok("foo-first1", "preinst", "install");
+ exec_script_ok("foo-first1", "postinst", "configure");
+ is(db_line("hosts"), "hosts: foo files dns");
+ exec_script_ok("foo-first1", "postrm", "remove");
+ is(db_line("hosts"), "hosts: files dns");
+ };
+
+ subtest "does not add if already present in line (service last)" => sub {
+ place_nsswitch_file("hosts", "files dns foo");
+ exec_script_ok("foo-first1", "preinst", "install");
+ exec_script_ok("foo-first1", "postinst", "configure");
+ is(db_line("hosts"), "hosts: files dns foo");
+ exec_script_ok("foo-first1", "postrm", "remove");
+ is(db_line("hosts"), "hosts: files dns");
+ };
+
+ subtest "does not add if already present in line (service last before comment)" => sub {
+ place_nsswitch_file("hosts", "files dns foo# comment");
+ exec_script_ok("foo-first1", "preinst", "install");
+ exec_script_ok("foo-first1", "postinst", "configure");
+ is(db_line("hosts"), "hosts: files dns foo# comment");
+ exec_script_ok("foo-first1", "postrm", "remove");
+ is(db_line("hosts"), "hosts: files dns# comment");
+ };
+
+ subtest "does not add if already present in line (service name with action)" => sub {
+ place_nsswitch_file("hosts", "files foo [NOTFOUND=return] dns");
+ exec_script_ok("foo-first2", "preinst", "install");
+ exec_script_ok("foo-first2", "postinst", "configure");
+ is(db_line("hosts"), "hosts: files foo [NOTFOUND=return] dns");
+ exec_script_ok("foo-first2", "postrm", "remove");
+ is(db_line("hosts"), "hosts: files dns");
+ };
+
+ subtest "does not if already present in line (service name without action)" => sub {
+ place_nsswitch_file("hosts", "files foo dns");
+ exec_script_ok("foo-first2", "preinst", "install");
+ exec_script_ok("foo-first2", "postinst", "configure");
+ is(db_line("hosts"), "hosts: files foo dns");
+ exec_script_ok("foo-first2", "postrm", "remove");
+ is(db_line("hosts"), "hosts: files dns");
+ };
+ };
+
+ subtest "position=last" => sub {
+ subtest "adds in last position" => sub {
+ place_nsswitch_file("hosts", "files other2 dns");
+ exec_script_ok("foo-last1", "preinst", "install");
+ exec_script_ok("foo-last1", "postinst", "configure");
+ is(db_line("hosts"), "hosts: files other2 dns foo");
+ exec_script_ok("foo-last1", "postrm", "remove");
+ is(db_line("hosts"), "hosts: files other2 dns");
+ };
+
+ subtest "adds in last position (with action)" => sub {
+ place_nsswitch_file("hosts", "files other2 dns");
+ exec_script_ok("foo-last2", "preinst", "install");
+ exec_script_ok("foo-last2", "postinst", "configure");
+ is(db_line("hosts"), "hosts: files other2 dns foo [NOTFOUND=return]");
+ exec_script_ok("foo-last2", "postrm", "remove");
+ is(db_line("hosts"), "hosts: files other2 dns");
+ };
+
+ subtest "adds in last position (multiple times)" => sub {
+ place_nsswitch_file("hosts", "files other2 dns");
+ exec_script_ok("foo-last3", "preinst", "install");
+ exec_script_ok("foo-last3", "postinst", "configure");
+ is(db_line("hosts"), "hosts: files other2 dns foo2 foo2 [NOTFOUND=return]");
+ exec_script_ok("foo-last3", "postrm", "remove");
+ is(db_line("hosts"), "hosts: files other2 dns");
+ };
+
+ subtest "adds before a comment" => sub {
+ place_nsswitch_file("hosts", "files other2 dns #a long comment");
+ exec_script_ok("foo-last1", "preinst", "install");
+ exec_script_ok("foo-last1", "postinst", "configure");
+ is(db_line("hosts"), "hosts: files other2 dns foo #a long comment");
+ exec_script_ok("foo-last1", "postrm", "remove");
+ is(db_line("hosts"), "hosts: files other2 dns #a long comment");
+ };
+
+ subtest "adds before a comment (no space)" => sub {
+ place_nsswitch_file("hosts", "files other2 dns#short comment");
+ exec_script_ok("foo-last1", "preinst", "install");
+ exec_script_ok("foo-last1", "postinst", "configure");
+ # The script unconditionally adds a space before the comment.
+ is(db_line("hosts"), "hosts: files other2 dns foo #short comment");
+ exec_script_ok("foo-last1", "postrm", "remove");
+ is(db_line("hosts"), "hosts: files other2 dns #short comment");
+ };
+ };
+
+ subtest "position=before" => sub {
+ subtest "adds before another" => sub {
+ place_nsswitch_file("hosts", "files other2 dns");
+ exec_script_ok("foo-before1", "preinst", "install");
+ exec_script_ok("foo-before1", "postinst", "configure");
+ is(db_line("hosts"), "hosts: files other2 foo dns");
+ exec_script_ok("foo-before1", "postrm", "remove");
+ is(db_line("hosts"), "hosts: files other2 dns");
+ };
+
+ subtest "adds before another (in presence of comments)" => sub {
+ place_nsswitch_file("hosts", "files other2 dns # comment");
+ exec_script_ok("foo-before1", "preinst", "install");
+ exec_script_ok("foo-before1", "postinst", "configure");
+ is(db_line("hosts"), "hosts: files other2 foo dns # comment");
+ exec_script_ok("foo-before1", "postrm", "remove");
+ is(db_line("hosts"), "hosts: files other2 dns # comment");
+ };
+
+ subtest "adds before another with action" => sub {
+ place_nsswitch_file("hosts", "files other2 dns [NOTFOUND=return]");
+ exec_script_ok("foo-before1", "preinst", "install");
+ exec_script_ok("foo-before1", "postinst", "configure");
+ is(db_line("hosts"), "hosts: files other2 foo dns [NOTFOUND=return]");
+ exec_script_ok("foo-before1", "postrm", "remove");
+ is(db_line("hosts"), "hosts: files other2 dns [NOTFOUND=return]");
+ };
+
+ subtest "does not add before another if missing" => sub {
+ place_nsswitch_file("hosts", "files other2");
+ exec_script_ok("foo-before1", "preinst", "install");
+ exec_script_ok("foo-before1", "postinst", "configure");
+ is(db_line("hosts"), "hosts: files other2");
+ exec_script_ok("foo-before1", "postrm", "remove");
+ is(db_line("hosts"), "hosts: files other2");
+ };
+
+ subtest "does not add if another missing (but in comment)" => sub {
+ place_nsswitch_file("hosts", "files other2 # dns");
+ exec_script_ok("foo-before1", "preinst", "install");
+ exec_script_ok("foo-before1", "postinst", "configure");
+ is(db_line("hosts"), "hosts: files other2 # dns");
+ exec_script_ok("foo-before1", "postrm", "remove");
+ is(db_line("hosts"), "hosts: files other2 # dns");
+ };
+
+ subtest "adds before another (multiple possibilites, one found)" => sub {
+ place_nsswitch_file("hosts", "files resolve other2");
+ exec_script_ok("foo-before2", "preinst", "install");
+ exec_script_ok("foo-before2", "postinst", "configure");
+ is(db_line("hosts"), "hosts: files foo resolve other2");
+ exec_script_ok("foo-before2", "postrm", "remove");
+ is(db_line("hosts"), "hosts: files resolve other2");
+ };
+
+ subtest "adds before another (multiple possibilites, same order)" => sub {
+ place_nsswitch_file("hosts", "files dns resolve other2");
+ exec_script_ok("foo-before2", "preinst", "install");
+ exec_script_ok("foo-before2", "postinst", "configure");
+ is(db_line("hosts"), "hosts: files foo dns resolve other2");
+ exec_script_ok("foo-before2", "postrm", "remove");
+ is(db_line("hosts"), "hosts: files dns resolve other2");
+ };
+
+ subtest "adds before another (multiple possibilites, inverted order)" => sub {
+ place_nsswitch_file("hosts", "files resolve other2 dns");
+ exec_script_ok("foo-before2", "preinst", "install");
+ exec_script_ok("foo-before2", "postinst", "configure");
+ is(db_line("hosts"), "hosts: files foo resolve other2 dns");
+ exec_script_ok("foo-before2", "postrm", "remove");
+ is(db_line("hosts"), "hosts: files resolve other2 dns");
+ };
+
+ subtest "adds before another (multiple possibilites, with action)" => sub {
+ place_nsswitch_file("hosts", "files resolve [!NOTFOUND=return] other2");
+ exec_script_ok("foo-before2", "preinst", "install");
+ exec_script_ok("foo-before2", "postinst", "configure");
+ is(db_line("hosts"), "hosts: files foo resolve [!NOTFOUND=return] other2");
+ exec_script_ok("foo-before2", "postrm", "remove");
+ is(db_line("hosts"), "hosts: files resolve [!NOTFOUND=return] other2");
+ };
+ };
+
+ subtest "position=after" => sub {
+ subtest "adds after another" => sub {
+ place_nsswitch_file("hosts", "files other2 dns");
+ exec_script_ok("foo-after1", "preinst", "install");
+ exec_script_ok("foo-after1", "postinst", "configure");
+ is(db_line("hosts"), "hosts: files other2 dns foo");
+ exec_script_ok("foo-after1", "postrm", "remove");
+ is(db_line("hosts"), "hosts: files other2 dns");
+ };
+
+ subtest "adds after another (in presence of comments)" => sub {
+ place_nsswitch_file("hosts", "files other2 dns # a comment");
+ exec_script_ok("foo-after1", "preinst", "install");
+ exec_script_ok("foo-after1", "postinst", "configure");
+ is(db_line("hosts"), "hosts: files other2 dns foo # a comment");
+ exec_script_ok("foo-after1", "postrm", "remove");
+ is(db_line("hosts"), "hosts: files other2 dns # a comment");
+ };
+
+ subtest "adds after another with action" => sub {
+ place_nsswitch_file("hosts", "dns [NOTFOUND=return] other2 files");
+ exec_script_ok("foo-after1", "preinst", "install");
+ exec_script_ok("foo-after1", "postinst", "configure");
+ is(db_line("hosts"), "hosts: dns [NOTFOUND=return] foo other2 files");
+ exec_script_ok("foo-after1", "postrm", "remove");
+ is(db_line("hosts"), "hosts: dns [NOTFOUND=return] other2 files");
+ };
+
+ subtest "does not add after another if missing (but in comment)" => sub {
+ place_nsswitch_file("hosts", "files other2 # dns");
+ exec_script_ok("foo-after1", "preinst", "install");
+ exec_script_ok("foo-after1", "postinst", "configure");
+ is(db_line("hosts"), "hosts: files other2 # dns");
+ exec_script_ok("foo-after1", "postrm", "remove");
+ is(db_line("hosts"), "hosts: files other2 # dns");
+ };
+
+ subtest "does not add after another if missing" => sub {
+ place_nsswitch_file("hosts", "files other2");
+ exec_script_ok("foo-after1", "preinst", "install");
+ exec_script_ok("foo-after1", "postinst", "configure");
+ is(db_line("hosts"), "hosts: files other2");
+ exec_script_ok("foo-after1", "postrm", "remove");
+ is(db_line("hosts"), "hosts: files other2");
+ };
+
+ subtest "adds after another (multiple possibilites)" => sub {
+ place_nsswitch_file("hosts", "files resolve other2");
+ exec_script_ok("foo-after2", "preinst", "install");
+ exec_script_ok("foo-after2", "postinst", "configure");
+ is(db_line("hosts"), "hosts: files foo resolve other2");
+ exec_script_ok("foo-after2", "postrm", "remove");
+ is(db_line("hosts"), "hosts: files resolve other2");
+ };
+ };
+
+ subtest "position=remove-only" => sub {
+ subtest "does not add remove-only services" => sub {
+ place_nsswitch_file("hosts", "files dns");
+ exec_script_ok("foo-remove-only1", "preinst", "install");
+ exec_script_ok("foo-remove-only1", "postinst", "configure");
+ is(db_line("hosts"), "hosts: foo files dns");
+ exec_script_ok("foo-remove-only1", "postrm", "remove");
+ is(db_line("hosts"), "hosts: files dns");
+ };
+
+ subtest "removes both added and already present services" => sub {
+ place_nsswitch_file("hosts", "foo files resolve dns");
+ exec_script_ok("foo-remove-only1", "postrm", "remove");
+ is(db_line("hosts"), "hosts: files dns");
+ };
+ };
+
+ subtest "addition" => sub {
+ subtest "skips if any service is already mentioned in a target database (1)" => sub {
+ place_nsswitch_file("shadow", "files foo dns");
+ exec_script_ok("foo-multidb1", "preinst", "install");
+ exec_script_ok("foo-multidb1", "postinst", "configure");
+ is(db_line("shadow"), "shadow: files foo dns");
+ exec_script_ok("foo-multidb1", "postrm", "remove");
+ is(db_line("shadow"), "shadow: files dns");
+ };
+
+ subtest "skips if any service is already mentioned in a target database (2)" => sub {
+ place_nsswitch_file("passwd", "baz files");
+ exec_script_ok("foo-multidb1", "preinst", "install");
+ exec_script_ok("foo-multidb1", "postinst", "configure");
+ is(db_line("passwd"), "passwd: baz files");
+ exec_script_ok("foo-multidb1", "postrm", "remove");
+ is(db_line("passwd"), "passwd: files");
+ };
+
+ subtest "adds if the service is mentioned in an unrelated database" => sub {
+ place_nsswitch_file("passwd", "files foo");
+ is(db_line("shadow"), "shadow: files");
+ exec_script_ok("foo-multidb1", "preinst", "install");
+ exec_script_ok("foo-multidb1", "postinst", "configure");
+ is(db_line("shadow"), "shadow: foo files foo2");
+ is(db_line("passwd"), "passwd: files foo baz");
+ exec_script_ok("foo-multidb1", "postrm", "remove");
+ is(db_line("shadow"), "shadow: files");
+ is(db_line("passwd"), "passwd: files foo");
+ };
+ };
+
+ subtest "removal" => sub {
+ subtest "succeeds if service has already been removed" => sub {
+ place_nsswitch_file("hosts", "files dns");
+ exec_script_ok("foo-other", "postrm", "remove");
+ is(db_line("hosts"), "hosts: files dns");
+ };
+
+ subtest "removes all instances of service (consecutive 1)" => sub {
+ place_nsswitch_file("hosts", "files foo foo [NOTFOUND=return] foo dns");
+ exec_script_ok("foo-other", "postrm", "remove");
+ is(db_line("hosts"), "hosts: files dns");
+ };
+
+ subtest "removes all instances of service (consecutive 2)" => sub {
+ place_nsswitch_file("hosts", "files foo [NOTFOUND=return] foo foo dns");
+ exec_script_ok("foo-other", "postrm", "remove");
+ is(db_line("hosts"), "hosts: files dns");
+ };
+
+ subtest "removes all instances of service (split 1)" => sub {
+ place_nsswitch_file("hosts", "files foo [NOTFOUND=return] foo dns foo");
+ exec_script_ok("foo-other", "postrm", "remove");
+ is(db_line("hosts"), "hosts: files dns");
+ };
+
+ subtest "removes all instances of service (split 2)" => sub {
+ place_nsswitch_file("hosts", "foo [NOTFOUND=return] files foo [!UNAVAIL=return] foo dns");
+ exec_script_ok("foo-other", "postrm", "remove");
+ is(db_line("hosts"), "hosts: files dns");
+ };
+
+ subtest "removes all instances of service (also during purge)" => sub {
+ place_nsswitch_file("hosts", "files foo foo [NOTFOUND=return] foo dns");
+ exec_script_ok("foo-other", "postrm", "purge");
+ is(db_line("hosts"), "hosts: files dns");
+ };
+
+ subtest "removes services with substring names" => sub {
+ place_nsswitch_file("hosts", "foo_extra files foo dns");
+ exec_script_ok("foo-substring", "postrm", "remove");
+ is(db_line("hosts"), "hosts: files dns");
+ };
+
+ subtest "removes services with substring names (in presence of comments)" => sub {
+ place_nsswitch_file("hosts", "foo_extra files foo dns# comment: foo is ok");
+ exec_script_ok("foo-substring", "postrm", "remove");
+ is(db_line("hosts"), "hosts: files dns# comment: foo is ok");
+ };
+ };
+
+ subtest "position=database-add" => sub {
+ subtest "adds a database if not already present (without service)" => sub {
+ place_nsswitch_file();
+ is(num_occurrences("mydb", dbs()), 0);
+ exec_script_ok("foo-newdb1", "preinst", "install");
+ exec_script_ok("foo-newdb1", "postinst", "configure");
+ is(db_line("mydb"), "mydb: ");
+ is(num_occurrences("mydb", dbs()), 1);
+ exec_script_ok("foo-newdb1", "postrm", "remove");
+ is(num_occurrences("mydb", dbs()), 0);
+ };
+
+ subtest "does not add the database if already present (without service)" => sub {
+ place_nsswitch_file();
+ is(num_occurrences("mydb", dbs()), 0);
+ # first install
+ exec_script_ok("foo-newdb1", "preinst", "install");
+ exec_script_ok("foo-newdb1", "postinst", "configure");
+ is(db_line("mydb"), "mydb: ");
+ is(num_occurrences("mydb", dbs()), 1);
+ # second install
+ exec_script_ok("foo-newdb1", "preinst", "install");
+ exec_script_ok("foo-newdb1", "postinst", "configure");
+ is(db_line("mydb"), "mydb: ");
+ is(num_occurrences("mydb", dbs()), 1);
+ exec_script_ok("foo-newdb1", "postrm", "remove");
+ is(num_occurrences("mydb", dbs()), 0);
+ };
+
+ subtest "adds a database if not already present (with service)" => sub {
+ place_nsswitch_file();
+ is(num_occurrences("mydb", dbs()), 0);
+ exec_script_ok("foo-newdb2", "preinst", "install");
+ exec_script_ok("foo-newdb2", "postinst", "configure");
+ is(db_line("mydb"), "mydb: foo "); # TODO: fix trailing space in v2
+ is(num_occurrences("mydb", dbs()), 1);
+ exec_script_ok("foo-newdb2", "postrm", "remove");
+ is(num_occurrences("mydb", dbs()), 0);
+ };
+
+ subtest "does not add the database if already present (with service)" => sub {
+ place_nsswitch_file();
+ is(num_occurrences("mydb", dbs()), 0);
+ # first install
+ exec_script_ok("foo-newdb2", "preinst", "install");
+ exec_script_ok("foo-newdb2", "postinst", "configure");
+ is(db_line("mydb"), "mydb: foo "); # TODO: fix trailing space in v2
+ is(num_occurrences("mydb", dbs()), 1);
+ # second install
+ exec_script_ok("foo-newdb2", "preinst", "install");
+ exec_script_ok("foo-newdb2", "postinst", "configure");
+ is(db_line("mydb"), "mydb: foo "); # TODO: fix trailing space in v2
+ is(num_occurrences("mydb", dbs()), 1);
+ # removal
+ exec_script_ok("foo-newdb2", "postrm", "remove");
+ is(num_occurrences("mydb", dbs()), 0);
+ };
+ };
+
+ subtest "position=detabase-require" => sub {
+ subtest "adds a service to the the database if already present" => sub {
+ place_nsswitch_file("mydb", "other");
+ is(num_occurrences("mydb", dbs()), 1);
+ exec_script_ok("foo-newdb3", "preinst", "install");
+ exec_script_ok("foo-newdb3", "postinst", "configure");
+ is(db_line("mydb"), "mydb: bar other");
+ is(num_occurrences("mydb", dbs()), 1);
+ exec_script_ok("foo-newdb3", "postrm", "remove");
+ is(db_line("mydb"), "mydb: other");
+ is(num_occurrences("mydb", dbs()), 1);
+ };
+
+ subtest "does not add a service if the database is missing" => sub {
+ place_nsswitch_file();
+ is(num_occurrences("mydb", dbs()), 0);
+ exec_script_ok("foo-newdb3", "preinst", "install");
+ exec_script_ok("foo-newdb3", "postinst", "configure");
+ is(num_occurrences("mydb", dbs()), 0);
+ exec_script_ok("foo-newdb3", "postrm", "remove");
+ is(num_occurrences("mydb", dbs()), 0);
+ };
+
+ subtest "does not remove the database during package removal" => sub {
+ place_nsswitch_file("mydb", " ");
+ is(num_occurrences("mydb", dbs()), 1);
+ exec_script_ok("foo-newdb3", "preinst", "install");
+ exec_script_ok("foo-newdb3", "postinst", "configure");
+ is(db_line("mydb"), "mydb: bar ");
+ is(num_occurrences("mydb", dbs()), 1);
+ exec_script_ok("foo-newdb3", "postrm", "remove");
+ is(db_line("mydb"), "mydb: ");
+ is(num_occurrences("mydb", dbs()), 1);
+ };
+ };
+
+ subtest "validation" => sub {
+ subtest "does not add debhelper snippets if .nss is empty" => sub {
+ my ($postinst_path) = find_script("foo-empty1", "postinst");
+ my ($postrm_path) = find_script("foo-empty1", "postrm");
+ is($postinst_path, undef);
+ is($postrm_path, undef);
+ };
+
+ subtest "does not add debhelper snippets if .nss is empty (with comments)" => sub {
+ my ($postinst_path) = find_script("foo-empty2", "postinst");
+ my ($postrm_path) = find_script("foo-empty2", "postrm");
+ is($postinst_path, undef);
+ is($postrm_path, undef);
+ };
+ };
+
+ subtest "example in docs" => sub {
+ place_nsswitch_file("hosts", "files dns");
+ exec_script_ok("foo-example", "preinst", "install");
+ exec_script_ok("foo-example", "postinst", "configure");
+ is(db_line("hosts"), "hosts: files mdns4_minimal [NOTFOUND=return] mdns4 dns");
+ exec_script_ok("foo-example", "postrm", "remove");
+ is(db_line("hosts"), "hosts: files dns");
+ };
+
+ ok(run_dh_tool('dh_clean'));
+};
+
+sub place_nsswitch_file {
+ my ($db, $line) = @_;
+ my $template_file = "$test_dir/nsswitch.conf.template";
+ my $conf_file = "debian/foo/etc/nsswitch.conf";
+
+ my $fd;
+ open($fd, '<', $template_file) or error("open($template_file): $!");
+ read($fd, my $conf, -s $fd);
+ close($fd);
+
+ if ($db && $line) {
+ my $db_line_re = "^$db:.*\$";
+ my $newline = "$db: $line";
+ if ($conf =~ /$db_line_re/m) {
+ $conf =~ s/$db_line_re/$newline/m;
+ } else {
+ $conf .= "\n$newline\n";
+ }
+ }
+
+ open($fd, '>', $conf_file) or error("open($conf_file): $!");
+ print($fd $conf);
+ close($fd);
+}
+
+sub exec_script_ok {
+ is(exec_script(@_), 0);
+}
+
+sub exec_script {
+ my ($package, $script, @args) = @_;
+ my ($script_path) = find_script($package, $script);
+ (defined $script_path && $script_path ne "") or error("No maintscript of type $script found");
+ system("sh", "-e", $script_path, @args);
+ return $? >> 8;
+}
+
+sub db_line {
+ my ($db) = @_;
+
+ my @lines = nsswitch_file_lines();
+
+ my $db_line_re = "^$db:";
+ my ($line) = grep({ m/$db_line_re/ } @lines);
+ $line //= "";
+ # Normalize spaces to simplify comparison.
+ $line =~ s/\s+/ /g;
+
+ return $line;
+}
+
+sub dbs {
+ my @lines = nsswitch_file_lines();
+
+ my @dbs = ();
+ foreach my $line (@lines) {
+ my ($db) = $line =~ m/^([a-zA-Z]+):/g;
+ push @dbs, $db if $db;
+ }
+
+ return @dbs;
+}
+
+sub nsswitch_file_lines {
+ open(my $fd, '<', "$dpkg_root/etc/nsswitch.conf");
+ my @lines = @{readlines($fd)};
+ close($fd);
+
+ return @lines;
+}
+
+sub num_occurrences {
+ my ($item, @array) = @_;
+
+ return scalar grep({$_ eq $item} @array);
+}
diff --git a/t/dh_installnss/nsswitch.conf.template b/t/dh_installnss/nsswitch.conf.template
new file mode 100644
index 0000000..8ecf84c
--- /dev/null
+++ b/t/dh_installnss/nsswitch.conf.template
@@ -0,0 +1,17 @@
+# A sample /etc/nsswitch.conf file
+
+passwd: files systemd
+group: files systemd
+shadow: files
+gshadow: files
+
+#hosts: files mdns4_minimal [NOTFOUND=return] dns
+hosts: files mdns4 [NOTFOUND=return] dns mymachines
+networks: files
+
+protocols: db files
+services: db files
+ethers: db files
+rpc: db files
+
+netgroup: nis