~ev/debconf/error-reports

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
#!/usr/bin/perl

=head1 NAME

debconf-set-selections - insert new default values into the debconf database

=cut

sub usage {
	print STDERR <<EOF;
Usage: debconf-set-selections [-vcu] [file]
  -v, --verbose     verbose output
  -c, --checkonly   only check the input file format
  -u, --unseen      do not set the 'seen' flag when preseeding values
EOF
	exit(1);
}

=head1 SYNOPSIS

 debconf-set-selections file
 debconf-get-selections | ssh newhost debconf-set-selections

=head1 DESCRIPTION

B<debconf-set-selections> can be used to pre-seed the debconf database with
answers, or to change answers in the database. Each question will be marked
as seen to prevent debconf from asking the question interactively.

Reads from a file if a filename is given, otherwise from stdin.

=head1 WARNING

Only use this command to seed debconf values for packages that will be or
are installed. Otherwise you can end up with values in the database for
uninstalled packages that will not go away, or with worse problems
involving shared values. It is recommended that this only be used to seed
the database if the originating machine has an identical install.

=head1 DATA FORMAT

The data is a series of lines. Lines beginning with a # character are
comments. Blank lines are ignored. All other lines set the value of one
question, and should contain four values, each separated by one character
of whitespace. The first value is the name of the package that owns the
question. The second is the name of the question, the third value is the
type of this question, and the fourth value (through the end of the line)
is the value to use for the answer of the question.

Alternatively, the third value can be "seen"; then the preseed line only
controls whether the question is marked as seen in debconf's database. Note
that preseeding a question's value defaults to marking that question as
seen, so to override the default value without marking a question seen, you
need two lines.

Lines can be continued to the next line by ending them with a "\"
character.

=head1 EXAMPLES

 # Force debconf priority to critical.
 debconf debconf/priority select critical

 # Override default frontend to readline, but allow user to select.
 debconf debconf/frontend select readline
 debconf debconf/frontend seen false

=head1 OPTIONS

=over 4

=item B<--verbose>, B<-v>

verbose output

=item B<--checkonly>, B<-c>

only check the input file format, do not save changes to database

=back

=head1 SEE ALSO

L<debconf-get-selections(1)>
(available in the debconf-utils package)

=cut

use warnings;
use strict;
use Debconf::Db;
use Debconf::Template;
use Getopt::Long;

use vars qw(%opts $filename $debug $error $checkonly $unseen);

sub info {
	my $msg = shift;
	print STDERR "info: $msg\n" if $debug;
}

sub warning {
	my $msg = shift;
	print STDERR "warning: $msg\n";
}

sub error {
	my $msg = shift;
	print STDERR "error: $msg\n";
	$error++
}

sub load_answer {
	my ($owner, $label, $type, $content) = @_;
	
	info "Loading answer for '$label'";

	# Set up the template. If it already exists, override its default
	# value.
	my $template=Debconf::Template->get($label);
	if (! $template) {
		$template=Debconf::Template->new($label, $owner, $type);
		$template->description("Dummy template");
		$template->extended_description("This is a fake template used to pre-seed the debconf database. If you are seeing this, something is probably wrong.");
	}
	else {
		$template->default($content);
	}
	$template->type($type);
	
	# The question should already exist, it was created along with the
	# template. Set it up.
	my $question=Debconf::Question->get($label);
	if (! $question) {
		error("Cannot find a question for $label");
		return;
	}
	$question->addowner($owner, $type);
	$question->value($content);
	if (! $unseen) {
		$question->flag("seen", "true");
	}
}

sub set_flag {
	my ($owner, $label, $flag, $content) = @_;

	info "Setting $flag flag";

	my $question=Debconf::Question->get($label);
	if (! $question) {
		error("Cannot find a question for $label");
		return;
	}
	$question->flag($flag, $content);
}

my @knowntypes = qw(select boolean string multiselect note password text title);
my @knownflags = qw(seen);

sub ok_format {
	my ($owner, $label, $type, $content) = @_;
	if (! defined $owner || ! defined $label || ! defined $content) {
		error "parse error on line $.: '$_'";
		return;
	}
	elsif (! grep { $_ eq $type } @knowntypes, @knownflags) {
		warning "Unknown type $type, skipping line $.";
		return;
	}
	else {
		return 1;
	}
}

sub mungeline ($) {
	my $line=shift;
	chomp $line;
	$line=~s/\r$//;
	return $line;
}


GetOptions(
	"verbose|v" => \$debug,
	"checkonly|c" => \$checkonly,
	"unseen|u" => \$unseen,
) || usage();

Debconf::Db->load;

$error = 0;

while (<>) {
	$_=mungeline($_);
	while (/\\$/ && ! eof) {
		s/\\$//;
		$_.=mungeline(<>);
	}
	next if /^\s*$/ || /^\s*\#/;
	# Allow multiple spaces between all values except the last one.
	# Extra whitespace in the content is significant.
	my ($owner, $label, $type, $content) = /^\s*(\S+)\s+(\S+)\s+(\S+)(?:\s(.*))?/;
	if (! defined $content) {
		$content='';
	}
	if (ok_format($owner, $label, $type, $content)) {
		if (grep { $_ eq $type } @knownflags) {
			info "Trying to set '$type' flag to '$content'";
			set_flag($owner, $label, $type, $content);
		}
		else {
			info "Trying to set '$label' [$type] to '$content'";
			load_answer($owner, $label, $type, $content);
		}
	}
}

if (! $checkonly) {
	Debconf::Db->save;
}

if ($error) {
	exit 1;
}

=head1 AUTHOR

Petter Reinholdtsen <pere@hungry.com>

=cut