#!/bin/sh -e # # 2021 Dennis Camera (dennis.camera at ssrq-sds-fds.ch) # # This file is part of cdist. # # cdist is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # cdist is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with cdist. If not, see . # # Determine current debconf selections' state. # Prints one of: # present: all selections are already set as they should. # different: one or more of the selections have a different value. # absent: one or more of the selections are not (currently) defined. # test -x /usr/bin/perl || { # cannot find perl (no perl ~ no debconf) echo 'absent' exit 0 } linesfile="${__object:?}/parameter/line" test -s "${linesfile}" || { if test -s "${__object:?}/parameter/file" then echo absent else echo present fi exit 0 } # assert __type_explorer is set (because it is used by the Perl script) : "${__type_explorer:?}" /usr/bin/perl -- - "${linesfile}" <<'EOF' use strict; use warnings "all"; use Fcntl qw(:DEFAULT :flock); use Debconf::Db; use Debconf::Question; # Extract @known... arrays from debconf-set-selections # These values are required to distinguish flags and values in the given lines. # DC: I couldn't think of a more ugly solution to the problem… my @knownflags; my @knowntypes; my $debconf_set_selections = '/usr/bin/debconf-set-selections'; if (-e $debconf_set_selections) { my $sed_known = 's/^my \(@known\(flags\|types\) = qw([a-z ]*);\).*$/\1/p'; eval `sed -n '$sed_known' '$debconf_set_selections'`; } sub mungeline ($) { my $line = shift; chomp $line; $line =~ s/\r$//; return $line; } sub fatal { printf STDERR @_; exit 1; } my $state = 'present'; sub state { my $new = shift; if ($state eq 'present' or ($state eq 'different' and $new eq 'absent')) { $state = $new; } } # Load Debconf DB but manually lock on the state explorer script, # because Debconf aborts immediately if executed concurrently. # This is not really an ideal solution because the Debconf DB could be locked by # another process (e.g. apt-get), but no way to achieve this could be found. # If you know how to, please provide a patch. my $lockfile = "%ENV{'__type_explorer'}/state"; if (open my $lock_fh, '+<', $lockfile) { flock $lock_fh, LOCK_EX or die "Cannot lock $lockfile"; } { Debconf::Db->load(readonly => 'true'); } while (<>) { # Read and process lines (taken from debconf-set-selections) $_ = mungeline($_); while (/\\$/ && ! eof) { s/\\$//; $_ .= mungeline(<>); } next if /^\s*$/ || /^\s*\#/; my ($owner, $label, $type, $content) = /^\s*(\S+)\s+(\S+)\s+(\S+)(?:\s(.*))?/ or fatal "invalid line: %s\n", $_; $content = '' unless defined $content; # Compare is and should state my $q = Debconf::Question->get($label); unless (defined $q) { # probably a preseed state 'absent'; next; } if (grep { $_ eq $q->type } @knownflags) { # This line wants to set a flag, presumably. if ($q->flag($q->type) ne $content) { state 'different'; } } else { # Otherwise, it's probably a value… if ($q->value ne $content) { state 'different'; } unless (grep { $_ eq $owner } (split /, /, $q->owners)) { state 'different'; } } } printf "%s\n", $state; EOF