/[kernel]/dists/squeeze/linux-2.6/debian/linux-base.postinst
ViewVC logotype

Contents of /dists/squeeze/linux-2.6/debian/linux-base.postinst

Parent Directory Parent Directory | Revision Log Revision Log


Revision 15873 - (show annotations) (download)
Tue Jun 15 00:25:07 2010 UTC (2 years, 11 months ago) by benh
Original Path: dists/sid/linux-2.6/debian/linux-base.postinst
File size: 41457 byte(s)
linux-base: Don't identify LVM2 PVs by UUID (Closes: #585852)
1 #!/usr/bin/perl
2
3 # Copyright 2009-2010 Ben Hutchings
4 #
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; either version 2 of the License, or
8 # (at your option) any later version.
9 #
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
14 #
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software
17 # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18
19 use strict;
20 use warnings;
21 use AptPkg::Config;
22 use Debconf::Client::ConfModule ':all';
23 use FileHandle;
24 use POSIX ();
25 use UUID;
26
27 # Since debconf clients get their standard input and output redirected
28 # to the debconf front-end, we need to redirect them again before
29 # running any other program.
30 sub _system {
31 my $pid = fork();
32 die "$!" unless defined($pid);
33 if ($pid == 0) {
34 # </dev/null
35 POSIX::close(0);
36 POSIX::open('/dev/null', POSIX::O_RDONLY) or die "$!";
37 # >&2
38 POSIX::dup2(2, 1) or die "$!";
39 exec(@_);
40 exit(255); # usual exit code for failed exec
41 } else {
42 waitpid($pid, 0);
43 # The built-in system() function does this substitution
44 if (POSIX::WIFEXITED($?) && POSIX::WEXITSTATUS($?) == 255) {
45 return -1;
46 } else {
47 return $?;
48 }
49 }
50 }
51
52 package DebianKernel::DiskId;
53
54 ### utility
55
56 # Import _system() function
57 *_system = \&main::_system;
58
59 sub id_to_path {
60 my ($id) = @_;
61 $id =~ m|^/|
62 or $id =~ s{^(LABEL|UUID)=}{'/dev/disk/by-' . lc($1) . '/'}e
63 or die "Could not map id $id to path";
64 return $id;
65 }
66
67 ### /etc/fstab
68
69 sub fstab_next {
70 # Based on my_getmntent() in mount_mntent.c
71
72 my ($file) = @_;
73 my $text = <$file>;
74 unless (defined($text)) {
75 return ();
76 }
77
78 my $line = $text;
79 $line =~ s/\r?\n$//;
80 $line =~ s/^[ \t]*//;
81 if ($line =~ /^(#|$)/) {
82 return ($text);
83 } else {
84 return ($text,
85 map({ s/\\([0-7][0-7][0-7])/chr(oct($1) & 0xff)/eg; $_; }
86 split(/[ \t]+/, $line)));
87 }
88 }
89
90 sub fstab_list {
91 my ($file) = @_;
92 my @bdevs;
93 while (1) {
94 my ($text, $bdev) = fstab_next($file);
95 last unless defined($text);
96 if (defined($bdev)) {
97 push @bdevs, $bdev;
98 }
99 }
100 return @bdevs;
101 }
102
103 sub fstab_update {
104 my ($old, $new, $map) = @_;
105 while (1) {
106 my ($text, $bdev) = fstab_next($old);
107 last unless defined($text);
108 if (defined($bdev) && defined(my $id = $map->{$bdev})) {
109 $text =~ s/^(\s*\S+)(.*)/# $1$2\n$id$2/;
110 }
111 $new->print("$text");
112 }
113 }
114
115 ### Kernel parameters
116
117 sub kernel_list {
118 my ($cmd_line) = @_;
119 return ($cmd_line =~ /\broot=(\S+)/) ? ($1) : ();
120 }
121
122 sub kernel_update {
123 my ($cmd_line, $map) = @_;
124 if ($cmd_line =~ /\broot=(\S+)/ && defined(my $id = $map->{$1})) {
125 $cmd_line =~ s/\broot=(\S+)/root=$id/;
126 return $cmd_line;
127 } else {
128 return undef;
129 }
130 }
131
132 ### shell script variable assignment
133
134 # Maintains enough context to find statement boundaries, and can parse
135 # variable definitions that do not include substitutions. I think.
136
137 sub shellvars_next {
138 my ($file) = @_;
139 my $text = '';
140 my @context = ('');
141 my $first = 1;
142 my $in_value = 0;
143 my ($name, $value);
144 my $unhandled = 0;
145
146 LINE:
147 while (<$file>) {
148 $text .= $_;
149
150 # variable assignment
151 if ($first && m/^\s*([A-Za-z_][A-Za-z0-9_]*)=/g) {
152 $name = $1;
153 $value = '';
154 $in_value = 1;
155 }
156
157 while (/\G(.*?)([#`'"(){}\s]|\\.|\$[({]?)/gs) {
158 my $end_pos = pos;
159 my $special = $2;
160
161 if ($in_value) {
162 # add non-special characters to the value verbatim
163 $value .= $1;
164 }
165
166 if ($context[$#context] eq '') {
167 # space outside quotes or brackets ends the value
168 if ($special =~ /^\s/) {
169 $in_value = 0;
170 if ($special eq "\n") {
171 last LINE;
172 }
173 }
174 # something else after the value means this is a command
175 # with an environment override, not a variable definition
176 elsif (defined($name) && !$in_value) {
177 $unhandled = 1;
178 }
179 }
180
181 # in single-quoted string
182 if ($context[$#context] eq "'") {
183 # only the terminating single-quote is special
184 if ($special eq "'") {
185 pop @context;
186 } else {
187 $value .= $special;
188 }
189 }
190 # backslash escape
191 elsif ($special =~ /^\\/) {
192 if ($in_value && $special ne "\\\n") {
193 $value .= substr($special, 1, 1);
194 }
195 }
196 # in backtick substitution
197 elsif ($context[$#context] eq '`') {
198 # backtick does not participate in nesting, so only the
199 # terminating backtick should be considered special
200 if ($special eq '`') {
201 pop @context;
202 }
203 }
204 # comment
205 elsif ($context[$#context] !~ /^['"]/ && $special eq '#') {
206 # ignore rest of the physical line, except the new-line
207 pos = $end_pos;
208 /\G.*/g;
209 next;
210 }
211 # start of backtick substitution
212 elsif ($special eq '`') {
213 push @context, '`';
214 $unhandled = 1;
215 }
216 # start of single/double-quoted string
217 elsif ($special =~ /^['"]/ && $context[$#context] !~ /^['"]/) {
218 push @context, $special;
219 }
220 # end of double-quoted string
221 elsif ($special eq '"' && $context[$#context] eq '"') {
222 pop @context;
223 }
224 # open bracket
225 elsif ($special =~ /^\$?\(/) {
226 push @context, ')';
227 $unhandled = 1;
228 } elsif ($special =~ /^\$\{/) {
229 push @context, '}';
230 $unhandled = 1;
231 }
232 # close bracket
233 elsif ($special =~ /^[)}]/ && $special eq $context[$#context]) {
234 pop @context;
235 }
236 # variable substitution
237 elsif ($special eq '$') {
238 $unhandled = 1;
239 }
240 # not a special character in this context (or a syntax error)
241 else {
242 if ($in_value) {
243 $value .= $special;
244 }
245 }
246
247 pos = $end_pos;
248 }
249
250 $first = 0;
251 }
252
253 if ($text eq '') {
254 return ();
255 } elsif ($unhandled) {
256 return ($text);
257 } else {
258 return ($text, $name, $value);
259 }
260 }
261
262 sub shellvars_quote {
263 my ($value) = @_;
264 $value =~ s/'/'\''/g;
265 return "'$value'";
266 }
267
268 ### GRUB 1 (grub-legacy) config
269
270 sub grub1_parse {
271 my ($file) = @_;
272 my @results = ();
273 my $text = '';
274 my $in_auto = 0;
275 my $in_opts = 0;
276
277 while (<$file>) {
278 if ($in_opts && /^\# (\w+)=(.*)/) {
279 push @results, [$text];
280 $text = '';
281 push @results, [$_, $1, $2];
282 } else {
283 $text .= $_;
284 if ($_ eq "### BEGIN AUTOMAGIC KERNELS LIST\n") {
285 $in_auto = 1;
286 } elsif ($_ eq "### END DEBIAN AUTOMAGIC KERNELS LIST\n") {
287 $in_auto = 0;
288 } elsif ($_ eq "## ## Start Default Options ##\n") {
289 $in_opts = $in_auto;
290 } elsif ($_ eq "## ## End Default Options ##\n") {
291 $in_opts = 0;
292 }
293 }
294 }
295
296 if ($text ne '') {
297 push @results, [$text];
298 }
299
300 return @results;
301 }
302
303 sub grub1_list {
304 my ($file) = @_;
305 my %options;
306 for (grub1_parse($file)) {
307 my ($text, $name, $value) = @$_;
308 next unless defined($name);
309 $options{$name} = $value;
310 }
311
312 my @bdevs;
313 if (exists($options{kopt_2_6})) {
314 push @bdevs, kernel_list($options{kopt_2_6});
315 } elsif (exists($options{kopt})) {
316 push @bdevs, kernel_list($options{kopt});
317 }
318 if (exists($options{xenkopt})) {
319 push @bdevs, kernel_list($options{xenkopt});
320 }
321 return @bdevs;
322 }
323
324 sub grub1_update {
325 my ($old, $new, $map) = @_;
326
327 my %options;
328 for (grub1_parse($old)) {
329 my ($text, $name, $value) = @$_;
330 next unless defined($name);
331 $options{$name} = $value;
332 }
333
334 $old->seek(0, 0);
335 for (grub1_parse($old)) {
336 my ($text, $name, $value) = @$_;
337 if (defined($name) &&
338 ($name eq 'kopt_2_6' ||
339 ($name eq 'kopt' && !exists($options{kopt_2_6})) ||
340 $name eq 'xenkopt')) {
341 if (defined(my $new_value = kernel_update($value, $map))) {
342 $text = "## $name=$value\n# $name=$new_value\n";
343 }
344 }
345 $new->print($text);
346 }
347 }
348
349 sub grub1_post {
350 _system('update-grub');
351 }
352
353 ### GRUB 2 config
354
355 sub grub2_list {
356 my ($file) = @_;
357 my @bdevs;
358
359 while (1) {
360 my ($text, $name, $value) = shellvars_next($file);
361 last unless defined($text);
362 if (defined($name) && $name =~ /^GRUB_CMDLINE_LINUX(?:_DEFAULT)?$/) {
363 push @bdevs, kernel_list($value);
364 }
365 }
366
367 return @bdevs;
368 }
369
370 sub grub2_update {
371 my ($old, $new, $map) = @_;
372 my @bdevs;
373
374 while (1) {
375 my ($text, $name, $value) = shellvars_next($old);
376 last unless defined($text);
377 if (defined($name) && $name =~ /^GRUB_CMDLINE_LINUX(?:_DEFAULT)?$/ &&
378 defined(my $new_value = kernel_update($value, $map))) {
379 $text =~ s/^/# /gm;
380 $text .= sprintf("%s=%s\n", $name, shellvars_quote($new_value));
381 }
382 $new->print($text);
383 }
384 }
385
386 sub grub2_post {
387 _system('grub-mkconfig', '-o', '/boot/grub/grub.cfg');
388 }
389
390 ### LILO
391
392 sub lilo_tokenize {
393 # Based on cfg_get_token() and next() in cfg.c.
394 # Line boundaries are *not* significant (except as white space) so
395 # we tokenize the whole file at once.
396
397 my ($file) = @_;
398 my @tokens = ();
399 my $text = '';
400 my $token;
401 my $in_quote = 0;
402
403 while (<$file>) {
404 # If this is the continuation of a multi-line quote, skip
405 # leading space and push back the necessary context.
406 if ($in_quote) {
407 s/^[ \t]*/"/;
408 $text .= $&;
409 }
410
411 pos = 0;
412 while (/\G \s* (?:\#.*)?
413 (?: (=) |
414 " ((?:[^"] | \\[\\"n])*) (" | \\\r?\n) |
415 ((?:[^\s\#="\\] | \\[^\r\n])+) (\\\r?\n)?)?
416 /gsx) {
417 my $cont;
418 my $new_text = $&;
419
420 if (defined($1)) {
421 # equals sign
422 $text = $new_text;
423 $token = $1;
424 $cont = 0;
425 } elsif (defined($2)) {
426 # quoted text
427 if (!$in_quote) {
428 $text = $new_text;
429 $token = $2;
430 } else {
431 $text .= substr($new_text, 1); # remove the quote again; ick
432 $token .= ' ' . $2;
433 }
434 $cont = $3 ne '"';
435 } elsif (defined($4)) {
436 # unquoted word
437 if (!defined($token)) {
438 $token = '';
439 }
440 $text .= $new_text;
441 $token .= $4;
442 $cont = defined($5);
443 } else {
444 $text .= $new_text;
445 $cont = $new_text eq '';
446 }
447
448 if (!$cont) {
449 if ($text =~ /(?:^|[^\\])\$/) {
450 # unhandled expansion
451 $token = undef;
452 } elsif (defined($token)) {
453 if ($in_quote) {
454 $token =~ s/\\(.)/$1 eq 'n' ? "\n" : $1/eg;
455 } else {
456 $token =~ s/\\(.)/$1/g;
457 }
458 }
459 push @tokens, [$text, $token];
460 $text = '';
461 $token = undef;
462 $in_quote = 0;
463 }
464 }
465 }
466
467 return @tokens;
468 }
469
470 sub lilo_list {
471 my ($file) = @_;
472 my @bdevs = ();
473 my @tokens = lilo_tokenize($file);
474 my $i = 0;
475 my $in_generic = 1; # global or image=/vmlinuz or image=/vmlinuz.old
476
477 while ($i <= $#tokens) {
478 # Configuration items are either <name> "=" <value> or <name> alone.
479 if ($#tokens - $i >= 2 &&
480 defined($tokens[$i + 1][1]) && $tokens[$i + 1][1] eq '=') {
481 my ($name, $value) = ($tokens[$i][1], $tokens[$i + 2][1]);
482 if (defined($name) && defined($value)) {
483 if ($name eq 'image') {
484 $in_generic = ($value =~ m|^/vmlinuz(?:\.old)?$|);
485 } elsif ($in_generic) {
486 if ($name =~ /^(?:boot|root)$/) {
487 push @bdevs, $value;
488 } elsif ($name =~ /^(?:addappend|append|literal)$/) {
489 push @bdevs, kernel_list($value);
490 }
491 }
492 }
493 $i += 3;
494 } else {
495 $i += 1;
496 }
497 }
498
499 return @bdevs;
500 }
501
502 sub _lilo_update {
503 my ($old, $new, $map, $replace) = @_;
504 my @tokens = lilo_tokenize($old);
505 my $i = 0;
506 my $in_generic = 1; # global or image=/vmlinuz or image=/vmlinuz.old
507
508 while ($i <= $#tokens) {
509 my $text = $tokens[$i][0];
510
511 if ($#tokens - $i >= 2 &&
512 defined($tokens[$i + 1][1]) && $tokens[$i + 1][1] eq '=') {
513 my ($name, $value) = ($tokens[$i][1], $tokens[$i + 2][1]);
514 my $new_value;
515 if (defined($name) && defined($value)) {
516 if ($name eq 'image') {
517 $in_generic = ($value =~ m|^/vmlinuz(?:\.old)?$|);
518 } elsif ($in_generic) {
519 if ($name eq 'boot') {
520 # 'boot' is used directly by the lilo command, which
521 # doesn't use libblkid
522 $new_value = $map->{$value} && id_to_path($map->{$value});
523 } elsif ($name eq 'root') {
524 # 'root' adds a root parameter to the kernel command
525 # line
526 $new_value = $map->{$value};
527 } elsif ($name =~ /^(?:addappend|append|literal)$/) {
528 # These are all destined for the kernel command line
529 # in some way
530 $new_value = kernel_update($value, $map);
531 }
532 }
533 }
534 if (defined($new_value)) {
535 $new_value =~ s/\\/\\\\/g;
536 $text = &{$replace}($name, $value, $new_value) ||
537 "\n# $name = $value\n$name = \"$new_value\"\n";
538 } else {
539 $text .= $tokens[$i + 1][0] . $tokens[$i + 2][0];
540 }
541 $i += 3;
542 } else {
543 $i += 1;
544 }
545
546 $new->print($text);
547 }
548 }
549
550 sub lilo_update {
551 my ($old, $new, $map) = @_;
552 _lilo_update($old, $new, $map, sub { return undef });
553 }
554
555 sub lilo_post {
556 _system('lilo');
557 }
558
559 ### SILO
560
561 sub silo_post {
562 _system('silo');
563 }
564
565 ### ELILO
566
567 sub elilo_update {
568 my ($old, $new, $map) = @_;
569 # Work around bug #581173 - boot value must have no space before
570 # and no quotes around it.
571 sub replace {
572 my ($name, $value, $new_value) = @_;
573 return ($name eq 'boot') ? "# boot=$value\nboot=$new_value\n" : undef;
574 }
575 _lilo_update($old, $new, $map, \&replace);
576 }
577
578 sub elilo_post {
579 _system('elilo');
580 }
581
582 ### extlinux
583
584 sub extlinux_old_path {
585 for ('/boot/extlinux', '/boot/boot/exlinux', '/extlinux') {
586 if (-e) {
587 return "$_/options.cfg";
588 }
589 }
590 return undef;
591 }
592
593 sub extlinux_old_list {
594 my ($file) = @_;
595 while (<$file>) {
596 if (/^## ROOT=(.*)/) {
597 return kernel_list($1);
598 }
599 }
600 return ();
601 }
602
603 sub extlinux_old_update {
604 my ($old, $new, $map) = @_;
605 while (<$old>) {
606 my $text = $_;
607 if (/^## ROOT=(.*)/) {
608 my $new_params = kernel_update($1, $map);
609 if (defined($new_params)) {
610 $text = "## $text" . "## ROOT=$new_params\n";
611 }
612 }
613 $new->print($text);
614 }
615 }
616
617 sub extlinux_new_list {
618 my ($file) = @_;
619 while (<$file>) {
620 if (/^# ROOT=(.*)/) {
621 return kernel_list($1);
622 }
623 }
624 return ();
625 }
626
627 sub extlinux_new_update {
628 my ($old, $new, $map) = @_;
629 while (<$old>) {
630 my $text = $_;
631 if (/^# ROOT=(.*)/) {
632 my $new_params = kernel_update($1, $map);
633 if (defined($new_params)) {
634 $text = "## $text" . "# ROOT=$new_params\n";
635 }
636 }
637 $new->print($text);
638 }
639 }
640
641 sub extlinux_post {
642 _system('update-extlinux');
643 }
644
645 # udev persistent-cd
646
647 sub udev_next {
648 my ($file) = @_;
649 my @results = ();
650
651 # Based on parse_file() and get_key() in udev-rules.c
652 while (1) {
653 my $text = <$file>;
654 last if !defined($text) || $text eq '';
655
656 if ($text =~ /^\s*(?:#|$)/) {
657 push @results, [$text];
658 } else {
659 my $end_pos = 0;
660 while ($text =~ /\G [\s,]* ((?:[^\s=+!:]|[+!:](?!=))+)
661 \s* ([=+!:]?=) "([^"]*)"/gx) {
662 push @results, [$&, $1, $2, $3];
663 $end_pos = pos($text);
664 }
665 push @results, [substr($text, $end_pos)];
666 last if $text !~ /\\\n$/;
667 }
668 }
669
670 return @results;
671 }
672
673 sub udev_parse_symlink_rule {
674 my ($path, $symlink);
675 for (@_) {
676 my ($text, $key, $op, $value) = @$_;
677 next if !defined($key);
678 if ($key eq 'ENV{ID_PATH}' && $op eq '==') {
679 $path = $value;
680 } elsif ($key eq 'SYMLINK' && $op eq '+=') {
681 $symlink = $value;
682 }
683 }
684 return ($path, $symlink);
685 }
686
687 # Find symlink rules using IDE device paths that aren't matched by rules
688 # using the corresponding SCSI device path. Return an array containing
689 # the corresponding path for each rule where this is the case and undef
690 # for all other rules.
691 sub udev_cd_find_unmatched_ide_rules {
692 my ($file) = @_;
693 my %wanted_rule;
694 my @unmatched;
695 my $i = 0;
696
697 while (1) {
698 my @keys = udev_next($file);
699 last if $#keys < 0;
700
701 my ($path, $symlink) = udev_parse_symlink_rule(@keys);
702 if (defined($path) && defined($symlink)) {
703 if ($path =~ /-ide-\d+:\d+$/) {
704 # libata uses the PATA controller and device numbers
705 # as SCSI host number and bus id. Channel number and
706 # LUN are always 0. The parent device path should
707 # stay the same.
708 $path =~ s/-ide-(\d+):(\d+)$/-scsi-$1:0:$2:0/;
709 my $rule_key = $path . ' ' . $symlink;
710 if (!exists($wanted_rule{$rule_key})) {
711 $wanted_rule{$rule_key} = $i;
712 $unmatched[$i] = $path;
713 }
714 } elsif ($path =~ /-scsi-\d+:\d+:\d+:\d+$/) {
715 my $rule_key = $path . ' ' . $symlink;
716 my $j = $wanted_rule{$rule_key};
717 if (defined($j) && $j >= 0) {
718 $unmatched[$j] = undef;
719 }
720 $wanted_rule{$rule_key} = -1;
721 }
722 }
723
724 ++$i;
725 }
726
727 return @unmatched;
728 }
729
730 sub udev_cd_needs_update {
731 my ($file) = @_;
732 my %paths;
733 for (udev_cd_find_unmatched_ide_rules($file)) {
734 if (defined($_)) {
735 $paths{$_} = 1;
736 }
737 }
738 return join('\n', map({"+ PATH=$_"} keys(%paths)));
739 }
740
741 sub udev_cd_update {
742 my ($old, $new) = @_; # ignore map
743
744 # Find which rules we will need to copy and edit, then rewind
745 my @unmatched = udev_cd_find_unmatched_ide_rules($old);
746 $old->seek(0, 0);
747
748 my $i = 0;
749 while (1) {
750 my @keys = udev_next($old);
751 last if $#keys < 0;
752
753 my $old_text = '';
754 my $new_text = '';
755
756 for (@keys) {
757 my ($text, $key, $op, $value) = @$_;
758 $old_text .= $text;
759 next unless defined($unmatched[$i]) && defined($key);
760
761 if ($key eq 'ENV{ID_PATH}' && $op eq '==') {
762 my $value = $unmatched[$i];
763 $new_text .= ", $key$op\"$value\"";
764 } else {
765 $new_text .= $text;
766 }
767 }
768
769 $new->print($old_text);
770 if ($unmatched[$i]) {
771 $new->print($new_text . "\n");
772 }
773
774 ++$i;
775 }
776 }
777
778 # initramfs-tools resume
779
780 sub initramfs_resume_list {
781 my ($file) = @_;
782 my @results = ();
783
784 while (1) {
785 my ($text, $name, $value) = shellvars_next($file);
786 last unless defined($text);
787 if (defined($name) && $name eq 'RESUME') {
788 $results[0] = $value;
789 }
790 }
791
792 return @results;
793 }
794
795 sub initramfs_resume_update {
796 my ($old, $new, $map) = @_;
797
798 while (1) {
799 my ($text, $name, $value) = shellvars_next($old);
800 last unless defined($text);
801 if (defined($name) && $name eq 'RESUME' &&
802 defined(my $new_value = $map->{$value})) {
803 $text =~ s/^/# /gm;
804 $text .= sprintf("%s=%s\n", $name, shellvars_quote($new_value));
805 }
806 $new->print($text);
807 }
808 }
809
810 # uswsusp resume
811
812 sub uswsusp_next {
813 # Based on parse_line() in config_parser.c
814
815 my ($file) = @_;
816 my $text = <$file>;
817
818 if (!defined($text) || $text eq '') {
819 return ();
820 }
821
822 local $_ = $text;
823 s/^\s*(?:#.*)?//;
824 s/\s*$//;
825
826 if ($text =~ /^([\w ]*\w)[ \t]*[:=][ \t]*(.+)$/) {
827 return ($text, $1, $2);
828 } else {
829 return ($text);
830 }
831 }
832
833 sub uswsusp_resume_list {
834 my ($file) = @_;
835 my @results = ();
836
837 while (1) {
838 my ($text, $name, $value) = uswsusp_next($file);
839 last unless defined($text);
840 if (defined($name) && $name eq 'resume device') {
841 $results[0] = $value;
842 }
843 }
844
845 return @results;
846 }
847
848 sub uswsusp_resume_update {
849 my ($old, $new, $map) = @_;
850
851 while (1) {
852 my ($text, $name, $value) = uswsusp_next($old);
853 last unless defined($text);
854 if (defined($name) && $name eq 'resume device' &&
855 defined(my $new_value = $map->{$value})) {
856 $text =~ s/^/# /gm;
857 $text .= sprintf("%s = %s\n", $name, id_to_path($new_value));
858 }
859 $new->print($text);
860 }
861 }
862
863 # cryptsetup
864
865 sub cryptsetup_next {
866 my ($file) = @_;
867 my $text = <$file>;
868 unless (defined($text)) {
869 return ();
870 }
871
872 my $line = $text;
873 if ($line =~ /^\s*(#|$)/) {
874 return ($text);
875 } else {
876 $line =~ s/\s*$//;
877 $line =~ s/^\s*//;
878 return ($text, split(/\s+/, $line, 4));
879 }
880 }
881
882 sub cryptsetup_list {
883 my ($file) = @_;
884 my (@results) = ();
885
886 while (1) {
887 my ($text, undef, $src) = cryptsetup_next($file);
888 last unless defined($text);
889 if (defined($src)) {
890 push @results, $src;
891 }
892 }
893
894 return @results;
895 }
896
897 sub cryptsetup_update {
898 my ($old, $new, $map) = @_;
899
900 while (1) {
901 my ($text, $dst, $src, $key, $opts) = cryptsetup_next($old);
902 last unless defined($text);
903 if (defined($src) && defined($map->{$src})) {
904 $text = "# $text" .
905 join(' ', $dst, $map->{$src}, $key, $opts) . "\n";
906 }
907 $new->print($text);
908 }
909 }
910
911 # hdparm
912
913 sub hdparm_list {
914 my ($file) = @_;
915 my (@results) = ();
916
917 # I really can't be bothered to parse this mess. Just see if
918 # there's anything like a device name on a non-comment line.
919 while (<$file>) {
920 if (!/^\s*#/) {
921 push @results, grep({m|^/dev/|} split(/\s+/));
922 }
923 }
924
925 return @results;
926 }
927
928 ### mdadm
929
930 sub mdadm_list {
931 my ($file) = @_;
932 my (@results) = ();
933
934 while (<$file>) {
935 # Look for DEVICE (case-insensitive, may be abbreviated to as
936 # little as 3 letters) followed by a whitespace-separated list
937 # of devices (or wildcards, or keywords!). Ignore comments
938 # (hash preceded by whitespace).
939 if (/^DEV(?:I(?:C(?:E)?)?)?[ \t]*((?:[^ \t]|[ \t][^#])*)/i) {
940 push @results, split(/[ \t]+/, $1);
941 }
942 }
943
944 return @results;
945 }
946
947 ### list of all configuration files and functions
948
949 my @config_files = ({packages => 'mount',
950 path => '/etc/fstab',
951 list => \&fstab_list,
952 update => \&fstab_update},
953 {packages => 'grub grub-legacy',
954 path => '/boot/grub/menu.lst',
955 list => \&grub1_list,
956 update => \&grub1_update,
957 post_update => \&grub1_post,
958 is_boot_loader => 1},
959 {packages => 'grub-common',
960 path => '/etc/default/grub',
961 list => \&grub2_list,
962 update => \&grub2_update,
963 post_update => \&grub2_post,
964 is_boot_loader => 1},
965 {packages => 'lilo',
966 path => '/etc/lilo.conf',
967 list => \&lilo_list,
968 update => \&lilo_update,
969 post_update => \&lilo_post,
970 is_boot_loader => 1},
971 {packages => 'silo',
972 path => '/etc/silo.conf',
973 list => \&lilo_list,
974 update => \&lilo_update,
975 post_update => \&silo_post,
976 is_boot_loader => 1},
977 {packages => 'quik',
978 path => '/etc/quik.conf',
979 list => \&lilo_list,
980 update => \&lilo_update,
981 is_boot_loader => 1},
982 {packages => 'yaboot',
983 path => '/etc/yaboot.conf',
984 list => \&lilo_list,
985 update => \&lilo_update,
986 is_boot_loader => 1},
987 {packages => 'elilo',
988 path => '/etc/elilo.conf',
989 list => \&lilo_list,
990 update => \&elilo_update,
991 post_update => \&elilo_post,
992 is_boot_loader => 1},
993 {packages => 'extlinux',
994 path => extlinux_old_path(),
995 list => \&extlinux_old_list,
996 update => \&extlinux_old_update,
997 post_update => \&extlinux_post,
998 is_boot_loader => 1},
999 {packages => 'extlinux',
1000 path => '/etc/default/extlinux',
1001 list => \&extlinux_new_list,
1002 update => \&extlinux_new_update,
1003 post_update => \&extlinux_post,
1004 is_boot_loader => 1},
1005 {packages => 'udev',
1006 path => '/etc/udev/rules.d/70-persistent-cd.rules',
1007 needs_update => \&udev_cd_needs_update,
1008 update => \&udev_cd_update},
1009 {packages => 'initramfs-tools',
1010 path => '/etc/initramfs-tools/conf.d/resume',
1011 list => \&initramfs_resume_list,
1012 update => \&initramfs_resume_update,
1013 # udev will source all files in this directory,
1014 # with few exceptions. Such as including a '^'.
1015 suffix => '^old'},
1016 {packages => 'uswsusp',
1017 path => '/etc/uswsusp.conf',
1018 list => \&uswsusp_resume_list,
1019 update => \&uswsusp_resume_update},
1020 {packages => 'cryptsetup',
1021 path => '/etc/crypttab',
1022 list => \&cryptsetup_list,
1023 update => \&cryptsetup_update},
1024 # mdadm.conf requires manual update because it may
1025 # contain wildcards.
1026 {packages => 'mdadm',
1027 path => '/etc/mdadm/mdadm.conf',
1028 list => \&mdadm_list},
1029 # hdparm.conf requires manual update because it
1030 # (1) refers to whole disks (2) might not work
1031 # properly with the new drivers (3) is in a very
1032 # special format.
1033 {packages => 'hdparm',
1034 path => '/etc/hdparm.conf',
1035 list => \&hdparm_list});
1036
1037 ### Filesystem labels and UUIDs
1038
1039 sub ext2_set_label {
1040 my ($bdev, $label) = @_;
1041 _system('tune2fs', '-L', $label, $bdev) == 0 or die "tune2fs failed: $?";
1042 }
1043 sub ext2_set_uuid {
1044 my ($bdev, $uuid) = @_;
1045 _system('tune2fs', '-U', $uuid, $bdev) == 0 or die "tune2fs failed: $?";
1046 }
1047
1048 sub jfs_set_label {
1049 my ($bdev, $label) = @_;
1050 _system('jfs_tune', '-L', $label, $bdev) == 0 or die "jfs_tune failed: $?";
1051 }
1052 sub jfs_set_uuid {
1053 my ($bdev, $uuid) = @_;
1054 _system('jfs_tune', '-U', $uuid, $bdev) == 0 or die "jfs_tune failed: $?";
1055 }
1056
1057 sub fat_set_label {
1058 my ($bdev, $label) = @_;
1059 _system('dosfslabel', $bdev, $label) == 0 or die "dosfslabel failed: $?";
1060 }
1061
1062 sub ntfs_set_label {
1063 my ($bdev, $label) = @_;
1064 _system('ntfslabel', $bdev, $label) == 0 or die "ntfslabel failed: $?";
1065 }
1066
1067 sub reiserfs_set_label {
1068 my ($bdev, $label) = @_;
1069 _system('reiserfstune', '--label', $label, $bdev)
1070 or die "reiserfstune failed: $?";
1071 }
1072 sub reiserfs_set_uuid {
1073 my ($bdev, $uuid) = @_;
1074 _system('reiserfstune', '--uuid', $uuid, $bdev)
1075 or die "reiserfstune failed: $?";
1076 }
1077
1078 # There is no command to relabel swap, and we mustn't run mkswap if
1079 # the partition is already in use. Thankfully the header format is
1080 # pretty simple; it starts with this structure:
1081 # struct swap_header_v1_2 {
1082 # char bootbits[1024]; /* Space for disklabel etc. */
1083 # unsigned int version;
1084 # unsigned int last_page;
1085 # unsigned int nr_badpages;
1086 # unsigned char uuid[16];
1087 # char volume_name[16];
1088 # unsigned int padding[117];
1089 # unsigned int badpages[1];
1090 # };
1091 # and has the signature 'SWAPSPACE2' at the end of the first page.
1092 use constant { SWAP_SIGNATURE => 'SWAPSPACE2',
1093 SWAP_UUID_OFFSET => 1036, SWAP_UUID_LEN => 16,
1094 SWAP_LABEL_OFFSET => 1052, SWAP_LABEL_LEN => 16 };
1095 sub _swap_set_field {
1096 my ($bdev, $offset, $value) = @_;
1097 my $pagesize = POSIX::sysconf(POSIX::_SC_PAGESIZE) or die "$!";
1098 my ($length, $signature);
1099
1100 my $fd = POSIX::open($bdev, POSIX::O_RDWR);
1101 defined($fd) or die "$!";
1102
1103 # Check the signature
1104 POSIX::lseek($fd, $pagesize - length(SWAP_SIGNATURE), POSIX::SEEK_SET);
1105 $length = POSIX::read($fd, $signature, length(SWAP_SIGNATURE));
1106 if (!defined($length) || $signature ne SWAP_SIGNATURE) {
1107 POSIX::close($fd);
1108 die "swap signature not found on $bdev";
1109 }
1110
1111 # Set the field
1112 POSIX::lseek($fd, $offset, POSIX::SEEK_SET);
1113 $length = POSIX::write($fd, $value, length($value));
1114 if (!defined($length) || $length != length($value)) {
1115 my $error = "$!";
1116 POSIX::close($fd);
1117 die $error;
1118 }
1119
1120 POSIX::close($fd);
1121 }
1122 sub swap_set_label {
1123 my ($bdev, $label) = @_;
1124 _swap_set_field($bdev, SWAP_LABEL_OFFSET, pack('Z' . SWAP_LABEL_LEN, $label));
1125 }
1126 sub swap_set_uuid {
1127 my ($bdev, $uuid) = @_;
1128 my $uuid_bin;
1129 if (UUID::parse($uuid, $uuid_bin) != 0 ||
1130 length($uuid_bin) != SWAP_UUID_LEN) {
1131 die "internal error: invalid UUID string";
1132 }
1133 _swap_set_field($bdev, SWAP_UUID_OFFSET, $uuid_bin);
1134 }
1135
1136 sub ufs_set_label {
1137 my ($bdev, $label) = @_;
1138 _system('tunefs.ufs', '-L', $label, $bdev) or die "tunefs.ufs failed: $?";
1139 }
1140
1141 sub xfs_set_label {
1142 my ($bdev, $label) = @_;
1143 _system('xfs_admin', '-L', $label, $bdev) or die "xfs_admin failed: $?";
1144 }
1145 sub xfs_set_uuid {
1146 my ($bdev, $uuid) = @_;
1147 _system('xfs_admin', '-U', $uuid, $bdev) or die "xfs_admin failed: $?";
1148 }
1149
1150 my %filesystem_types = (
1151 ext2 => { label_len => 16, set_label => \&ext2_set_label,
1152 set_uuid => \&ext2_set_uuid },
1153 ext3 => { label_len => 16, set_label => \&ext2_set_label,
1154 set_uuid => \&ext2_set_uuid },
1155 ext4 => { label_len => 16, set_label => \&ext2_set_label,
1156 set_uuid => \&ext2_set_uuid },
1157 jfs => { label_len => 16, set_label => \&jfs_set_label,
1158 set_uuid => \&jfs_set_uuid },
1159 msdos => { label_len => 11, set_label => \&fat_set_label },
1160 ntfs => { label_len => 128, set_label => \&ntfs_set_label },
1161 reiserfs => { label_len => 16, set_label => \&reiserfs_set_label,
1162 set_uuid => \&reiserfs_set_uuid },
1163 swap => { label_len => SWAP_LABEL_LEN, set_label => \&swap_set_label,
1164 set_uuid => \&swap_set_uuid },
1165 ufs => { label_len => 32, set_label => \&ufs_set_label },
1166 vfat => { label_len => 11, set_label => \&fat_set_label },
1167 xfs => { label_len => 12, set_label => \&xfs_set_label,
1168 set_uuid => \&xfs_set_uuid }
1169 );
1170
1171 my %bdev_map;
1172 my %id_map;
1173
1174 sub scan_config_files {
1175 my @configs;
1176
1177 # Find all IDE/SCSI disks mentioned in configurations
1178 for my $config (@config_files) {
1179 # Is the file present?
1180 my $path = $config->{path};
1181 if (!defined($path)) {
1182 next;
1183 }
1184 my $file = new FileHandle($path, 'r');
1185 if (!defined($file)) {
1186 if ($! == POSIX::ENOENT) {
1187 next;
1188 }
1189 die "$!";
1190 }
1191
1192 # Are any of the related packages wanted or installed?
1193 my $wanted = 0;
1194 my $installed = 0;
1195 my $packages = $config->{packages};
1196 for (`dpkg-query 2>/dev/null --showformat '\${status}\\n' -W $packages`)
1197 {
1198 $wanted = 1 if /^install /;
1199 $installed = 1 if / installed\n$/;
1200 }
1201 if (!$wanted && !$installed) {
1202 next;
1203 }
1204
1205 my @matched_bdevs = ();
1206 my $id_map_text;
1207 my $needs_update;
1208
1209 if (exists($config->{needs_update})) {
1210 $id_map_text = &{$config->{needs_update}}($file);
1211 $needs_update = defined($id_map_text) && $id_map_text ne '';
1212 } elsif (exists($config->{list})) {
1213 for my $bdev (&{$config->{list}}($file)) {
1214 # Match standard IDE and SCSI device names, plus wildcards
1215 # in disk device names to allow for mdadm insanity.
1216 if ($bdev =~ m{^/dev/(?:[hs]d[a-z\?\*][\d\?\*]*|
1217 s(?:cd|r)\d+)$}x &&
1218 ($bdev =~ m/[\?\*]/ || -b $bdev)) {
1219 $bdev_map{$bdev} = {};
1220 push @matched_bdevs, $bdev;
1221 }
1222 }
1223 $needs_update = @matched_bdevs > 0;
1224 } else {
1225 # Needs manual update
1226 $needs_update = 1;
1227 }
1228
1229 push @configs, {config => $config,
1230 devices => \@matched_bdevs,
1231 id_map_text => $id_map_text,
1232 installed => $installed,
1233 needs_update => $needs_update};
1234 }
1235
1236 my $fstab = new FileHandle('/etc/fstab', 'r') or die "$!";
1237 while (1) {
1238 my ($text, $bdev, $path, $type) = fstab_next($fstab);
1239 last unless defined($text);
1240 if (defined($type) && exists($bdev_map{$bdev})) {
1241 $bdev_map{$bdev}->{path} = $path;
1242 $bdev_map{$bdev}->{type} = $type;
1243 }
1244 }
1245 $fstab->close();
1246
1247 return @configs;
1248 }
1249
1250 sub add_tag {
1251 # Map disks to labels/UUIDs and vice versa. Include all disks in
1252 # the reverse mapping so we can detect ambiguity.
1253 my ($bdev, $name, $value, $new) = @_;
1254 my $id = "$name=$value";
1255 push @{$id_map{$id}}, $bdev;
1256 if (exists($bdev_map{$bdev})) {
1257 $bdev_map{$bdev}->{$name} = $value;
1258 push @{$bdev_map{$bdev}->{ids}}, $id;
1259 }
1260 if ($new) {
1261 $bdev_map{$bdev}->{new_id} = $id;
1262 }
1263 }
1264
1265 sub scan_devices {
1266 my $id_command;
1267 if (-x '/sbin/vol_id') {
1268 $id_command = '/sbin/vol_id';
1269 } else {
1270 $id_command = 'blkid -o udev -s LABEL -s UUID -s TYPE';
1271 }
1272 for (`blkid -o device`) {
1273 chomp;
1274 my $bdev = $_;
1275 for (`$id_command '$bdev'`) {
1276 if (/^ID_FS_(LABEL|UUID)_ENC=(.+)\n$/) {
1277 add_tag($bdev, $1, $2);
1278 } elsif (/^ID_FS_TYPE=(.+)\n$/ && exists($bdev_map{$bdev})) {
1279 $bdev_map{$bdev}->{type} //= $1;
1280 }
1281 }
1282 }
1283
1284 # Discard UUIDs for LVM2 PVs, as we assume there are symlinks for all
1285 # UUIDs under /dev/disk/by-uuid and this is not true for PVs.
1286 # Discard all labels and UUIDs(!) that are ambiguous.
1287 # Discard all labels with 'unsafe' characters (escaped by blkid using
1288 # backslashes) as they will not be usable in all configuration files.
1289 # Similarly for '#' which blkid surprisingly does not consider unsafe.
1290 # Sort each device's IDs in reverse lexical order so that UUIDs are
1291 # preferred.
1292 for my $bdev (keys(%bdev_map)) {
1293 if ($bdev_map{$bdev}->{type} eq 'LVM2_member') {
1294 @{$bdev_map{$bdev}->{ids}} = ();
1295 } else {
1296 @{$bdev_map{$bdev}->{ids}} =
1297 sort({$b cmp $a}
1298 grep({ @{$id_map{$_}} == 1 && $_ !~ /[\\#]/ }
1299 @{$bdev_map{$bdev}->{ids}}));
1300 }
1301 }
1302
1303 # Add persistent aliases for CD/DVD/BD drives
1304 my $cd_rules =
1305 new FileHandle('/etc/udev/rules.d/70-persistent-cd.rules', 'r');
1306 while (defined($cd_rules)) {
1307 my @keys = udev_next($cd_rules);
1308 last if $#keys < 0;
1309
1310 my ($path, $symlink) = udev_parse_symlink_rule(@keys);
1311 if (defined($path) && defined($symlink)) {
1312 $symlink =~ s{^(?!/)}{/dev/};
1313 my $bdev = readlink($symlink) or next;
1314 $bdev =~ s{^(?!/)}{/dev/};
1315 if (exists($bdev_map{$bdev})) {
1316 push @{$bdev_map{$bdev}->{ids}}, $symlink;
1317 }
1318 }
1319 }
1320 }
1321
1322 sub assign_new_ids {
1323 my $hostname = (POSIX::uname())[1];
1324
1325 # For all devices that have no alternate device ids, suggest setting
1326 # UUIDs, labelling them based on fstab or just using a generic label.
1327 for my $bdev (keys(%bdev_map)) {
1328 next if $#{$bdev_map{$bdev}->{ids}} >= 0;
1329
1330 my $type = $bdev_map{$bdev}->{type};
1331 next unless defined($type) && exists($filesystem_types{$type});
1332
1333 if (defined($filesystem_types{$type}->{set_uuid})) {
1334 my ($uuid_bin, $uuid);
1335 UUID::generate($uuid_bin);
1336 UUID::unparse($uuid_bin, $uuid);
1337 add_tag($bdev, 'UUID', $uuid, 1);
1338 next;
1339 }
1340
1341 my $label_len = $filesystem_types{$type}->{label_len};
1342 my $label;
1343 use bytes; # string lengths are in bytes
1344
1345 if (defined($bdev_map{$bdev}->{path})) {
1346 # Convert path/type to label; prepend hostname if possible;
1347 # append numeric suffix if necessary.
1348
1349 my $base;
1350 if ($bdev_map{$bdev}->{path} =~ m|^/|) {
1351 $base = $bdev_map{$bdev}->{path};
1352 } else {
1353 $base = $bdev_map{$bdev}->{type};
1354 }
1355 $base =~ s/[^\w]+/-/g;
1356 $base =~ s/^-//g;
1357 $base =~ s/-$//g;
1358
1359 my $n = 0;
1360 my $suffix = '';
1361 do {
1362 $label = "$hostname-$base$suffix";
1363 if (length($label) > $label_len) {
1364 $label = substr($base, 0, $label_len - length($suffix))
1365 . $suffix;
1366 }
1367 $n++;
1368 $suffix = "-$n";
1369 } while (exists($id_map{"LABEL=$label"}));
1370 } else {
1371 my $n = 0;
1372 my $suffix;
1373 do {
1374 $n++;
1375 $suffix = "-$n";
1376 $label = substr($hostname, 0, $label_len - length($suffix))
1377 . $suffix;
1378 } while (exists($id_map{"LABEL=$label"}));
1379 }
1380
1381 add_tag($bdev, 'LABEL', $label, 1);
1382 }
1383 }
1384
1385 sub set_new_ids {
1386 for my $bdev (keys(%bdev_map)) {
1387 my $bdev_info = $bdev_map{$bdev};
1388 if ($bdev_info->{new_id}) {
1389 my ($name, $value) = split(/=/, $bdev_info->{new_id}, 2);
1390 my $setter;
1391 if ($name eq 'UUID') {
1392 $setter = $filesystem_types{$bdev_info->{type}}->{set_uuid};
1393 } elsif ($name eq 'LABEL') {
1394 $setter = $filesystem_types{$bdev_info->{type}}->{set_label};
1395 }
1396 defined($setter) or die "internal error: invalid new_id type";
1397 &{$setter}($bdev, $value);
1398 }
1399 }
1400 }
1401
1402 sub update_config {
1403 my $map = shift;
1404
1405 for my $match (@_) {
1406 # Generate a new config
1407 my $path = $match->{config}->{path};
1408 my $old = new FileHandle($path, 'r') or die "$!";
1409 my $new = new FileHandle("$path.new", POSIX::O_WRONLY | POSIX::O_CREAT,
1410 0600)
1411 or die "$!";
1412 &{$match->{config}->{update}}($old, $new, $map);
1413 $old->close();
1414 $new->close();
1415
1416 # New config should have same permissions as the old
1417 my (undef, undef, $mode, undef, $uid, $gid) = stat($path) or die "$!";
1418 chown($uid, $gid, "$path.new") or die "$!";
1419 chmod($mode & 07777, "$path.new") or die "$!";
1420
1421 # Back up the old config and replace with the new
1422 my $old_path = $path . ($match->{config}->{suffix} || '.old');
1423 unlink($old_path);
1424 link($path, $old_path) or die "$!";
1425 rename("$path.new", $path) or die "$!";
1426
1427 # If the package is installed, run the post-update function
1428 if ($match->{installed} && $match->{config}->{post_update}) {
1429 &{$match->{config}->{post_update}}();
1430 }
1431 }
1432 }
1433
1434 sub transition {
1435 use Debconf::Client::ConfModule ':all';
1436
1437 %bdev_map = ();
1438 %id_map = ();
1439
1440 my @found_configs = scan_config_files();
1441 my @matched_configs = grep({$_->{needs_update}} @found_configs);
1442 my @auto_configs = grep({defined($_->{config}->{update})} @matched_configs);
1443 my $found_boot_loader =
1444 grep({$_->{config}->{is_boot_loader} && $_->{installed}} @found_configs);
1445 my %update_map = ();
1446
1447 # We can skip all of this if we didn't find any configuration
1448 # files that need conversion and we found the configuration file
1449 # for an installed boot loader.
1450 if (!@matched_configs && $found_boot_loader) {
1451 return;
1452 }
1453
1454 my ($question, $answer, $ret, $seen);
1455
1456 $question = 'linux-base/disk-id-convert-auto';
1457 ($ret, $seen) = input('high', $question);
1458 if ($ret && $ret != 30) {
1459 die "Error setting debconf question $question: $seen";
1460 }
1461 ($ret, $seen) = go();
1462 if ($ret && $ret != 30) {
1463 die "Error asking debconf question $question: $seen";
1464 }
1465 ($ret, $answer) = get($question);
1466 die "Error retrieving answer for $question: $answer" if $ret;
1467
1468 if (@auto_configs && $answer eq 'true') {
1469 scan_devices();
1470 assign_new_ids();
1471
1472 # Construct the device ID update map
1473 for my $bdev (keys(%bdev_map)) {
1474 if (@{$bdev_map{$bdev}->{ids}}) {
1475 $update_map{$bdev} = $bdev_map{$bdev}->{ids}->[0];
1476 }
1477 }
1478
1479 # Weed out configurations which will be unaffected by this
1480 # mapping or by a custom mapping described in id_map_text.
1481 @auto_configs = grep({ defined($_->{id_map_text}) ||
1482 grep({exists($update_map{$_})}
1483 @{$_->{devices}}) }
1484 @auto_configs);
1485 }
1486
1487 if (@auto_configs && $answer eq 'true') {
1488 if (grep({$bdev_map{$_}->{new_id}} keys(%bdev_map))) {
1489 $question = 'linux-base/disk-id-convert-plan';
1490 ($ret, $seen) = subst($question, 'relabel',
1491 join("\\n",
1492 map({sprintf("%s: %s",
1493 $_, $bdev_map{$_}->{new_id})}
1494 grep({$bdev_map{$_}->{new_id}}
1495 keys(%bdev_map)))));
1496 die "Error setting debconf substitutions in $question: $seen" if $ret;
1497 } else {
1498 $question = 'linux-base/disk-id-convert-plan-no-relabel';
1499 }
1500 ($ret, $seen) = subst($question, 'id_map',
1501 join("\\n",
1502 map({sprintf("%s: %s", $_, $update_map{$_})}
1503 keys(%update_map)),
1504 grep({defined}
1505 map({$_->{id_map_text}} @auto_configs))));
1506 die "Error setting debconf substitutions in $question: $seen" if $ret;
1507 ($ret, $seen) = subst($question, 'files',
1508 join(', ',
1509 map({$_->{config}->{path}} @auto_configs)));
1510 die "Error setting debconf substitutions in $question: $seen" if $ret;
1511 ($ret, $seen) = input('high', $question);
1512 if ($ret && $ret != 30) {
1513 die "Error setting debconf question $question: $seen";
1514 }
1515 ($ret, $seen) = go();
1516 if ($ret && $ret != 30) {
1517 die "Error asking debconf question $question: $seen";
1518 }
1519 ($ret, $answer) = get($question);
1520 die "Error retrieving answer for $question: $answer" if $ret;
1521
1522 if ($answer eq 'true') {
1523 set_new_ids();
1524 update_config(\%update_map, @auto_configs);
1525 }
1526 }
1527
1528 my @unconv_files = ();
1529 for my $match (@matched_configs) {
1530 if (!defined($match->{config}->{update})) {
1531 push @unconv_files, $match->{config}->{path};
1532 } else {
1533 my @unconv_bdevs = grep({!exists($update_map{$_})}
1534 @{$match->{devices}});
1535 if (@unconv_bdevs) {
1536 push @unconv_files, sprintf('%s: %s', $match->{config}->{path},
1537 join(', ',@unconv_bdevs));
1538 }
1539 }
1540 }
1541 if (@unconv_files) {
1542 $question = 'linux-base/disk-id-manual';
1543 ($ret, $seen) = subst($question, 'unconverted',
1544 join("\\n", @unconv_files));
1545 die "Error setting debconf substitutions in $question: $seen" if $ret;
1546 ($ret, $seen) = input('high', $question);
1547 if ($ret && $ret != 30) {
1548 die "Error setting debconf note $question: $seen";
1549 }
1550 ($ret, $seen) = go();
1551 if ($ret && $ret != 30) {
1552 die "Error showing debconf note $question: $seen";
1553 }
1554 }
1555
1556 # Also note whether some (unknown) boot loader configuration file
1557 # must be manually converted.
1558 if (!$found_boot_loader) {
1559 $question = 'linux-base/disk-id-manual-boot-loader';
1560 ($ret, $seen) = input('high', $question);
1561 if ($ret && $ret != 30) {
1562 die "Error setting debconf note $question: $seen";
1563 }
1564 ($ret, $seen) = go();
1565 if ($ret && $ret != 30) {
1566 die "Error showing debconf note $question: $seen";
1567 }
1568 }
1569 }
1570
1571 package main;
1572
1573 capb('escape');
1574
1575 sub compare_versions {
1576 return $AptPkg::Config::_config->system->versioning->compare(@_);
1577 }
1578
1579 # No upgrade work is necessary during a fresh system installation.
1580 # But since linux-base is a new dependency of linux-image-* and did
1581 # not exist until needed for the libata transition, we cannot simply
1582 # test whether this is a fresh installation of linux-base. Instead,
1583 # we test:
1584 # - does /etc/fstab exist yet (this won't even work without it), and
1585 # - are any linux-image-* packages installed yet?
1586 sub is_fresh_installation {
1587 if (-f '/etc/fstab') {
1588 for (`dpkg-query 2>/dev/null --showformat '\${status}\\n' -W 'linux-image-*'`) {
1589 return 0 if / installed\n$/;
1590 }
1591 }
1592 return 1;
1593 }
1594
1595 my $deb_arch = `dpkg --print-architecture`;
1596 chomp $deb_arch;
1597
1598 if ($deb_arch ne 's390') {
1599 my $libata_transition_ver =
1600 ($deb_arch eq 'i386' || $deb_arch eq 'amd64') ? '2.6.32-10' : '2.6.32-11';
1601 if ($ARGV[0] eq 'reconfigure' || defined($ENV{DEBCONF_RECONFIGURE}) ||
1602 (!is_fresh_installation() &&
1603 compare_versions($ARGV[1], $libata_transition_ver) < 0)) {
1604 DebianKernel::DiskId::transition();
1605 }
1606 }
1607
1608 exec("set -e\nset -- @ARGV\n" . << 'EOF');
1609 #DEBHELPER#
1610 EOF

  ViewVC Help
Powered by ViewVC 1.1.5